commit 50b48aec6ddd451a6d1709c0942477b503457663 Author: tpearson Date: Wed Feb 3 02:15:56 2010 +0000 Added abandoned KDE3 version of K3B git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/k3b@1084400 283d02a7-25f6-0310-bc7c-ecb5cbfe19da diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..8363f0c --- /dev/null +++ b/AUTHORS @@ -0,0 +1,2 @@ +Sebastian Trueg +Christian Kvasny diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..034359f --- /dev/null +++ b/COPYING @@ -0,0 +1,280 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) 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 +this service 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 make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. 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. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +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 +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the 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 a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE 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. + + END OF TERMS AND CONDITIONS diff --git a/COPYING-DOCS b/COPYING-DOCS new file mode 100644 index 0000000..4a0fe1c --- /dev/null +++ b/COPYING-DOCS @@ -0,0 +1,397 @@ + GNU Free Documentation License + Version 1.2, November 2002 + + + Copyright (C) 2000,2001,2002 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + +0. PREAMBLE + +The purpose of this License is to make a manual, textbook, or other +functional and useful document "free" in the sense of freedom: to +assure everyone the effective freedom to copy and redistribute it, +with or without modifying it, either commercially or noncommercially. +Secondarily, this License preserves for the author and publisher a way +to get credit for their work, while not being considered responsible +for modifications made by others. + +This License is a kind of "copyleft", which means that derivative +works of the document must themselves be free in the same sense. It +complements the GNU General Public License, which is a copyleft +license designed for free software. + +We have designed this License in order to use it for manuals for free +software, because free software needs free documentation: a free +program should come with manuals providing the same freedoms that the +software does. But this License is not limited to software manuals; +it can be used for any textual work, regardless of subject matter or +whether it is published as a printed book. We recommend this License +principally for works whose purpose is instruction or reference. + + +1. APPLICABILITY AND DEFINITIONS + +This License applies to any manual or other work, in any medium, that +contains a notice placed by the copyright holder saying it can be +distributed under the terms of this License. Such a notice grants a +world-wide, royalty-free license, unlimited in duration, to use that +work under the conditions stated herein. The "Document", below, +refers to any such manual or work. Any member of the public is a +licensee, and is addressed as "you". You accept the license if you +copy, modify or distribute the work in a way requiring permission +under copyright law. + +A "Modified Version" of the Document means any work containing the +Document or a portion of it, either copied verbatim, or with +modifications and/or translated into another language. + +A "Secondary Section" is a named appendix or a front-matter section of +the Document that deals exclusively with the relationship of the +publishers or authors of the Document to the Document's overall subject +(or to related matters) and contains nothing that could fall directly +within that overall subject. (Thus, if the Document is in part a +textbook of mathematics, a Secondary Section may not explain any +mathematics.) The relationship could be a matter of historical +connection with the subject or with related matters, or of legal, +commercial, philosophical, ethical or political position regarding +them. + +The "Invariant Sections" are certain Secondary Sections whose titles +are designated, as being those of Invariant Sections, in the notice +that says that the Document is released under this License. If a +section does not fit the above definition of Secondary then it is not +allowed to be designated as Invariant. The Document may contain zero +Invariant Sections. If the Document does not identify any Invariant +Sections then there are none. + +The "Cover Texts" are certain short passages of text that are listed, +as Front-Cover Texts or Back-Cover Texts, in the notice that says that +the Document is released under this License. A Front-Cover Text may +be at most 5 words, and a Back-Cover Text may be at most 25 words. + +A "Transparent" copy of the Document means a machine-readable copy, +represented in a format whose specification is available to the +general public, that is suitable for revising the document +straightforwardly with generic text editors or (for images composed of +pixels) generic paint programs or (for drawings) some widely available +drawing editor, and that is suitable for input to text formatters or +for automatic translation to a variety of formats suitable for input +to text formatters. A copy made in an otherwise Transparent file +format whose markup, or absence of markup, has been arranged to thwart +or discourage subsequent modification by readers is not Transparent. +An image format is not Transparent if used for any substantial amount +of text. A copy that is not "Transparent" is called "Opaque". + +Examples of suitable formats for Transparent copies include plain +ASCII without markup, Texinfo input format, LaTeX input format, SGML +or XML using a publicly available DTD, and standard-conforming simple +HTML, PostScript or PDF designed for human modification. Examples of +transparent image formats include PNG, XCF and JPG. Opaque formats +include proprietary formats that can be read and edited only by +proprietary word processors, SGML or XML for which the DTD and/or +processing tools are not generally available, and the +machine-generated HTML, PostScript or PDF produced by some word +processors for output purposes only. + +The "Title Page" means, for a printed book, the title page itself, +plus such following pages as are needed to hold, legibly, the material +this License requires to appear in the title page. For works in +formats which do not have any title page as such, "Title Page" means +the text near the most prominent appearance of the work's title, +preceding the beginning of the body of the text. + +A section "Entitled XYZ" means a named subunit of the Document whose +title either is precisely XYZ or contains XYZ in parentheses following +text that translates XYZ in another language. (Here XYZ stands for a +specific section name mentioned below, such as "Acknowledgements", +"Dedications", "Endorsements", or "History".) To "Preserve the Title" +of such a section when you modify the Document means that it remains a +section "Entitled XYZ" according to this definition. + +The Document may include Warranty Disclaimers next to the notice which +states that this License applies to the Document. These Warranty +Disclaimers are considered to be included by reference in this +License, but only as regards disclaiming warranties: any other +implication that these Warranty Disclaimers may have is void and has +no effect on the meaning of this License. + + +2. VERBATIM COPYING + +You may copy and distribute the Document in any medium, either +commercially or noncommercially, provided that this License, the +copyright notices, and the license notice saying this License applies +to the Document are reproduced in all copies, and that you add no other +conditions whatsoever to those of this License. You may not use +technical measures to obstruct or control the reading or further +copying of the copies you make or distribute. However, you may accept +compensation in exchange for copies. If you distribute a large enough +number of copies you must also follow the conditions in section 3. + +You may also lend copies, under the same conditions stated above, and +you may publicly display copies. + + +3. COPYING IN QUANTITY + +If you publish printed copies (or copies in media that commonly have +printed covers) of the Document, numbering more than 100, and the +Document's license notice requires Cover Texts, you must enclose the +copies in covers that carry, clearly and legibly, all these Cover +Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on +the back cover. Both covers must also clearly and legibly identify +you as the publisher of these copies. The front cover must present +the full title with all words of the title equally prominent and +visible. You may add other material on the covers in addition. +Copying with changes limited to the covers, as long as they preserve +the title of the Document and satisfy these conditions, can be treated +as verbatim copying in other respects. + +If the required texts for either cover are too voluminous to fit +legibly, you should put the first ones listed (as many as fit +reasonably) on the actual cover, and continue the rest onto adjacent +pages. + +If you publish or distribute Opaque copies of the Document numbering +more than 100, you must either include a machine-readable Transparent +copy along with each Opaque copy, or state in or with each Opaque copy +a computer-network location from which the general network-using +public has access to download using public-standard network protocols +a complete Transparent copy of the Document, free of added material. +If you use the latter option, you must take reasonably prudent steps, +when you begin distribution of Opaque copies in quantity, to ensure +that this Transparent copy will remain thus accessible at the stated +location until at least one year after the last time you distribute an +Opaque copy (directly or through your agents or retailers) of that +edition to the public. + +It is requested, but not required, that you contact the authors of the +Document well before redistributing any large number of copies, to give +them a chance to provide you with an updated version of the Document. + + +4. MODIFICATIONS + +You may copy and distribute a Modified Version of the Document under +the conditions of sections 2 and 3 above, provided that you release +the Modified Version under precisely this License, with the Modified +Version filling the role of the Document, thus licensing distribution +and modification of the Modified Version to whoever possesses a copy +of it. In addition, you must do these things in the Modified Version: + +A. Use in the Title Page (and on the covers, if any) a title distinct + from that of the Document, and from those of previous versions + (which should, if there were any, be listed in the History section + of the Document). You may use the same title as a previous version + if the original publisher of that version gives permission. +B. List on the Title Page, as authors, one or more persons or entities + responsible for authorship of the modifications in the Modified + Version, together with at least five of the principal authors of the + Document (all of its principal authors, if it has fewer than five), + unless they release you from this requirement. +C. State on the Title page the name of the publisher of the + Modified Version, as the publisher. +D. Preserve all the copyright notices of the Document. +E. Add an appropriate copyright notice for your modifications + adjacent to the other copyright notices. +F. Include, immediately after the copyright notices, a license notice + giving the public permission to use the Modified Version under the + terms of this License, in the form shown in the Addendum below. +G. Preserve in that license notice the full lists of Invariant Sections + and required Cover Texts given in the Document's license notice. +H. Include an unaltered copy of this License. +I. Preserve the section Entitled "History", Preserve its Title, and add + to it an item stating at least the title, year, new authors, and + publisher of the Modified Version as given on the Title Page. If + there is no section Entitled "History" in the Document, create one + stating the title, year, authors, and publisher of the Document as + given on its Title Page, then add an item describing the Modified + Version as stated in the previous sentence. +J. Preserve the network location, if any, given in the Document for + public access to a Transparent copy of the Document, and likewise + the network locations given in the Document for previous versions + it was based on. These may be placed in the "History" section. + You may omit a network location for a work that was published at + least four years before the Document itself, or if the original + publisher of the version it refers to gives permission. +K. For any section Entitled "Acknowledgements" or "Dedications", + Preserve the Title of the section, and preserve in the section all + the substance and tone of each of the contributor acknowledgements + and/or dedications given therein. +L. Preserve all the Invariant Sections of the Document, + unaltered in their text and in their titles. Section numbers + or the equivalent are not considered part of the section titles. +M. Delete any section Entitled "Endorsements". Such a section + may not be included in the Modified Version. +N. Do not retitle any existing section to be Entitled "Endorsements" + or to conflict in title with any Invariant Section. +O. Preserve any Warranty Disclaimers. + +If the Modified Version includes new front-matter sections or +appendices that qualify as Secondary Sections and contain no material +copied from the Document, you may at your option designate some or all +of these sections as invariant. To do this, add their titles to the +list of Invariant Sections in the Modified Version's license notice. +These titles must be distinct from any other section titles. + +You may add a section Entitled "Endorsements", provided it contains +nothing but endorsements of your Modified Version by various +parties--for example, statements of peer review or that the text has +been approved by an organization as the authoritative definition of a +standard. + +You may add a passage of up to five words as a Front-Cover Text, and a +passage of up to 25 words as a Back-Cover Text, to the end of the list +of Cover Texts in the Modified Version. Only one passage of +Front-Cover Text and one of Back-Cover Text may be added by (or +through arrangements made by) any one entity. If the Document already +includes a cover text for the same cover, previously added by you or +by arrangement made by the same entity you are acting on behalf of, +you may not add another; but you may replace the old one, on explicit +permission from the previous publisher that added the old one. + +The author(s) and publisher(s) of the Document do not by this License +give permission to use their names for publicity for or to assert or +imply endorsement of any Modified Version. + + +5. COMBINING DOCUMENTS + +You may combine the Document with other documents released under this +License, under the terms defined in section 4 above for modified +versions, provided that you include in the combination all of the +Invariant Sections of all of the original documents, unmodified, and +list them all as Invariant Sections of your combined work in its +license notice, and that you preserve all their Warranty Disclaimers. + +The combined work need only contain one copy of this License, and +multiple identical Invariant Sections may be replaced with a single +copy. If there are multiple Invariant Sections with the same name but +different contents, make the title of each such section unique by +adding at the end of it, in parentheses, the name of the original +author or publisher of that section if known, or else a unique number. +Make the same adjustment to the section titles in the list of +Invariant Sections in the license notice of the combined work. + +In the combination, you must combine any sections Entitled "History" +in the various original documents, forming one section Entitled +"History"; likewise combine any sections Entitled "Acknowledgements", +and any sections Entitled "Dedications". You must delete all sections +Entitled "Endorsements". + + +6. COLLECTIONS OF DOCUMENTS + +You may make a collection consisting of the Document and other documents +released under this License, and replace the individual copies of this +License in the various documents with a single copy that is included in +the collection, provided that you follow the rules of this License for +verbatim copying of each of the documents in all other respects. + +You may extract a single document from such a collection, and distribute +it individually under this License, provided you insert a copy of this +License into the extracted document, and follow this License in all +other respects regarding verbatim copying of that document. + + +7. AGGREGATION WITH INDEPENDENT WORKS + +A compilation of the Document or its derivatives with other separate +and independent documents or works, in or on a volume of a storage or +distribution medium, is called an "aggregate" if the copyright +resulting from the compilation is not used to limit the legal rights +of the compilation's users beyond what the individual works permit. +When the Document is included in an aggregate, this License does not +apply to the other works in the aggregate which are not themselves +derivative works of the Document. + +If the Cover Text requirement of section 3 is applicable to these +copies of the Document, then if the Document is less than one half of +the entire aggregate, the Document's Cover Texts may be placed on +covers that bracket the Document within the aggregate, or the +electronic equivalent of covers if the Document is in electronic form. +Otherwise they must appear on printed covers that bracket the whole +aggregate. + + +8. TRANSLATION + +Translation is considered a kind of modification, so you may +distribute translations of the Document under the terms of section 4. +Replacing Invariant Sections with translations requires special +permission from their copyright holders, but you may include +translations of some or all Invariant Sections in addition to the +original versions of these Invariant Sections. You may include a +translation of this License, and all the license notices in the +Document, and any Warranty Disclaimers, provided that you also include +the original English version of this License and the original versions +of those notices and disclaimers. In case of a disagreement between +the translation and the original version of this License or a notice +or disclaimer, the original version will prevail. + +If a section in the Document is Entitled "Acknowledgements", +"Dedications", or "History", the requirement (section 4) to Preserve +its Title (section 1) will typically require changing the actual +title. + + +9. TERMINATION + +You may not copy, modify, sublicense, or distribute the Document except +as expressly provided for under this License. Any other attempt to +copy, modify, sublicense or distribute the Document is void, and will +automatically terminate your rights under this License. However, +parties who have received copies, or rights, from you under this +License will not have their licenses terminated so long as such +parties remain in full compliance. + + +10. FUTURE REVISIONS OF THIS LICENSE + +The Free Software Foundation may publish new, revised versions +of the GNU Free Documentation 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. See +http://www.gnu.org/copyleft/. + +Each version of the License is given a distinguishing version number. +If the Document specifies that a particular numbered version of this +License "or any later version" applies to it, you have the option of +following the terms and conditions either of that specified version or +of any later version that has been published (not as a draft) by the +Free Software Foundation. If the Document does not specify a version +number of this License, you may choose any version ever published (not +as a draft) by the Free Software Foundation. + + +ADDENDUM: How to use this License for your documents + +To use this License in a document you have written, include a copy of +the License in the document and put the following copyright and +license notices just after the title page: + + Copyright (c) YEAR YOUR NAME. + Permission is granted to copy, distribute and/or modify this document + under the terms of the GNU Free Documentation License, Version 1.2 + or any later version published by the Free Software Foundation; + with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. + A copy of the license is included in the section entitled "GNU + Free Documentation License". + +If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, +replace the "with...Texts." line with this: + + with the Invariant Sections being LIST THEIR TITLES, with the + Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST. + +If you have Invariant Sections without Cover Texts, or some other +combination of the three, merge those two alternatives to suit the +situation. + +If your document contains nontrivial examples of program code, we +recommend releasing these examples in parallel under your choice of +free software license, such as the GNU General Public License, +to permit their use in free software. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..c4477a1 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,743 @@ +1.0.5 +===== + * Fix CD Copy device selection (Bug 151924) + * Fixed HAL mounting (thanks to Ken Milmore) + * Always wait for the drive to become ready before starting verification. + +1.0.4 +===== + * Never use growisofs parameter -dvd-compat with DVD-RW media in restricted overwrite mode + * Unmount medium before DVD formatting + * Silently (without introducing new strings for translation) allow the burning of files + bigger than 4 GB with appropriate versions of genisoimage or mkisofs. + * Do only reload the medium before verification if necessary, i.e. if the newly written + track cannot be read otherwise (many old drives depend on this). Hopefully this will + at least work around the aweful "DMA disabled" bug for many users. + +1.0.3 +===== + * Reverted to old behaviour of reloading medium before verification. Not enough + testing had been done before introducing this and some systems fail to read the + medium before reload (Bugs 147297, 147328, 147420, 147698). + * Do not crash when the currently playing audio project item is removed (Bug 147548). + * Added desktop actions to handle empty media with K3b. + * Fixed read retry when reading data tracks (Bug 147778) + * K3b's dialogs now honor the global button layout setting (Bug 147799) + * Do not crash on mp3 files without tags if compiled with taglib support (Bug 142651) + * Do not allow to copy a rewritable media to itself. + * Fixed crash on startup with devices that return bogus GET PERFORMANCE data (Bug 147676) + +1.0.2 +===== + * Properly determine the capacity of complete CD-R(W) media. + * Mark a data project as modified if files are renamed. + * Allow adding of all actions to the welcome window (Bug 145866) + * Added "NoDisplay=true" property to k3b-cue.desktop and k3b-iso.desktop + * Fixed supported write speed detection on some devices + * No reload before verification and between writing sessions (CD copy + Mixed Mode CD) anymore + +1.0.1 +===== + * Fixed crash when using the Device menu without a selected device. + * Fixed DVD copy when reading from a DVD+RW. + * Fixed --without-alsa configure check + * Fixed a crash in Video DVD ripping when the title does not contain an audio stream + * Only use the mkisofs parameters -biblio, -copyright, and -abstract if they have been set. Using them + with invalid values (empty) seems to result in broken iso images sometimes. + * Better compatibility with recent transcode development branch + * Fixed Multisession import size handling. + * Fixed Lame quality preset handling. + * Made libk3bdevice really thread-safe. This fixes the disabled DMA bug! + * New configure check --without-cdrecord-suid-root to disable K3b's check for cdrecord permissions. + Although not recommended it is requested by many distributors. + * Changed the order of the buttons in the tool dialogs to match the KDE order. + * Added handling of the newly introduced genisoimage parameter -allow-limited-size + * Make the K3b Sox audio encoder plugin work with newer sox versions (Thanks, Stephan.) + +1.0 +=== + * K3b now includes a VideoDVD kio slave. It can be used in Konqueror through the protocol videodvd:/ + to copy the files from a VideoDVD with on-the-fly decryption if libdvdcss is installed. + (Be aware that in some countries it is not permitted to use libdvdcss.) + * New Device menu containing all the actions possible for a device (like eject, unmount, ...). + This includes the possibility of assigning shortcuts to these kind of actions. + * K3b now warns if user parameters for external programs have been specified. This has been introduced + because there were some bug report that were caused by faulty user parameters. + * Cleaned up all the job classes: No job creates a widget anymore. This allows for non-GUI usage of libk3b. + For example in a kioslave. + * New option in the data project to not cache the inodes. That means it is possible to have multiple + actual copies of the same file on one CD/DVD. + * K3b now tries to disable stuff that might influence the burning process. This includes the KDED module + mediamanager, SuSEPlugger, and automounting (currently supported: subfs, supermount). + * New Audio Track source editor dialog to cut audio track sources at the beginning and the end. + * Splitted "read retries" and "ignore read errors" for data and audio sectors in cd copy and set new + defaults for audio sectors which make more sense: 5 retires and skip unreadable sectors. + * New Mediamanager which makes K3b always know which device contains which medium. This makes medium handling + more smooth and the user now selects a medium instead of a device. + Other advantages: + - No waiting time anymore when asking for information on media (including for example Audio CD ripping). + - Nice default image filenames. + - CD Copy: Enable/disable options based on the source medium + - Automatically select newly inserted media as burning medium + * DCOP call directBurn() now returns a boolean value stating if the process could be started. + * New DCOP calls cddaRip(), videocdrip(), and videodvdrip() with media:/ url support. + * K3b can now handle media:/ urls from the command line to specify devices + * Better Lame settings dialog. Easier to use for the novice user and better defaults. + * Nicer Ogg Vorbis encoder settings dialog. + * K3b now shows the DVD Medium ID in the disk information view. + * K3b now displays a rough estimate on the remaining time for the current job. + * New automatic media size mode for the projects. This means K3b uses the size from an inserted medium + for the project maximum size. + * Make a suggestion for the filename when saving a project based on the Volume ID (data projects) or the + CD-Text title (Audio CD) + * The Audio encoder plugins are now able to provide (very simplistic) user feedback in case of an error. + * New settings "Swap byte order" and "Write Wave header" in the audio encoding plugin using external apps. + This makes way for the usage of such programs as mppenc to encode Musepack files. In fact, mppenc is set up + as a default along with flac if installed. + * New DCOP interface: K3bJobInterface which provides DCOP signals for the currently running job. It may, + for example, be used to provide information to a Karamba module. + * New KFile plugin for K3b projects. For now it only shows the type of the project (Data DVD or Audio CD or ...) + but may be extended to show arbitrary information. + * K3b now chooses default image names based on the project name or the volumeid/cdtext title in case of + CD/DVD copy. + * The K3b Project DCOP Interface now uses the QString type for url parameters instead of KURL. + * Save/load audio cd track sources in audio projects + * Display a beautified volume id. For example: THE_TRANSPORTER -> The Transporter + * Check if the image directory exists before starting to create a project image + * Possibility to hide the OSD temporarily for one process. + * Completely rewritten Video DVD ripping and transcoding support: + - Simple on-the-fly transcoding of Video DVD titles + - Interface similar to Audio CD ripping + - Preview images in the ripping window + - Automatic clipping + - Simple resizing with automatic aspect ratio handling + * File System presets for all data projects including all the advanced options. + * Completely rewritten data project verification + - K3b now compares the written image instead of the single files + - Verification of Video DVD projects + * Little GUI changes: + - Changed the dialog layout in the action dialogs. + - Simplified the layout of the burn dialogs for data projects (more advanced settings hidden) + - Improved theme support (transparent themes) + * Device buffer status display for DVD burning with growisofs >= 7.0 + * Support for Audio CD ripping with libcdio instead of libcdparanoia + * Support for Cdrkit, the Debian fork of cdrtools + +0.12.17 +======= + * Fixed saving/loading of the file view configuration. + * Improved ffmpeg autoconf check. + * More FreeBSD Compile fixes (thanks to Heiner Eichmann). + * Fixed symbolic link handling in data projects (a bug introduced in 0.12.16) + * Use UTF-8 encoding to store and load local CDDB entries. + * Never use growisofs parameter -dvd-compat with DVD+RW media. + * Fixed flac audio encoding for the audio project conversion feature. + +0.12.16 +======= + * FreeBSD Compile fixes (thanks to Heiner Eichmann). + * Always force 44.1khz in the Lame MP3 encoder plugin. + * Fixed VideoDVD creation on rewritable media. + * NetBSD support (thanks to Mark Davies). + * Fixed Copy of Enhanced Audio CDs with CD-Text + * Changed default boot cataloge name from "boot.cataloge" to "boot.catalog" + * Fixed a crash when reusing the same DVD Iso Image writing dialog. + * Ignore case when comparing MD5 sums entered by the user. + * Make sure that filenames in a data project's folder are unique. + * Allow index statements bigger than 99 minutes in cue files. + * Properly set the length of SCSI commands (this fixes some device detection problems). + +0.12.15 +======= + * Write more metadata tags in the default setup of the external encoder plugin. + * Fixed on-the-fly Video DVD creation + * Fixed data project verification in case filenames had to be shortened due to Joliet limitations. + * Use -dvd-compat parameter to close DVDs in on-the-fly mode. + * Fixed libdvdcss handling (again), no crashes anymore. + * Fixed the "invalid url" bug. + * Use SG IO for scsi commands with newer linux kernels. This should fix problems with scsi device + detection. + * Warn about shortened filenames due to Joliet restrictions before starting the burning process. + +0.12.14 +======= + * Make sure new projects are not already marked as modified. + * Fixed (hopefully) the last bug related to Data project verification. + +0.12.13 +======= + * Honor umask when creating directories for Audio CD ripping. + * Only update the buffer state for DVD burning if it really changes. + * Fixed a crash in verification if the CD/DVD does not contain RR extensions. + * Lowered default DVD writing buffer size to 32 MB to avoid "memorylock limit" problems + as described on http://fy.chalmers.se/~appro/linux/DVD+RW/tools/ + * Fixed loading of libdvdcss. + +0.12.12 +======= + * Fixed another bug in the iso options code which sometimes resulted in a failed verification. + * Properly close the reading device when copying VideoDVDs. This bug resulted in a blocked device. + * Fixed handling of filenames in libdvdcss backend (this fixes VideoDVD copy). + +0.12.11 +======= + * Fixed selection in the audio CD ripping window. + * Fixed info block handling in WAVE audio file decoder: no more clicks at the end. + * Introduced a hack which fixes the "Wav detected as Mpeg file" bug. + * Fixed Auto multisession mode for DVD+RW and DVD-RW in restricted overwrite mode in case + a previous session was imported. + * Fixed a crash with HAL >= 0.5 when exiting K3b. + * Allow copying of double layer DVDs with a size below 4.3 GB to single layer media. + * Support for the ring buffer in growisofs 6.0. + * Use .iso extension for images instead of .img + * Properly remove the image file in case verification failed. + * Ignore mounting state of a medium when showing its contents. + * Fixed a bug in the iso options code which sometimes resulted in a failed verification. + * Properly handle cue files withan image file name like image.bin.cue + image.bin + * Write a proper Xing header when encoding VBR mp3 files. + +0.12.10 +======= + * Fixed Auto multisession mode in DVD projects + * Fixed crash in dcop call directBurn in case no valid burner device was set. + * Fixed verification of datacd projects when using the MaxIso9660 option without the OmitVersionNumber option + +0.12.9 +====== + * New project dcop calls: + directBurn() - directly starts the burn process without user interaction + setBurnDevice(QString) - set the burn device to be used + * Disable the cd-text fields if cd-text writing is disabled. + * New Alsa audio output plugin. + * If a DVD project does not fill up the DVD completely do not close the DVD in automatic + multisession mode. + * Fixed problems with filenames ending in backslashes. + * Fixed verification problems with localized characters. + * Added error handling for incorrectly encoded filenames. + * Automatically use a newly installed version of an external application at the next K3b start. + * Complete new set of K3b action icons for project types and tools. Many thanks to Marcel Dierkes. + * Show text on the burn button to make it catch the eye. + * Support for media:// urls in the Image writing dialogs. + * Fixed problems with files bigger than 2 GB on some systems. + +0.12.8 +====== + * Load index0 value in audio project. + * Ignore case in cue files. + * The "eject media" setting was not used properly in some situations (thanks to simon@munton.demon.co.uk for the patch) + * Fixed a bug in the mp3 decoder which caused it to miss some perfectly valid mp3 files. + +0.12.7 +====== + * Fixed crash when refreshing the device list. + * Fixed cancellation of adding files to a data project. + * Fixed on-the-fly data project burning. + * Backported a warning about following links to folders (K3b cannot do that after the link has + been added to the project). + +0.12.6 +====== + * Copy XA Form1 tracks always in TAO writing mode. + * Support for media:/ urls. + * No extra whitespace when renaming audio files in a data project anymore. + * Fixed verification of multisession CDs (thanks to simon@munton.demon.co.uk) + * Preserve directory access time in data projects when using the "backup" option. + * Disable the "audio normalization" option in case the normalize program is not installed. + +0.12.5 +====== + * Fixed the progressbar in the file view + * It is possible to add the "New Data DVD Project" button to the welcome window again. + * Fixed problems with unreadable items when using a non-standard color scheme + * Properly set the permissions on cdrecord versions >= 2.01.01a02 + * Fixed the "Disabled start button in Copy dialog" bug. + * Little window layout fix in K3bSetup2. + * Always use sector size 2048 when only creating an image in CD Copy. This means extracted + iso images from CDs with non-Mode1 tracks are useable again. + * Preserve directory permissions and user/group id in data projects when using the "backup" option. + +0.12.4 +====== + * Fixed --cdimage and --dvdimage parameters. + * Fixed the file browser menu. Now it contains the bookmarks and "add to project" actions again. + * Fixed Index 0 (Pregap) handling in audio cue files. + * Improved handling of broken cue files: K3b now searches the directory for image files that could fit + the cue file in case the FILE entry is bogus. + * Always try to create a new session in case the old one has been imported regardless of the inserted + medium's free space. + * Fixed DVD-RW Restricted Overwrite media handling + * Use RAW writing mode for audio CDs in case the writer does not support DAO but RAW. + * Fixed compile problems with latest ffmpeg builds. + +0.12.3 +====== + * Ignore dock config from K3b versions older than 0.12 + * Do not delete DVD project iso image if "remove image" is unchecked. + * Properly load multisession default settings. + * Update device selection boxes when devices are added or removed via HAL. + * Properly cancel DVD project writing. + * Fixed DVD+RW session import + +0.12.2 +====== + * After for example copying a CD when the dialog comes up again keep the last settings. + * Default to incremental sequential writing mode when copying a DVD to a DVD-R. + * Fixed a crash when the DVD copy dialog is reused. + * Fixed inline editing in the audio CD view (without bigger changes this only works with a + rather strange selection mode.) + * Show the configured splash screen image instead of the default. + * Fixed eMovix 0.9 default settings handling. + * Import session: disable RockRidge if the previous session does not contain RR extensions. + This fixes the problem with strange filenames if the new session is mounted via RR. + * Fixed the --cdimage parameter. + * Changed max copies from 99 to 999. + * Improved session import dialog. + * Properly default to DVD size in Video DVD project. + * Fixed automatic multisession handling for DVD+RW media. + * Fixed handbook installation. + * Fixed HAL backend: devices are properly removed now. + * Ignore K3b Themes that do not follow the new filename scheme. + +0.12.1 +Fixed compilation problems with older musepack library version. +Fixed compile problem with older gcc versions. +Enable verification checkbox for ISO9660 images in the CD writing dialog. +Do not report success even if audio project conversion failed. + +0.12 +Added "Mpeg Still" support to Video-CD Project +FreeBSD support (thanks to Adriaan De Groot) +Support for all global CD-Text fields with cdrecord. +Some GUI changes: cleaned up the action dialogs, moved the burnfree option to the global settings dialog + since turning it off should be a very seldomly used task. +Added support for multiple copies to the projects. +Added missed VCD 3.0 track interpretation option for SVCD's +New Lame encoding plugin providing a proper configuration dialog. +Added Bookmarks to the file browser. +Fixed window layering problem with windowmanagers != kwm +Added KPart plugin which converts a list of audio files into one of the supported encoder formats. +Allow disabling of CD-Text reading in cd-copy to overcome problems with CD-Text on some drives. +Check CD-Text crc when copying +Fixed incorrect PBC order, PBC now should work on all "standalone" DVD Players +Fixed waittime bug for PBC infinite timeout. +Import Audio Cue files into an audio project. +It is now possible to open an iso image or an audio cue file just like a project file. +Create cue files for an audio CD ripped into one single file +Show writer buffer state in addition to fifo buffer when writing CDs. +Show device buffer state for DVD writing (does not work always yet) +Fixed read and save setting in VideoCD project. +Big parts of the audio project have been rewritten to have a way better design: + - K3b now does not create additional silence between the tracks by default + the pregap is treated as part of the previous track like in all other + writing applications. + - Instead it's possible to add additional silence manually to a track. + - Allow multible sources for one track. + - Split tracks, merge tracks. + - Improved track dialog. +K3b now always writes a logfile in $(KDEHOME)/share/apps/k3b/lastlog.log +New device configuration format which solves all issues with removable devices like USB. +Copy CSS encrypted DVDs if libdvdcss is installed. +Libsndfile decoder plugin. This includes support for AIFF audio files. +ffmpeg decoder plugin. This includes support for wma audio files. +Musepack audio decoder plugin. +Use DAO writing mode for data CDs when overwrite is enabled. +Added option to load the last used settings in addition to the default user settings in every + action dialog. +Show system device name in case the string representing two devices are equal. +Fixed the docking issues. No floating dock windows anymore. :) I have no idea why I wasn't able to do this + before... it was so easy after all. +Plugin based Audio Output system for Audio project "preview". +Dropped id3lib in favor of TagLib (great work Scott :) +When the speed for an on-the-fly audio project is set to "Auto" K3b now determines the max writing speed. +Do not close dialogs after the action is done (for example cd copy) +Directly copy Audio tracks from an Audio CD to an Audio project. +Session management +Made K3b a unique application only allowing one instance. +Improved dcop interface for data projects which allows to add and remove items + to and from specific folders in the project. +Conditional audio ripping pattern. Now what does that mean? It means that you can do stuff like: + "if the track has a genre encoded use it, otherwise use 'misc'" and stuff like that. +New project plugin interface. Example: the audio project cddb plugin is now a project plugin +MusicBrainz support (Query audio file tags over the internet) +K3b now has a "smart" automatic multisession handling in Data projects. +Replaced the system tray by an OSD inspired by the one in amaroK +Better symlink handling with proper size information if "follow symlinks" is activated. +HAL support (turn on your USB writer while K3b is running and see it getting detected automatically) +eMovix 0.9.0 support + +0.11.10 +Support Mp3 files starting with multiple ID3 tags. +Improved ~ handling in the QuickDirSelector. +Save/Load composer fields in audio projects +Save/Load default DVD Copy reading device + +0.11.9 +Fixed data project size calculation (for good this time). + +0.11.8 +K3b now searches for the Debian cdrecord wrapper script and properly selects the cdrecord version to use + (cdrecord.mmap or cdrecord.shm) based on the kernel version. This should fix all problems with + K3bSetup on Debian. +Fixed writing speed parsing with patched cdrecord +Add leading zero to tracknumber meta data field when encoding audio tracks. +Fixed data project size calculation if files from different devices have the same inode number. +It is now possible to enter hexadecimal values in the boot image load segment fields. +Fixed external program encoder plugin (this includes lame and flac encoding) + +0.11.7 +Check size of returned CD-TEXT data to be a multiple of the pack length. This should fix problems + with CD copy. +Audio Project: Do not overwrite CD-Text values loaded from the project file with the ones detected. +Added --copydvd command line parameter +Do only read MCN and ISRCs when copying an audio cd since scanning them takes a very long time. +Fixed cdrdao 1.1.8 version handling (no ATAPI warning) +Fixed crash when using the Audiometadatarenamer on Movix Projects +Automatically enable UDF extensions in case the project contains files bigger then 2 gb. + +0.11.6 +Fixed length calculation for long FLAC files. +Allow Audio CDs that violate the Red Book standard (Tracks shorter than 4 seconds) +Some improvements in disk-info retrieval + +0.11.5 +Do not ask for overwriting directories in cloning dialog +Again fixed some disk detection problems which were introduced with the previous fixes :-( +Fixed a crash which occured if the last boot image was displayed in the fileview while removing it. +Support for ID3 Tags in FLAC files. +Support for cdrdao 1.1.8. + +0.11.4 +Fixed adding of hidden files (wrong naming of config entries) +Use a default imagefile name for cloning if none was specified. +Use the Joliet names if no Rockridge is available in session import + +0.11.3 +fixed features detection with some devices. +fixed multisession writing on some systems (K3b used to open the device instead of leaving it to mkisofs to + prevent permission problems. Sadly this does not work with all systems since it seems that K3b does + not close the device early enough so cdrecord cannot open it.) + +0.11.2 +K3bProcess now has a clean API and a non-stupid implementation which fixes the kde 3.2 issue +way better than the hotfix from 0.11.1. +Fixed a crash at K3b start which happened with ROM drives that return zero length modepage 0x05 data. +fixed onthefly DVD copy issues +K3b now uses the internal reader for DVD copy instead of readcd +added read retries and "ignore read error" options to the dvd copy dialog +fixed handling of empty raw toc data +fixed the bug that made K3b try to use cdrdao for DVD iso image writing. +add files to a project by dropping them on the corresponding tab +removed the "query cddb" option from the copy dialog since this is configured globally anyway. +fixed loading of VideoDVD projects +Fixed VideoDVD project with a HACK. mkisofs is not able to create a VideoDVD using graft-points which + is the default in K3b. So now K3b links all VIDEO_TS files in a temp directory. + +0.11.1 +fixed an issue introduced with KDE 3.2rc1 which caused on-the-fly data writing to fail all the time. + (If you need to know: For some reason KProcess makes the Stdin fd O_NONBLOCK. This way mkisofs is + not able to write properly to cdrecord's stdin anymore.) + +0.11 +fixed libcdparanoia-loading on Debian (and maybe some other systems) +fixed crash at end of image creation in DVD project +fixed filesize display for very large files and projects (integer overflow) +fixed CD-TEXT reading. On some systems some senseless characters where appended. +fixed Id3lib detection in configure.in.in +added primitive supermount support +kernel 2.5 compile fixes (thanks to ismail (cartman) d�mez ) +K3b now defaults to the generic-mmc cdrdao driver if the used burner is not listed in + cdrdao's driver table. As all modern drives use the generic-mmc driver anyway this + is valid and prevents from a lot of newbie problems. +Added a thememanager and the new crystal look by Everaldo +K3b does not mount the disk for session import or data verification anymore. This way supermount + users will have no problems. +merged cue/bin and isoimage burning in one dialog which provides image-type-detection + supported so far: iso, cue, cdrdao toc, cdrecord clone images +better systemconfigcheck messages when cdrecord is not running with root privs +proper automatic writing mode and writing app selection for non-DAO-capable writers +overwriting of files in a new session +default CD size is now 80 min +generic resampling for all audio plugins +support for mono files +support for 8Bit wave files +FLAC decoding plugin (thanks to John Steele Scott) +check if a DVD-R(W) writer supports incremental streaming before trying multisession +check if a DVD-R(W) writer supports testwriting before trying a simulation +fixed DVD-Copy. We needed to determine the size of the data to copy for ourselves instead of relying + on the kernel +Automatic CD-writing speed selection (chooses always the max for now) +Technical info about audiofiles in the audio project are displayed in the track properties dialog +One may now add complete dirs to an audio project +Detection of Justlink support +Finally the device handling is completely independant. No calls to cdrecord anymore. That's why we +now have a libk3bdevice. +Improved writing speed estimation for audio tracks. +Added a button which determines the supported writing speeds with the mounted media. this way it is possible + to also select dvd writing speeds other than 1x +fixed directory sorting in iso filesystems +fixed boot image file sorting +Joliet long support (103 chars joliet filenames) +improved meta tag handling for audio encoding, support for album title and stuff +fixed crash when only creating images without an installed cd writer +writing speed is loaded correctly again +Completely rewritten CD copy: + - Copy Audio, multisession and Mixed mode CDs. + - Copy CD-TEXT + - Create CD-TEXT from Cddb entries + - Audio reading with cdparanoia for high quality ripping + - no cdrdao anymore +Support for new growisofs option to specify the size of a written image in DAO mode +Added check for free space in temp dir to dvd copy +Added a script to simplify the start of K3bSetup2. + +0.10 +DVD writing support with the DVD+RW-tools by Andy Polyakov +DVD formatting +DVD Copy (pure data dvd copy without any video transcoding) +CD Cloning with cdrtools >= 2.01a17 +device capabilities detection without cdrecord. This solves the long startup problem with ATAPI devices. +moved audio ripping pattern configuration from options dialog to audio ripping dialog +option to automatically erase CD-RWs and DVD-RWs without asking before writing +dragging files from a data project to the audio player (basically it's just a KURLDrag so it may be dragged + everywhere) +K3b is now divided in three libs and the main application: libk3bcore, libk3btools, and libk3bproject + this makes creating KParts-plugins easy. Two examples can be found in the tests/kpartplugins dir + one of them is a former K3b option which allowed to use audio meta data to rename files while + adding them to a data project. Now this is done by a plugin and a much higher degree of user + interaction. +Iso9660 file sorting (mkisofs -sort) +libid3 support for better mp3 tag access (we had that in some very old version but back then + K3b depended on it. Now it defaults to using KFileMetaInfo if it's not available) +Pluggable audio decoding +Pluggable audio encoding and completely rewritten audio ripping + much faster now due to a much better threading +Check for read permission when adding files to a project +file filter in binimagewritingdialog and isoimagewritingdialog (thanx to David Maciejak) +Verification of written data (compares md5 sums of all written files). +K3bSetup is not longer compiled unless explicit activated (K3bSetup is outdated and K3bSetup2 is still not ready) +K3b now also compiles without aRts. In this case the audioplayer will be useless (but still there) +no need for special mkisofs permissons anymore. K3b now openes the device itself when importing + an old session. +added a little color animation when dropping files onto a directory in data projects + it is always hard to tell if one dropped on the correct dir. If some one has a better animation + I would be interested in replacing this simple one. +Added CD-TEXT reading (used for Audio CD ripping) +sox encoder plugin to encode to all audio formats supported by sox (will anyone ever use this??) +encoder plugin that let's you specify a commandline to encode the data. Typical example would be calling lame to + encode to mp3. +much better TOC reading. K3b now displays multisession info. +m3u Playlist creation for ripped audio files +replaced the old K3bSetup with a quite simple KControl Module which is only able to change the + needed permission for devices and external programs. Everything else is nowadays done + by the distros. + + +0.9 +support for eMovix 0.8.0rc2 +better data project size calculation + +0.9pre2 +support for writing CD-Text with cdrecord +support for writing audio and mixed-mode CDs on-the-fly with cdrecord >= 2.01a13 +no gui blocking when reloading the media while writing a two-session mixed-mode cd +nodma option in eMovix project +fixed problems with audio decoding (the process sometimes stalled) + +0.9pre1 +added system notification +added eMovix project +added bootable cd support (multible images) +K3b now allows automatic writing mode selection to be sure to always use the best writing mode (DAO, TAO) +the environment PATH is searched for external bins +more error handling +dropped KDE/QT 3.0.x compatibility, now K3b requires at least 3.1 +internals: + devices rewrite, use generic packet ioctl's + cdinfo rewrite, use generic packet ioctl's + merged cdrdaoparser and cdrdaowriter +added multisession cd copy +fixed onlyCreateImage (this time for real!) +added option to hide main window while writing +fixed temp-dir problems with nfs-mounted home directories + K3b now uses the default kde tempdir +Resmgr support +added user datamode selection (mode1, mode2(form1)) +support for relative paths in playlists (thanx to Nick Bloke) +new progressdialog +faster cddb access (older versions just queried all entries, now only the selected one gets queried) +K3b is now threaded. +Gui beautifying. +videocd: + add playback control (PBC) + add customizing of Gaps and Margins + add HQ-VIDEOCD support + add relaxed APS support (this controls whether APS constraints are strict or relaxed) + add category restriction support + add an option to create always an empty `/SEGMENT' directory (some Players need this) + fixed load and saveUserDefaults + fixed autodetection VCD Typ (now the user can turn off this feature) +added audio volume normalization +added udf support to data project +user commands for external programs are separated by space now since the comma just + made problems for options like "--driver generic-mmc" which had to be specified + as "--driver, generic-mmc" +support for newer versions of cdrecord which have a slighly changed user interface +support for cuefile writing with cdrecord > 2.01a14 + +0.8.1 +fixed compiling problems with kernel < 2.4.3 +fixed onlyCreateImage in data project +fixed handling of cdrecord burnfree/burnproof driveroption in versions < 1.10 +fixed error with localized docking config that caused empty windows when changing the language +introduced workaround for serious cdrdao bug that caused tocfiles to be deleted +disabled the delete shortcut in the fileview (way too many users deleted files by accident when they + wanted to remove project items) + +0.8 +advanced options: manually selection of writing app (cdrecord or cdrdao) + +changed the option dialog layout -> smaller window + +fixed problems with first pregap in audio project: + no need to set the first pregap to 0 on some writers anymore + no 4 second pregap before first tracks anymore + +fixed problems with detecting some audio tracks that had flags like preemp set + +removed cdparanoia dependancy (dynamic linking) +big internal changes +split bin/cue writing from iso-image-writing +better cdcopy (mainly more options) +customizeable audio ripping + +mixed mode cd creation +video cd creation +video cd on cd-i support +better error handling + +indivdual selection of final size for encoded movie +clean vob dir before start and restore it (i.e playing wiht PowerDVD stores +config files in the directory) + +AC3-passthrough mode for DIVX Encoding +DND for AudioCD-Ripping to harddisc. + + +0.7.5 +Added session import +little reordering of menus +fixed the "cdrecord error 255" bug +fixed some i18n issues +improved mp3 file detection +added K3b project mimetype +added konqueror servicemenu entries +now KoStore is used for saving documents +K3bSetup is started with the correct language now +MD5 sum is only calculated on demand (but still asynchronous) +fixed K3bSetup linking problems + +0.7.4 +fixed bug that caused stupid mountpoints to be assigned to the devices +Mounting dvd with UDF filesystem (uppercase words) should now work (copy ifo-files). +beautified cddb setup +internal cddb change (rewrite) +fixed problems when writing mp3 and ogg vorbis files together +burnproof support for cdrecord <= 1.11a02 works again (and also for the new cdrecord ;) +Fix audiolanguange parsing for transcode 0.6.2 (wrong entries in k3bDVDRip.xml) +Bugfix Selecting ripping dir with file dialog and new directory now shows the available space properly. +Bugfix Cancel one pass in encoding now works +If select "Add to project" in the context menu of the file/dir tree a dialog (audio/data) asks +for creating a new data or audio project. + +0.7.3 +fixed compile problems with gcc 3.x + +0.7.2 +added md5sum to iso-image dialog +fixed compile problem when ogg-vorbis is not installed +fixed iso-image volume descriptor problem that caused all descriptors to be enclosed in quotation marks +added raw-copy option +better external program handling + +0.7.1 +audio: + fixed mp3 resampling problems + better handling of newly added tracks +data: + proper symlink handling + better support of the mkisofs options + option for adding hidden files + backup permissions +device: + support for symlinks in fstab +misc: + progress display in the K3b titlebar + better progress display in systray + +0.7 +DivX/XviD encoding +enhanced cddb support +new artwork from Ayo +fixed some device detection problems +fixed problems with long filenames and Joliet +some gui enhancements +added libmad to the sources +removed id3lib + +0.6pre2 +added ogg-vorbis support +added iso ids to diskInfo +fixed iso project input fields + +0.6pre1 +well... I don't know.. everything? + +0.5.1 +fixed bug that caused a compile error on some systems +fixed problems with audio cd writing +disabled projects while writing (needed for writing in the background) + +0.5.0 +-fixed mkisofs 1.14 problems +-audio on-the-fly burning (even corrupted mp3-files) +-saving/loading of projects +-atip and toc info +-cd-ripping (wav) with extended pattern support +-cddb support +-play audio cds +-extended option-dialog +-hide first track on audio-cds +-detection of ide-devices as cd-rom +-blanking of cdrws +-writing of existing iso-images +-optional setting of cdrdao driver for every scsi-device +-burn in the background (it's even possible to write on two writers simultaneous or write a cd and create an image (if your system is fast enough ;-)) +-K3b checks for an empty disk before writing! +-and like every time some other stuff i cannot remember ;-) + +0.4.3 +Fixed bug that caused K3b to crash while detecting devices +highly improved adding of files and directories to a data project +adding empty directories to data project via context menu +disabled audio on-the-fly burning due to a problem that caused faulty cds + +0.4.2 +added new DirTree (code from Konqueror) +added new device-management (the scsi-bus is checked directly) +detection of Burn-Proof-capable drives +some bugfixes + +0.4.1 +added whitespace-treatment +dock-positions are saved + +0.4.0 +Added ISO-cd support +file-tree creation via drag'n'drop +renaming of files +support of most of the mkisofs-features +improved audiotrack dialog +use of ID3Lib + +... and other things i really cannot remember... ;-) + diff --git a/FAQ b/FAQ new file mode 100644 index 0000000..3802d3b --- /dev/null +++ b/FAQ @@ -0,0 +1,82 @@ +Q: Compiling K3b fails with errors like this: + base_k3badvanceddataimagesettings.cpp:185: invalid use of undefined type + `struct KComboBox' + base_k3badvanceddataimagesettings.h:17: forward declaration of `struct + KComboBox' +A: The QTDesigner tool 'uic' is not able to find the kde widget plugins. + To solve this run 'qtconfig' and add '$KDEDIR/lib/kde3/plugins' to the plugin search path + (replace $KDEDIR with your kde base dir). + + +Q: K3b thinks my SCSI device is IDE. +A: If you are using the rpm from SuSE your version of K3bSetup is not able to set the + permissions that K3b needs the devices to have. The SuSE guys seem to think messing with + permissions is too dangerous. It is recommended to always compile from source to have all + K3b features. + + +Q: Where has all the fancy graphic gone? +A: Most likely you installed K3b in the wrong directory. All KDE programs are installed in the + KDE dirtree (SuSE: /opt/kde3, RedHat: /usr). If you compile K3b from source it defaults + to either $KDEDIR or /usr/local. To install in the correct directory you need to specify the prefix + to configure like this: + ./configure --prefix=`kde-config --prefix` + That will install K3b relative to the correct path. + + +Q: The linking always breaks with the missing -laudio. +A: You need to install NAS. + + +Q: Where can I find K3bSetup2? +A: K3bSetup2 is a KControlCenter Module. You can find it in the System Administration section or start + it manually with "kdesu kcmshell k3bsetup2". + There also is a script since K3b 0.11 called k3bsetup. + + +Q: My writer supports writing at speed X but K3b shows Y as a max. +A: K3b determined the maximum writing speed the first time you start it. Since the speed reported by the + writer always depends on the mounted medium this may not be the real max. + To manually change it open the K3b settings in the device section and click on the value. You will + be presented with a spinbox which allows to change the speed. + + +Q: Writing fails with the following cdrecord message: + "Cannot allocate memory. Cannot get SCSI I/O buffer." +A: Since kernel 2.6.9 suid root programs are not allowed to use the SCSI subsystem. + To solve this issue either configure cdrecord to run without root privileges: chmod 755 /usr/bin/cdrecord + or run K3b as root (which is not recommended but works also). + + +Q: Writing fails with the following cdrecord message over and over again: + "Error trying to open /dev/hdc exclusively (Device or resource busy)..." +A: You are using a patched cdrecord version which tries to open the device exclusively which fails because + your are probably also using automounting. The solutions are to disable automounting altogether (and this is + the recommended solution as automounting can cause other more serious problems with CD/DVD writing) or to + install a non-patched cdrecord version. + +Q: My DVD drive supports 16X but K3B keeps burning at 1X! What's happening? + +A: Your kernel most likely didn't apply optimal settings for your drive when it detected it. You can find out + what are the current settings of your drive with the command "hdparm -v /dev/dvd": + + /dev/dvd: + IO_support = 0 (default 16-bit) + unmaskirq = 0 (off) + using_dma = 0 (off) + keepsettings = 0 (off) + readonly = 0 (off) + readahead = 256 (on) + + The following options are known to maximize burning and playback performance: + + hdparm -d1 -c1 -a8 -u1 /dev/dvd + + To make these options permanent, a quick and dirty solution is to include the command in /etc/rc.local. + Consult your distribution documentation for a tailored solution. + + Some drives have buggy DMA support. If you experience instability, leave these options disabled. + + Some useful references: + http://www.togaware.com/linux/survivor/CD_DVD_Drives.shtml + http://www.linuxjournal.com/article/6921 diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..4ce45cb --- /dev/null +++ b/INSTALL @@ -0,0 +1,51 @@ +Installing K3b 1.0 +------------------ + + +What you need to run K3b: + mandatory: + - since K3b is a CD writing program a cd writer would be a good thing to have ;-) + - the QT3 library (at least version 3.2) + - the KDE3 libraries (at least version 3.2) + - the cdparanoia library for cd ripping from Monty + - the cdrtools (cdrecord, mkisofs) from Joerg Schilling + - the dvd+rw-tools by Andy Polyakov for DVD writing + + optional: + - cdrdao, the other linux cd writing program from Andreas Mueller + - the transcode tools for DVD ripping and DivX/XviD encoding from Thomas Oestreich + - vcdimager >= 0.7 for creating video cds + - libmad for mp3 decoding + - ogg-vorbis libraries for encoding and decoding + - the FLAC++ libraries for flac-decoding + - the eMovix package + - TagLib by Scott Wheeler for reading Meta data tags + - the musepack (or now mpcdec) library for decoding Musepack audio files + - the ffmpeg library to decode other audio file formats such as wma + - the sndfile library to decode audio file formats such as AIFF or VOC + - the lame library to encode audio files in the mp3 format + - sox to encode audio files in formats such as AIFF or VOC + - a dynamically compiled libffmpeg for wma decoding + - the musicbrainz library for metadata queries for single audio titles + +After that it's all the same: + + ./configure + +or try ./configure --help to learn about the options. + +If configure was successful you are presented with a list of configure results that shows +which optional features are enabled. Now just compile K3b: + + make + +Now you are ready to install: + + make install (as root) + + +See PERMISSIONS on hints how to properly setup the permissions to use K3b without problems. + + +Have fun +Sebastian Trueg (trueg@k3b.org) diff --git a/KNOWNBUGS b/KNOWNBUGS new file mode 100644 index 0000000..e69de29 diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..6d2b67a --- /dev/null +++ b/Makefile.am @@ -0,0 +1,11 @@ +if with_k3bsetup1 + K3BSETUPDIR=k3bsetup +endif + +EXTRA_DIST = AUTHORS COPYING ChangeLog INSTALL README TODO k3b.lsm admin configure.in.in + +AUTOMAKE_OPTIONS = foreign 1.5 + +#include admin/deps.am + +SUBDIRS = doc libk3bdevice libk3b src kioslaves plugins kfile-plugins $(K3BSETUPDIR) diff --git a/PERMISSIONS b/PERMISSIONS new file mode 100644 index 0000000..1fe56bf --- /dev/null +++ b/PERMISSIONS @@ -0,0 +1,32 @@ +K3b needs some special permissions to work properly. Most distrobutions come with permissions that I don't like +very much and make problems when adding new CD/DVD devices to your system. +If you set up your system as follows you can be sure to never have K3b permission problems again. + +1. Disable pam authentication for cdrom and burner devices in /etc/security/console.perm. Otherwise your permissions + will be overwritten when loggin in and it's not possible for two users to use K3b at the same time. + In my opinion one should disable this completely and create a proper configuration instead. The most annoying + issue with this pam stuff is that you cannot have two sessions with two different users running because the first + one owns all the sound and cd devices. + +2. Create a cdrom or cdrw or whatever group (if it not already exists) and add all users that should be able to + use K3b to that group. You may also skip this step and let everybody use K3b. In that case simply use root as + the group and permissions 4711 and 666 instead of 4710 and 660 in the following steps. + +3. Change the permissions of cdrecord and cdrdao to 4710 root.cdrom (substitute cdrom with the group from 2). + This way both will run suid root which allows them to increase their scheduling priority resulting in a more + stable burning process. + +4. Change the permissions of all your cdrom device to 660 root.cdrom (substitute cdrom with the group from 2). + With devfs you may do this with lines like this (the first changes all ide cd devices while the second takes + care of the scsi cd devices): + REGISTER ^ide/host.*/bus.*/target.*/lun.*/cd PERMISSIONS root.cdrom 660 + REGISTER ^scsi/host.*/bus.*/target.*/lun.*/cd PERMISSIONS root.cdrom 660 + In case you are not using devfs you may determine the devices by running K3b once as root and looking in the + device settings. The corresponding devices are listed there. + +5. Change the permissions of the generic SCSI devices to 660 root.cdrom (substitute cdrom with the group from 2). + Both cdrecord and cdrdao use the generic devices to access the scsi drives. So you don't need to perform this step + if you only have IDE devices. + Use a line like the following for devfs: + REGISTER ^scsi/host.*/bus.*/target.*/lun.*/generic PERMISSIONS root.cdrom 660 + In case you are not using devfs the devices are /dev/sg*. diff --git a/README b/README new file mode 100644 index 0000000..6bb3640 --- /dev/null +++ b/README @@ -0,0 +1,92 @@ +K3b Version 1.0 + +Thanx for downloading K3b - The CD Kreator + +These are the features so far: + - the most userfriendly interface ever ;-) + - themable + + - Media-centric user interface: + - Select the medium to use for burning instead of the device + - K3b always knows about all optical devices and inserted media and adjusts the UI accordingly + + - writing audio-cds + - On-the-fly decoding of many audio formats through plugin struxture + (decoding plugins for mp3, ogg vorbis, flac, wave, musepack, wma, aiff, and others) + - CD-Text support + - Metadata support, fill CD-Text from metadata or via Internet queries (CDDB + Musicbrainz) + - little gimmick: hide the first track (so that you have to search back from the + beginning of the cd to find it) + - volume level normalization (only when writing with an image) + - multiple sources for one track possible (merging of tracks, splitting of tracks, + adding silence of arbitrary length) + - integrated "preview" player + - Directly add audio tracks from other CDs and let K3b take care of the rest. + + - writing ISO9660-CDs and DVDs + - Joliet/Rockridge support + - Udf filestructures (no pure Udf so far) + - create image/write image + - writing on-the-fly + - creating of file-tree via drag'n'drop (as easy as it could be) + - removing files and directories from data tree + - moving files within the project + - adding new empty directories to data tree + - renaming of files (manually or automatically for mp3-files) (for joliet and rockrigde) + - support for most of the mkisofs-options (I don't think anyone will ever use them! ;-)) + - multisession support (including importing old sessions and overwriting files from old sessions) + Automagically multisession handling: start, continue, or finish multisession CDs and DVDs based on + the size of the project and the remaining capacity on the media. + - El Torito bootable CD/DVD support + + - writing Video CDs + - VCD 1.1, 2.0, SVCD + - CD-i support (Version 4) + + - writing mixed-mode CDs + - CD-Extra (CD-Plus, Enhanced Audio CD) support + + - writing eMovix CDs and DVDs + + - writing data DVDs + - Support for DVD-R(W) and DVD+R(W) + - Support for DVD+R Double Layer media + + - formatting DVD-RWs and DVD+RWs + + - writing existing iso-images and cue/bin images to CD + - Writing of Audio cue file images on-the-fly (All audio formats supported) + + - CD copy (data, audio, mixed mode) + + - DVD copy + + - CD cloning with cdrecord >=2.01a17 + + - blanking of CD-RWs + - Also automagically before writing a CD. + + - CD ripping to wav, mp3, ogg-vorbis, flac, or whatever format needed + - encoding plugin system + - Cddb support + - sophisticated pattern system to automatically organize the ripped tracks + - m3u playlist creation + - CD-TEXT support + + - DVD ripping with the transcode tools + - Support for automatic clipping + - DivX/XviD encoding + + - Retrieving CD/DVD info and toc + + - Powerful default and automatic settings + + +See INSTALL for further information + + +Please report bugs (with k3b output!) and tell me what you like/dislike +about the user-interface! + +Have fun +Sebastian Trueg (trueg@k3b.org) diff --git a/RELEASE_HOWTO b/RELEASE_HOWTO new file mode 100644 index 0000000..7346b6a --- /dev/null +++ b/RELEASE_HOWTO @@ -0,0 +1,27 @@ +Howto create a K3b release (stable branch) + +1. create a package from the stable branch using the createPackage.sh script: + createPackage.sh -a k3b -av 0.12 -ab branches/stable/extragear/multimedia --notoplevel -ib branches/stable/l10n + -is extragear-multimedia --pofiles "k3b libk3b libk3bdevice k3bsetup" --postprocess postprocessk3b.sh --split + --admin /branches/KDE/3.4/kde-common/admin + +2. Make sure the version in src/main.cpp, k3b.lsm, README, INSTALL is valid. + Check the version in libk3b. + +3. Create the tarball. + +4. Test the tarball. That includes removing any trace of K3b from the test system before and in the ideal + case compile on a minimal system meaning minimal KDE/QT versions. + +5. Upload the tarball to upload.sf.net/incoming and create a release on www.sourceforge.net (or use releaseforge, + a nice little application which automates the whole sourceforge release thing). + +6. Create a news entry on www.k3b.org and update the download page. + +7. Promote the release on www.kde-apps.org and freshmeat.net (the latter may also be done with releaseforge) + +8. Send an announcement email to: + k3b-user@lists.sourceforge.net + k3b-announce@lists.sourceforge.net + kde-extra-gear@kde.org + kde-announce@kde.org diff --git a/TODO b/TODO new file mode 100644 index 0000000..02bd01e --- /dev/null +++ b/TODO @@ -0,0 +1,22 @@ ++ integrated Audio CD player (as part of the audio project preview) + +- video cd photoalbum, portfolio +- video cd Interactive Menues (automenues) +- video cd split long mpegs (volume set) +- video dvd creation with menu support +- Support for other playlist formats + ++ video cd ripping ++ video cd mpeg-still support ++ video cd Navigation + ++ Alsa output plugin ++ Rewrite of the DVD ripping/encoding stuff + + Encoding on-the-fly (no extra encoding dialog) + + Do not rip in a special format but save the Video DVD as + a normal VideoDVD structure (or encoded) + +legend: +- planned +* work in progress ++ done diff --git a/acinclude.m4 b/acinclude.m4 new file mode 100644 index 0000000..6b26319 --- /dev/null +++ b/acinclude.m4 @@ -0,0 +1,11945 @@ +## -*- autoconf -*- + +dnl This file is part of the KDE libraries/packages +dnl Copyright (C) 1997 Janos Farkas (chexum@shadow.banki.hu) +dnl (C) 1997,98,99 Stephan Kulow (coolo@kde.org) + +dnl This file is free software; you can redistribute it and/or +dnl modify it under the terms of the GNU Library General Public +dnl License as published by the Free Software Foundation; either +dnl version 2 of the License, or (at your option) any later version. + +dnl This library is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +dnl Library General Public License for more details. + +dnl You should have received a copy of the GNU Library General Public License +dnl along with this library; see the file COPYING.LIB. If not, write to +dnl the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +dnl Boston, MA 02110-1301, USA. + +dnl IMPORTANT NOTE: +dnl Please do not modify this file unless you expect your modifications to be +dnl carried into every other module in the repository. +dnl +dnl Single-module modifications are best placed in configure.in for kdelibs +dnl and kdebase or configure.in.in if present. + +# KDE_PATH_X_DIRECT +dnl Internal subroutine of AC_PATH_X. +dnl Set ac_x_includes and/or ac_x_libraries. +AC_DEFUN([KDE_PATH_X_DIRECT], +[ +AC_REQUIRE([KDE_CHECK_LIB64]) + +if test "$ac_x_includes" = NO; then + # Guess where to find include files, by looking for this one X11 .h file. + test -z "$x_direct_test_include" && x_direct_test_include=X11/Intrinsic.h + + # First, try using that file with no special directory specified. +AC_TRY_CPP([#include <$x_direct_test_include>], +[# We can compile using X headers with no special include directory. +ac_x_includes=], +[# Look for the header file in a standard set of common directories. +# Check X11 before X11Rn because it is often a symlink to the current release. + for ac_dir in \ + /usr/X11/include \ + /usr/X11R6/include \ + /usr/X11R5/include \ + /usr/X11R4/include \ + \ + /usr/include/X11 \ + /usr/include/X11R6 \ + /usr/include/X11R5 \ + /usr/include/X11R4 \ + \ + /usr/local/X11/include \ + /usr/local/X11R6/include \ + /usr/local/X11R5/include \ + /usr/local/X11R4/include \ + \ + /usr/local/include/X11 \ + /usr/local/include/X11R6 \ + /usr/local/include/X11R5 \ + /usr/local/include/X11R4 \ + \ + /usr/X386/include \ + /usr/x386/include \ + /usr/XFree86/include/X11 \ + \ + /usr/include \ + /usr/local/include \ + /usr/unsupported/include \ + /usr/athena/include \ + /usr/local/x11r5/include \ + /usr/lpp/Xamples/include \ + \ + /usr/openwin/include \ + /usr/openwin/share/include \ + ; \ + do + if test -r "$ac_dir/$x_direct_test_include"; then + ac_x_includes=$ac_dir + break + fi + done]) +fi # $ac_x_includes = NO + +if test "$ac_x_libraries" = NO; then + # Check for the libraries. + + test -z "$x_direct_test_library" && x_direct_test_library=Xt + test -z "$x_direct_test_function" && x_direct_test_function=XtMalloc + + # See if we find them without any special options. + # Don't add to $LIBS permanently. + ac_save_LIBS="$LIBS" + LIBS="-l$x_direct_test_library $LIBS" +AC_TRY_LINK([#include ], [${x_direct_test_function}(1)], +[LIBS="$ac_save_LIBS" +# We can link X programs with no special library path. +ac_x_libraries=], +[LIBS="$ac_save_LIBS" +# First see if replacing the include by lib works. +# Check X11 before X11Rn because it is often a symlink to the current release. +for ac_dir in `echo "$ac_x_includes" | sed s/include/lib${kdelibsuff}/` \ + /usr/X11/lib${kdelibsuff} \ + /usr/X11R6/lib${kdelibsuff} \ + /usr/X11R5/lib${kdelibsuff} \ + /usr/X11R4/lib${kdelibsuff} \ + \ + /usr/lib${kdelibsuff}/X11 \ + /usr/lib${kdelibsuff}/X11R6 \ + /usr/lib${kdelibsuff}/X11R5 \ + /usr/lib${kdelibsuff}/X11R4 \ + \ + /usr/local/X11/lib${kdelibsuff} \ + /usr/local/X11R6/lib${kdelibsuff} \ + /usr/local/X11R5/lib${kdelibsuff} \ + /usr/local/X11R4/lib${kdelibsuff} \ + \ + /usr/local/lib${kdelibsuff}/X11 \ + /usr/local/lib${kdelibsuff}/X11R6 \ + /usr/local/lib${kdelibsuff}/X11R5 \ + /usr/local/lib${kdelibsuff}/X11R4 \ + \ + /usr/X386/lib${kdelibsuff} \ + /usr/x386/lib${kdelibsuff} \ + /usr/XFree86/lib${kdelibsuff}/X11 \ + \ + /usr/lib${kdelibsuff} \ + /usr/local/lib${kdelibsuff} \ + /usr/unsupported/lib${kdelibsuff} \ + /usr/athena/lib${kdelibsuff} \ + /usr/local/x11r5/lib${kdelibsuff} \ + /usr/lpp/Xamples/lib${kdelibsuff} \ + /lib/usr/lib${kdelibsuff}/X11 \ + \ + /usr/openwin/lib${kdelibsuff} \ + /usr/openwin/share/lib${kdelibsuff} \ + ; \ +do +dnl Don't even attempt the hair of trying to link an X program! + for ac_extension in a so sl; do + if test -r $ac_dir/lib${x_direct_test_library}.$ac_extension; then + ac_x_libraries=$ac_dir + break 2 + fi + done +done]) +fi # $ac_x_libraries = NO +]) + + +dnl ------------------------------------------------------------------------ +dnl Find a file (or one of more files in a list of dirs) +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([AC_FIND_FILE], +[ +$3=NO +for i in $2; +do + for j in $1; + do + echo "configure: __oline__: $i/$j" >&AC_FD_CC + if test -r "$i/$j"; then + echo "taking that" >&AC_FD_CC + $3=$i + break 2 + fi + done +done +]) + +dnl KDE_FIND_PATH(program-name, variable-name, list-of-dirs, +dnl if-not-found, test-parameter, prepend-path) +dnl +dnl Look for program-name in list-of-dirs+$PATH. +dnl If prepend-path is set, look in $PATH+list-of-dirs instead. +dnl If found, $variable-name is set. If not, if-not-found is evaluated. +dnl test-parameter: if set, the program is executed with this arg, +dnl and only a successful exit code is required. +AC_DEFUN([KDE_FIND_PATH], +[ + AC_MSG_CHECKING([for $1]) + if test -n "$$2"; then + kde_cv_path="$$2"; + else + kde_cache=`echo $1 | sed 'y%./+-%__p_%'` + + AC_CACHE_VAL(kde_cv_path_$kde_cache, + [ + kde_cv_path="NONE" + kde_save_IFS=$IFS + IFS=':' + dirs="" + for dir in $PATH; do + dirs="$dirs $dir" + done + if test -z "$6"; then dnl Append dirs in PATH (default) + dirs="$3 $dirs" + else dnl Prepend dirs in PATH (if 6th arg is set) + dirs="$dirs $3" + fi + IFS=$kde_save_IFS + + for dir in $dirs; do + if test -x "$dir/$1"; then + if test -n "$5" + then + evalstr="$dir/$1 $5 2>&1 " + if eval $evalstr; then + kde_cv_path="$dir/$1" + break + fi + else + kde_cv_path="$dir/$1" + break + fi + fi + done + + eval "kde_cv_path_$kde_cache=$kde_cv_path" + + ]) + + eval "kde_cv_path=\"`echo '$kde_cv_path_'$kde_cache`\"" + + fi + + if test -z "$kde_cv_path" || test "$kde_cv_path" = NONE; then + AC_MSG_RESULT(not found) + $4 + else + AC_MSG_RESULT($kde_cv_path) + $2=$kde_cv_path + + fi +]) + +AC_DEFUN([KDE_MOC_ERROR_MESSAGE], +[ + AC_MSG_ERROR([No Qt meta object compiler (moc) found! +Please check whether you installed Qt correctly. +You need to have a running moc binary. +configure tried to run $ac_cv_path_moc and the test didn't +succeed. If configure shouldn't have tried this one, set +the environment variable MOC to the right one before running +configure. +]) +]) + +AC_DEFUN([KDE_UIC_ERROR_MESSAGE], +[ + AC_MSG_WARN([No Qt ui compiler (uic) found! +Please check whether you installed Qt correctly. +You need to have a running uic binary. +configure tried to run $ac_cv_path_uic and the test didn't +succeed. If configure shouldn't have tried this one, set +the environment variable UIC to the right one before running +configure. +]) +]) + + +AC_DEFUN([KDE_CHECK_UIC_FLAG], +[ + AC_MSG_CHECKING([whether uic supports -$1 ]) + kde_cache=`echo $1 | sed 'y% .=/+-%____p_%'` + AC_CACHE_VAL(kde_cv_prog_uic_$kde_cache, + [ + cat >conftest.ui < +EOT + ac_uic_testrun="$UIC_PATH -$1 $2 conftest.ui >/dev/null" + if AC_TRY_EVAL(ac_uic_testrun); then + eval "kde_cv_prog_uic_$kde_cache=yes" + else + eval "kde_cv_prog_uic_$kde_cache=no" + fi + rm -f conftest* + ]) + + if eval "test \"`echo '$kde_cv_prog_uic_'$kde_cache`\" = yes"; then + AC_MSG_RESULT([yes]) + : + $3 + else + AC_MSG_RESULT([no]) + : + $4 + fi +]) + + +dnl ------------------------------------------------------------------------ +dnl Find the meta object compiler and the ui compiler in the PATH, +dnl in $QTDIR/bin, and some more usual places +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([AC_PATH_QT_MOC_UIC], +[ + AC_REQUIRE([KDE_CHECK_PERL]) + qt_bindirs="" + for dir in $kde_qt_dirs; do + qt_bindirs="$qt_bindirs $dir/bin $dir/src/moc" + done + qt_bindirs="$qt_bindirs /usr/bin /usr/X11R6/bin /usr/local/qt/bin" + if test ! "$ac_qt_bindir" = "NO"; then + qt_bindirs="$ac_qt_bindir $qt_bindirs" + fi + + KDE_FIND_PATH(moc, MOC, [$qt_bindirs], [KDE_MOC_ERROR_MESSAGE]) + if test -z "$UIC_NOT_NEEDED"; then + KDE_FIND_PATH(uic, UIC_PATH, [$qt_bindirs], [UIC_PATH=""]) + if test -z "$UIC_PATH" ; then + KDE_UIC_ERROR_MESSAGE + exit 1 + else + UIC=$UIC_PATH + + if test $kde_qtver = 3; then + KDE_CHECK_UIC_FLAG(L,[/nonexistent],ac_uic_supports_libpath=yes,ac_uic_supports_libpath=no) + KDE_CHECK_UIC_FLAG(nounload,,ac_uic_supports_nounload=yes,ac_uic_supports_nounload=no) + + if test x$ac_uic_supports_libpath = xyes; then + UIC="$UIC -L \$(kde_widgetdir)" + fi + if test x$ac_uic_supports_nounload = xyes; then + UIC="$UIC -nounload" + fi + fi + fi + else + UIC="echo uic not available: " + fi + + AC_SUBST(MOC) + AC_SUBST(UIC) + + UIC_TR="i18n" + if test $kde_qtver = 3; then + UIC_TR="tr2i18n" + fi + + AC_SUBST(UIC_TR) +]) + +AC_DEFUN([KDE_1_CHECK_PATHS], +[ + KDE_1_CHECK_PATH_HEADERS + + KDE_TEST_RPATH= + + if test -n "$USE_RPATH"; then + + if test -n "$kde_libraries"; then + KDE_TEST_RPATH="-R $kde_libraries" + fi + + if test -n "$qt_libraries"; then + KDE_TEST_RPATH="$KDE_TEST_RPATH -R $qt_libraries" + fi + + if test -n "$x_libraries"; then + KDE_TEST_RPATH="$KDE_TEST_RPATH -R $x_libraries" + fi + + KDE_TEST_RPATH="$KDE_TEST_RPATH $KDE_EXTRA_RPATH" + fi + +AC_MSG_CHECKING([for KDE libraries installed]) +ac_link='$LIBTOOL_SHELL --silent --mode=link ${CXX-g++} -o conftest $CXXFLAGS $all_includes $CPPFLAGS $LDFLAGS $all_libraries conftest.$ac_ext $LIBS -lkdecore $LIBQT $KDE_TEST_RPATH 1>&5' + +if AC_TRY_EVAL(ac_link) && test -s conftest; then + AC_MSG_RESULT(yes) +else + AC_MSG_ERROR([your system fails at linking a small KDE application! +Check, if your compiler is installed correctly and if you have used the +same compiler to compile Qt and kdelibs as you did use now. +For more details about this problem, look at the end of config.log.]) +fi + +if eval `KDEDIR= ./conftest 2>&5`; then + kde_result=done +else + kde_result=problems +fi + +KDEDIR= ./conftest 2> /dev/null >&5 # make an echo for config.log +kde_have_all_paths=yes + +KDE_SET_PATHS($kde_result) + +]) + +AC_DEFUN([KDE_SET_PATHS], +[ + kde_cv_all_paths="kde_have_all_paths=\"yes\" \ + kde_htmldir=\"$kde_htmldir\" \ + kde_appsdir=\"$kde_appsdir\" \ + kde_icondir=\"$kde_icondir\" \ + kde_sounddir=\"$kde_sounddir\" \ + kde_datadir=\"$kde_datadir\" \ + kde_locale=\"$kde_locale\" \ + kde_cgidir=\"$kde_cgidir\" \ + kde_confdir=\"$kde_confdir\" \ + kde_kcfgdir=\"$kde_kcfgdir\" \ + kde_mimedir=\"$kde_mimedir\" \ + kde_toolbardir=\"$kde_toolbardir\" \ + kde_wallpaperdir=\"$kde_wallpaperdir\" \ + kde_templatesdir=\"$kde_templatesdir\" \ + kde_bindir=\"$kde_bindir\" \ + kde_servicesdir=\"$kde_servicesdir\" \ + kde_servicetypesdir=\"$kde_servicetypesdir\" \ + kde_moduledir=\"$kde_moduledir\" \ + kde_styledir=\"$kde_styledir\" \ + kde_widgetdir=\"$kde_widgetdir\" \ + xdg_appsdir=\"$xdg_appsdir\" \ + xdg_menudir=\"$xdg_menudir\" \ + xdg_directorydir=\"$xdg_directorydir\" \ + kde_result=$1" +]) + +AC_DEFUN([KDE_SET_DEFAULT_PATHS], +[ +if test "$1" = "default"; then + + if test -z "$kde_htmldir"; then + kde_htmldir='\${datadir}/doc/HTML' + fi + if test -z "$kde_appsdir"; then + kde_appsdir='\${datadir}/applnk' + fi + if test -z "$kde_icondir"; then + kde_icondir='\${datadir}/icons' + fi + if test -z "$kde_sounddir"; then + kde_sounddir='\${datadir}/sounds' + fi + if test -z "$kde_datadir"; then + kde_datadir='\${datadir}/apps' + fi + if test -z "$kde_locale"; then + kde_locale='\${datadir}/locale' + fi + if test -z "$kde_cgidir"; then + kde_cgidir='\${exec_prefix}/cgi-bin' + fi + if test -z "$kde_confdir"; then + kde_confdir='\${datadir}/config' + fi + if test -z "$kde_kcfgdir"; then + kde_kcfgdir='\${datadir}/config.kcfg' + fi + if test -z "$kde_mimedir"; then + kde_mimedir='\${datadir}/mimelnk' + fi + if test -z "$kde_toolbardir"; then + kde_toolbardir='\${datadir}/toolbar' + fi + if test -z "$kde_wallpaperdir"; then + kde_wallpaperdir='\${datadir}/wallpapers' + fi + if test -z "$kde_templatesdir"; then + kde_templatesdir='\${datadir}/templates' + fi + if test -z "$kde_bindir"; then + kde_bindir='\${exec_prefix}/bin' + fi + if test -z "$kde_servicesdir"; then + kde_servicesdir='\${datadir}/services' + fi + if test -z "$kde_servicetypesdir"; then + kde_servicetypesdir='\${datadir}/servicetypes' + fi + if test -z "$kde_moduledir"; then + if test "$kde_qtver" = "2"; then + kde_moduledir='\${libdir}/kde2' + else + kde_moduledir='\${libdir}/kde3' + fi + fi + if test -z "$kde_styledir"; then + kde_styledir='\${libdir}/kde3/plugins/styles' + fi + if test -z "$kde_widgetdir"; then + kde_widgetdir='\${libdir}/kde3/plugins/designer' + fi + if test -z "$xdg_appsdir"; then + xdg_appsdir='\${datadir}/applications/kde' + fi + if test -z "$xdg_menudir"; then + xdg_menudir='\${sysconfdir}/xdg/menus' + fi + if test -z "$xdg_directorydir"; then + xdg_directorydir='\${datadir}/desktop-directories' + fi + + KDE_SET_PATHS(defaults) + +else + + if test $kde_qtver = 1; then + AC_MSG_RESULT([compiling]) + KDE_1_CHECK_PATHS + else + AC_MSG_ERROR([path checking not yet supported for KDE 2]) + fi + +fi +]) + +AC_DEFUN([KDE_CHECK_PATHS_FOR_COMPLETENESS], +[ if test -z "$kde_htmldir" || test -z "$kde_appsdir" || + test -z "$kde_icondir" || test -z "$kde_sounddir" || + test -z "$kde_datadir" || test -z "$kde_locale" || + test -z "$kde_cgidir" || test -z "$kde_confdir" || + test -z "$kde_kcfgdir" || + test -z "$kde_mimedir" || test -z "$kde_toolbardir" || + test -z "$kde_wallpaperdir" || test -z "$kde_templatesdir" || + test -z "$kde_bindir" || test -z "$kde_servicesdir" || + test -z "$kde_servicetypesdir" || test -z "$kde_moduledir" || + test -z "$kde_styledir" || test -z "kde_widgetdir" || + test -z "$xdg_appsdir" || test -z "$xdg_menudir" || test -z "$xdg_directorydir" || + test "x$kde_have_all_paths" != "xyes"; then + kde_have_all_paths=no + fi +]) + +AC_DEFUN([KDE_MISSING_PROG_ERROR], +[ + AC_MSG_ERROR([The important program $1 was not found! +Please check whether you installed KDE correctly. +]) +]) + +AC_DEFUN([KDE_MISSING_ARTS_ERROR], +[ + AC_MSG_ERROR([The important program $1 was not found! +Please check whether you installed aRts correctly or use +--without-arts to compile without aRts support (this will remove functionality). +]) +]) + +AC_DEFUN([KDE_SET_DEFAULT_BINDIRS], +[ + kde_default_bindirs="/usr/bin /usr/local/bin /opt/local/bin /usr/X11R6/bin /opt/kde/bin /opt/kde3/bin /usr/kde/bin /usr/local/kde/bin" + test -n "$KDEDIR" && kde_default_bindirs="$KDEDIR/bin $kde_default_bindirs" + if test -n "$KDEDIRS"; then + kde_save_IFS=$IFS + IFS=: + for dir in $KDEDIRS; do + kde_default_bindirs="$dir/bin $kde_default_bindirs " + done + IFS=$kde_save_IFS + fi +]) + +AC_DEFUN([KDE_SUBST_PROGRAMS], +[ + AC_ARG_WITH(arts, + AC_HELP_STRING([--without-arts],[build without aRts [default=no]]), + [build_arts=$withval], + [build_arts=yes] + ) + AM_CONDITIONAL(include_ARTS, test "$build_arts" '!=' "no") + if test "$build_arts" = "no"; then + AC_DEFINE(WITHOUT_ARTS, 1, [Defined if compiling without arts]) + fi + + KDE_SET_DEFAULT_BINDIRS + kde_default_bindirs="$exec_prefix/bin $prefix/bin $kde_libs_prefix/bin $kde_default_bindirs" + KDE_FIND_PATH(dcopidl, DCOPIDL, [$kde_default_bindirs], [KDE_MISSING_PROG_ERROR(dcopidl)]) + KDE_FIND_PATH(dcopidl2cpp, DCOPIDL2CPP, [$kde_default_bindirs], [KDE_MISSING_PROG_ERROR(dcopidl2cpp)]) + if test "$build_arts" '!=' "no"; then + KDE_FIND_PATH(mcopidl, MCOPIDL, [$kde_default_bindirs], [KDE_MISSING_ARTS_ERROR(mcopidl)]) + KDE_FIND_PATH(artsc-config, ARTSCCONFIG, [$kde_default_bindirs], [KDE_MISSING_ARTS_ERROR(artsc-config)]) + fi + KDE_FIND_PATH(meinproc, MEINPROC, [$kde_default_bindirs]) + + kde32ornewer=1 + kde33ornewer=1 + if test -n "$kde_qtver" && test "$kde_qtver" -lt 3; then + kde32ornewer= + kde33ornewer= + else + if test "$kde_qtver" = "3"; then + if test "$kde_qtsubver" -le 1; then + kde32ornewer= + fi + if test "$kde_qtsubver" -le 2; then + kde33ornewer= + fi + if test "$KDECONFIG" != "compiled"; then + if test `$KDECONFIG --version | grep KDE | sed 's/KDE: \(...\).*/\1/'` = 3.2; then + kde33ornewer= + fi + fi + fi + fi + + if test -n "$kde32ornewer"; then + KDE_FIND_PATH(kconfig_compiler, KCONFIG_COMPILER, [$kde_default_bindirs], [KDE_MISSING_PROG_ERROR(kconfig_compiler)]) + KDE_FIND_PATH(dcopidlng, DCOPIDLNG, [$kde_default_bindirs], [KDE_MISSING_PROG_ERROR(dcopidlng)]) + fi + if test -n "$kde33ornewer"; then + KDE_FIND_PATH(makekdewidgets, MAKEKDEWIDGETS, [$kde_default_bindirs], [KDE_MISSING_PROG_ERROR(makekdewidgets)]) + AC_SUBST(MAKEKDEWIDGETS) + fi + KDE_FIND_PATH(xmllint, XMLLINT, [${prefix}/bin ${exec_prefix}/bin], [XMLLINT=""]) + + if test -n "$MEINPROC" -a "$MEINPROC" != "compiled"; then + kde_sharedirs="/usr/share/kde /usr/local/share /usr/share /opt/kde3/share /opt/kde/share $prefix/share" + test -n "$KDEDIR" && kde_sharedirs="$KDEDIR/share $kde_sharedirs" + AC_FIND_FILE(apps/ksgmltools2/customization/kde-chunk.xsl, $kde_sharedirs, KDE_XSL_STYLESHEET) + if test "$KDE_XSL_STYLESHEET" = "NO"; then + KDE_XSL_STYLESHEET="" + else + KDE_XSL_STYLESHEET="$KDE_XSL_STYLESHEET/apps/ksgmltools2/customization/kde-chunk.xsl" + fi + fi + + DCOP_DEPENDENCIES='$(DCOPIDL)' + if test -n "$kde32ornewer"; then + KCFG_DEPENDENCIES='$(KCONFIG_COMPILER)' + DCOP_DEPENDENCIES='$(DCOPIDL) $(DCOPIDLNG)' + AC_SUBST(KCONFIG_COMPILER) + AC_SUBST(KCFG_DEPENDENCIES) + AC_SUBST(DCOPIDLNG) + fi + AC_SUBST(DCOPIDL) + AC_SUBST(DCOPIDL2CPP) + AC_SUBST(DCOP_DEPENDENCIES) + AC_SUBST(MCOPIDL) + AC_SUBST(ARTSCCONFIG) + AC_SUBST(MEINPROC) + AC_SUBST(KDE_XSL_STYLESHEET) + AC_SUBST(XMLLINT) +])dnl + +AC_DEFUN([AC_CREATE_KFSSTND], +[ +AC_REQUIRE([AC_CHECK_RPATH]) + +AC_MSG_CHECKING([for KDE paths]) +kde_result="" +kde_cached_paths=yes +AC_CACHE_VAL(kde_cv_all_paths, +[ + KDE_SET_DEFAULT_PATHS($1) + kde_cached_paths=no +]) +eval "$kde_cv_all_paths" +KDE_CHECK_PATHS_FOR_COMPLETENESS +if test "$kde_have_all_paths" = "no" && test "$kde_cached_paths" = "yes"; then + # wrong values were cached, may be, we can set better ones + kde_result= + kde_htmldir= kde_appsdir= kde_icondir= kde_sounddir= + kde_datadir= kde_locale= kde_cgidir= kde_confdir= kde_kcfgdir= + kde_mimedir= kde_toolbardir= kde_wallpaperdir= kde_templatesdir= + kde_bindir= kde_servicesdir= kde_servicetypesdir= kde_moduledir= + kde_have_all_paths= + kde_styledir= + kde_widgetdir= + xdg_appsdir = xdg_menudir= xdg_directorydir= + KDE_SET_DEFAULT_PATHS($1) + eval "$kde_cv_all_paths" + KDE_CHECK_PATHS_FOR_COMPLETENESS + kde_result="$kde_result (cache overridden)" +fi +if test "$kde_have_all_paths" = "no"; then + AC_MSG_ERROR([configure could not run a little KDE program to test the environment. +Since it had compiled and linked before, it must be a strange problem on your system. +Look at config.log for details. If you are not able to fix this, look at +http://www.kde.org/faq/installation.html or any www.kde.org mirror. +(If you're using an egcs version on Linux, you may update binutils!) +]) +else + rm -f conftest* + AC_MSG_RESULT($kde_result) +fi + +bindir=$kde_bindir + +KDE_SUBST_PROGRAMS + +]) + +AC_DEFUN([AC_SUBST_KFSSTND], +[ +AC_SUBST(kde_htmldir) +AC_SUBST(kde_appsdir) +AC_SUBST(kde_icondir) +AC_SUBST(kde_sounddir) +AC_SUBST(kde_datadir) +AC_SUBST(kde_locale) +AC_SUBST(kde_confdir) +AC_SUBST(kde_kcfgdir) +AC_SUBST(kde_mimedir) +AC_SUBST(kde_wallpaperdir) +AC_SUBST(kde_bindir) +dnl X Desktop Group standards +AC_SUBST(xdg_appsdir) +AC_SUBST(xdg_menudir) +AC_SUBST(xdg_directorydir) +dnl for KDE 2 +AC_SUBST(kde_templatesdir) +AC_SUBST(kde_servicesdir) +AC_SUBST(kde_servicetypesdir) +AC_SUBST(kde_moduledir) +AC_SUBST(kdeinitdir, '$(kde_moduledir)') +AC_SUBST(kde_styledir) +AC_SUBST(kde_widgetdir) +if test "$kde_qtver" = 1; then + kde_minidir="$kde_icondir/mini" +else +# for KDE 1 - this breaks KDE2 apps using minidir, but +# that's the plan ;-/ + kde_minidir="/dev/null" +fi +dnl AC_SUBST(kde_minidir) +dnl AC_SUBST(kde_cgidir) +dnl AC_SUBST(kde_toolbardir) +]) + +AC_DEFUN([KDE_MISC_TESTS], +[ + dnl Checks for libraries. + AC_CHECK_LIB(util, main, [LIBUTIL="-lutil"]) dnl for *BSD + AC_SUBST(LIBUTIL) + AC_CHECK_LIB(compat, main, [LIBCOMPAT="-lcompat"]) dnl for *BSD + AC_SUBST(LIBCOMPAT) + kde_have_crypt= + AC_CHECK_LIB(crypt, crypt, [LIBCRYPT="-lcrypt"; kde_have_crypt=yes], + AC_CHECK_LIB(c, crypt, [kde_have_crypt=yes], [ + AC_MSG_WARN([you have no crypt in either libcrypt or libc. +You should install libcrypt from another source or configure with PAM +support]) + kde_have_crypt=no + ])) + AC_SUBST(LIBCRYPT) + if test $kde_have_crypt = yes; then + AC_DEFINE_UNQUOTED(HAVE_CRYPT, 1, [Defines if your system has the crypt function]) + fi + AC_CHECK_SOCKLEN_T + AC_CHECK_LIB(dnet, dnet_ntoa, [X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet"]) + if test $ac_cv_lib_dnet_dnet_ntoa = no; then + AC_CHECK_LIB(dnet_stub, dnet_ntoa, + [X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet_stub"]) + fi + AC_CHECK_FUNC(inet_ntoa) + if test $ac_cv_func_inet_ntoa = no; then + AC_CHECK_LIB(nsl, inet_ntoa, X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl") + fi + AC_CHECK_FUNC(connect) + if test $ac_cv_func_connect = no; then + AC_CHECK_LIB(socket, connect, X_EXTRA_LIBS="-lsocket $X_EXTRA_LIBS", , + $X_EXTRA_LIBS) + fi + + AC_CHECK_FUNC(remove) + if test $ac_cv_func_remove = no; then + AC_CHECK_LIB(posix, remove, X_EXTRA_LIBS="$X_EXTRA_LIBS -lposix") + fi + + # BSDI BSD/OS 2.1 needs -lipc for XOpenDisplay. + AC_CHECK_FUNC(shmat, , + AC_CHECK_LIB(ipc, shmat, X_EXTRA_LIBS="$X_EXTRA_LIBS -lipc")) + + # more headers that need to be explicitly included on darwin + AC_CHECK_HEADERS(sys/types.h stdint.h) + + # sys/bitypes.h is needed for uint32_t and friends on Tru64 + AC_CHECK_HEADERS(sys/bitypes.h) + + # darwin requires a poll emulation library + AC_CHECK_LIB(poll, poll, LIB_POLL="-lpoll") + + # for some image handling on Mac OS X + AC_CHECK_HEADERS(Carbon/Carbon.h) + + # CoreAudio framework + AC_CHECK_HEADER(CoreAudio/CoreAudio.h, [ + AC_DEFINE(HAVE_COREAUDIO, 1, [Define if you have the CoreAudio API]) + FRAMEWORK_COREAUDIO="-Wl,-framework,CoreAudio" + ]) + + AC_CHECK_RES_INIT + AC_SUBST(LIB_POLL) + AC_SUBST(FRAMEWORK_COREAUDIO) + LIBSOCKET="$X_EXTRA_LIBS" + AC_SUBST(LIBSOCKET) + AC_SUBST(X_EXTRA_LIBS) + AC_CHECK_LIB(ucb, killpg, [LIBUCB="-lucb"]) dnl for Solaris2.4 + AC_SUBST(LIBUCB) + + case $host in dnl this *is* LynxOS specific + *-*-lynxos* ) + AC_MSG_CHECKING([LynxOS header file wrappers]) + [CFLAGS="$CFLAGS -D__NO_INCLUDE_WARN__"] + AC_MSG_RESULT(disabled) + AC_CHECK_LIB(bsd, gethostbyname, [LIBSOCKET="-lbsd"]) dnl for LynxOS + ;; + esac + + KDE_CHECK_TYPES + KDE_CHECK_LIBDL + KDE_CHECK_STRLCPY + KDE_CHECK_PIE_SUPPORT + +# darwin needs this to initialize the environment +AC_CHECK_HEADERS(crt_externs.h) +AC_CHECK_FUNC(_NSGetEnviron, [AC_DEFINE(HAVE_NSGETENVIRON, 1, [Define if your system needs _NSGetEnviron to set up the environment])]) + +AH_VERBATIM(_DARWIN_ENVIRON, +[ +#if defined(HAVE_NSGETENVIRON) && defined(HAVE_CRT_EXTERNS_H) +# include +# include +# define environ (*_NSGetEnviron()) +#endif +]) + +AH_VERBATIM(_AIX_STRINGS_H_BZERO, +[ +/* + * AIX defines FD_SET in terms of bzero, but fails to include + * that defines bzero. + */ + +#if defined(_AIX) +#include +#endif +]) + +AC_CHECK_FUNCS([vsnprintf snprintf]) + +AH_VERBATIM(_TRU64,[ +/* + * On HP-UX, the declaration of vsnprintf() is needed every time ! + */ + +#if !defined(HAVE_VSNPRINTF) || defined(hpux) +#if __STDC__ +#include +#include +#else +#include +#endif +#ifdef __cplusplus +extern "C" +#endif +int vsnprintf(char *str, size_t n, char const *fmt, va_list ap); +#ifdef __cplusplus +extern "C" +#endif +int snprintf(char *str, size_t n, char const *fmt, ...); +#endif +]) + +]) + +dnl ------------------------------------------------------------------------ +dnl Find the header files and libraries for X-Windows. Extended the +dnl macro AC_PATH_X +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([K_PATH_X], +[ +AC_REQUIRE([KDE_MISC_TESTS])dnl +AC_REQUIRE([KDE_CHECK_LIB64]) + +AC_ARG_ENABLE( + embedded, + AC_HELP_STRING([--enable-embedded],[link to Qt-embedded, don't use X]), + kde_use_qt_emb=$enableval, + kde_use_qt_emb=no +) + +AC_ARG_ENABLE( + qtopia, + AC_HELP_STRING([--enable-qtopia],[link to Qt-embedded, link to the Qtopia Environment]), + kde_use_qt_emb_palm=$enableval, + kde_use_qt_emb_palm=no +) + +AC_ARG_ENABLE( + mac, + AC_HELP_STRING([--enable-mac],[link to Qt/Mac (don't use X)]), + kde_use_qt_mac=$enableval, + kde_use_qt_mac=no +) + +# used to disable x11-specific stuff on special platforms +AM_CONDITIONAL(include_x11, test "$kde_use_qt_emb" = "no" && test "$kde_use_qt_mac" = "no") + +if test "$kde_use_qt_emb" = "no" && test "$kde_use_qt_mac" = "no"; then + +AC_MSG_CHECKING(for X) + +AC_CACHE_VAL(kde_cv_have_x, +[# One or both of the vars are not set, and there is no cached value. +if test "{$x_includes+set}" = set || test "$x_includes" = NONE; then + kde_x_includes=NO +else + kde_x_includes=$x_includes +fi +if test "{$x_libraries+set}" = set || test "$x_libraries" = NONE; then + kde_x_libraries=NO +else + kde_x_libraries=$x_libraries +fi + +# below we use the standard autoconf calls +ac_x_libraries=$kde_x_libraries +ac_x_includes=$kde_x_includes + +KDE_PATH_X_DIRECT +dnl AC_PATH_X_XMKMF picks /usr/lib as the path for the X libraries. +dnl Unfortunately, if compiling with the N32 ABI, this is not the correct +dnl location. The correct location is /usr/lib32 or an undefined value +dnl (the linker is smart enough to pick the correct default library). +dnl Things work just fine if you use just AC_PATH_X_DIRECT. +dnl Solaris has a similar problem. AC_PATH_X_XMKMF forces x_includes to +dnl /usr/openwin/include, which doesn't work. /usr/include does work, so +dnl x_includes should be left alone. +case "$host" in +mips-sgi-irix6*) + ;; +*-*-solaris*) + ;; +*) + _AC_PATH_X_XMKMF + if test -z "$ac_x_includes"; then + ac_x_includes="." + fi + if test -z "$ac_x_libraries"; then + ac_x_libraries="/usr/lib${kdelibsuff}" + fi +esac +#from now on we use our own again + +# when the user already gave --x-includes, we ignore +# what the standard autoconf macros told us. +if test "$kde_x_includes" = NO; then + kde_x_includes=$ac_x_includes +fi + +# for --x-libraries too +if test "$kde_x_libraries" = NO; then + kde_x_libraries=$ac_x_libraries +fi + +if test "$kde_x_includes" = NO; then + AC_MSG_ERROR([Can't find X includes. Please check your installation and add the correct paths!]) +fi + +if test "$kde_x_libraries" = NO; then + AC_MSG_ERROR([Can't find X libraries. Please check your installation and add the correct paths!]) +fi + +# Record where we found X for the cache. +kde_cv_have_x="have_x=yes \ + kde_x_includes=$kde_x_includes kde_x_libraries=$kde_x_libraries" +])dnl + +eval "$kde_cv_have_x" + +if test "$have_x" != yes; then + AC_MSG_RESULT($have_x) + no_x=yes +else + AC_MSG_RESULT([libraries $kde_x_libraries, headers $kde_x_includes]) +fi + +if test -z "$kde_x_includes" || test "x$kde_x_includes" = xNONE; then + X_INCLUDES="" + x_includes="."; dnl better than nothing :- + else + x_includes=$kde_x_includes + X_INCLUDES="-I$x_includes" +fi + +if test -z "$kde_x_libraries" || test "x$kde_x_libraries" = xNONE || test "$kde_x_libraries" = "/usr/lib"; then + X_LDFLAGS="" + x_libraries="/usr/lib"; dnl better than nothing :- + else + x_libraries=$kde_x_libraries + X_LDFLAGS="-L$x_libraries" +fi +all_includes="$X_INCLUDES" +all_libraries="$X_LDFLAGS $LDFLAGS_AS_NEEDED $LDFLAGS_NEW_DTAGS" + +# Check for libraries that X11R6 Xt/Xaw programs need. +ac_save_LDFLAGS="$LDFLAGS" +LDFLAGS="$LDFLAGS $X_LDFLAGS" +# SM needs ICE to (dynamically) link under SunOS 4.x (so we have to +# check for ICE first), but we must link in the order -lSM -lICE or +# we get undefined symbols. So assume we have SM if we have ICE. +# These have to be linked with before -lX11, unlike the other +# libraries we check for below, so use a different variable. +# --interran@uluru.Stanford.EDU, kb@cs.umb.edu. +AC_CHECK_LIB(ICE, IceConnectionNumber, + [LIBSM="-lSM -lICE"], , $X_EXTRA_LIBS) +LDFLAGS="$ac_save_LDFLAGS" + +LIB_X11='-lX11 $(LIBSOCKET)' + +AC_MSG_CHECKING(for libXext) +AC_CACHE_VAL(kde_cv_have_libXext, +[ +kde_ldflags_safe="$LDFLAGS" +kde_libs_safe="$LIBS" + +LDFLAGS="$LDFLAGS $X_LDFLAGS $USER_LDFLAGS" +LIBS="-lXext -lX11 $LIBSOCKET" + +AC_TRY_LINK([ +#include +#ifdef STDC_HEADERS +# include +#endif +], +[ +printf("hello Xext\n"); +], +kde_cv_have_libXext=yes, +kde_cv_have_libXext=no +) + +LDFLAGS=$kde_ldflags_safe +LIBS=$kde_libs_safe +]) + +AC_MSG_RESULT($kde_cv_have_libXext) + +if test "$kde_cv_have_libXext" = "no"; then + AC_MSG_ERROR([We need a working libXext to proceed. Since configure +can't find it itself, we stop here assuming that make wouldn't find +them either.]) +fi + +LIB_XEXT="-lXext" +QTE_NORTTI="" + +elif test "$kde_use_qt_emb" = "yes"; then + dnl We're using QT Embedded + CPPFLAGS=-DQWS + CXXFLAGS="$CXXFLAGS -fno-rtti" + QTE_NORTTI="-fno-rtti -DQWS" + X_PRE_LIBS="" + LIB_X11="" + LIB_XEXT="" + LIB_XRENDER="" + LIBSM="" + X_INCLUDES="" + X_LDFLAGS="" + x_includes="" + x_libraries="" +elif test "$kde_use_qt_mac" = "yes"; then + dnl We're using QT/Mac (I use QT_MAC so that qglobal.h doesn't *have* to + dnl be included to get the information) --Sam + CXXFLAGS="$CXXFLAGS -DQT_MAC -no-cpp-precomp" + CFLAGS="$CFLAGS -DQT_MAC -no-cpp-precomp" + X_PRE_LIBS="" + LIB_X11="" + LIB_XEXT="" + LIB_XRENDER="" + LIBSM="" + X_INCLUDES="" + X_LDFLAGS="" + x_includes="" + x_libraries="" +fi +AC_SUBST(X_PRE_LIBS) +AC_SUBST(LIB_X11) +AC_SUBST(LIB_XRENDER) +AC_SUBST(LIBSM) +AC_SUBST(X_INCLUDES) +AC_SUBST(X_LDFLAGS) +AC_SUBST(x_includes) +AC_SUBST(x_libraries) +AC_SUBST(QTE_NORTTI) +AC_SUBST(LIB_XEXT) + +]) + +AC_DEFUN([KDE_PRINT_QT_PROGRAM], +[ +AC_REQUIRE([KDE_USE_QT]) +cat > conftest.$ac_ext < +#include +EOF +if test "$kde_qtver" = "2"; then +cat >> conftest.$ac_ext < +#include +#include +EOF + +if test $kde_qtsubver -gt 0; then +cat >> conftest.$ac_ext <> conftest.$ac_ext < +#include +#include +EOF +fi + +echo "#if ! ($kde_qt_verstring)" >> conftest.$ac_ext +cat >> conftest.$ac_ext <> conftest.$ac_ext <> conftest.$ac_ext <> conftest.$ac_ext <> conftest.$ac_ext <&AC_FD_CC + cat conftest.$ac_ext >&AC_FD_CC +fi + +rm -f conftest* +CXXFLAGS="$ac_cxxflags_safe" +LDFLAGS="$ac_ldflags_safe" +LIBS="$ac_libs_safe" + +LD_LIBRARY_PATH="$ac_LD_LIBRARY_PATH_safe" +export LD_LIBRARY_PATH +LIBRARY_PATH="$ac_LIBRARY_PATH" +export LIBRARY_PATH +AC_LANG_RESTORE +]) + +if test "$kde_cv_qt_direct" = "yes"; then + AC_MSG_RESULT(yes) + $1 +else + AC_MSG_RESULT(no) + $2 +fi +]) + +dnl ------------------------------------------------------------------------ +dnl Try to find the Qt headers and libraries. +dnl $(QT_LDFLAGS) will be -Lqtliblocation (if needed) +dnl and $(QT_INCLUDES) will be -Iqthdrlocation (if needed) +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([AC_PATH_QT_1_3], +[ +AC_REQUIRE([K_PATH_X]) +AC_REQUIRE([KDE_USE_QT]) +AC_REQUIRE([KDE_CHECK_LIB64]) + +dnl ------------------------------------------------------------------------ +dnl Add configure flag to enable linking to MT version of Qt library. +dnl ------------------------------------------------------------------------ + +AC_ARG_ENABLE( + mt, + AC_HELP_STRING([--disable-mt],[link to non-threaded Qt (deprecated)]), + kde_use_qt_mt=$enableval, + [ + if test $kde_qtver = 3; then + kde_use_qt_mt=yes + else + kde_use_qt_mt=no + fi + ] +) + +USING_QT_MT="" + +dnl ------------------------------------------------------------------------ +dnl If we not get --disable-qt-mt then adjust some vars for the host. +dnl ------------------------------------------------------------------------ + +KDE_MT_LDFLAGS= +KDE_MT_LIBS= +if test "x$kde_use_qt_mt" = "xyes"; then + KDE_CHECK_THREADING + if test "x$kde_use_threading" = "xyes"; then + CPPFLAGS="$USE_THREADS -DQT_THREAD_SUPPORT $CPPFLAGS" + KDE_MT_LDFLAGS="$USE_THREADS" + KDE_MT_LIBS="$LIBPTHREAD" + else + kde_use_qt_mt=no + fi +fi +AC_SUBST(KDE_MT_LDFLAGS) +AC_SUBST(KDE_MT_LIBS) + +kde_qt_was_given=yes + +dnl ------------------------------------------------------------------------ +dnl If we haven't been told how to link to Qt, we work it out for ourselves. +dnl ------------------------------------------------------------------------ +if test -z "$LIBQT_GLOB"; then + if test "x$kde_use_qt_emb" = "xyes"; then + LIBQT_GLOB="libqte.*" + else + LIBQT_GLOB="libqt.*" + fi +fi + +dnl ------------------------------------------------------------ +dnl If we got --enable-embedded then adjust the Qt library name. +dnl ------------------------------------------------------------ +if test "x$kde_use_qt_emb" = "xyes"; then + qtlib="qte" +else + qtlib="qt" +fi + +kde_int_qt="-l$qtlib" + +if test -z "$LIBQPE"; then +dnl ------------------------------------------------------------ +dnl If we got --enable-palmtop then add -lqpe to the link line +dnl ------------------------------------------------------------ + if test "x$kde_use_qt_emb" = "xyes"; then + if test "x$kde_use_qt_emb_palm" = "xyes"; then + LIB_QPE="-lqpe" + else + LIB_QPE="" + fi + else + LIB_QPE="" + fi +fi + +dnl ------------------------------------------------------------------------ +dnl If we got --enable-qt-mt then adjust the Qt library name for the host. +dnl ------------------------------------------------------------------------ + +if test "x$kde_use_qt_mt" = "xyes"; then + LIBQT="-l$qtlib-mt" + kde_int_qt="-l$qtlib-mt" + LIBQT_GLOB="lib$qtlib-mt.*" + USING_QT_MT="using -mt" +else + LIBQT="-l$qtlib" +fi + +if test $kde_qtver != 1; then + + AC_REQUIRE([AC_FIND_PNG]) + AC_REQUIRE([AC_FIND_JPEG]) + LIBQT="$LIBQT $LIBPNG $LIBJPEG" +fi + +if test $kde_qtver = 3; then + AC_REQUIRE([KDE_CHECK_LIBDL]) + LIBQT="$LIBQT $LIBDL" +fi + +AC_MSG_CHECKING([for Qt]) + +if test "x$kde_use_qt_emb" != "xyes" && test "x$kde_use_qt_mac" != "xyes"; then +LIBQT="$LIBQT $X_PRE_LIBS -lXext -lX11 $LIBSM $LIBSOCKET" +fi +ac_qt_includes=NO ac_qt_libraries=NO ac_qt_bindir=NO +qt_libraries="" +qt_includes="" +AC_ARG_WITH(qt-dir, + AC_HELP_STRING([--with-qt-dir=DIR],[where the root of Qt is installed ]), + [ ac_qt_includes="$withval"/include + ac_qt_libraries="$withval"/lib${kdelibsuff} + ac_qt_bindir="$withval"/bin + ]) + +AC_ARG_WITH(qt-includes, + AC_HELP_STRING([--with-qt-includes=DIR],[where the Qt includes are. ]), + [ + ac_qt_includes="$withval" + ]) + +kde_qt_libs_given=no + +AC_ARG_WITH(qt-libraries, + AC_HELP_STRING([--with-qt-libraries=DIR],[where the Qt library is installed.]), + [ ac_qt_libraries="$withval" + kde_qt_libs_given=yes + ]) + +AC_CACHE_VAL(ac_cv_have_qt, +[#try to guess Qt locations + +qt_incdirs="" +for dir in $kde_qt_dirs; do + qt_incdirs="$qt_incdirs $dir/include $dir" +done +if test -z "$PKG_CONFIG"; then + AC_PATH_PROG(PKG_CONFIG, pkg-config, no) +fi +if test "$PKG_CONFIG" != "no" ; then + if $PKG_CONFIG --exists qt-mt ; then + qt_incdirs="$qt_incdirs `$PKG_CONFIG --variable=includedir qt-mt`" + fi +fi +qt_incdirs="$QTINC $qt_incdirs /usr/local/qt/include /usr/include/qt /usr/include /usr/X11R6/include/X11/qt /usr/X11R6/include/qt /usr/X11R6/include/qt2 /usr/include/qt3 $x_includes" +if test ! "$ac_qt_includes" = "NO"; then + qt_incdirs="$ac_qt_includes $qt_incdirs" +fi + +if test "$kde_qtver" != "1"; then + kde_qt_header=qstyle.h +else + kde_qt_header=qglobal.h +fi + +AC_FIND_FILE($kde_qt_header, $qt_incdirs, qt_incdir) +ac_qt_includes="$qt_incdir" + +qt_libdirs="" +for dir in $kde_qt_dirs; do + qt_libdirs="$qt_libdirs $dir/lib${kdelibsuff} $dir/lib $dir" +done +if test -z "$PKG_CONFIG"; then + AC_PATH_PROG(PKG_CONFIG, pkg-config, no) +fi +if test "$PKG_CONFIG" != "no" ; then + if $PKG_CONFIG --exists qt-mt ; then + qt_libdirs="$qt_incdirs `$PKG_CONFIG --variable=libdir qt-mt`" + fi +fi +qt_libdirs="$QTLIB $qt_libdirs /usr/X11R6/lib /usr/lib /usr/local/qt/lib $x_libraries" +if test ! "$ac_qt_libraries" = "NO"; then + qt_libdir=$ac_qt_libraries +else + qt_libdirs="$ac_qt_libraries $qt_libdirs" + # if the Qt was given, the chance is too big that libqt.* doesn't exist + qt_libdir=NONE + for dir in $qt_libdirs; do + try="ls -1 $dir/${LIBQT_GLOB}" + if test -n "`$try 2> /dev/null`"; then qt_libdir=$dir; break; else echo "tried $dir" >&AC_FD_CC ; fi + done +fi +for a in $qt_libdir/lib`echo ${kde_int_qt} | sed 's,^-l,,'`_incremental.*; do + if test -e "$a"; then + LIBQT="$LIBQT ${kde_int_qt}_incremental" + break + fi +done + +ac_qt_libraries="$qt_libdir" + +AC_LANG_SAVE +AC_LANG_CPLUSPLUS + +ac_cxxflags_safe="$CXXFLAGS" +ac_ldflags_safe="$LDFLAGS" +ac_libs_safe="$LIBS" + +CXXFLAGS="$CXXFLAGS -I$qt_incdir $all_includes" +LDFLAGS="$LDFLAGS -L$qt_libdir $all_libraries $USER_LDFLAGS $KDE_MT_LDFLAGS" +LIBS="$LIBS $LIBQT $KDE_MT_LIBS" + +KDE_PRINT_QT_PROGRAM + +if AC_TRY_EVAL(ac_link) && test -s conftest; then + rm -f conftest* +else + echo "configure: failed program was:" >&AC_FD_CC + cat conftest.$ac_ext >&AC_FD_CC + ac_qt_libraries="NO" +fi +rm -f conftest* +CXXFLAGS="$ac_cxxflags_safe" +LDFLAGS="$ac_ldflags_safe" +LIBS="$ac_libs_safe" + +AC_LANG_RESTORE +if test "$ac_qt_includes" = NO || test "$ac_qt_libraries" = NO; then + ac_cv_have_qt="have_qt=no" + ac_qt_notfound="" + missing_qt_mt="" + if test "$ac_qt_includes" = NO; then + if test "$ac_qt_libraries" = NO; then + ac_qt_notfound="(headers and libraries)"; + else + ac_qt_notfound="(headers)"; + fi + else + if test "x$kde_use_qt_mt" = "xyes"; then + missing_qt_mt=" +Make sure that you have compiled Qt with thread support!" + ac_qt_notfound="(library $qtlib-mt)"; + else + ac_qt_notfound="(library $qtlib)"; + fi + fi + + AC_MSG_ERROR([Qt ($kde_qt_minversion) $ac_qt_notfound not found. Please check your installation! +For more details about this problem, look at the end of config.log.$missing_qt_mt]) +else + have_qt="yes" +fi +]) + +eval "$ac_cv_have_qt" + +if test "$have_qt" != yes; then + AC_MSG_RESULT([$have_qt]); +else + ac_cv_have_qt="have_qt=yes \ + ac_qt_includes=$ac_qt_includes ac_qt_libraries=$ac_qt_libraries" + AC_MSG_RESULT([libraries $ac_qt_libraries, headers $ac_qt_includes $USING_QT_MT]) + + qt_libraries="$ac_qt_libraries" + qt_includes="$ac_qt_includes" +fi + +if test ! "$kde_qt_libs_given" = "yes" && test ! "$kde_qtver" = 3; then + KDE_CHECK_QT_DIRECT(qt_libraries= ,[]) +fi + +AC_SUBST(qt_libraries) +AC_SUBST(qt_includes) + +if test "$qt_includes" = "$x_includes" || test -z "$qt_includes"; then + QT_INCLUDES="" +else + QT_INCLUDES="-I$qt_includes" + all_includes="$QT_INCLUDES $all_includes" +fi + +if test "$qt_libraries" = "$x_libraries" || test -z "$qt_libraries"; then + QT_LDFLAGS="" +else + QT_LDFLAGS="-L$qt_libraries" + all_libraries="$QT_LDFLAGS $all_libraries" +fi +test -z "$KDE_MT_LDFLAGS" || all_libraries="$all_libraries $KDE_MT_LDFLAGS" + +AC_SUBST(QT_INCLUDES) +AC_SUBST(QT_LDFLAGS) +AC_PATH_QT_MOC_UIC + +KDE_CHECK_QT_JPEG + +if test "x$kde_use_qt_emb" != "xyes" && test "x$kde_use_qt_mac" != "xyes"; then +LIB_QT="$kde_int_qt $LIBJPEG_QT "'$(LIBZ) $(LIBPNG) -lXext $(LIB_X11) $(LIBSM)' +else +LIB_QT="$kde_int_qt $LIBJPEG_QT "'$(LIBZ) $(LIBPNG)' +fi +test -z "$KDE_MT_LIBS" || LIB_QT="$LIB_QT $KDE_MT_LIBS" +for a in $qt_libdir/lib`echo ${kde_int_qt} | sed 's,^-l,,'`_incremental.*; do + if test -e "$a"; then + LIB_QT="$LIB_QT ${kde_int_qt}_incremental" + break + fi +done + +AC_SUBST(LIB_QT) +AC_SUBST(LIB_QPE) + +AC_SUBST(kde_qtver) +]) + +AC_DEFUN([AC_PATH_QT], +[ +AC_PATH_QT_1_3 +]) + +AC_DEFUN([KDE_CHECK_UIC_PLUGINS], +[ +AC_REQUIRE([AC_PATH_QT_MOC_UIC]) + +if test x$ac_uic_supports_libpath = xyes; then + +AC_MSG_CHECKING([if UIC has KDE plugins available]) +AC_CACHE_VAL(kde_cv_uic_plugins, +[ +cat > actest.ui << EOF + +NewConnectionDialog + + + + testInput + + + + +EOF + + + +kde_cv_uic_plugins=no +kde_line="$UIC_PATH -L $kde_widgetdir" +if test x$ac_uic_supports_nounload = xyes; then + kde_line="$kde_line -nounload" +fi +kde_line="$kde_line -impl actest.h actest.ui > actest.cpp" +if AC_TRY_EVAL(kde_line); then + # if you're trying to debug this check and think it's incorrect, + # better check your installation. The check _is_ correct - your + # installation is not. + if test -f actest.cpp && grep klineedit actest.cpp > /dev/null; then + kde_cv_uic_plugins=yes + fi +fi +rm -f actest.ui actest.cpp +]) + +AC_MSG_RESULT([$kde_cv_uic_plugins]) +if test "$kde_cv_uic_plugins" != yes; then + AC_MSG_ERROR([ +you need to install kdelibs first. + +If you did install kdelibs, then the Qt version that is picked up by +this configure is not the same version you used to compile kdelibs. +The Qt Plugin installed by kdelibs is *ONLY* loadable if it is the +_same Qt version_, compiled with the _same compiler_ and the same Qt +configuration settings. +]) +fi +fi +]) + +AC_DEFUN([KDE_CHECK_FINAL], +[ + AC_ARG_ENABLE(final, + AC_HELP_STRING([--enable-final], + [build size optimized apps (experimental - needs lots of memory)]), + kde_use_final=$enableval, kde_use_final=no) + + if test "x$kde_use_final" = "xyes"; then + KDE_USE_FINAL_TRUE="" + KDE_USE_FINAL_FALSE="#" + else + KDE_USE_FINAL_TRUE="#" + KDE_USE_FINAL_FALSE="" + fi + AC_SUBST(KDE_USE_FINAL_TRUE) + AC_SUBST(KDE_USE_FINAL_FALSE) +]) + +AC_DEFUN([KDE_CHECK_CLOSURE], +[ + AC_ARG_ENABLE(closure, + AC_HELP_STRING([--enable-closure],[delay template instantiation]), + kde_use_closure=$enableval, kde_use_closure=no) + + KDE_NO_UNDEFINED="" + if test "x$kde_use_closure" = "xyes"; then + KDE_USE_CLOSURE_TRUE="" + KDE_USE_CLOSURE_FALSE="#" +# CXXFLAGS="$CXXFLAGS $REPO" + else + KDE_USE_CLOSURE_TRUE="#" + KDE_USE_CLOSURE_FALSE="" + KDE_NO_UNDEFINED="" + case $host in + *-*-linux-gnu) + KDE_CHECK_COMPILER_FLAG([Wl,--no-undefined], + [KDE_CHECK_COMPILER_FLAG([Wl,--allow-shlib-undefined], + [KDE_NO_UNDEFINED="-Wl,--no-undefined -Wl,--allow-shlib-undefined"], + [KDE_NO_UNDEFINED=""])], + [KDE_NO_UNDEFINED=""]) + ;; + esac + fi + AC_SUBST(KDE_USE_CLOSURE_TRUE) + AC_SUBST(KDE_USE_CLOSURE_FALSE) + AC_SUBST(KDE_NO_UNDEFINED) +]) + +dnl Check if the linker supports --enable-new-dtags and --as-needed +AC_DEFUN([KDE_CHECK_NEW_LDFLAGS], +[ + AC_ARG_ENABLE(new_ldflags, + AC_HELP_STRING([--enable-new-ldflags], + [enable the new linker flags]), + kde_use_new_ldflags=$enableval, + kde_use_new_ldflags=no) + + LDFLAGS_AS_NEEDED="" + LDFLAGS_NEW_DTAGS="" + if test "x$kde_use_new_ldflags" = "xyes"; then + LDFLAGS_NEW_DTAGS="" + KDE_CHECK_COMPILER_FLAG([Wl,--enable-new-dtags], + [LDFLAGS_NEW_DTAGS="-Wl,--enable-new-dtags"],) + + KDE_CHECK_COMPILER_FLAG([Wl,--as-needed], + [LDFLAGS_AS_NEEDED="-Wl,--as-needed"],) + fi + AC_SUBST(LDFLAGS_AS_NEEDED) + AC_SUBST(LDFLAGS_NEW_DTAGS) +]) + +AC_DEFUN([KDE_CHECK_NMCHECK], +[ + AC_ARG_ENABLE(nmcheck,AC_HELP_STRING([--enable-nmcheck],[enable automatic namespace cleanness check]), + kde_use_nmcheck=$enableval, kde_use_nmcheck=no) + + if test "$kde_use_nmcheck" = "yes"; then + KDE_USE_NMCHECK_TRUE="" + KDE_USE_NMCHECK_FALSE="#" + else + KDE_USE_NMCHECK_TRUE="#" + KDE_USE_NMCHECK_FALSE="" + fi + AC_SUBST(KDE_USE_NMCHECK_TRUE) + AC_SUBST(KDE_USE_NMCHECK_FALSE) +]) + +AC_DEFUN([KDE_EXPAND_MAKEVAR], [ +savex=$exec_prefix +test "x$exec_prefix" = xNONE && exec_prefix=$prefix +tmp=$$2 +while $1=`eval echo "$tmp"`; test "x$$1" != "x$tmp"; do tmp=$$1; done +exec_prefix=$savex +]) + +dnl ------------------------------------------------------------------------ +dnl Now, the same with KDE +dnl $(KDE_LDFLAGS) will be the kdeliblocation (if needed) +dnl and $(kde_includes) will be the kdehdrlocation (if needed) +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([AC_BASE_PATH_KDE], +[ +AC_REQUIRE([KDE_CHECK_STL]) +AC_REQUIRE([AC_PATH_QT])dnl +AC_REQUIRE([KDE_CHECK_LIB64]) + +AC_CHECK_RPATH +AC_MSG_CHECKING([for KDE]) + +if test "${prefix}" != NONE; then + kde_includes=${includedir} + KDE_EXPAND_MAKEVAR(ac_kde_includes, includedir) + + kde_libraries=${libdir} + KDE_EXPAND_MAKEVAR(ac_kde_libraries, libdir) + +else + ac_kde_includes= + ac_kde_libraries= + kde_libraries="" + kde_includes="" +fi + +AC_CACHE_VAL(ac_cv_have_kde, +[#try to guess kde locations + +if test "$kde_qtver" = 1; then + kde_check_header="ksock.h" + kde_check_lib="libkdecore.la" +else + kde_check_header="ksharedptr.h" + kde_check_lib="libkio.la" +fi + +if test -z "$1"; then + +kde_incdirs="$kde_libs_prefix/include /usr/lib/kde/include /usr/local/kde/include /usr/local/include /usr/kde/include /usr/include/kde /usr/include /opt/kde3/include /opt/kde/include $x_includes $qt_includes" +test -n "$KDEDIR" && kde_incdirs="$KDEDIR/include $KDEDIR/include/kde $KDEDIR $kde_incdirs" +kde_incdirs="$ac_kde_includes $kde_incdirs" +AC_FIND_FILE($kde_check_header, $kde_incdirs, kde_incdir) +ac_kde_includes="$kde_incdir" + +if test -n "$ac_kde_includes" && test ! -r "$ac_kde_includes/$kde_check_header"; then + AC_MSG_ERROR([ +in the prefix, you've chosen, are no KDE headers installed. This will fail. +So, check this please and use another prefix!]) +fi + +kde_libdirs="$kde_libs_prefix/lib${kdelibsuff} /usr/lib/kde/lib${kdelibsuff} /usr/local/kde/lib${kdelibsuff} /usr/kde/lib${kdelibsuff} /usr/lib${kdelibsuff}/kde /usr/lib${kdelibsuff}/kde3 /usr/lib${kdelibsuff} /usr/X11R6/lib${kdelibsuff} /usr/local/lib${kdelibsuff} /opt/kde3/lib${kdelibsuff} /opt/kde/lib${kdelibsuff} /usr/X11R6/kde/lib${kdelibsuff}" +test -n "$KDEDIR" && kde_libdirs="$KDEDIR/lib${kdelibsuff} $KDEDIR $kde_libdirs" +kde_libdirs="$ac_kde_libraries $libdir $kde_libdirs" +AC_FIND_FILE($kde_check_lib, $kde_libdirs, kde_libdir) +ac_kde_libraries="$kde_libdir" + +kde_widgetdir=NO +dnl this might be somewhere else +AC_FIND_FILE("kde3/plugins/designer/kdewidgets.la", $kde_libdirs, kde_widgetdir) + +if test -n "$ac_kde_libraries" && test ! -r "$ac_kde_libraries/$kde_check_lib"; then +AC_MSG_ERROR([ +in the prefix, you've chosen, are no KDE libraries installed. This will fail. +So, check this please and use another prefix!]) +fi + +if test -n "$kde_widgetdir" && test ! -r "$kde_widgetdir/kde3/plugins/designer/kdewidgets.la"; then +AC_MSG_ERROR([ +I can't find the designer plugins. These are required and should have been installed +by kdelibs]) +fi + +if test -n "$kde_widgetdir"; then + kde_widgetdir="$kde_widgetdir/kde3/plugins/designer" +fi + + +if test "$ac_kde_includes" = NO || test "$ac_kde_libraries" = NO || test "$kde_widgetdir" = NO; then + ac_cv_have_kde="have_kde=no" +else + ac_cv_have_kde="have_kde=yes \ + ac_kde_includes=$ac_kde_includes ac_kde_libraries=$ac_kde_libraries" +fi + +else dnl test -z $1, e.g. from kdelibs + + ac_cv_have_kde="have_kde=no" + +fi +])dnl + +eval "$ac_cv_have_kde" + +if test "$have_kde" != "yes"; then + if test "${prefix}" = NONE; then + ac_kde_prefix="$ac_default_prefix" + else + ac_kde_prefix="$prefix" + fi + if test "$exec_prefix" = NONE; then + ac_kde_exec_prefix="$ac_kde_prefix" + AC_MSG_RESULT([will be installed in $ac_kde_prefix]) + else + ac_kde_exec_prefix="$exec_prefix" + AC_MSG_RESULT([will be installed in $ac_kde_prefix and $ac_kde_exec_prefix]) + fi + + kde_libraries="${libdir}" + kde_includes="${includedir}" + +else + ac_cv_have_kde="have_kde=yes \ + ac_kde_includes=$ac_kde_includes ac_kde_libraries=$ac_kde_libraries" + AC_MSG_RESULT([libraries $ac_kde_libraries, headers $ac_kde_includes]) + + kde_libraries="$ac_kde_libraries" + kde_includes="$ac_kde_includes" +fi +AC_SUBST(kde_libraries) +AC_SUBST(kde_includes) + +if test "$kde_includes" = "$x_includes" || test "$kde_includes" = "$qt_includes" || test "$kde_includes" = "/usr/include"; then + KDE_INCLUDES="" +else + KDE_INCLUDES="-I$kde_includes" + all_includes="$KDE_INCLUDES $all_includes" +fi + +KDE_DEFAULT_CXXFLAGS="-DQT_CLEAN_NAMESPACE -DQT_NO_ASCII_CAST -DQT_NO_STL -DQT_NO_COMPAT -DQT_NO_TRANSLATION" + +KDE_LDFLAGS="-L$kde_libraries" +if test ! "$kde_libraries" = "$x_libraries" && test ! "$kde_libraries" = "$qt_libraries" ; then + all_libraries="$KDE_LDFLAGS $all_libraries" +fi + +AC_SUBST(KDE_LDFLAGS) +AC_SUBST(KDE_INCLUDES) + +AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) + +all_libraries="$all_libraries $USER_LDFLAGS" +all_includes="$all_includes $USER_INCLUDES" +AC_SUBST(all_includes) +AC_SUBST(all_libraries) + +if test -z "$1"; then +KDE_CHECK_UIC_PLUGINS +fi + +ac_kde_libraries="$kde_libdir" + +AC_SUBST(AUTODIRS) + + +]) + +AC_DEFUN([KDE_CHECK_EXTRA_LIBS], +[ +AC_MSG_CHECKING(for extra includes) +AC_ARG_WITH(extra-includes,AC_HELP_STRING([--with-extra-includes=DIR],[adds non standard include paths]), + kde_use_extra_includes="$withval", + kde_use_extra_includes=NONE +) +kde_extra_includes= +if test -n "$kde_use_extra_includes" && \ + test "$kde_use_extra_includes" != "NONE"; then + + ac_save_ifs=$IFS + IFS=':' + for dir in $kde_use_extra_includes; do + kde_extra_includes="$kde_extra_includes $dir" + USER_INCLUDES="$USER_INCLUDES -I$dir" + done + IFS=$ac_save_ifs + kde_use_extra_includes="added" +else + kde_use_extra_includes="no" +fi +AC_SUBST(USER_INCLUDES) + +AC_MSG_RESULT($kde_use_extra_includes) + +kde_extra_libs= +AC_MSG_CHECKING(for extra libs) +AC_ARG_WITH(extra-libs,AC_HELP_STRING([--with-extra-libs=DIR],[adds non standard library paths]), + kde_use_extra_libs=$withval, + kde_use_extra_libs=NONE +) +if test -n "$kde_use_extra_libs" && \ + test "$kde_use_extra_libs" != "NONE"; then + + ac_save_ifs=$IFS + IFS=':' + for dir in $kde_use_extra_libs; do + kde_extra_libs="$kde_extra_libs $dir" + KDE_EXTRA_RPATH="$KDE_EXTRA_RPATH -R $dir" + USER_LDFLAGS="$USER_LDFLAGS -L$dir" + done + IFS=$ac_save_ifs + kde_use_extra_libs="added" +else + kde_use_extra_libs="no" +fi + +AC_SUBST(USER_LDFLAGS) + +AC_MSG_RESULT($kde_use_extra_libs) + +]) + +AC_DEFUN([KDE_1_CHECK_PATH_HEADERS], +[ + AC_MSG_CHECKING([for KDE headers installed]) + AC_LANG_SAVE + AC_LANG_CPLUSPLUS +cat > conftest.$ac_ext < +#endif +#include +#include "confdefs.h" +#include + +int main() { + printf("kde_htmldir=\\"%s\\"\n", KApplication::kde_htmldir().data()); + printf("kde_appsdir=\\"%s\\"\n", KApplication::kde_appsdir().data()); + printf("kde_icondir=\\"%s\\"\n", KApplication::kde_icondir().data()); + printf("kde_sounddir=\\"%s\\"\n", KApplication::kde_sounddir().data()); + printf("kde_datadir=\\"%s\\"\n", KApplication::kde_datadir().data()); + printf("kde_locale=\\"%s\\"\n", KApplication::kde_localedir().data()); + printf("kde_cgidir=\\"%s\\"\n", KApplication::kde_cgidir().data()); + printf("kde_confdir=\\"%s\\"\n", KApplication::kde_configdir().data()); + printf("kde_mimedir=\\"%s\\"\n", KApplication::kde_mimedir().data()); + printf("kde_toolbardir=\\"%s\\"\n", KApplication::kde_toolbardir().data()); + printf("kde_wallpaperdir=\\"%s\\"\n", + KApplication::kde_wallpaperdir().data()); + printf("kde_bindir=\\"%s\\"\n", KApplication::kde_bindir().data()); + printf("kde_partsdir=\\"%s\\"\n", KApplication::kde_partsdir().data()); + printf("kde_servicesdir=\\"/tmp/dummy\\"\n"); + printf("kde_servicetypesdir=\\"/tmp/dummy\\"\n"); + printf("kde_moduledir=\\"/tmp/dummy\\"\n"); + printf("kde_styledir=\\"/tmp/dummy\\"\n"); + printf("kde_widgetdir=\\"/tmp/dummy\\"\n"); + printf("xdg_appsdir=\\"/tmp/dummy\\"\n"); + printf("xdg_menudir=\\"/tmp/dummy\\"\n"); + printf("xdg_directorydir=\\"/tmp/dummy\\"\n"); + printf("kde_kcfgdir=\\"/tmp/dummy\\"\n"); + return 0; + } +EOF + + ac_save_CPPFLAGS=$CPPFLAGS + CPPFLAGS="$all_includes $CPPFLAGS" + if AC_TRY_EVAL(ac_compile); then + AC_MSG_RESULT(yes) + else + AC_MSG_ERROR([your system is not able to compile a small KDE application! +Check, if you installed the KDE header files correctly. +For more details about this problem, look at the end of config.log.]) + fi + CPPFLAGS=$ac_save_CPPFLAGS + + AC_LANG_RESTORE +]) + +AC_DEFUN([KDE_CHECK_KDEQTADDON], +[ +AC_MSG_CHECKING(for kde-qt-addon) +AC_CACHE_VAL(kde_cv_have_kdeqtaddon, +[ + kde_ldflags_safe="$LDFLAGS" + kde_libs_safe="$LIBS" + kde_cxxflags_safe="$CXXFLAGS" + + LIBS="-lkde-qt-addon $LIBQT $LIBS" + CXXFLAGS="$CXXFLAGS -I$prefix/include -I$prefix/include/kde $all_includes" + LDFLAGS="$LDFLAGS $all_libraries $USER_LDFLAGS" + + AC_TRY_LINK([ + #include + ], + [ + QDomDocument doc; + ], + kde_cv_have_kdeqtaddon=yes, + kde_cv_have_kdeqtaddon=no + ) + + LDFLAGS=$kde_ldflags_safe + LIBS=$kde_libs_safe + CXXFLAGS=$kde_cxxflags_safe +]) + +AC_MSG_RESULT($kde_cv_have_kdeqtaddon) + +if test "$kde_cv_have_kdeqtaddon" = "no"; then + AC_MSG_ERROR([Can't find libkde-qt-addon. You need to install it first. +It is a separate package (and CVS module) named kde-qt-addon.]) +fi +]) + +AC_DEFUN([KDE_CREATE_LIBS_ALIASES], +[ + AC_REQUIRE([KDE_MISC_TESTS]) + AC_REQUIRE([KDE_CHECK_LIBDL]) + AC_REQUIRE([K_PATH_X]) + +if test $kde_qtver = 3; then + case $host in + *cygwin*) lib_kded="-lkdeinit_kded" ;; + *) lib_kded="" ;; + esac + AC_SUBST(LIB_KDED, $lib_kded) + AC_SUBST(LIB_KDECORE, "-lkdecore") + AC_SUBST(LIB_KDEUI, "-lkdeui") + AC_SUBST(LIB_KIO, "-lkio") + AC_SUBST(LIB_KJS, "-lkjs") + AC_SUBST(LIB_SMB, "-lsmb") + AC_SUBST(LIB_KAB, "-lkab") + AC_SUBST(LIB_KABC, "-lkabc") + AC_SUBST(LIB_KHTML, "-lkhtml") + AC_SUBST(LIB_KSPELL, "-lkspell") + AC_SUBST(LIB_KPARTS, "-lkparts") + AC_SUBST(LIB_KDEPRINT, "-lkdeprint") + AC_SUBST(LIB_KUTILS, "-lkutils") + AC_SUBST(LIB_KDEPIM, "-lkdepim") + AC_SUBST(LIB_KIMPROXY, "-lkimproxy") + AC_SUBST(LIB_KNEWSTUFF, "-lknewstuff") + AC_SUBST(LIB_KDNSSD, "-lkdnssd") + AC_SUBST(LIB_KUNITTEST, "-lkunittest") +# these are for backward compatibility + AC_SUBST(LIB_KSYCOCA, "-lkio") + AC_SUBST(LIB_KFILE, "-lkio") +elif test $kde_qtver = 2; then + AC_SUBST(LIB_KDECORE, "-lkdecore") + AC_SUBST(LIB_KDEUI, "-lkdeui") + AC_SUBST(LIB_KIO, "-lkio") + AC_SUBST(LIB_KSYCOCA, "-lksycoca") + AC_SUBST(LIB_SMB, "-lsmb") + AC_SUBST(LIB_KFILE, "-lkfile") + AC_SUBST(LIB_KAB, "-lkab") + AC_SUBST(LIB_KHTML, "-lkhtml") + AC_SUBST(LIB_KSPELL, "-lkspell") + AC_SUBST(LIB_KPARTS, "-lkparts") + AC_SUBST(LIB_KDEPRINT, "-lkdeprint") +else + AC_SUBST(LIB_KDECORE, "-lkdecore -lXext $(LIB_QT)") + AC_SUBST(LIB_KDEUI, "-lkdeui $(LIB_KDECORE)") + AC_SUBST(LIB_KFM, "-lkfm $(LIB_KDECORE)") + AC_SUBST(LIB_KFILE, "-lkfile $(LIB_KFM) $(LIB_KDEUI)") + AC_SUBST(LIB_KAB, "-lkab $(LIB_KIMGIO) $(LIB_KDECORE)") +fi +]) + +AC_DEFUN([AC_PATH_KDE], +[ + AC_BASE_PATH_KDE + AC_ARG_ENABLE(path-check,AC_HELP_STRING([--disable-path-check],[don't try to find out, where to install]), + [ + if test "$enableval" = "no"; + then ac_use_path_checking="default" + else ac_use_path_checking="" + fi + ], + [ + if test "$kde_qtver" = 1; + then ac_use_path_checking="" + else ac_use_path_checking="default" + fi + ] + ) + + AC_CREATE_KFSSTND($ac_use_path_checking) + + AC_SUBST_KFSSTND + KDE_CREATE_LIBS_ALIASES +]) + +dnl KDE_CHECK_FUNC_EXT(, [headers], [sample-use], [C prototype], [autoheader define], [call if found]) +AC_DEFUN([KDE_CHECK_FUNC_EXT], +[ +AC_MSG_CHECKING(for $1) +AC_CACHE_VAL(kde_cv_func_$1, +[ +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +save_CXXFLAGS="$CXXFLAGS" +kde_safe_LIBS="$LIBS" +LIBS="$LIBS $X_EXTRA_LIBS" +if test "$GXX" = "yes"; then +CXXFLAGS="$CXXFLAGS -pedantic-errors" +fi +AC_TRY_COMPILE([ +$2 +], +[ +$3 +], +kde_cv_func_$1=yes, +kde_cv_func_$1=no) +CXXFLAGS="$save_CXXFLAGS" +LIBS="$kde_safe_LIBS" +AC_LANG_RESTORE +]) + +AC_MSG_RESULT($kde_cv_func_$1) + +AC_MSG_CHECKING([if $1 needs custom prototype]) +AC_CACHE_VAL(kde_cv_proto_$1, +[ +if test "x$kde_cv_func_$1" = xyes; then + kde_cv_proto_$1=no +else + case "$1" in + setenv|unsetenv|usleep|random|srandom|seteuid|mkstemps|mkstemp|revoke|vsnprintf|strlcpy|strlcat) + kde_cv_proto_$1="yes - in libkdefakes" + ;; + *) + kde_cv_proto_$1=unknown + ;; + esac +fi + +if test "x$kde_cv_proto_$1" = xunknown; then + +AC_LANG_SAVE +AC_LANG_CPLUSPLUS + kde_safe_libs=$LIBS + LIBS="$LIBS $X_EXTRA_LIBS" + AC_TRY_LINK([ +$2 + +extern "C" $4; +], +[ +$3 +], +[ kde_cv_func_$1=yes + kde_cv_proto_$1=yes ], + [kde_cv_proto_$1="$1 unavailable"] +) +LIBS=$kde_safe_libs +AC_LANG_RESTORE +fi +]) +AC_MSG_RESULT($kde_cv_proto_$1) + +if test "x$kde_cv_func_$1" = xyes; then + AC_DEFINE(HAVE_$5, 1, [Define if you have $1]) + $6 +fi +if test "x$kde_cv_proto_$1" = xno; then + AC_DEFINE(HAVE_$5_PROTO, 1, + [Define if you have the $1 prototype]) +fi + +AH_VERBATIM([_HAVE_$5_PROTO], +[ +#if !defined(HAVE_$5_PROTO) +#ifdef __cplusplus +extern "C" { +#endif +$4; +#ifdef __cplusplus +} +#endif +#endif +]) +]) + +AC_DEFUN([AC_CHECK_SETENV], +[ + KDE_CHECK_FUNC_EXT(setenv, [ +#include +], + [setenv("VAR", "VALUE", 1);], + [int setenv (const char *, const char *, int)], + [SETENV]) +]) + +AC_DEFUN([AC_CHECK_UNSETENV], +[ + KDE_CHECK_FUNC_EXT(unsetenv, [ +#include +], + [unsetenv("VAR");], + [void unsetenv (const char *)], + [UNSETENV]) +]) + +AC_DEFUN([AC_CHECK_GETDOMAINNAME], +[ + KDE_CHECK_FUNC_EXT(getdomainname, [ +#include +#include +#include +], + [ +char buffer[200]; +getdomainname(buffer, 200); +], + [#include + int getdomainname (char *, size_t)], + [GETDOMAINNAME]) +]) + +AC_DEFUN([AC_CHECK_GETHOSTNAME], +[ + KDE_CHECK_FUNC_EXT(gethostname, [ +#include +#include +], + [ +char buffer[200]; +gethostname(buffer, 200); +], + [int gethostname (char *, unsigned int)], + [GETHOSTNAME]) +]) + +AC_DEFUN([AC_CHECK_USLEEP], +[ + KDE_CHECK_FUNC_EXT(usleep, [ +#include +], + [ +usleep(200); +], + [int usleep (unsigned int)], + [USLEEP]) +]) + + +AC_DEFUN([AC_CHECK_RANDOM], +[ + KDE_CHECK_FUNC_EXT(random, [ +#include +], + [ +random(); +], + [long int random(void)], + [RANDOM]) + + KDE_CHECK_FUNC_EXT(srandom, [ +#include +], + [ +srandom(27); +], + [void srandom(unsigned int)], + [SRANDOM]) + +]) + +AC_DEFUN([AC_CHECK_INITGROUPS], +[ + KDE_CHECK_FUNC_EXT(initgroups, [ +#include +#include +#include +], + [ +char buffer[200]; +initgroups(buffer, 27); +], + [int initgroups(const char *, gid_t)], + [INITGROUPS]) +]) + +AC_DEFUN([AC_CHECK_MKSTEMPS], +[ + KDE_CHECK_FUNC_EXT(mkstemps, [ +#include +#include +], + [ +mkstemps("/tmp/aaaXXXXXX", 6); +], + [int mkstemps(char *, int)], + [MKSTEMPS]) +]) + +AC_DEFUN([AC_CHECK_MKSTEMP], +[ + KDE_CHECK_FUNC_EXT(mkstemp, [ +#include +#include +], + [ +mkstemp("/tmp/aaaXXXXXX"); +], + [int mkstemp(char *)], + [MKSTEMP]) +]) + +AC_DEFUN([AC_CHECK_MKDTEMP], +[ + KDE_CHECK_FUNC_EXT(mkdtemp, [ +#include +#include +], + [ +mkdtemp("/tmp/aaaXXXXXX"); +], + [char *mkdtemp(char *)], + [MKDTEMP]) +]) + + +AC_DEFUN([AC_CHECK_RES_INIT], +[ + AC_MSG_CHECKING([if res_init needs -lresolv]) + kde_libs_safe="$LIBS" + LIBS="$LIBS $X_EXTRA_LIBS -lresolv" + AC_TRY_LINK( + [ +#include +#include +#include +#include + ], + [ + res_init(); + ], + [ + LIBRESOLV="-lresolv" + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_RES_INIT, 1, [Define if you have the res_init function]) + ], + [ AC_MSG_RESULT(no) ] + ) + LIBS=$kde_libs_safe + AC_SUBST(LIBRESOLV) + + KDE_CHECK_FUNC_EXT(res_init, + [ +#include +#include +#include +#include + ], + [res_init()], + [int res_init(void)], + [RES_INIT]) +]) + +AC_DEFUN([AC_CHECK_STRLCPY], +[ + KDE_CHECK_FUNC_EXT(strlcpy, [ +#include +], +[ char buf[20]; + strlcpy(buf, "KDE function test", sizeof(buf)); +], + [unsigned long strlcpy(char*, const char*, unsigned long)], + [STRLCPY]) +]) + +AC_DEFUN([AC_CHECK_STRLCAT], +[ + KDE_CHECK_FUNC_EXT(strlcat, [ +#include +], +[ char buf[20]; + buf[0]='\0'; + strlcat(buf, "KDE function test", sizeof(buf)); +], + [unsigned long strlcat(char*, const char*, unsigned long)], + [STRLCAT]) +]) + +AC_DEFUN([AC_CHECK_RES_QUERY], +[ + KDE_CHECK_FUNC_EXT(res_query, [ +#include +#include +#include +#include +#include +], +[ +res_query(NULL, 0, 0, NULL, 0); +], + [int res_query(const char *, int, int, unsigned char *, int)], + [RES_QUERY]) +]) + +AC_DEFUN([AC_CHECK_DN_SKIPNAME], +[ + KDE_CHECK_FUNC_EXT(dn_skipname, [ +#include +#include +#include +#include +], +[ +dn_skipname (NULL, NULL); +], + [int dn_skipname (unsigned char *, unsigned char *)], + [DN_SKIPNAME]) +]) + + +AC_DEFUN([AC_FIND_GIF], + [AC_MSG_CHECKING([for giflib]) +AC_CACHE_VAL(ac_cv_lib_gif, +[ac_save_LIBS="$LIBS" +if test "x$kde_use_qt_emb" != "xyes" && test "x$kde_use_qt_mac" != "xyes"; then +LIBS="$all_libraries -lgif -lX11 $LIBSOCKET" +else +LIBS="$all_libraries -lgif" +fi +AC_TRY_LINK(dnl +[ +#ifdef __cplusplus +extern "C" { +#endif +int GifLastError(void); +#ifdef __cplusplus +} +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +], + [return GifLastError();], + eval "ac_cv_lib_gif=yes", + eval "ac_cv_lib_gif=no") +LIBS="$ac_save_LIBS" +])dnl +if eval "test \"`echo $ac_cv_lib_gif`\" = yes"; then + AC_MSG_RESULT(yes) + AC_DEFINE_UNQUOTED(HAVE_LIBGIF, 1, [Define if you have libgif]) +else + AC_MSG_ERROR(You need giflib30. Please install the kdesupport package) +fi +]) + +AC_DEFUN([KDE_FIND_JPEG_HELPER], +[ +AC_MSG_CHECKING([for libjpeg$2]) +AC_CACHE_VAL(ac_cv_lib_jpeg_$1, +[ +ac_save_LIBS="$LIBS" +LIBS="$all_libraries $USER_LDFLAGS -ljpeg$2 -lm" +ac_save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS $all_includes $USER_INCLUDES" +AC_TRY_LINK( +[ +#ifdef __cplusplus +extern "C" { +#endif +void jpeg_CreateDecompress(); +#ifdef __cplusplus +} +#endif +], +[jpeg_CreateDecompress();], + eval "ac_cv_lib_jpeg_$1=-ljpeg$2", + eval "ac_cv_lib_jpeg_$1=no") +LIBS="$ac_save_LIBS" +CFLAGS="$ac_save_CFLAGS" +]) + +if eval "test ! \"`echo $ac_cv_lib_jpeg_$1`\" = no"; then + LIBJPEG="$ac_cv_lib_jpeg_$1" + AC_MSG_RESULT($ac_cv_lib_jpeg_$1) +else + AC_MSG_RESULT(no) + $3 +fi + +]) + +AC_DEFUN([AC_FIND_JPEG], +[ +dnl first look for libraries +KDE_FIND_JPEG_HELPER(6b, 6b, + KDE_FIND_JPEG_HELPER(normal, [], + [ + LIBJPEG= + ] + ) +) + +dnl then search the headers (can't use simply AC_TRY_xxx, as jpeglib.h +dnl requires system dependent includes loaded before it) +jpeg_incdirs="$includedir /usr/include /usr/local/include $kde_extra_includes" +AC_FIND_FILE(jpeglib.h, $jpeg_incdirs, jpeg_incdir) +test "x$jpeg_incdir" = xNO && jpeg_incdir= + +dnl if headers _and_ libraries are missing, this is no error, and we +dnl continue with a warning (the user will get no jpeg support in khtml) +dnl if only one is missing, it means a configuration error, but we still +dnl only warn +if test -n "$jpeg_incdir" && test -n "$LIBJPEG" ; then + AC_DEFINE_UNQUOTED(HAVE_LIBJPEG, 1, [Define if you have libjpeg]) +else + if test -n "$jpeg_incdir" || test -n "$LIBJPEG" ; then + AC_MSG_WARN([ +There is an installation error in jpeg support. You seem to have only one +of either the headers _or_ the libraries installed. You may need to either +provide correct --with-extra-... options, or the development package of +libjpeg6b. You can get a source package of libjpeg from http://www.ijg.org/ +Disabling JPEG support. +]) + else + AC_MSG_WARN([libjpeg not found. disable JPEG support.]) + fi + jpeg_incdir= + LIBJPEG= +fi + +AC_SUBST(LIBJPEG) +AH_VERBATIM(_AC_CHECK_JPEG, +[/* + * jpeg.h needs HAVE_BOOLEAN, when the system uses boolean in system + * headers and I'm too lazy to write a configure test as long as only + * unixware is related + */ +#ifdef _UNIXWARE +#define HAVE_BOOLEAN +#endif +]) +]) + +AC_DEFUN([KDE_CHECK_QT_JPEG], +[ +if test -n "$LIBJPEG"; then +AC_MSG_CHECKING([if Qt needs $LIBJPEG]) +AC_CACHE_VAL(kde_cv_qt_jpeg, +[ +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +ac_save_LIBS="$LIBS" +LIBS="$all_libraries $USER_LDFLAGS $LIBQT" +LIBS=`echo $LIBS | sed "s/$LIBJPEG//"` +ac_save_CXXFLAGS="$CXXFLAGS" +CXXFLAGS="$CXXFLAGS $all_includes $USER_INCLUDES" +AC_TRY_LINK( +[#include ], + [ + int argc; + char** argv; + QApplication app(argc, argv);], + eval "kde_cv_qt_jpeg=no", + eval "kde_cv_qt_jpeg=yes") +LIBS="$ac_save_LIBS" +CXXFLAGS="$ac_save_CXXFLAGS" +AC_LANG_RESTORE +fi +]) + +if eval "test ! \"`echo $kde_cv_qt_jpeg`\" = no"; then + AC_MSG_RESULT(yes) + LIBJPEG_QT='$(LIBJPEG)' +else + AC_MSG_RESULT(no) + LIBJPEG_QT= +fi + +]) + +AC_DEFUN([AC_FIND_ZLIB], +[ +AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) +AC_MSG_CHECKING([for libz]) +AC_CACHE_VAL(ac_cv_lib_z, +[ +kde_save_LIBS="$LIBS" +LIBS="$all_libraries $USER_LDFLAGS -lz $LIBSOCKET" +kde_save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS $all_includes $USER_INCLUDES" +AC_TRY_LINK(dnl +[ +#include +#include +], +[ + char buf[42]; + gzFile f = (gzFile) 0; + /* this would segfault.. but we only link, don't run */ + (void) gzgets(f, buf, sizeof(buf)); + + return (strcmp(zlibVersion(), ZLIB_VERSION) == 0); +], + eval "ac_cv_lib_z='-lz'", + eval "ac_cv_lib_z=no") +LIBS="$kde_save_LIBS" +CFLAGS="$kde_save_CFLAGS" +])dnl +if test ! "$ac_cv_lib_z" = no; then + AC_DEFINE_UNQUOTED(HAVE_LIBZ, 1, [Define if you have libz]) + LIBZ="$ac_cv_lib_z" + AC_MSG_RESULT($ac_cv_lib_z) +else + AC_MSG_ERROR(not found. + Possibly configure picks up an outdated version + installed by XFree86. Remove it from your system. + + Check your installation and look into config.log) + LIBZ="" +fi +AC_SUBST(LIBZ) +]) + +AC_DEFUN([KDE_TRY_TIFFLIB], +[ +AC_MSG_CHECKING([for libtiff $1]) + +AC_CACHE_VAL(kde_cv_libtiff_$1, +[ +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +kde_save_LIBS="$LIBS" +if test "x$kde_use_qt_emb" != "xyes" && test "x$kde_use_qt_mac" != "xyes"; then +LIBS="$all_libraries $USER_LDFLAGS -l$1 $LIBJPEG $LIBZ -lX11 $LIBSOCKET -lm" +else +LIBS="$all_libraries $USER_LDFLAGS -l$1 $LIBJPEG $LIBZ -lm" +fi +kde_save_CXXFLAGS="$CXXFLAGS" +CXXFLAGS="$CXXFLAGS $all_includes $USER_INCLUDES" + +AC_TRY_LINK(dnl +[ +#include +], + [return (TIFFOpen( "", "r") == 0); ], +[ + kde_cv_libtiff_$1="-l$1 $LIBJPEG $LIBZ" +], [ + kde_cv_libtiff_$1=no +]) + +LIBS="$kde_save_LIBS" +CXXFLAGS="$kde_save_CXXFLAGS" +AC_LANG_RESTORE +]) + +if test "$kde_cv_libtiff_$1" = "no"; then + AC_MSG_RESULT(no) + LIBTIFF="" + $3 +else + LIBTIFF="$kde_cv_libtiff_$1" + AC_MSG_RESULT(yes) + AC_DEFINE_UNQUOTED(HAVE_LIBTIFF, 1, [Define if you have libtiff]) + $2 +fi + +]) + +AC_DEFUN([AC_FIND_TIFF], +[ +AC_REQUIRE([K_PATH_X]) +AC_REQUIRE([AC_FIND_ZLIB]) +AC_REQUIRE([AC_FIND_JPEG]) +AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) + +KDE_TRY_TIFFLIB(tiff, [], + KDE_TRY_TIFFLIB(tiff34)) + +AC_SUBST(LIBTIFF) +]) + +AC_DEFUN([KDE_FIND_LIBEXR], +[ +AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) +AC_REQUIRE([AC_FIND_ZLIB]) +AC_CACHE_VAL(ac_cv_libexr, +[ + if test -z "$PKG_CONFIG"; then + AC_PATH_PROG(PKG_CONFIG, pkg-config, no) + fi + + AC_MSG_CHECKING([for OpenEXR libraries]) + + if test "$PKG_CONFIG" = "no" ; then + AC_MSG_RESULT(no) + echo "*** The pkg-config script could not be found. Make sure it is" + echo "*** in your path, or set the PKG_CONFIG environment variable" + echo "*** to the full path to pkg-config." + echo "*** Or see http://www.freedesktop.org/software/pkgconfig to get pkg-config." + else + if ! $PKG_CONFIG --exists OpenEXR ; then + AC_MSG_RESULT(no) + EXRSTATUS=no + else + if ! $PKG_CONFIG --atleast-version="1.1.1" OpenEXR ; then + AC_MSG_RESULT(no) + EXRSTATUS=old + else + kde_save_LIBS="$LIBS" + LIBS="$LIBS $all_libraries $USER_LDFLAGS `pkg-config --libs OpenEXR` $LIBZ" + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + kde_save_CXXFLAGS="$CXXFLAGS" + EXR_FLAGS=`$PKG_CONFIG --cflags OpenEXR` + CXXFLAGS="$CXXFLAGS $all_includes $USER_INCLUDES $EXR_FLAGS" + + AC_TRY_LINK(dnl + [ + #include + ], + [ + using namespace Imf; + RgbaInputFile file ("dummy"); + return 0; + ], + eval "ac_cv_libexr='`pkg-config --libs OpenEXR`'", + eval "ac_cv_libexr=no" + ) + LIBS="$kde_save_LIBS" + CXXFLAGS="$kde_save_CXXFLAGS" + AC_LANG_RESTORE + ])dnl + if eval "test ! \"`echo $ac_cv_libexr`\" = no"; then + AC_DEFINE_UNQUOTED(HAVE_EXR, 1, [Define if you have OpenEXR]) + LIB_EXR="$ac_cv_libexr" + AC_MSG_RESULT($ac_cv_libexr) + else + AC_MSG_RESULT(no) + LIB_EXR="" + fi + fi + fi + fi + AC_SUBST(LIB_EXR) + AC_SUBST(EXR_FLAGS) +]) + + + +AC_DEFUN([AC_FIND_PNG], +[ +AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) +AC_REQUIRE([AC_FIND_ZLIB]) +AC_MSG_CHECKING([for libpng]) +AC_CACHE_VAL(ac_cv_lib_png, +[ +kde_save_LIBS="$LIBS" +if test "x$kde_use_qt_emb" != "xyes" && test "x$kde_use_qt_mac" != "xyes"; then +LIBS="$LIBS $all_libraries $USER_LDFLAGS -lpng $LIBZ -lm -lX11 $LIBSOCKET" +else +LIBS="$LIBS $all_libraries $USER_LDFLAGS -lpng $LIBZ -lm" +fi +kde_save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS $all_includes $USER_INCLUDES" + +AC_TRY_LINK(dnl + [ + #include + ], + [ + png_structp png_ptr = png_create_read_struct( /* image ptr */ + PNG_LIBPNG_VER_STRING, 0, 0, 0 ); + return( png_ptr != 0 ); + ], + eval "ac_cv_lib_png='-lpng $LIBZ -lm'", + eval "ac_cv_lib_png=no" +) +LIBS="$kde_save_LIBS" +CFLAGS="$kde_save_CFLAGS" +])dnl +if eval "test ! \"`echo $ac_cv_lib_png`\" = no"; then + AC_DEFINE_UNQUOTED(HAVE_LIBPNG, 1, [Define if you have libpng]) + LIBPNG="$ac_cv_lib_png" + AC_SUBST(LIBPNG) + AC_MSG_RESULT($ac_cv_lib_png) +else + AC_MSG_RESULT(no) + LIBPNG="" + AC_SUBST(LIBPNG) +fi +]) + + +AC_DEFUN([AC_FIND_JASPER], +[ +AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) +AC_REQUIRE([AC_FIND_JPEG]) +AC_MSG_CHECKING([for jasper]) +AC_CACHE_VAL(ac_cv_jasper, +[ +kde_save_LIBS="$LIBS" +LIBS="$LIBS $all_libraries $USER_LDFLAGS -ljasper $LIBJPEG -lm" +kde_save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS $all_includes $USER_INCLUDES" + +AC_TRY_LINK(dnl + [ + #include + ], + [ + return( jas_init() ); + ], + eval "ac_cv_jasper='-ljasper $LIBJPEG -lm'", + eval "ac_cv_jasper=no" +) +LIBS="$kde_save_LIBS" +CFLAGS="$kde_save_CFLAGS" +])dnl +if eval "test ! \"`echo $ac_cv_jasper`\" = no"; then + AC_DEFINE_UNQUOTED(HAVE_JASPER, 1, [Define if you have jasper]) + LIB_JASPER="$ac_cv_jasper" + AC_MSG_RESULT($ac_cv_jasper) +else + AC_MSG_RESULT(no) + LIB_JASPER="" +fi +AC_SUBST(LIB_JASPER) +]) + +AC_DEFUN([AC_CHECK_BOOL], +[ + AC_DEFINE_UNQUOTED(HAVE_BOOL, 1, [You _must_ have bool]) +]) + +AC_DEFUN([AC_CHECK_GNU_EXTENSIONS], +[ +AC_MSG_CHECKING(if you need GNU extensions) +AC_CACHE_VAL(ac_cv_gnu_extensions, +[ +cat > conftest.c << EOF +#include + +#ifdef __GNU_LIBRARY__ +yes +#endif +EOF + +if (eval "$ac_cpp conftest.c") 2>&5 | + egrep "yes" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_gnu_extensions=yes +else + ac_cv_gnu_extensions=no +fi +]) + +AC_MSG_RESULT($ac_cv_gnu_extensions) +if test "$ac_cv_gnu_extensions" = "yes"; then + AC_DEFINE_UNQUOTED(_GNU_SOURCE, 1, [Define if you need to use the GNU extensions]) +fi +]) + +AC_DEFUN([KDE_CHECK_COMPILER_FLAG], +[ +AC_MSG_CHECKING([whether $CXX supports -$1]) +kde_cache=`echo $1 | sed 'y% .=/+-,%____p__%'` +AC_CACHE_VAL(kde_cv_prog_cxx_$kde_cache, +[ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -$1" + AC_TRY_LINK([],[ return 0; ], [eval "kde_cv_prog_cxx_$kde_cache=yes"], []) + CXXFLAGS="$save_CXXFLAGS" + AC_LANG_RESTORE +]) +if eval "test \"`echo '$kde_cv_prog_cxx_'$kde_cache`\" = yes"; then + AC_MSG_RESULT(yes) + : + $2 +else + AC_MSG_RESULT(no) + : + $3 +fi +]) + +AC_DEFUN([KDE_CHECK_C_COMPILER_FLAG], +[ +AC_MSG_CHECKING([whether $CC supports -$1]) +kde_cache=`echo $1 | sed 'y% .=/+-,%____p__%'` +AC_CACHE_VAL(kde_cv_prog_cc_$kde_cache, +[ + AC_LANG_SAVE + AC_LANG_C + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -$1" + AC_TRY_LINK([],[ return 0; ], [eval "kde_cv_prog_cc_$kde_cache=yes"], []) + CFLAGS="$save_CFLAGS" + AC_LANG_RESTORE +]) +if eval "test \"`echo '$kde_cv_prog_cc_'$kde_cache`\" = yes"; then + AC_MSG_RESULT(yes) + : + $2 +else + AC_MSG_RESULT(no) + : + $3 +fi +]) + + +dnl AC_REMOVE_FORBIDDEN removes forbidden arguments from variables +dnl use: AC_REMOVE_FORBIDDEN(CC, [-forbid -bad-option whatever]) +dnl it's all white-space separated +AC_DEFUN([AC_REMOVE_FORBIDDEN], +[ __val=$$1 + __forbid=" $2 " + if test -n "$__val"; then + __new="" + ac_save_IFS=$IFS + IFS=" " + for i in $__val; do + case "$__forbid" in + *" $i "*) AC_MSG_WARN([found forbidden $i in $1, removing it]) ;; + *) # Careful to not add spaces, where there were none, because otherwise + # libtool gets confused, if we change e.g. CXX + if test -z "$__new" ; then __new=$i ; else __new="$__new $i" ; fi ;; + esac + done + IFS=$ac_save_IFS + $1=$__new + fi +]) + + +AC_DEFUN([KDE_CHECK_FOR_BAD_COMPILER], +[ + AC_MSG_CHECKING([whether $CC is blacklisted]) + + dnl In theory we have tu run this test against $CC and $CXX + dnl in C and in C++ mode, because its perfectly legal for + dnl the user to mix compiler versions, since C has a defined + dnl ABI. + dnl + dnl For now, we assume the user is not on crack. + + AC_TRY_COMPILE([ +#ifdef __GNUC__ +#if __GNUC__ == 4 && __GNUC_MINOR__ == 0 && __GNUC_PATCHLEVEL__ == 0 +choke me +#endif +#endif +], , + kde_bad_compiler=no, + kde_bad_compiler=yes +) + + AC_MSG_RESULT($kde_bad_compiler) + +if test "$kde_bad_compiler" = "yes"; then + AC_MSG_ERROR([ + +This particular compiler version is blacklisted because it +is known to miscompile KDE. Please use a newer version, or +if that is not yet available, choose an older version. + +Please do not report a bug or bother us reporting this +configure error. We know about it, and we introduced +it by intention to avoid untraceable bugs or crashes in KDE. + +]) +fi + +]) + + +AC_DEFUN([KDE_CHECK_FOR_OPT_NOINLINE_MATCH], +[ + AC_CACHE_CHECK([whether system headers can cope with -O2 -fno-inline], + kde_cv_opt_noinline_match, + [ + kde_cv_opt_noinline_match=irrelevant + dnl if we don't use both -O2 and -fno-inline, this check is moot + if echo "$CFLAGS" | grep -e -O2 >/dev/null 2>/dev/null \ + && echo "$CFLAGS" | grep -e -fno-inline >/dev/null 2>/dev/null ; then + + ac_cflags_save="$CFLAGS" + CFLAGS="$CFLAGS -D_USE_GNU" + + AC_TRY_LINK([ + #include +], [ const char *pt, *et; + et = __extension__ ({ char __a0, __a1, __a2; (__builtin_constant_p ( ";," ) && ((size_t)(const void *)(( ";," )+ 1) - (size_t)(const void *)( ";," ) == 1) ? ((__a0 =((__const char *) ( ";," ))[0], __a0 == '\0') ? ((void) ( pt ),((void *)0) ) : ((__a1 = ((__const char *) ( ";," ))[1], __a1== '\0') ? (__extension__ (__builtin_constant_p ( __a0 ) && ( __a0 ) == '\0' ? (char *) __rawmemchr ( pt , __a0) : strchr( pt , __a0 ))) : ((__a2 = ((__const char *) ( ";," ))[2], __a2 == '\0') ? __strpbrk_c2 ( pt , __a0, __a1) :(((__const char *) ( ";," ))[3] == '\0' ? __strpbrk_c3 ( pt ,__a0, __a1, __a2): strpbrk ( pt , ";," ))))) : strpbrk ( pt , ";," )); }) ; +], + kde_cv_opt_noinline_match=yes, + kde_cv_opt_noinline_match=no + ) + + CFLAGS="$ac_cflags_save" + fi + ]) +]) + + +dnl AC_VALIDIFY_CXXFLAGS checks for forbidden flags the user may have given +AC_DEFUN([AC_VALIDIFY_CXXFLAGS], +[dnl +if test "x$kde_use_qt_emb" != "xyes"; then + AC_REMOVE_FORBIDDEN(CXX, [-fno-rtti -rpath]) + AC_REMOVE_FORBIDDEN(CXXFLAGS, [-fno-rtti -rpath]) +else + AC_REMOVE_FORBIDDEN(CXX, [-rpath]) + AC_REMOVE_FORBIDDEN(CXXFLAGS, [-rpath]) +fi +]) + +AC_DEFUN([AC_CHECK_COMPILERS], +[ + AC_ARG_ENABLE(debug, + AC_HELP_STRING([--enable-debug=ARG],[enables debug symbols (yes|no|full) [default=no]]), + [ + case $enableval in + yes) + kde_use_debug_code="yes" + kde_use_debug_define=no + ;; + full) + kde_use_debug_code="full" + kde_use_debug_define=no + ;; + *) + kde_use_debug_code="no" + kde_use_debug_define=yes + ;; + esac + ], + [kde_use_debug_code="no" + kde_use_debug_define=no + ]) + + dnl Just for configure --help + AC_ARG_ENABLE(dummyoption, + AC_HELP_STRING([--disable-debug], + [disables debug output and debug symbols [default=no]]), + [],[]) + + AC_ARG_ENABLE(strict, + AC_HELP_STRING([--enable-strict], + [compiles with strict compiler options (may not work!)]), + [ + if test $enableval = "no"; then + kde_use_strict_options="no" + else + kde_use_strict_options="yes" + fi + ], [kde_use_strict_options="no"]) + + AC_ARG_ENABLE(warnings,AC_HELP_STRING([--disable-warnings],[disables compilation with -Wall and similar]), + [ + if test $enableval = "no"; then + kde_use_warnings="no" + else + kde_use_warnings="yes" + fi + ], [kde_use_warnings="yes"]) + + dnl enable warnings for debug build + if test "$kde_use_debug_code" != "no"; then + kde_use_warnings=yes + fi + + AC_ARG_ENABLE(profile,AC_HELP_STRING([--enable-profile],[creates profiling infos [default=no]]), + [kde_use_profiling=$enableval], + [kde_use_profiling="no"] + ) + + dnl this prevents stupid AC_PROG_CC to add "-g" to the default CFLAGS + CFLAGS=" $CFLAGS" + + AC_PROG_CC + + AC_PROG_CPP + + if test "$GCC" = "yes"; then + if test "$kde_use_debug_code" != "no"; then + if test $kde_use_debug_code = "full"; then + CFLAGS="-g3 -fno-inline $CFLAGS" + else + CFLAGS="-g -O2 -fno-schedule-insns -fno-inline $CFLAGS" + fi + else + CFLAGS="-O2 $CFLAGS" + fi + fi + + if test "$kde_use_debug_define" = "yes"; then + CFLAGS="-DNDEBUG $CFLAGS" + fi + + + case "$host" in + *-*-sysv4.2uw*) CFLAGS="-D_UNIXWARE $CFLAGS";; + *-*-sysv5uw7*) CFLAGS="-D_UNIXWARE7 $CFLAGS";; + esac + + if test -z "$LDFLAGS" && test "$kde_use_debug_code" = "no" && test "$GCC" = "yes"; then + LDFLAGS="" + fi + + CXXFLAGS=" $CXXFLAGS" + + AC_PROG_CXX + + KDE_CHECK_FOR_BAD_COMPILER + + if test "$GXX" = "yes" || test "$CXX" = "KCC"; then + if test "$kde_use_debug_code" != "no"; then + if test "$CXX" = "KCC"; then + CXXFLAGS="+K0 -Wall -pedantic -W -Wpointer-arith -Wwrite-strings $CXXFLAGS" + else + if test "$kde_use_debug_code" = "full"; then + CXXFLAGS="-g3 -fno-inline $CXXFLAGS" + else + CXXFLAGS="-g -O2 -fno-schedule-insns -fno-inline $CXXFLAGS" + fi + fi + KDE_CHECK_COMPILER_FLAG(fno-builtin,[CXXFLAGS="-fno-builtin $CXXFLAGS"]) + + dnl convenience compiler flags + KDE_CHECK_COMPILER_FLAG(Woverloaded-virtual, [WOVERLOADED_VIRTUAL="-Woverloaded-virtual"], [WOVERLOADED_VRITUAL=""]) + AC_SUBST(WOVERLOADED_VIRTUAL) + else + if test "$CXX" = "KCC"; then + CXXFLAGS="+K3 $CXXFLAGS" + else + CXXFLAGS="-O2 $CXXFLAGS" + fi + fi + fi + + if test "$kde_use_debug_define" = "yes"; then + CXXFLAGS="-DNDEBUG -DNO_DEBUG $CXXFLAGS" + fi + + if test "$kde_use_profiling" = "yes"; then + KDE_CHECK_COMPILER_FLAG(pg, + [ + CFLAGS="-pg $CFLAGS" + CXXFLAGS="-pg $CXXFLAGS" + ]) + fi + + if test "$kde_use_warnings" = "yes"; then + if test "$GCC" = "yes"; then + CXXFLAGS="-Wall -W -Wpointer-arith $CXXFLAGS" + case $host in + *-*-linux-gnu) + CFLAGS="-std=iso9899:1990 -W -Wall -Wchar-subscripts -Wshadow -Wpointer-arith -Wmissing-prototypes -Wwrite-strings -D_XOPEN_SOURCE=500 -D_BSD_SOURCE $CFLAGS" + CXXFLAGS="-ansi -D_XOPEN_SOURCE=500 -D_BSD_SOURCE -Wcast-align -Wchar-subscripts $CXXFLAGS" + KDE_CHECK_COMPILER_FLAG(Wmissing-format-attribute, [CXXFLAGS="$CXXFLAGS -Wformat-security -Wmissing-format-attribute"]) + KDE_CHECK_C_COMPILER_FLAG(Wmissing-format-attribute, [CFLAGS="$CFLAGS -Wformat-security -Wmissing-format-attribute"]) + ;; + esac + KDE_CHECK_COMPILER_FLAG(Wundef,[CXXFLAGS="-Wundef $CXXFLAGS"]) + KDE_CHECK_COMPILER_FLAG(Wno-long-long,[CXXFLAGS="-Wno-long-long $CXXFLAGS"]) + dnl ### FIXME: revert for KDE 4 + KDE_CHECK_COMPILER_FLAG(Wno-non-virtual-dtor,[CXXFLAGS="$CXXFLAGS -Wno-non-virtual-dtor"]) + fi + fi + + if test "$GXX" = "yes" && test "$kde_use_strict_options" = "yes"; then + CXXFLAGS="-Wcast-qual -Wshadow -Wcast-align $CXXFLAGS" + fi + + AC_ARG_ENABLE(pch, + AC_HELP_STRING([--enable-pch], + [enables precompiled header support (currently only KCC or gcc >=3.4+unsermake) [default=no]]), + [ kde_use_pch=$enableval ],[ kde_use_pch=no ]) + + HAVE_GCC_VISIBILITY=0 + AC_SUBST([HAVE_GCC_VISIBILITY]) + + if test "$GXX" = "yes"; then + gcc_no_reorder_blocks=NO + KDE_CHECK_COMPILER_FLAG(fno-reorder-blocks,[gcc_no_reorder_blocks=YES]) + if test $kde_use_debug_code != "no" && \ + test $kde_use_debug_code != "full" && \ + test "YES" = "$gcc_no_reorder_blocks" ; then + CXXFLAGS="$CXXFLAGS -fno-reorder-blocks" + CFLAGS="$CFLAGS -fno-reorder-blocks" + fi + KDE_CHECK_COMPILER_FLAG(fno-exceptions,[CXXFLAGS="$CXXFLAGS -fno-exceptions"]) + KDE_CHECK_COMPILER_FLAG(fno-check-new, [CXXFLAGS="$CXXFLAGS -fno-check-new"]) + KDE_CHECK_COMPILER_FLAG(fno-common, [CXXFLAGS="$CXXFLAGS -fno-common"]) + KDE_CHECK_COMPILER_FLAG(fexceptions, [USE_EXCEPTIONS="-fexceptions"], USE_EXCEPTIONS= ) + ENABLE_PERMISSIVE_FLAG="-fpermissive" + + if test "$kde_use_pch" = "yes"; then + AC_MSG_CHECKING(whether gcc supports precompiling c header files) + echo >conftest.h + if $CC -x c-header conftest.h >/dev/null 2>/dev/null; then + kde_gcc_supports_pch=yes + AC_MSG_RESULT(yes) + else + kde_gcc_supports_pch=no + AC_MSG_RESULT(no) + fi + if test "$kde_gcc_supports_pch" = "yes"; then + AC_MSG_CHECKING(whether gcc supports precompiling c++ header files) + if $CXX -x c++-header conftest.h >/dev/null 2>/dev/null; then + kde_gcc_supports_pch=yes + AC_MSG_RESULT(yes) + else + kde_gcc_supports_pch=no + AC_MSG_RESULT(no) + fi + fi + rm -f conftest.h conftest.h.gch + fi + + KDE_CHECK_FOR_OPT_NOINLINE_MATCH + if test "x$kde_cv_opt_noinline_match" = "xno" ; then + CFLAGS="`echo "$CFLAGS" | sed "s/ -fno-inline//"`" + fi + fi + AM_CONDITIONAL(unsermake_enable_pch, test "$kde_use_pch" = "yes" && test "$kde_gcc_supports_pch" = "yes") + if test "$CXX" = "KCC"; then + dnl unfortunately we currently cannot disable exception support in KCC + dnl because doing so is binary incompatible and Qt by default links with exceptions :-( + dnl KDE_CHECK_COMPILER_FLAG(-no_exceptions,[CXXFLAGS="$CXXFLAGS --no_exceptions"]) + dnl KDE_CHECK_COMPILER_FLAG(-exceptions, [USE_EXCEPTIONS="--exceptions"], USE_EXCEPTIONS= ) + + if test "$kde_use_pch" = "yes"; then + dnl TODO: support --pch-dir! + KDE_CHECK_COMPILER_FLAG(-pch,[CXXFLAGS="$CXXFLAGS --pch"]) + dnl the below works (but the dir must exist), but it's + dnl useless for a whole package. + dnl The are precompiled headers for each source file, so when compiling + dnl from scratch, it doesn't make a difference, and they take up + dnl around ~5Mb _per_ sourcefile. + dnl KDE_CHECK_COMPILER_FLAG(-pch_dir /tmp, + dnl [CXXFLAGS="$CXXFLAGS --pch_dir `pwd`/pcheaders"]) + fi + dnl this flag controls inlining. by default KCC inlines in optimisation mode + dnl all implementations that are defined inside the class {} declaration. + dnl because of templates-compatibility with broken gcc compilers, this + dnl can cause excessive inlining. This flag limits it to a sane level + KDE_CHECK_COMPILER_FLAG(-inline_keyword_space_time=6,[CXXFLAGS="$CXXFLAGS --inline_keyword_space_time=6"]) + KDE_CHECK_COMPILER_FLAG(-inline_auto_space_time=2,[CXXFLAGS="$CXXFLAGS --inline_auto_space_time=2"]) + KDE_CHECK_COMPILER_FLAG(-inline_implicit_space_time=2.0,[CXXFLAGS="$CXXFLAGS --inline_implicit_space_time=2.0"]) + KDE_CHECK_COMPILER_FLAG(-inline_generated_space_time=2.0,[CXXFLAGS="$CXXFLAGS --inline_generated_space_time=2.0"]) + dnl Some source files are shared between multiple executables + dnl (or libraries) and some of those need template instantiations. + dnl In that case KCC needs to compile those sources with + dnl --one_instantiation_per_object. To make it easy for us we compile + dnl _all_ objects with that flag (--one_per is a shorthand). + KDE_CHECK_COMPILER_FLAG(-one_per, [CXXFLAGS="$CXXFLAGS --one_per"]) + fi + AC_SUBST(USE_EXCEPTIONS) + dnl obsolete macro - provided to keep things going + USE_RTTI= + AC_SUBST(USE_RTTI) + + case "$host" in + *-*-irix*) test "$GXX" = yes && CXXFLAGS="-D_LANGUAGE_C_PLUS_PLUS -D__LANGUAGE_C_PLUS_PLUS $CXXFLAGS" ;; + *-*-sysv4.2uw*) CXXFLAGS="-D_UNIXWARE $CXXFLAGS";; + *-*-sysv5uw7*) CXXFLAGS="-D_UNIXWARE7 $CXXFLAGS";; + *-*-solaris*) + if test "$GXX" = yes; then + libstdcpp=`$CXX -print-file-name=libstdc++.so` + if test ! -f $libstdcpp; then + AC_MSG_ERROR([You've compiled gcc without --enable-shared. This doesn't work with KDE. Please recompile gcc with --enable-shared to receive a libstdc++.so]) + fi + fi + ;; + esac + + AC_VALIDIFY_CXXFLAGS + + AC_PROG_CXXCPP + + if test "$GCC" = yes; then + NOOPT_CFLAGS=-O0 + fi + KDE_CHECK_COMPILER_FLAG(O0,[NOOPT_CXXFLAGS=-O0]) + + AC_ARG_ENABLE(coverage, + AC_HELP_STRING([--enable-coverage],[use gcc coverage testing]), [ + if test "$am_cv_CC_dependencies_compiler_type" = "gcc3"; then + ac_coverage_compiler="-fprofile-arcs -ftest-coverage" + ac_coverage_linker="-lgcc" + elif test "$am_cv_CC_dependencies_compiler_type" = "gcc"; then + ac_coverage_compiler="-fprofile-arcs -ftest-coverage" + ac_coverage_linker="" + else + AC_MSG_ERROR([coverage with your compiler is not supported]) + fi + CFLAGS="$CFLAGS $ac_coverage_compiler" + CXXFLAGS="$CXXFLAGS $ac_coverage_compiler" + LDFLAGS="$LDFLAGS $ac_coverage_linker" + ]) + + AC_SUBST(NOOPT_CXXFLAGS) + AC_SUBST(NOOPT_CFLAGS) + AC_SUBST(ENABLE_PERMISSIVE_FLAG) + + KDE_CHECK_NEW_LDFLAGS + KDE_CHECK_FINAL + KDE_CHECK_CLOSURE + KDE_CHECK_NMCHECK + + ifdef([AM_DEPENDENCIES], AC_REQUIRE([KDE_ADD_DEPENDENCIES]), []) +]) + +AC_DEFUN([KDE_CHECK_VISIBILITY_GCC_BUG], + [ + AC_CACHE_CHECK([for gcc -fvisibility-inlines-hidden bug], kde_cv_val_gcc_visibility_bug, + [ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + + safe_CXXFLAGS=$CXXFLAGS + safe_LDFLAGS=$LDFLAGS + CXXFLAGS="$CXXFLAGS -fPIC -fvisibility-inlines-hidden -O0" + LDFLAGS="$LDFLAGS -shared -fPIC" + + AC_TRY_LINK( + [ + /* http://gcc.gnu.org/bugzilla/show_bug.cgi?id=19664 */ + #include + int some_function( void ) __attribute__ ((visibility("default"))); + int some_function( void ) + { + std::string s("blafasel"); + return 0; + } + ], [/* elvis is alive */], + kde_cv_val_gcc_visibility_bug=no, kde_cv_val_gcc_visibility_bug=yes) + + CXXFLAGS=$safe_CXXFLAGS + LDFLAGS=$safe_LDFLAGS + AC_LANG_RESTORE + ] + ) + + if test x$kde_cv_val_gcc_visibility_bug = xno; then + CXXFLAGS="$CXXFLAGS -fvisibility-inlines-hidden" + fi + ] +) + +AC_DEFUN([KDE_ENABLE_HIDDEN_VISIBILITY], +[ + AC_BEFORE([AC_PATH_QT_1_3], [KDE_ENABLE_HIDDEN_VISIBILITY]) + + AC_MSG_CHECKING([grepping for visibility push/pop in headers]) + + if test "x$GXX" = "xyes"; then + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + AC_EGREP_CPP( + [GCC visibility push], + [ #include + ], + [ + AC_MSG_RESULT(yes) + kde_stdc_visibility_patched=yes ], + [ + AC_MSG_RESULT(no) + AC_MSG_WARN([Your libstdc++ doesn't appear to be patched for + visibility support. Disabling -fvisibility=hidden]) + + kde_stdc_visibility_patched=no ]) + + AC_LANG_RESTORE + + kde_have_gcc_visibility=no + KDE_CHECK_COMPILER_FLAG(fvisibility=hidden, + [ + kde_have_gcc_visibility=yes + dnl the whole toolchain is just a mess, gcc is just too buggy + dnl to handle STL with visibility enabled. Lets reconsider + dnl when gcc 4.2 is out or when things get fixed in the compiler. + dnl Contact mueller@kde.org for details. + AC_ARG_ENABLE(gcc-hidden-visibility, + AC_HELP_STRING([--enable-gcc-hidden-visibility],[toolchain hidden visibility [default=no]]), + [kde_have_gcc_visibility=$enableval], + [kde_have_gcc_visibility=no]) + + AC_CACHE_CHECK([if Qt is patched for -fvisibility], kde_cv_val_qt_gcc_visibility_patched, + [ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + + safe_CXXFLAGS=$CXXFLAGS + CXXFLAGS="$CXXFLAGS $all_includes" + + AC_TRY_COMPILE( + [ +#include +#if Q_EXPORT - 0 != 0 +/* if this compiles, then Q_EXPORT is undefined */ +/* if Q_EXPORT is nonempty, this will break compilation */ +#endif + ], [/* elvis is alive */], + kde_cv_val_qt_gcc_visibility_patched=no, kde_cv_val_qt_gcc_visibility_patched=yes) + + CXXFLAGS=$safe_CXXFLAGS + AC_LANG_RESTORE + ] + ) + + if test x$kde_have_gcc_visibility = "xyes" && test x$kde_stdc_visibility_patched = "xyes" && test x$kde_cv_val_qt_gcc_visibility_patched = "xyes"; then + CXXFLAGS="$CXXFLAGS -fvisibility=hidden" + KDE_CHECK_VISIBILITY_GCC_BUG + HAVE_GCC_VISIBILITY=1 + AC_DEFINE_UNQUOTED(__KDE_HAVE_GCC_VISIBILITY, "$HAVE_GCC_VISIBILITY", [define to 1 if -fvisibility is supported]) + fi + ]) + fi +]) + +AC_DEFUN([KDE_ADD_DEPENDENCIES], +[ + [A]M_DEPENDENCIES(CC) + [A]M_DEPENDENCIES(CXX) +]) + +dnl just a wrapper to clean up configure.in +AC_DEFUN([KDE_PROG_LIBTOOL], +[ +AC_REQUIRE([AC_CHECK_COMPILERS]) +AC_REQUIRE([AC_ENABLE_SHARED]) +AC_REQUIRE([AC_ENABLE_STATIC]) + +AC_REQUIRE([AC_LIBTOOL_DLOPEN]) +AC_REQUIRE([KDE_CHECK_LIB64]) + +AC_OBJEXT +AC_EXEEXT + +AM_PROG_LIBTOOL +AC_LIBTOOL_CXX + +LIBTOOL_SHELL="/bin/sh ./libtool" +# LIBTOOL="$LIBTOOL --silent" +KDE_PLUGIN="-avoid-version -module -no-undefined \$(KDE_NO_UNDEFINED) \$(KDE_RPATH) \$(KDE_MT_LDFLAGS)" +AC_SUBST(KDE_PLUGIN) + +# This hack ensures that libtool creates shared libs for kunittest plugins. By default check_LTLIBRARIES makes static libs. +KDE_CHECK_PLUGIN="\$(KDE_PLUGIN) -rpath \$(libdir)" +AC_SUBST(KDE_CHECK_PLUGIN) + +# we patch configure quite some so we better keep that consistent for incremental runs +AC_SUBST(AUTOCONF,'$(SHELL) $(top_srcdir)/admin/cvs.sh configure || touch configure') +]) + +AC_DEFUN([KDE_CHECK_LIB64], +[ + AC_ARG_ENABLE(libsuffix, + AC_HELP_STRING([--enable-libsuffix], + [/lib directory suffix (64,32,none,auto[=default])]), + kdelibsuff=$enableval, kdelibsuff="auto") + + if test "$kdelibsuff" = "auto"; then + +cat > conftest.c << EOF +#include +int main() { + return 0; +} +EOF + kdelibsuff=`$CC conftest.c -o conftest.out; ldd conftest.out |sed -ne '/libc.so/{ + s,.*/lib\([[^\/]]*\)/.*,\1, + p +}'` + rm -rf conftest.* + fi + + if test "$kdelibsuff" = "no" || test "$kdelibsuff" = "none"; then + kdelibsuff= + fi + if test -z "$kdelibsuff"; then + AC_MSG_RESULT([not using lib directory suffix]) + AC_DEFINE(KDELIBSUFF, [""], Suffix for lib directories) + else + if test "$libdir" = '${exec_prefix}/lib'; then + libdir="$libdir${kdelibsuff}" + AC_SUBST([libdir], ["$libdir"]) dnl ugly hack for lib64 platforms + fi + AC_DEFINE_UNQUOTED(KDELIBSUFF, ["${kdelibsuff}"], Suffix for lib directories) + AC_MSG_RESULT([using lib directory suffix $kdelibsuff]) + fi +]) + +AC_DEFUN([KDE_CHECK_TYPES], +[ AC_CHECK_SIZEOF(int, 4)dnl + AC_CHECK_SIZEOF(short)dnl + AC_CHECK_SIZEOF(long, 4)dnl + AC_CHECK_SIZEOF(char *, 4)dnl +])dnl + +dnl Not used - kept for compat only? +AC_DEFUN([KDE_DO_IT_ALL], +[ +AC_CANONICAL_SYSTEM +AC_ARG_PROGRAM +AM_INIT_AUTOMAKE($1, $2) +AM_DISABLE_LIBRARIES +AC_PREFIX_DEFAULT(${KDEDIR:-/usr/local/kde}) +AC_CHECK_COMPILERS +KDE_PROG_LIBTOOL +AM_KDE_WITH_NLS +AC_PATH_KDE +]) + +AC_DEFUN([AC_CHECK_RPATH], +[ +AC_MSG_CHECKING(for rpath) +AC_ARG_ENABLE(rpath, + AC_HELP_STRING([--disable-rpath],[do not use the rpath feature of ld]), + USE_RPATH=$enableval, USE_RPATH=yes) + +if test -z "$KDE_RPATH" && test "$USE_RPATH" = "yes"; then + + KDE_RPATH="-R \$(libdir)" + + if test "$kde_libraries" != "$libdir"; then + KDE_RPATH="$KDE_RPATH -R \$(kde_libraries)" + fi + + if test -n "$qt_libraries"; then + KDE_RPATH="$KDE_RPATH -R \$(qt_libraries)" + fi + dnl $x_libraries is set to /usr/lib in case + if test -n "$X_LDFLAGS"; then + X_RPATH="-R \$(x_libraries)" + KDE_RPATH="$KDE_RPATH $X_RPATH" + fi + if test -n "$KDE_EXTRA_RPATH"; then + KDE_RPATH="$KDE_RPATH \$(KDE_EXTRA_RPATH)" + fi +fi +AC_SUBST(KDE_EXTRA_RPATH) +AC_SUBST(KDE_RPATH) +AC_SUBST(X_RPATH) +AC_MSG_RESULT($USE_RPATH) +]) + +dnl Check for the type of the third argument of getsockname +AC_DEFUN([AC_CHECK_SOCKLEN_T], +[ + AC_MSG_CHECKING(for socklen_t) + AC_CACHE_VAL(kde_cv_socklen_t, + [ + AC_LANG_PUSH(C++) + kde_cv_socklen_t=no + AC_TRY_COMPILE([ + #include + #include + ], + [ + socklen_t len; + getpeername(0,0,&len); + ], + [ + kde_cv_socklen_t=yes + kde_cv_socklen_t_equiv=socklen_t + ]) + AC_LANG_POP(C++) + ]) + AC_MSG_RESULT($kde_cv_socklen_t) + if test $kde_cv_socklen_t = no; then + AC_MSG_CHECKING([for socklen_t equivalent for socket functions]) + AC_CACHE_VAL(kde_cv_socklen_t_equiv, + [ + kde_cv_socklen_t_equiv=int + AC_LANG_PUSH(C++) + for t in int size_t unsigned long "unsigned long"; do + AC_TRY_COMPILE([ + #include + #include + ], + [ + $t len; + getpeername(0,0,&len); + ], + [ + kde_cv_socklen_t_equiv="$t" + break + ]) + done + AC_LANG_POP(C++) + ]) + AC_MSG_RESULT($kde_cv_socklen_t_equiv) + fi + AC_DEFINE_UNQUOTED(kde_socklen_t, $kde_cv_socklen_t_equiv, + [type to use in place of socklen_t if not defined]) + AC_DEFINE_UNQUOTED(ksize_t, $kde_cv_socklen_t_equiv, + [type to use in place of socklen_t if not defined (deprecated, use kde_socklen_t)]) +]) + +dnl This is a merge of some macros out of the gettext aclocal.m4 +dnl since we don't need anything, I took the things we need +dnl the copyright for them is: +dnl > +dnl Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc. +dnl This Makefile.in is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without +dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A +dnl PARTICULAR PURPOSE. +dnl > +dnl for this file it is relicensed under LGPL + +AC_DEFUN([AM_KDE_WITH_NLS], + [ + dnl If we use NLS figure out what method + + AM_PATH_PROG_WITH_TEST_KDE(MSGFMT, msgfmt, + [test -n "`$ac_dir/$ac_word --version 2>&1 | grep 'GNU gettext'`"], msgfmt) + AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT) + + if test -z "`$GMSGFMT --version 2>&1 | grep 'GNU gettext'`"; then + AC_MSG_RESULT([found msgfmt program is not GNU msgfmt; ignore it]) + GMSGFMT=":" + fi + MSGFMT=$GMSGFMT + AC_SUBST(GMSGFMT) + AC_SUBST(MSGFMT) + + AM_PATH_PROG_WITH_TEST_KDE(XGETTEXT, xgettext, + [test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"], :) + + dnl Test whether we really found GNU xgettext. + if test "$XGETTEXT" != ":"; then + dnl If it is no GNU xgettext we define it as : so that the + dnl Makefiles still can work. + if $XGETTEXT --omit-header /dev/null 2> /dev/null; then + : ; + else + AC_MSG_RESULT( + [found xgettext programs is not GNU xgettext; ignore it]) + XGETTEXT=":" + fi + fi + AC_SUBST(XGETTEXT) + + ]) + +# Search path for a program which passes the given test. +# Ulrich Drepper , 1996. + +# serial 1 +# Stephan Kulow: I appended a _KDE against name conflicts + +dnl AM_PATH_PROG_WITH_TEST_KDE(VARIABLE, PROG-TO-CHECK-FOR, +dnl TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]]) +AC_DEFUN([AM_PATH_PROG_WITH_TEST_KDE], +[# Extract the first word of "$2", so it can be a program name with args. +set dummy $2; ac_word=[$]2 +AC_MSG_CHECKING([for $ac_word]) +AC_CACHE_VAL(ac_cv_path_$1, +[case "[$]$1" in + /*) + ac_cv_path_$1="[$]$1" # Let the user override the test with a path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in ifelse([$5], , $PATH, [$5]); do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if [$3]; then + ac_cv_path_$1="$ac_dir/$ac_word" + break + fi + fi + done + IFS="$ac_save_ifs" +dnl If no 4th arg is given, leave the cache variable unset, +dnl so AC_PATH_PROGS will keep looking. +ifelse([$4], , , [ test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4" +])dnl + ;; +esac])dnl +$1="$ac_cv_path_$1" +if test -n "[$]$1"; then + AC_MSG_RESULT([$]$1) +else + AC_MSG_RESULT(no) +fi +AC_SUBST($1)dnl +]) + + +# Check whether LC_MESSAGES is available in . +# Ulrich Drepper , 1995. + +# serial 1 + +AC_DEFUN([AM_LC_MESSAGES], + [if test $ac_cv_header_locale_h = yes; then + AC_CACHE_CHECK([for LC_MESSAGES], am_cv_val_LC_MESSAGES, + [AC_TRY_LINK([#include ], [return LC_MESSAGES], + am_cv_val_LC_MESSAGES=yes, am_cv_val_LC_MESSAGES=no)]) + if test $am_cv_val_LC_MESSAGES = yes; then + AC_DEFINE(HAVE_LC_MESSAGES, 1, [Define if your locale.h file contains LC_MESSAGES]) + fi + fi]) + +dnl From Jim Meyering. +dnl FIXME: migrate into libit. + +AC_DEFUN([AM_FUNC_OBSTACK], +[AC_CACHE_CHECK([for obstacks], am_cv_func_obstack, + [AC_TRY_LINK([#include "obstack.h"], + [struct obstack *mem;obstack_free(mem,(char *) 0)], + am_cv_func_obstack=yes, + am_cv_func_obstack=no)]) + if test $am_cv_func_obstack = yes; then + AC_DEFINE(HAVE_OBSTACK) + else + LIBOBJS="$LIBOBJS obstack.o" + fi +]) + +dnl From Jim Meyering. Use this if you use the GNU error.[ch]. +dnl FIXME: Migrate into libit + +AC_DEFUN([AM_FUNC_ERROR_AT_LINE], +[AC_CACHE_CHECK([for error_at_line], am_cv_lib_error_at_line, + [AC_TRY_LINK([],[error_at_line(0, 0, "", 0, "");], + am_cv_lib_error_at_line=yes, + am_cv_lib_error_at_line=no)]) + if test $am_cv_lib_error_at_line = no; then + LIBOBJS="$LIBOBJS error.o" + fi + AC_SUBST(LIBOBJS)dnl +]) + +# Macro to add for using GNU gettext. +# Ulrich Drepper , 1995. + +# serial 1 +# Stephan Kulow: I put a KDE in it to avoid name conflicts + +AC_DEFUN([AM_KDE_GNU_GETTEXT], + [AC_REQUIRE([AC_PROG_MAKE_SET])dnl + AC_REQUIRE([AC_PROG_RANLIB])dnl + AC_REQUIRE([AC_HEADER_STDC])dnl + AC_REQUIRE([AC_TYPE_OFF_T])dnl + AC_REQUIRE([AC_TYPE_SIZE_T])dnl + AC_REQUIRE([AC_FUNC_ALLOCA])dnl + AC_REQUIRE([AC_FUNC_MMAP])dnl + AC_REQUIRE([AM_KDE_WITH_NLS])dnl + AC_CHECK_HEADERS([limits.h locale.h nl_types.h string.h values.h alloca.h]) + AC_CHECK_FUNCS([getcwd munmap putenv setlocale strchr strcasecmp \ +__argz_count __argz_stringify __argz_next]) + + AC_MSG_CHECKING(for stpcpy) + AC_CACHE_VAL(kde_cv_func_stpcpy, + [ + kde_safe_cxxflags=$CXXFLAGS + CXXFLAGS="-Werror" + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + AC_TRY_COMPILE([ + #include + ], + [ + char buffer[200]; + stpcpy(buffer, buffer); + ], + kde_cv_func_stpcpy=yes, + kde_cv_func_stpcpy=no) + AC_LANG_RESTORE + CXXFLAGS=$kde_safe_cxxflags + ]) + AC_MSG_RESULT($kde_cv_func_stpcpy) + if eval "test \"`echo $kde_cv_func_stpcpy`\" = yes"; then + AC_DEFINE(HAVE_STPCPY, 1, [Define if you have stpcpy]) + fi + + AM_LC_MESSAGES + + if test "x$CATOBJEXT" != "x"; then + if test "x$ALL_LINGUAS" = "x"; then + LINGUAS= + else + AC_MSG_CHECKING(for catalogs to be installed) + NEW_LINGUAS= + for lang in ${LINGUAS=$ALL_LINGUAS}; do + case "$ALL_LINGUAS" in + *$lang*) NEW_LINGUAS="$NEW_LINGUAS $lang" ;; + esac + done + LINGUAS=$NEW_LINGUAS + AC_MSG_RESULT($LINGUAS) + fi + + dnl Construct list of names of catalog files to be constructed. + if test -n "$LINGUAS"; then + for lang in $LINGUAS; do CATALOGS="$CATALOGS $lang$CATOBJEXT"; done + fi + fi + + ]) + +AC_DEFUN([AC_HAVE_XPM], + [AC_REQUIRE_CPP()dnl + AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) + + test -z "$XPM_LDFLAGS" && XPM_LDFLAGS= + test -z "$XPM_INCLUDE" && XPM_INCLUDE= + + AC_ARG_WITH(xpm,AC_HELP_STRING([--without-xpm],[disable color pixmap XPM tests]), + xpm_test=$withval, xpm_test="yes") + if test "x$xpm_test" = xno; then + ac_cv_have_xpm=no + else + AC_MSG_CHECKING(for XPM) + AC_CACHE_VAL(ac_cv_have_xpm, + [ + ac_save_ldflags="$LDFLAGS" + ac_save_cflags="$CFLAGS" + if test "x$kde_use_qt_emb" != "xyes" && test "x$kde_use_qt_mac" != "xyes"; then + LDFLAGS="$LDFLAGS $X_LDFLAGS $USER_LDFLAGS $LDFLAGS $XPM_LDFLAGS $all_libraries -lXpm -lX11 -lXext $LIBZ $LIBSOCKET" + else + LDFLAGS="$LDFLAGS $X_LDFLAGS $USER_LDFLAGS $LDFLAGS $XPM_LDFLAGS $all_libraries -lXpm $LIBZ $LIBSOCKET" + fi + CFLAGS="$CFLAGS $X_INCLUDES $USER_INCLUDES" + test -n "$XPM_INCLUDE" && CFLAGS="-I$XPM_INCLUDE $CFLAGS" + AC_TRY_LINK([#include ],[], + ac_cv_have_xpm="yes",ac_cv_have_xpm="no") + LDFLAGS="$ac_save_ldflags" + CFLAGS="$ac_save_cflags" + ])dnl + + if test "$ac_cv_have_xpm" = no; then + AC_MSG_RESULT(no) + XPM_LDFLAGS="" + XPMINC="" + $2 + else + AC_DEFINE(HAVE_XPM, 1, [Define if you have XPM support]) + if test "$XPM_LDFLAGS" = ""; then + XPMLIB='-lXpm $(LIB_X11)' + else + XPMLIB="-L$XPM_LDFLAGS -lXpm "'$(LIB_X11)' + fi + if test "$XPM_INCLUDE" = ""; then + XPMINC="" + else + XPMINC="-I$XPM_INCLUDE" + fi + AC_MSG_RESULT(yes) + $1 + fi + fi + AC_SUBST(XPMINC) + AC_SUBST(XPMLIB) +]) + +AC_DEFUN([AC_HAVE_DPMS], + [AC_REQUIRE_CPP()dnl + AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) + + test -z "$DPMS_LDFLAGS" && DPMS_LDFLAGS= + test -z "$DPMS_INCLUDE" && DPMS_INCLUDE= + DPMS_LIB= + + AC_ARG_WITH(dpms,AC_HELP_STRING([--without-dpms],[disable DPMS power saving]), + dpms_test=$withval, dpms_test="yes") + if test "x$dpms_test" = xno; then + ac_cv_have_dpms=no + else + AC_MSG_CHECKING(for DPMS) + dnl Note: ac_cv_have_dpms can be no, yes, or -lXdpms. + dnl 'yes' means DPMS_LIB="", '-lXdpms' means DPMS_LIB="-lXdpms". + AC_CACHE_VAL(ac_cv_have_dpms, + [ + if test "x$kde_use_qt_emb" = "xyes" || test "x$kde_use_qt_mac" = "xyes"; then + AC_MSG_RESULT(no) + ac_cv_have_dpms="no" + else + ac_save_ldflags="$LDFLAGS" + ac_save_cflags="$CFLAGS" + ac_save_libs="$LIBS" + LDFLAGS="$LDFLAGS $DPMS_LDFLAGS $all_libraries" + LIBS="-lX11 -lXext $LIBSOCKET" + CFLAGS="$CFLAGS $X_INCLUDES" + test -n "$DPMS_INCLUDE" && CFLAGS="-I$DPMS_INCLUDE $CFLAGS" + AC_TRY_LINK([ + #include + #include + #include + #include + int foo_test_dpms() + { return DPMSSetTimeouts( 0, 0, 0, 0 ); }],[], + ac_cv_have_dpms="yes", [ + LIBS="-lXdpms $LIBS" + AC_TRY_LINK([ + #include + #include + #include + #include + int foo_test_dpms() + { return DPMSSetTimeouts( 0, 0, 0, 0 ); }],[], + [ + ac_cv_have_dpms="-lXdpms" + ],ac_cv_have_dpms="no") + ]) + LDFLAGS="$ac_save_ldflags" + CFLAGS="$ac_save_cflags" + LIBS="$ac_save_libs" + fi + ])dnl + + if test "$ac_cv_have_dpms" = no; then + AC_MSG_RESULT(no) + DPMS_LDFLAGS="" + DPMSINC="" + $2 + else + AC_DEFINE(HAVE_DPMS, 1, [Define if you have DPMS support]) + if test "$ac_cv_have_dpms" = "-lXdpms"; then + DPMS_LIB="-lXdpms" + fi + if test "$DPMS_LDFLAGS" = ""; then + DPMSLIB="$DPMS_LIB "'$(LIB_X11)' + else + DPMSLIB="$DPMS_LDFLAGS $DPMS_LIB "'$(LIB_X11)' + fi + if test "$DPMS_INCLUDE" = ""; then + DPMSINC="" + else + DPMSINC="-I$DPMS_INCLUDE" + fi + AC_MSG_RESULT(yes) + $1 + fi + fi + ac_save_cflags="$CFLAGS" + CFLAGS="$CFLAGS $X_INCLUDES" + test -n "$DPMS_INCLUDE" && CFLAGS="-I$DPMS_INCLUDE $CFLAGS" + AH_TEMPLATE(HAVE_DPMSCAPABLE_PROTO, + [Define if you have the DPMSCapable prototype in ]) + AC_CHECK_DECL(DPMSCapable, + AC_DEFINE(HAVE_DPMSCAPABLE_PROTO),, + [#include + #include ]) + AH_TEMPLATE(HAVE_DPMSINFO_PROTO, + [Define if you have the DPMSInfo prototype in ]) + AC_CHECK_DECL(DPMSInfo, + AC_DEFINE(HAVE_DPMSINFO_PROTO),, + [#include + #include ]) + CFLAGS="$ac_save_cflags" + AC_SUBST(DPMSINC) + AC_SUBST(DPMSLIB) +]) + +AC_DEFUN([AC_HAVE_GL], + [AC_REQUIRE_CPP()dnl + AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) + + test -z "$GL_LDFLAGS" && GL_LDFLAGS= + test -z "$GL_INCLUDE" && GL_INCLUDE= + + AC_ARG_WITH(gl,AC_HELP_STRING([--without-gl],[disable 3D GL modes]), + gl_test=$withval, gl_test="yes") + if test "x$kde_use_qt_emb" = "xyes"; then + # GL and Qt Embedded is a no-go for now. + ac_cv_have_gl=no + elif test "x$gl_test" = xno; then + ac_cv_have_gl=no + else + AC_MSG_CHECKING(for GL) + AC_CACHE_VAL(ac_cv_have_gl, + [ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + ac_save_ldflags=$LDFLAGS + ac_save_cxxflags=$CXXFLAGS + ac_save_libs=$LIBS + LDFLAGS="$LDFLAGS $GL_LDFLAGS $X_LDFLAGS $all_libraries" + LIBS="$LIBS -lGL -lGLU" + test "x$kde_use_qt_mac" != xyes && test "x$kde_use_qt_emb" != xyes && LIBS="$LIBS -lX11" + LIBS="$LIBS $LIB_XEXT -lm $LIBSOCKET" + CXXFLAGS="$CFLAGS $X_INCLUDES" + test -n "$GL_INCLUDE" && CFLAGS="-I$GL_INCLUDE $CFLAGS" + AC_TRY_LINK([#include +#include +], [], + ac_cv_have_gl="yes", ac_cv_have_gl="no") + AC_LANG_RESTORE + LDFLAGS=$ac_save_ldflags + CXXFLAGS=$ac_save_cxxflags + LIBS=$ac_save_libs + ])dnl + + if test "$ac_cv_have_gl" = "no"; then + AC_MSG_RESULT(no) + GL_LDFLAGS="" + GLINC="" + $2 + else + AC_DEFINE(HAVE_GL, 1, [Defines if you have GL (Mesa, OpenGL, ...)]) + if test "$GL_LDFLAGS" = ""; then + GLLIB='-lGLU -lGL $(LIB_X11)' + else + GLLIB="$GL_LDFLAGS -lGLU -lGL "'$(LIB_X11)' + fi + if test "$GL_INCLUDE" = ""; then + GLINC="" + else + GLINC="-I$GL_INCLUDE" + fi + AC_MSG_RESULT($ac_cv_have_gl) + $1 + fi + fi + AC_SUBST(GLINC) + AC_SUBST(GLLIB) +]) + + + dnl shadow password and PAM magic - maintained by ossi@kde.org + +AC_DEFUN([KDE_PAM], [ + AC_REQUIRE([KDE_CHECK_LIBDL]) + + want_pam= + AC_ARG_WITH(pam, + AC_HELP_STRING([--with-pam[=ARG]],[enable support for PAM: ARG=[yes|no|service name]]), + [ if test "x$withval" = "xyes"; then + want_pam=yes + pam_service=kde + elif test "x$withval" = "xno"; then + want_pam=no + else + want_pam=yes + pam_service=$withval + fi + ], [ pam_service=kde ]) + + use_pam= + PAMLIBS= + if test "x$want_pam" != xno; then + AC_CHECK_LIB(pam, pam_start, [ + AC_CHECK_HEADER(security/pam_appl.h, + [ pam_header=security/pam_appl.h ], + [ AC_CHECK_HEADER(pam/pam_appl.h, + [ pam_header=pam/pam_appl.h ], + [ + AC_MSG_WARN([PAM detected, but no headers found! +Make sure you have the necessary development packages installed.]) + ] + ) + ] + ) + ], , $LIBDL) + if test -z "$pam_header"; then + if test "x$want_pam" = xyes; then + AC_MSG_ERROR([--with-pam was specified, but cannot compile with PAM!]) + fi + else + AC_DEFINE(HAVE_PAM, 1, [Defines if you have PAM (Pluggable Authentication Modules)]) + PAMLIBS="$PAM_MISC_LIB -lpam $LIBDL" + use_pam=yes + + dnl darwin claims to be something special + if test "$pam_header" = "pam/pam_appl.h"; then + AC_DEFINE(HAVE_PAM_PAM_APPL_H, 1, [Define if your PAM headers are in pam/ instead of security/]) + fi + + dnl test whether struct pam_message is const (Linux) or not (Sun) + AC_MSG_CHECKING(for const pam_message) + AC_EGREP_HEADER([struct pam_message], $pam_header, + [ AC_EGREP_HEADER([const struct pam_message], $pam_header, + [AC_MSG_RESULT([const: Linux-type PAM])], + [AC_MSG_RESULT([nonconst: Sun-type PAM]) + AC_DEFINE(PAM_MESSAGE_NONCONST, 1, [Define if your PAM support takes non-const arguments (Solaris)])] + )], + [AC_MSG_RESULT([not found - assume const, Linux-type PAM])]) + fi + fi + + AC_SUBST(PAMLIBS) +]) + +dnl DEF_PAM_SERVICE(arg name, full name, define name) +AC_DEFUN([DEF_PAM_SERVICE], [ + AC_ARG_WITH($1-pam, + AC_HELP_STRING([--with-$1-pam=[val]],[override PAM service from --with-pam for $2]), + [ if test "x$use_pam" = xyes; then + $3_PAM_SERVICE=$withval + else + AC_MSG_ERROR([Cannot use use --with-$1-pam, as no PAM was detected. +You may want to enforce it by using --with-pam.]) + fi + ], + [ if test "x$use_pam" = xyes; then + $3_PAM_SERVICE="$pam_service" + fi + ]) + if test -n "$$3_PAM_SERVICE"; then + AC_MSG_RESULT([The PAM service used by $2 will be $$3_PAM_SERVICE]) + AC_DEFINE_UNQUOTED($3_PAM_SERVICE, "$$3_PAM_SERVICE", [The PAM service to be used by $2]) + fi + AC_SUBST($3_PAM_SERVICE) +]) + +AC_DEFUN([KDE_SHADOWPASSWD], [ + AC_REQUIRE([KDE_PAM]) + + AC_CHECK_LIB(shadow, getspent, + [ LIBSHADOW="-lshadow" + ac_use_shadow=yes + ], + [ dnl for UnixWare + AC_CHECK_LIB(gen, getspent, + [ LIBGEN="-lgen" + ac_use_shadow=yes + ], + [ AC_CHECK_FUNC(getspent, + [ ac_use_shadow=yes ], + [ ac_use_shadow=no ]) + ]) + ]) + AC_SUBST(LIBSHADOW) + AC_SUBST(LIBGEN) + + AC_MSG_CHECKING([for shadow passwords]) + + AC_ARG_WITH(shadow, + AC_HELP_STRING([--with-shadow],[If you want shadow password support]), + [ if test "x$withval" != "xno"; then + use_shadow=yes + else + use_shadow=no + fi + ], [ + use_shadow="$ac_use_shadow" + ]) + + if test "x$use_shadow" = xyes; then + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_SHADOW, 1, [Define if you use shadow passwords]) + else + AC_MSG_RESULT(no) + LIBSHADOW= + LIBGEN= + fi + + dnl finally make the relevant binaries setuid root, if we have shadow passwds. + dnl this still applies, if we could use it indirectly through pam. + if test "x$use_shadow" = xyes || + ( test "x$use_pam" = xyes && test "x$ac_use_shadow" = xyes ); then + case $host in + *-*-freebsd* | *-*-netbsd* | *-*-openbsd*) + SETUIDFLAGS="-m 4755 -o root";; + *) + SETUIDFLAGS="-m 4755";; + esac + fi + AC_SUBST(SETUIDFLAGS) + +]) + +AC_DEFUN([KDE_PASSWDLIBS], [ + AC_REQUIRE([KDE_MISC_TESTS]) dnl for LIBCRYPT + AC_REQUIRE([KDE_PAM]) + AC_REQUIRE([KDE_SHADOWPASSWD]) + + if test "x$use_pam" = "xyes"; then + PASSWDLIBS="$PAMLIBS" + else + PASSWDLIBS="$LIBCRYPT $LIBSHADOW $LIBGEN" + fi + + dnl FreeBSD uses a shadow-like setup, where /etc/passwd holds the users, but + dnl /etc/master.passwd holds the actual passwords. /etc/master.passwd requires + dnl root to read, so kcheckpass needs to be root (even when using pam, since pam + dnl may need to read /etc/master.passwd). + case $host in + *-*-freebsd*) + SETUIDFLAGS="-m 4755 -o root" + ;; + *) + ;; + esac + + AC_SUBST(PASSWDLIBS) +]) + +AC_DEFUN([KDE_CHECK_LIBDL], +[ +AC_CHECK_LIB(dl, dlopen, [ +LIBDL="-ldl" +ac_cv_have_dlfcn=yes +]) + +AC_CHECK_LIB(dld, shl_unload, [ +LIBDL="-ldld" +ac_cv_have_shload=yes +]) + +AC_SUBST(LIBDL) +]) + +AC_DEFUN([KDE_CHECK_DLOPEN], +[ +KDE_CHECK_LIBDL +AC_CHECK_HEADERS(dlfcn.h dl.h) +if test "$ac_cv_header_dlfcn_h" = "no"; then + ac_cv_have_dlfcn=no +fi + +if test "$ac_cv_header_dl_h" = "no"; then + ac_cv_have_shload=no +fi + +dnl XXX why change enable_dlopen? its already set by autoconf's AC_ARG_ENABLE +dnl (MM) +AC_ARG_ENABLE(dlopen, +AC_HELP_STRING([--disable-dlopen],[link statically [default=no]]), +enable_dlopen=$enableval, +enable_dlopen=yes) + +# override the user's opinion, if we know it better ;) +if test "$ac_cv_have_dlfcn" = "no" && test "$ac_cv_have_shload" = "no"; then + enable_dlopen=no +fi + +if test "$ac_cv_have_dlfcn" = "yes"; then + AC_DEFINE_UNQUOTED(HAVE_DLFCN, 1, [Define if you have dlfcn]) +fi + +if test "$ac_cv_have_shload" = "yes"; then + AC_DEFINE_UNQUOTED(HAVE_SHLOAD, 1, [Define if you have shload]) +fi + +if test "$enable_dlopen" = no ; then + test -n "$1" && eval $1 +else + test -n "$2" && eval $2 +fi + +]) + +AC_DEFUN([KDE_CHECK_DYNAMIC_LOADING], +[ +KDE_CHECK_DLOPEN(libtool_enable_shared=yes, libtool_enable_static=no) +KDE_PROG_LIBTOOL +AC_MSG_CHECKING([dynamic loading]) +eval "`egrep '^build_libtool_libs=' libtool`" +if test "$build_libtool_libs" = "yes" && test "$enable_dlopen" = "yes"; then + dynamic_loading=yes + AC_DEFINE_UNQUOTED(HAVE_DYNAMIC_LOADING) +else + dynamic_loading=no +fi +AC_MSG_RESULT($dynamic_loading) +if test "$dynamic_loading" = "yes"; then + $1 +else + $2 +fi +]) + +AC_DEFUN([KDE_ADD_INCLUDES], +[ +if test -z "$1"; then + test_include="Pix.h" +else + test_include="$1" +fi + +AC_MSG_CHECKING([for libg++ ($test_include)]) + +AC_CACHE_VAL(kde_cv_libgpp_includes, +[ +kde_cv_libgpp_includes=no + + for ac_dir in \ + \ + /usr/include/g++ \ + /usr/include \ + /usr/unsupported/include \ + /opt/include \ + $extra_include \ + ; \ + do + if test -r "$ac_dir/$test_include"; then + kde_cv_libgpp_includes=$ac_dir + break + fi + done +]) + +AC_MSG_RESULT($kde_cv_libgpp_includes) +if test "$kde_cv_libgpp_includes" != "no"; then + all_includes="-I$kde_cv_libgpp_includes $all_includes $USER_INCLUDES" +fi +]) +]) + +AC_DEFUN([KDE_CHECK_LIBPTHREAD], +[ + dnl This code is here specifically to handle the + dnl various flavors of threading library on FreeBSD + dnl 4-, 5-, and 6-, and the (weird) rules around it. + dnl There may be an environment PTHREAD_LIBS that + dnl specifies what to use; otherwise, search for it. + dnl -pthread is special cased and unsets LIBPTHREAD + dnl below if found. + LIBPTHREAD="" + + if test -n "$PTHREAD_LIBS"; then + if test "x$PTHREAD_LIBS" = "x-pthread" ; then + LIBPTHREAD="PTHREAD" + else + PTHREAD_LIBS_save="$PTHREAD_LIBS" + PTHREAD_LIBS=`echo "$PTHREAD_LIBS_save" | sed -e 's,^-l,,g'` + AC_MSG_CHECKING([for pthread_create in $PTHREAD_LIBS]) + KDE_CHECK_LIB($PTHREAD_LIBS, pthread_create, [ + LIBPTHREAD="$PTHREAD_LIBS_save"]) + PTHREAD_LIBS="$PTHREAD_LIBS_save" + fi + fi + + dnl Is this test really needed, in the face of the Tru64 test below? + if test -z "$LIBPTHREAD"; then + AC_CHECK_LIB(pthread, pthread_create, [LIBPTHREAD="-lpthread"]) + fi + + dnl This is a special Tru64 check, see BR 76171 issue #18. + if test -z "$LIBPTHREAD" ; then + AC_MSG_CHECKING([for pthread_create in -lpthread]) + kde_safe_libs=$LIBS + LIBS="$LIBS -lpthread" + AC_TRY_LINK([#include ],[(void)pthread_create(0,0,0,0);],[ + AC_MSG_RESULT(yes) + LIBPTHREAD="-lpthread"],[ + AC_MSG_RESULT(no)]) + LIBS=$kde_safe_libs + fi + + dnl Un-special-case for FreeBSD. + if test "x$LIBPTHREAD" = "xPTHREAD" ; then + LIBPTHREAD="" + fi + + AC_SUBST(LIBPTHREAD) +]) + +AC_DEFUN([KDE_CHECK_PTHREAD_OPTION], +[ + USE_THREADS="" + if test -z "$LIBPTHREAD"; then + KDE_CHECK_COMPILER_FLAG(pthread, [USE_THREADS="-D_THREAD_SAFE -pthread"]) + fi + + AH_VERBATIM(__svr_define, [ +#if defined(__SVR4) && !defined(__svr4__) +#define __svr4__ 1 +#endif +]) + case $host_os in + solaris*) + KDE_CHECK_COMPILER_FLAG(mt, [USE_THREADS="-mt"]) + CPPFLAGS="$CPPFLAGS -D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -DUSE_SOLARIS -DSVR4" + ;; + freebsd*) + CPPFLAGS="$CPPFLAGS -D_THREAD_SAFE $PTHREAD_CFLAGS" + ;; + aix*) + CPPFLAGS="$CPPFLAGS -D_THREAD_SAFE" + LIBPTHREAD="$LIBPTHREAD -lc_r" + ;; + linux*) CPPFLAGS="$CPPFLAGS -D_REENTRANT" + if test "$CXX" = "KCC"; then + CXXFLAGS="$CXXFLAGS --thread_safe" + NOOPT_CXXFLAGS="$NOOPT_CXXFLAGS --thread_safe" + fi + ;; + *) + ;; + esac + AC_SUBST(USE_THREADS) + AC_SUBST(LIBPTHREAD) +]) + +AC_DEFUN([KDE_CHECK_THREADING], +[ + AC_REQUIRE([KDE_CHECK_LIBPTHREAD]) + AC_REQUIRE([KDE_CHECK_PTHREAD_OPTION]) + dnl default is yes if libpthread is found and no if no libpthread is available + if test -z "$LIBPTHREAD"; then + if test -z "$USE_THREADS"; then + kde_check_threading_default=no + else + kde_check_threading_default=yes + fi + else + kde_check_threading_default=yes + fi + AC_ARG_ENABLE(threading,AC_HELP_STRING([--disable-threading],[disables threading even if libpthread found]), + kde_use_threading=$enableval, kde_use_threading=$kde_check_threading_default) + if test "x$kde_use_threading" = "xyes"; then + AC_DEFINE(HAVE_LIBPTHREAD, 1, [Define if you have a working libpthread (will enable threaded code)]) + fi +]) + +AC_DEFUN([KDE_TRY_LINK_PYTHON], +[ +if test "$kde_python_link_found" = no; then + +if test "$1" = normal; then + AC_MSG_CHECKING(if a Python application links) +else + AC_MSG_CHECKING(if Python depends on $2) +fi + +AC_CACHE_VAL(kde_cv_try_link_python_$1, +[ +kde_save_cflags="$CFLAGS" +CFLAGS="$CFLAGS $PYTHONINC" +kde_save_libs="$LIBS" +LIBS="$LIBS $LIBPYTHON $2 $LIBDL $LIBSOCKET" +kde_save_ldflags="$LDFLAGS" +LDFLAGS="$LDFLAGS $PYTHONLIB" + +AC_TRY_LINK( +[ +#include +],[ + PySys_SetArgv(1, 0); +], + [kde_cv_try_link_python_$1=yes], + [kde_cv_try_link_python_$1=no] +) +CFLAGS="$kde_save_cflags" +LIBS="$kde_save_libs" +LDFLAGS="$kde_save_ldflags" +]) + +if test "$kde_cv_try_link_python_$1" = "yes"; then + AC_MSG_RESULT(yes) + kde_python_link_found=yes + if test ! "$1" = normal; then + LIBPYTHON="$LIBPYTHON $2" + fi + $3 +else + AC_MSG_RESULT(no) + $4 +fi + +fi + +]) + +AC_DEFUN([KDE_CHECK_PYTHON_DIR], +[ +AC_MSG_CHECKING([for Python directory]) + +AC_CACHE_VAL(kde_cv_pythondir, +[ + if test -z "$PYTHONDIR"; then + kde_cv_pythondir=/usr/local + else + kde_cv_pythondir="$PYTHONDIR" + fi +]) + +AC_ARG_WITH(pythondir, +AC_HELP_STRING([--with-pythondir=pythondir],[use python installed in pythondir]), +[ + ac_python_dir=$withval +], ac_python_dir=$kde_cv_pythondir +) + +AC_MSG_RESULT($ac_python_dir) +]) + +AC_DEFUN([KDE_CHECK_PYTHON_INTERN], +[ +AC_REQUIRE([KDE_CHECK_LIBDL]) +AC_REQUIRE([KDE_CHECK_LIBPTHREAD]) +AC_REQUIRE([KDE_CHECK_PYTHON_DIR]) + +if test -z "$1"; then + version="1.5" +else + version="$1" +fi + +AC_MSG_CHECKING([for Python$version]) + +python_incdirs="$ac_python_dir/include /usr/include /usr/local/include/ $kde_extra_includes" +AC_FIND_FILE(Python.h, $python_incdirs, python_incdir) +if test ! -r $python_incdir/Python.h; then + AC_FIND_FILE(python$version/Python.h, $python_incdirs, python_incdir) + python_incdir=$python_incdir/python$version + if test ! -r $python_incdir/Python.h; then + python_incdir=no + fi +fi + +PYTHONINC=-I$python_incdir + +python_libdirs="$ac_python_dir/lib$kdelibsuff /usr/lib$kdelibsuff /usr/local /usr/lib$kdelibsuff $kde_extra_libs" +AC_FIND_FILE(libpython$version.so, $python_libdirs, python_libdir) +if test ! -r $python_libdir/libpython$version.so; then + AC_FIND_FILE(libpython$version.a, $python_libdirs, python_libdir) + if test ! -r $python_libdir/libpython$version.a; then + AC_FIND_FILE(python$version/config/libpython$version.a, $python_libdirs, python_libdir) + python_libdir=$python_libdir/python$version/config + if test ! -r $python_libdir/libpython$version.a; then + python_libdir=no + fi + fi +fi + +PYTHONLIB=-L$python_libdir +kde_orig_LIBPYTHON=$LIBPYTHON +if test -z "$LIBPYTHON"; then + LIBPYTHON=-lpython$version +fi + +AC_FIND_FILE(python$version/copy.py, $python_libdirs, python_moddir) +python_moddir=$python_moddir/python$version +if test ! -r $python_moddir/copy.py; then + python_moddir=no +fi + +PYTHONMODDIR=$python_moddir + +AC_MSG_RESULT(header $python_incdir library $python_libdir modules $python_moddir) + +if test x$python_incdir = xno || test x$python_libdir = xno || test x$python_moddir = xno; then + LIBPYTHON=$kde_orig_LIBPYTHON + test "x$PYTHONLIB" = "x-Lno" && PYTHONLIB="" + test "x$PYTHONINC" = "x-Ino" && PYTHONINC="" + $2 +else + dnl Note: this test is very weak + kde_python_link_found=no + KDE_TRY_LINK_PYTHON(normal) + KDE_TRY_LINK_PYTHON(m, -lm) + KDE_TRY_LINK_PYTHON(pthread, $LIBPTHREAD) + KDE_TRY_LINK_PYTHON(tcl, -ltcl) + KDE_TRY_LINK_PYTHON(db2, -ldb2) + KDE_TRY_LINK_PYTHON(m_and_thread, [$LIBPTHREAD -lm]) + KDE_TRY_LINK_PYTHON(m_and_thread_and_util, [$LIBPTHREAD -lm -lutil]) + KDE_TRY_LINK_PYTHON(m_and_thread_and_db3, [$LIBPTHREAD -lm -ldb-3 -lutil]) + KDE_TRY_LINK_PYTHON(pthread_and_db3, [$LIBPTHREAD -ldb-3]) + KDE_TRY_LINK_PYTHON(m_and_thread_and_db, [$LIBPTHREAD -lm -ldb -ltermcap -lutil]) + KDE_TRY_LINK_PYTHON(pthread_and_dl, [$LIBPTHREAD $LIBDL -lutil -lreadline -lncurses -lm]) + KDE_TRY_LINK_PYTHON(pthread_and_panel_curses, [$LIBPTHREAD $LIBDL -lm -lpanel -lcurses]) + KDE_TRY_LINK_PYTHON(m_and_thread_and_db_special, [$LIBPTHREAD -lm -ldb -lutil], [], + [AC_MSG_WARN([it seems, Python depends on another library. + Please set LIBPYTHON to '-lpython$version -lotherlib' before calling configure to fix this + and contact the authors to let them know about this problem]) + ]) + + LIBPYTHON="$LIBPYTHON $LIBDL $LIBSOCKET" + AC_SUBST(PYTHONINC) + AC_SUBST(PYTHONLIB) + AC_SUBST(LIBPYTHON) + AC_SUBST(PYTHONMODDIR) + AC_DEFINE(HAVE_PYTHON, 1, [Define if you have the development files for python]) +fi + +]) + + +AC_DEFUN([KDE_CHECK_PYTHON], +[ + KDE_CHECK_PYTHON_INTERN("2.5", + [KDE_CHECK_PYTHON_INTERN("2.4", + [KDE_CHECK_PYTHON_INTERN("2.3", + [KDE_CHECK_PYTHON_INTERN("2.2", + [KDE_CHECK_PYTHON_INTERN("2.1", + [KDE_CHECK_PYTHON_INTERN("2.0", + [KDE_CHECK_PYTHON_INTERN($1, $2) ]) + ]) + ]) + ]) + ]) + ]) +]) + +AC_DEFUN([KDE_CHECK_STL], +[ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="`echo $CXXFLAGS | sed s/-fno-exceptions//`" + + AC_MSG_CHECKING([if C++ programs can be compiled]) + AC_CACHE_VAL(kde_cv_stl_works, + [ + AC_TRY_COMPILE([ +#include +using namespace std; +],[ + string astring="Hallo Welt."; + astring.erase(0, 6); // now astring is "Welt" + return 0; +], kde_cv_stl_works=yes, + kde_cv_stl_works=no) +]) + + AC_MSG_RESULT($kde_cv_stl_works) + + if test "$kde_cv_stl_works" = "yes"; then + # back compatible + AC_DEFINE_UNQUOTED(HAVE_SGI_STL, 1, [Define if you have a STL implementation by SGI]) + else + AC_MSG_ERROR([Your Installation isn't able to compile simple C++ programs. +Check config.log for details - if you're using a Linux distribution you might miss +a package named similar to libstdc++-dev.]) + fi + + CXXFLAGS="$ac_save_CXXFLAGS" + AC_LANG_RESTORE +]) + +AC_DEFUN([AC_FIND_QIMGIO], + [AC_REQUIRE([AC_FIND_JPEG]) +AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) +AC_MSG_CHECKING([for qimgio]) +AC_CACHE_VAL(ac_cv_lib_qimgio, +[ +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +ac_save_LIBS="$LIBS" +ac_save_CXXFLAGS="$CXXFLAGS" +LIBS="$all_libraries -lqimgio -lpng -lz $LIBJPEG $LIBQT" +CXXFLAGS="$CXXFLAGS -I$qt_incdir $all_includes" +AC_TRY_RUN(dnl +[ +#include +#include +int main() { + QString t = "hallo"; + t.fill('t'); + qInitImageIO(); +} +], + ac_cv_lib_qimgio=yes, + ac_cv_lib_qimgio=no, + ac_cv_lib_qimgio=no) +LIBS="$ac_save_LIBS" +CXXFLAGS="$ac_save_CXXFLAGS" +AC_LANG_RESTORE +])dnl +if eval "test \"`echo $ac_cv_lib_qimgio`\" = yes"; then + LIBQIMGIO="-lqimgio -lpng -lz $LIBJPEG" + AC_MSG_RESULT(yes) + AC_DEFINE_UNQUOTED(HAVE_QIMGIO, 1, [Define if you have the Qt extension qimgio available]) + AC_SUBST(LIBQIMGIO) +else + AC_MSG_RESULT(not found) +fi +]) + +AC_DEFUN([AM_DISABLE_LIBRARIES], +[ + AC_PROVIDE([AM_ENABLE_STATIC]) + AC_PROVIDE([AM_ENABLE_SHARED]) + enable_static=no + enable_shared=yes +]) + + +AC_DEFUN([AC_CHECK_UTMP_FILE], +[ + AC_MSG_CHECKING([for utmp file]) + + AC_CACHE_VAL(kde_cv_utmp_file, + [ + kde_cv_utmp_file=no + + for ac_file in \ + \ + /var/run/utmp \ + /var/adm/utmp \ + /etc/utmp \ + ; \ + do + if test -r "$ac_file"; then + kde_cv_utmp_file=$ac_file + break + fi + done + ]) + + if test "$kde_cv_utmp_file" != "no"; then + AC_DEFINE_UNQUOTED(UTMP, "$kde_cv_utmp_file", [Define the file for utmp entries]) + $1 + AC_MSG_RESULT($kde_cv_utmp_file) + else + $2 + AC_MSG_RESULT([non found]) + fi +]) + + +AC_DEFUN([KDE_CREATE_SUBDIRSLIST], +[ + +DO_NOT_COMPILE="$DO_NOT_COMPILE CVS debian bsd-port admin" +TOPSUBDIRS="" + +if test ! -s $srcdir/subdirs; then + dnl Note: Makefile.common creates subdirs, so this is just a fallback + files=`cd $srcdir && ls -1` + dirs=`for i in $files; do if test -d $i; then echo $i; fi; done` + for i in $dirs; do + echo $i >> $srcdir/subdirs + done +fi + +ac_topsubdirs= +if test -s $srcdir/inst-apps; then + ac_topsubdirs="`cat $srcdir/inst-apps`" +elif test -s $srcdir/subdirs; then + ac_topsubdirs="`cat $srcdir/subdirs`" +fi + +for i in $ac_topsubdirs; do + AC_MSG_CHECKING([if $i should be compiled]) + if test -d $srcdir/$i; then + install_it="yes" + for j in $DO_NOT_COMPILE; do + if test $i = $j; then + install_it="no" + fi + done + else + install_it="no" + fi + AC_MSG_RESULT($install_it) + vari=`echo $i | sed -e 's,[[-+.@]],_,g'` + if test $install_it = "yes"; then + TOPSUBDIRS="$TOPSUBDIRS $i" + eval "$vari""_SUBDIR_included=yes" + else + eval "$vari""_SUBDIR_included=no" + fi +done + +AC_SUBST(TOPSUBDIRS) +]) + +AC_DEFUN([KDE_CHECK_NAMESPACES], +[ +AC_MSG_CHECKING(whether C++ compiler supports namespaces) +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +AC_TRY_COMPILE([ +], +[ +namespace Foo { + extern int i; + namespace Bar { + extern int i; + } +} + +int Foo::i = 0; +int Foo::Bar::i = 1; +],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_NAMESPACES) +], [ +AC_MSG_RESULT(no) +]) +AC_LANG_RESTORE +]) + +dnl ------------------------------------------------------------------------ +dnl Check for S_ISSOCK macro. Doesn't exist on Unix SCO. faure@kde.org +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([AC_CHECK_S_ISSOCK], +[ +AC_MSG_CHECKING(for S_ISSOCK) +AC_CACHE_VAL(ac_cv_have_s_issock, +[ +AC_TRY_LINK( +[ +#include +], +[ +struct stat buff; +int b = S_ISSOCK( buff.st_mode ); +], +ac_cv_have_s_issock=yes, +ac_cv_have_s_issock=no) +]) +AC_MSG_RESULT($ac_cv_have_s_issock) +if test "$ac_cv_have_s_issock" = "yes"; then + AC_DEFINE_UNQUOTED(HAVE_S_ISSOCK, 1, [Define if sys/stat.h declares S_ISSOCK.]) +fi + +AH_VERBATIM(_ISSOCK, +[ +#ifndef HAVE_S_ISSOCK +#define HAVE_S_ISSOCK +#define S_ISSOCK(mode) (1==0) +#endif +]) + +]) + +dnl ------------------------------------------------------------------------ +dnl Check for MAXPATHLEN macro, defines KDEMAXPATHLEN. faure@kde.org +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([AC_CHECK_KDEMAXPATHLEN], +[ +AC_MSG_CHECKING(for MAXPATHLEN) +AC_CACHE_VAL(ac_cv_maxpathlen, +[ +cat > conftest.$ac_ext < +#endif +#include +#include +#ifndef MAXPATHLEN +#define MAXPATHLEN 1024 +#endif + +KDE_HELLO MAXPATHLEN + +EOF + +ac_try="$ac_cpp conftest.$ac_ext 2>/dev/null | grep '^KDE_HELLO' >conftest.out" + +if AC_TRY_EVAL(ac_try) && test -s conftest.out; then + ac_cv_maxpathlen=`sed 's#KDE_HELLO ##' conftest.out` +else + ac_cv_maxpathlen=1024 +fi + +rm conftest.* + +]) +AC_MSG_RESULT($ac_cv_maxpathlen) +AC_DEFINE_UNQUOTED(KDEMAXPATHLEN,$ac_cv_maxpathlen, [Define a safe value for MAXPATHLEN] ) +]) + +AC_DEFUN([KDE_CHECK_HEADER], +[ + kde_safe_cppflags=$CPPFLAGS + CPPFLAGS="$CPPFLAGS $all_includes" + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + AC_CHECK_HEADER([$1], [$2], [$3], [$4]) + AC_LANG_RESTORE + CPPFLAGS=$kde_safe_cppflags +]) + +AC_DEFUN([KDE_CHECK_HEADERS], +[ + AH_CHECK_HEADERS([$1]) + AC_LANG_SAVE + kde_safe_cppflags=$CPPFLAGS + CPPFLAGS="$CPPFLAGS $all_includes" + AC_LANG_CPLUSPLUS + AC_CHECK_HEADERS([$1], [$2], [$3], [$4]) + CPPFLAGS=$kde_safe_cppflags + AC_LANG_RESTORE +]) + +AC_DEFUN([KDE_FAST_CONFIGURE], +[ + dnl makes configure fast (needs perl) + AC_ARG_ENABLE(fast-perl, AC_HELP_STRING([--disable-fast-perl],[disable fast Makefile generation (needs perl)]), + with_fast_perl=$enableval, with_fast_perl=yes) +]) + +AC_DEFUN([KDE_CONF_FILES], +[ + val= + if test -f $srcdir/configure.files ; then + val=`sed -e 's%^%\$(top_srcdir)/%' $srcdir/configure.files` + fi + CONF_FILES= + if test -n "$val" ; then + for i in $val ; do + CONF_FILES="$CONF_FILES $i" + done + fi + AC_SUBST(CONF_FILES) +])dnl + +dnl This sets the prefix, for arts and kdelibs +dnl Do NOT use in any other module. +dnl It only looks at --prefix, KDEDIR and falls back to /usr/local/kde +AC_DEFUN([KDE_SET_PREFIX_CORE], +[ + unset CDPATH + dnl make $KDEDIR the default for the installation + AC_PREFIX_DEFAULT(${KDEDIR:-/usr/local/kde}) + + if test "x$prefix" = "xNONE"; then + prefix=$ac_default_prefix + ac_configure_args="$ac_configure_args --prefix=$prefix" + fi + # And delete superfluous '/' to make compares easier + prefix=`echo "$prefix" | sed 's,//*,/,g' | sed -e 's,/$,,'` + exec_prefix=`echo "$exec_prefix" | sed 's,//*,/,g' | sed -e 's,/$,,'` + + kde_libs_prefix='$(prefix)' + kde_libs_htmldir='$(kde_htmldir)' + AC_SUBST(kde_libs_prefix) + AC_SUBST(kde_libs_htmldir) + KDE_FAST_CONFIGURE + KDE_CONF_FILES +]) + + +AC_DEFUN([KDE_SET_PREFIX], +[ + unset CDPATH + dnl We can't give real code to that macro, only a value. + dnl It only matters for --help, since we set the prefix in this function anyway. + AC_PREFIX_DEFAULT(${KDEDIR:-the kde prefix}) + + KDE_SET_DEFAULT_BINDIRS + if test "x$prefix" = "xNONE"; then + dnl no prefix given: look for kde-config in the PATH and deduce the prefix from it + KDE_FIND_PATH(kde-config, KDECONFIG, [$kde_default_bindirs], [KDE_MISSING_PROG_ERROR(kde-config)], [], prepend) + else + dnl prefix given: look for kde-config, preferrably in prefix, otherwise in PATH + kde_save_PATH="$PATH" + PATH="$exec_prefix/bin:$prefix/bin:$PATH" + KDE_FIND_PATH(kde-config, KDECONFIG, [$kde_default_bindirs], [KDE_MISSING_PROG_ERROR(kde-config)], [], prepend) + PATH="$kde_save_PATH" + fi + + kde_libs_prefix=`$KDECONFIG --prefix` + if test -z "$kde_libs_prefix" || test ! -x "$kde_libs_prefix"; then + AC_MSG_ERROR([$KDECONFIG --prefix outputed the non existant prefix '$kde_libs_prefix' for kdelibs. + This means it has been moved since you installed it. + This won't work. Please recompile kdelibs for the new prefix. + ]) + fi + kde_libs_htmldir=`$KDECONFIG --install html --expandvars` + + AC_MSG_CHECKING([where to install]) + if test "x$prefix" = "xNONE"; then + prefix=$kde_libs_prefix + AC_MSG_RESULT([$prefix (as returned by kde-config)]) + else + dnl --prefix was given. Compare prefixes and warn (in configure.in.bot.end) if different + given_prefix=$prefix + AC_MSG_RESULT([$prefix (as requested)]) + fi + + # And delete superfluous '/' to make compares easier + prefix=`echo "$prefix" | sed 's,//*,/,g' | sed -e 's,/$,,'` + exec_prefix=`echo "$exec_prefix" | sed 's,//*,/,g' | sed -e 's,/$,,'` + given_prefix=`echo "$given_prefix" | sed 's,//*,/,g' | sed -e 's,/$,,'` + + AC_SUBST(KDECONFIG) + AC_SUBST(kde_libs_prefix) + AC_SUBST(kde_libs_htmldir) + + KDE_FAST_CONFIGURE + KDE_CONF_FILES +]) + +pushdef([AC_PROG_INSTALL], +[ + dnl our own version, testing for a -p flag + popdef([AC_PROG_INSTALL]) + dnl as AC_PROG_INSTALL works as it works we first have + dnl to save if the user didn't specify INSTALL, as the + dnl autoconf one overwrites INSTALL and we have no chance to find + dnl out afterwards + test -n "$INSTALL" && kde_save_INSTALL_given=$INSTALL + test -n "$INSTALL_PROGRAM" && kde_save_INSTALL_PROGRAM_given=$INSTALL_PROGRAM + test -n "$INSTALL_SCRIPT" && kde_save_INSTALL_SCRIPT_given=$INSTALL_SCRIPT + AC_PROG_INSTALL + + if test -z "$kde_save_INSTALL_given" ; then + # OK, user hasn't given any INSTALL, autoconf found one for us + # now we test, if it supports the -p flag + AC_MSG_CHECKING(for -p flag to install) + rm -f confinst.$$.* > /dev/null 2>&1 + echo "Testtest" > confinst.$$.orig + ac_res=no + if ${INSTALL} -p confinst.$$.orig confinst.$$.new > /dev/null 2>&1 ; then + if test -f confinst.$$.new ; then + # OK, -p seems to do no harm to install + INSTALL="${INSTALL} -p" + ac_res=yes + fi + fi + rm -f confinst.$$.* + AC_MSG_RESULT($ac_res) + fi + dnl the following tries to resolve some signs and wonders coming up + dnl with different autoconf/automake versions + dnl e.g.: + dnl *automake 1.4 install-strip sets A_M_INSTALL_PROGRAM_FLAGS to -s + dnl and has INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(A_M_INSTALL_PROGRAM_FLAGS) + dnl it header-vars.am, so there the actual INSTALL_PROGRAM gets the -s + dnl *automake 1.4a (and above) use INSTALL_STRIP_FLAG and only has + dnl INSTALL_PROGRAM = @INSTALL_PROGRAM@ there, but changes the + dnl install-@DIR@PROGRAMS targets to explicitly use that flag + dnl *autoconf 2.13 is dumb, and thinks it can use INSTALL_PROGRAM as + dnl INSTALL_SCRIPT, which breaks with automake <= 1.4 + dnl *autoconf >2.13 (since 10.Apr 1999) has not that failure + dnl *sometimes KDE does not use the install-@DIR@PROGRAM targets from + dnl automake (due to broken Makefile.am or whatever) to install programs, + dnl and so does not see the -s flag in automake > 1.4 + dnl to clean up that mess we: + dnl +set INSTALL_PROGRAM to use INSTALL_STRIP_FLAG + dnl which cleans KDE's program with automake > 1.4; + dnl +set INSTALL_SCRIPT to only use INSTALL, to clean up autoconf's problems + dnl with automake<=1.4 + dnl note that dues to this sometimes two '-s' flags are used (if KDE + dnl properly uses install-@DIR@PROGRAMS, but I don't care + dnl + dnl And to all this comes, that I even can't write in comments variable + dnl names used by automake, because it is so stupid to think I wanted to + dnl _use_ them, therefor I have written A_M_... instead of AM_ + dnl hmm, I wanted to say something ... ahh yes: Arghhh. + + if test -z "$kde_save_INSTALL_PROGRAM_given" ; then + INSTALL_PROGRAM='${INSTALL} $(INSTALL_STRIP_FLAG)' + fi + if test -z "$kde_save_INSTALL_SCRIPT_given" ; then + INSTALL_SCRIPT='${INSTALL}' + fi +])dnl + +AC_DEFUN([KDE_LANG_CPLUSPLUS], +[AC_LANG_CPLUSPLUS +ac_link='rm -rf SunWS_cache; ${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&AC_FD_CC' +pushdef([AC_LANG_CPLUSPLUS], [popdef([AC_LANG_CPLUSPLUS]) KDE_LANG_CPLUSPLUS]) +]) + +pushdef([AC_LANG_CPLUSPLUS], +[popdef([AC_LANG_CPLUSPLUS]) +KDE_LANG_CPLUSPLUS +]) + +AC_DEFUN([KDE_CHECK_LONG_LONG], +[ +AC_MSG_CHECKING(for long long) +AC_CACHE_VAL(kde_cv_c_long_long, +[ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + AC_TRY_LINK([], [ + long long foo = 0; + foo = foo+1; + ], + kde_cv_c_long_long=yes, kde_cv_c_long_long=no) + AC_LANG_RESTORE +]) +AC_MSG_RESULT($kde_cv_c_long_long) +if test "$kde_cv_c_long_long" = yes; then + AC_DEFINE(HAVE_LONG_LONG, 1, [Define if you have long long as datatype]) +fi +]) + +AC_DEFUN([KDE_CHECK_LIB], +[ + kde_save_LDFLAGS="$LDFLAGS" + dnl AC_CHECK_LIB modifies LIBS, so save it here + kde_save_LIBS="$LIBS" + LDFLAGS="$LDFLAGS $all_libraries" + case $host_os in + aix*) LDFLAGS="-brtl $LDFLAGS" + test "$GCC" = yes && LDFLAGS="-Wl,$LDFLAGS" + ;; + esac + AC_CHECK_LIB($1, $2, $3, $4, $5) + LDFLAGS="$kde_save_LDFLAGS" + LIBS="$kde_save_LIBS" +]) + +AC_DEFUN([KDE_JAVA_PREFIX], +[ + dir=`dirname "$1"` + base=`basename "$1"` + list=`ls -1 $dir 2> /dev/null` + for entry in $list; do + if test -d $dir/$entry/bin; then + case $entry in + $base) + javadirs="$javadirs $dir/$entry/bin" + ;; + esac + elif test -d $dir/$entry/jre/bin; then + case $entry in + $base) + javadirs="$javadirs $dir/$entry/jre/bin" + ;; + esac + fi + done +]) + +dnl KDE_CHEC_JAVA_DIR(onlyjre) +AC_DEFUN([KDE_CHECK_JAVA_DIR], +[ + +AC_ARG_WITH(java, +AC_HELP_STRING([--with-java=javadir],[use java installed in javadir, --without-java disables]), +[ ac_java_dir=$withval +], ac_java_dir="" +) + +AC_MSG_CHECKING([for Java]) + +dnl at this point ac_java_dir is either a dir, 'no' to disable, or '' to say look in $PATH +if test "x$ac_java_dir" = "xno"; then + kde_java_bindir=no + kde_java_includedir=no + kde_java_libjvmdir=no + kde_java_libgcjdir=no + kde_java_libhpidir=no +else + if test "x$ac_java_dir" = "x"; then + + + dnl No option set -> collect list of candidate paths + if test -n "$JAVA_HOME"; then + KDE_JAVA_PREFIX($JAVA_HOME) + fi + KDE_JAVA_PREFIX(/usr/j2se) + KDE_JAVA_PREFIX(/usr/lib/j2se) + KDE_JAVA_PREFIX(/usr/j*dk*) + KDE_JAVA_PREFIX(/usr/lib/j*dk*) + KDE_JAVA_PREFIX(/opt/j*sdk*) + KDE_JAVA_PREFIX(/usr/lib/java*) + KDE_JAVA_PREFIX(/usr/java*) + KDE_JAVA_PREFIX(/usr/java/j*dk*) + KDE_JAVA_PREFIX(/usr/java/j*re*) + KDE_JAVA_PREFIX(/usr/lib/SunJava2*) + KDE_JAVA_PREFIX(/usr/lib/SunJava*) + KDE_JAVA_PREFIX(/usr/lib/IBMJava2*) + KDE_JAVA_PREFIX(/usr/lib/IBMJava*) + KDE_JAVA_PREFIX(/opt/java*) + + kde_cv_path="NONE" + kde_save_IFS=$IFS + IFS=':' + for dir in $PATH; do + if test -d "$dir"; then + javadirs="$javadirs $dir" + fi + done + IFS=$kde_save_IFS + jredirs= + + dnl Now javadirs contains a list of paths that exist, all ending with bin/ + for dir in $javadirs; do + dnl Check for the java executable + if test -x "$dir/java"; then + sane_path=$(cd $dir; /bin/pwd) + dnl And also check for a libjvm.so somewhere under there + dnl Since we have to go to the parent dir, /usr/bin is excluded, /usr is too big. + if test "$sane_path" != "/usr/bin"; then + libjvmdir=`find $dir/.. -name libjvm.so | sed 's,libjvm.so,,'|head -n 1` + if test ! -f $libjvmdir/libjvm.so; then continue; fi + jredirs="$jredirs $dir" + fi + fi + done + + dnl Now jredirs contains a reduced list, of paths where both java and ../**/libjvm.so was found + JAVAC= + JAVA= + kde_java_bindir=no + for dir in $jredirs; do + JAVA="$dir/java" + kde_java_bindir=$dir + if test -x "$dir/javac"; then + JAVAC="$dir/javac" + break + fi + done + + if test -n "$JAVAC"; then + dnl this substitution might not work - well, we test for jni.h below + kde_java_includedir=`echo $JAVAC | sed -e 's,bin/javac$,include/,'` + else + kde_java_includedir=no + fi + else + dnl config option set + kde_java_bindir=$ac_java_dir/bin + if test -x $ac_java_dir/bin/java && test ! -x $ac_java_dir/bin/javac; then + kde_java_includedir=no + else + kde_java_includedir=$ac_java_dir/include + fi + fi +fi + +dnl At this point kde_java_bindir and kde_java_includedir are either set or "no" +if test "x$kde_java_bindir" != "xno"; then + + dnl Look for libjvm.so + kde_java_libjvmdir=`find $kde_java_bindir/.. -name libjvm.so | sed 's,libjvm.so,,'|head -n 1` + dnl Look for libgcj.so + kde_java_libgcjdir=`find $kde_java_bindir/.. -name libgcj.so | sed 's,libgcj.so,,'|head -n 1` + dnl Look for libhpi.so and avoid green threads + kde_java_libhpidir=`find $kde_java_bindir/.. -name libhpi.so | grep -v green | sed 's,libhpi.so,,' | head -n 1` + + dnl Now check everything's fine under there + dnl the include dir is our flag for having the JDK + if test -d "$kde_java_includedir"; then + if test ! -x "$kde_java_bindir/javac"; then + AC_MSG_ERROR([javac not found under $kde_java_bindir - it seems you passed a wrong --with-java.]) + fi + if test ! -x "$kde_java_bindir/javah"; then + AC_MSG_ERROR([javah not found under $kde_java_bindir. javac was found though! Use --with-java or --without-java.]) + fi + if test ! -x "$kde_java_bindir/jar"; then + AC_MSG_ERROR([jar not found under $kde_java_bindir. javac was found though! Use --with-java or --without-java.]) + fi + if test ! -r "$kde_java_includedir/jni.h"; then + AC_MSG_ERROR([jni.h not found under $kde_java_includedir. Use --with-java or --without-java.]) + fi + + jni_includes="-I$kde_java_includedir" + dnl Strange thing, jni.h requires jni_md.h which is under genunix here.. + dnl and under linux here.. + + dnl not needed for gcj + + if test "x$kde_java_libgcjdir" = "x"; then + test -d "$kde_java_includedir/linux" && jni_includes="$jni_includes -I$kde_java_includedir/linux" + test -d "$kde_java_includedir/solaris" && jni_includes="$jni_includes -I$kde_java_includedir/solaris" + test -d "$kde_java_includedir/genunix" && jni_includes="$jni_includes -I$kde_java_includedir/genunix" + fi + + else + JAVAC= + jni_includes= + fi + + if test "x$kde_java_libgcjdir" = "x"; then + if test ! -r "$kde_java_libjvmdir/libjvm.so"; then + AC_MSG_ERROR([libjvm.so not found under $kde_java_libjvmdir. Use --without-java.]) + fi + else + if test ! -r "$kde_java_libgcjdir/libgcj.so"; then + AC_MSG_ERROR([libgcj.so not found under $kde_java_libgcjdir. Use --without-java.]) + fi + fi + + if test ! -x "$kde_java_bindir/java"; then + AC_MSG_ERROR([java not found under $kde_java_bindir. javac was found though! Use --with-java or --without-java.]) + fi + + dnl not needed for gcj compile + + if test "x$kde_java_libgcjdir" = "x"; then + if test ! -r "$kde_java_libhpidir/libhpi.so"; then + AC_MSG_ERROR([libhpi.so not found under $kde_java_libhpidir. Use --without-java.]) + fi + fi + + if test -n "$jni_includes"; then + dnl Check for JNI version + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + ac_cxxflags_safe="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS $all_includes $jni_includes" + + AC_TRY_COMPILE([ + #include + ], + [ + #ifndef JNI_VERSION_1_2 + Syntax Error + #endif + ],[ kde_jni_works=yes ], + [ kde_jni_works=no ]) + + if test $kde_jni_works = no; then + AC_MSG_ERROR([Incorrect version of $kde_java_includedir/jni.h. + You need to have Java Development Kit (JDK) version 1.2. + + Use --with-java to specify another location. + Use --without-java to configure without java support. + Or download a newer JDK and try again. + See e.g. http://java.sun.com/products/jdk/1.2 ]) + fi + + CXXFLAGS="$ac_cxxflags_safe" + AC_LANG_RESTORE + + dnl All tests ok, inform and subst the variables + + JAVAC=$kde_java_bindir/javac + JAVAH=$kde_java_bindir/javah + JAR=$kde_java_bindir/jar + AC_DEFINE_UNQUOTED(PATH_JAVA, "$kde_java_bindir/java", [Define where your java executable is]) + if test "x$kde_java_libgcjdir" = "x"; then + JVMLIBS="-L$kde_java_libjvmdir -ljvm -L$kde_java_libhpidir -lhpi" + else + JVMLIBS="-L$kde_java_libgcjdir -lgcj" + fi + AC_MSG_RESULT([java JDK in $kde_java_bindir]) + + else + AC_DEFINE_UNQUOTED(PATH_JAVA, "$kde_java_bindir/java", [Define where your java executable is]) + AC_MSG_RESULT([java JRE in $kde_java_bindir]) + fi +elif test -d "/Library/Java/Home"; then + kde_java_bindir="/Library/Java/Home/bin" + jni_includes="-I/Library/Java/Home/include" + + JAVAC=$kde_java_bindir/javac + JAVAH=$kde_java_bindir/javah + JAR=$kde_java_bindir/jar + JVMLIBS="-Wl,-framework,JavaVM" + + AC_DEFINE_UNQUOTED(PATH_JAVA, "$kde_java_bindir/java", [Define where your java executable is]) + AC_MSG_RESULT([Apple Java Framework]) +else + AC_MSG_RESULT([none found]) +fi + +AC_SUBST(JAVAC) +AC_SUBST(JAVAH) +AC_SUBST(JAR) +AC_SUBST(JVMLIBS) +AC_SUBST(jni_includes) + +# for backward compat +kde_cv_java_includedir=$kde_java_includedir +kde_cv_java_bindir=$kde_java_bindir +]) + +dnl this is a redefinition of autoconf 2.5x's AC_FOREACH. +dnl When the argument list becomes big, as in KDE for AC_OUTPUT in +dnl big packages, m4_foreach is dog-slow. So use our own version of +dnl it. (matz@kde.org) +m4_define([mm_foreach], +[m4_pushdef([$1])_mm_foreach($@)m4_popdef([$1])]) +m4_define([mm_car], [[$1]]) +m4_define([mm_car2], [[$@]]) +m4_define([_mm_foreach], +[m4_if(m4_quote($2), [], [], + [m4_define([$1], mm_car($2))$3[]_mm_foreach([$1], + mm_car2(m4_shift($2)), + [$3])])]) +m4_define([AC_FOREACH], +[mm_foreach([$1], m4_split(m4_normalize([$2])), [$3])]) + +AC_DEFUN([KDE_NEED_FLEX], +[ +kde_libs_safe=$LIBS +LIBS="$LIBS $USER_LDFLAGS" +AM_PROG_LEX +LIBS=$kde_libs_safe +if test -z "$LEXLIB"; then + AC_MSG_ERROR([You need to have flex installed.]) +fi +AC_SUBST(LEXLIB) +]) + +AC_DEFUN([AC_PATH_QTOPIA], +[ + dnl TODO: use AC_CACHE_VAL + + if test -z "$1"; then + qtopia_minver_maj=1 + qtopia_minver_min=5 + qtopia_minver_pat=0 + else + qtopia_minver_maj=`echo "$1" | sed -e "s/^\(.*\)\..*\..*$/\1/"` + qtopia_minver_min=`echo "$1" | sed -e "s/^.*\.\(.*\)\..*$/\1/"` + qtopia_minver_pat=`echo "$1" | sed -e "s/^.*\..*\.\(.*\)$/\1/"` + fi + + qtopia_minver="$qtopia_minver_maj$qtopia_minver_min$qtopia_minver_pat" + qtopia_minverstr="$qtopia_minver_maj.$qtopia_minver_min.$qtopia_minver_pat" + + AC_REQUIRE([AC_PATH_QT]) + + AC_MSG_CHECKING([for Qtopia]) + + LIB_QTOPIA="-lqpe" + AC_SUBST(LIB_QTOPIA) + + kde_qtopia_dirs="$QPEDIR /opt/Qtopia" + + ac_qtopia_incdir=NO + + AC_ARG_WITH(qtopia-dir, + AC_HELP_STRING([--with-qtopia-dir=DIR],[where the root of Qtopia is installed]), + [ ac_qtopia_incdir="$withval"/include] ) + + qtopia_incdirs="" + for dir in $kde_qtopia_dirs; do + qtopia_incdirs="$qtopia_incdirs $dir/include" + done + + if test ! "$ac_qtopia_incdir" = "NO"; then + qtopia_incdirs="$ac_qtopia_incdir $qtopia_incdirs" + fi + + qtopia_incdir="" + AC_FIND_FILE(qpe/qpeapplication.h, $qtopia_incdirs, qtopia_incdir) + ac_qtopia_incdir="$qtopia_incdir" + + if test -z "$qtopia_incdir"; then + AC_MSG_ERROR([Cannot find Qtopia headers. Please check your installation.]) + fi + + qtopia_ver_maj=`cat $qtopia_incdir/qpe/version.h | sed -n -e 's,.*QPE_VERSION "\(.*\)\..*\..*".*,\1,p'`; + qtopia_ver_min=`cat $qtopia_incdir/qpe/version.h | sed -n -e 's,.*QPE_VERSION ".*\.\(.*\)\..*".*,\1,p'`; + qtopia_ver_pat=`cat $qtopia_incdir/qpe/version.h | sed -n -e 's,.*QPE_VERSION ".*\..*\.\(.*\)".*,\1,p'`; + + qtopia_ver="$qtopia_ver_maj$qtopia_ver_min$qtopia_ver_pat" + qtopia_verstr="$qtopia_ver_maj.$qtopia_ver_min.$qtopia_ver_pat" + if test "$qtopia_ver" -lt "$qtopia_minver"; then + AC_MSG_ERROR([found Qtopia version $qtopia_verstr but version $qtopia_minverstr +is required.]) + fi + + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + + ac_cxxflags_safe="$CXXFLAGS" + ac_ldflags_safe="$LDFLAGS" + ac_libs_safe="$LIBS" + + CXXFLAGS="$CXXFLAGS -I$qtopia_incdir $all_includes" + LDFLAGS="$LDFLAGS $QT_LDFLAGS $all_libraries $USER_LDFLAGS $KDE_MT_LDFLAGS" + LIBS="$LIBS $LIB_QTOPIA $LIBQT" + + cat > conftest.$ac_ext < +#include + +int main( int argc, char **argv ) +{ + QPEApplication app( argc, argv ); + return 0; +} +EOF + + if AC_TRY_EVAL(ac_link) && test -s conftest; then + rm -f conftest* + else + rm -f conftest* + AC_MSG_ERROR([Cannot link small Qtopia Application. For more details look at +the end of config.log]) + fi + + CXXFLAGS="$ac_cxxflags_safe" + LDFLAGS="$ac_ldflags_safe" + LIBS="$ac_libs_safe" + + AC_LANG_RESTORE + + QTOPIA_INCLUDES="-I$qtopia_incdir" + AC_SUBST(QTOPIA_INCLUDES) + + AC_MSG_RESULT([found version $qtopia_verstr with headers at $qtopia_incdir]) +]) + + +AC_DEFUN([KDE_INIT_DOXYGEN], +[ +AC_MSG_CHECKING([for Qt docs]) +kde_qtdir= +if test "${with_qt_dir+set}" = set; then + kde_qtdir="$with_qt_dir" +fi + +AC_FIND_FILE(qsql.html, [ $kde_qtdir/doc/html $QTDIR/doc/html /usr/share/doc/packages/qt3/html /usr/lib/qt/doc /usr/lib/qt3/doc /usr/lib/qt3/doc/html /usr/doc/qt3/html /usr/doc/qt3 /usr/share/doc/qt3-doc /usr/share/qt3/doc/html /usr/X11R6/share/doc/qt/html ], QTDOCDIR) +AC_MSG_RESULT($QTDOCDIR) + +AC_SUBST(QTDOCDIR) + +KDE_FIND_PATH(dot, DOT, [], []) +if test -n "$DOT"; then + KDE_HAVE_DOT="YES" +else + KDE_HAVE_DOT="NO" +fi +AC_SUBST(KDE_HAVE_DOT) +KDE_FIND_PATH(doxygen, DOXYGEN, [], []) +AC_SUBST(DOXYGEN) + +DOXYGEN_PROJECT_NAME="$1" +DOXYGEN_PROJECT_NUMBER="$2" +AC_SUBST(DOXYGEN_PROJECT_NAME) +AC_SUBST(DOXYGEN_PROJECT_NUMBER) + +KDE_HAS_DOXYGEN=no +if test -n "$DOXYGEN" && test -x "$DOXYGEN" && test -f $QTDOCDIR/qsql.html; then + KDE_HAS_DOXYGEN=yes +fi +AC_SUBST(KDE_HAS_DOXYGEN) + +]) + + +AC_DEFUN([AC_FIND_BZIP2], +[ +AC_MSG_CHECKING([for bzDecompress in libbz2]) +AC_CACHE_VAL(ac_cv_lib_bzip2, +[ +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +kde_save_LIBS="$LIBS" +LIBS="$all_libraries $USER_LDFLAGS -lbz2 $LIBSOCKET" +kde_save_CXXFLAGS="$CXXFLAGS" +CXXFLAGS="$CXXFLAGS $all_includes $USER_INCLUDES" +AC_TRY_LINK(dnl +[ +#define BZ_NO_STDIO +#include +], + [ bz_stream s; (void) bzDecompress(&s); ], + eval "ac_cv_lib_bzip2='-lbz2'", + eval "ac_cv_lib_bzip2=no") +LIBS="$kde_save_LIBS" +CXXFLAGS="$kde_save_CXXFLAGS" +AC_LANG_RESTORE +])dnl +AC_MSG_RESULT($ac_cv_lib_bzip2) + +if test ! "$ac_cv_lib_bzip2" = no; then + BZIP2DIR=bzip2 + + LIBBZ2="$ac_cv_lib_bzip2" + AC_SUBST(LIBBZ2) + +else + + cxx_shared_flag= + ld_shared_flag= + KDE_CHECK_COMPILER_FLAG(shared, [ + ld_shared_flag="-shared" + ]) + KDE_CHECK_COMPILER_FLAG(fPIC, [ + cxx_shared_flag="-fPIC" + ]) + + AC_MSG_CHECKING([for BZ2_bzDecompress in (shared) libbz2]) + AC_CACHE_VAL(ac_cv_lib_bzip2_prefix, + [ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + kde_save_LIBS="$LIBS" + LIBS="$all_libraries $USER_LDFLAGS $ld_shared_flag -lbz2 $LIBSOCKET" + kde_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CFLAGS $cxx_shared_flag $all_includes $USER_INCLUDES" + + AC_TRY_LINK(dnl + [ + #define BZ_NO_STDIO + #include + ], + [ bz_stream s; (void) BZ2_bzDecompress(&s); ], + eval "ac_cv_lib_bzip2_prefix='-lbz2'", + eval "ac_cv_lib_bzip2_prefix=no") + LIBS="$kde_save_LIBS" + CXXFLAGS="$kde_save_CXXFLAGS" + AC_LANG_RESTORE + ])dnl + + AC_MSG_RESULT($ac_cv_lib_bzip2_prefix) + + if test ! "$ac_cv_lib_bzip2_prefix" = no; then + BZIP2DIR=bzip2 + + LIBBZ2="$ac_cv_lib_bzip2_prefix" + AC_SUBST(LIBBZ2) + + AC_DEFINE(NEED_BZ2_PREFIX, 1, [Define if the libbz2 functions need the BZ2_ prefix]) + dnl else, we just ignore this + fi + +fi +AM_CONDITIONAL(include_BZIP2, test -n "$BZIP2DIR") +]) + +dnl ------------------------------------------------------------------------ +dnl Try to find the SSL headers and libraries. +dnl $(SSL_LDFLAGS) will be -Lsslliblocation (if needed) +dnl and $(SSL_INCLUDES) will be -Isslhdrlocation (if needed) +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([KDE_CHECK_SSL], +[ +LIBSSL="-lssl -lcrypto" +AC_REQUIRE([KDE_CHECK_LIB64]) + +ac_ssl_includes=NO ac_ssl_libraries=NO +ssl_libraries="" +ssl_includes="" +AC_ARG_WITH(ssl-dir, + AC_HELP_STRING([--with-ssl-dir=DIR],[where the root of OpenSSL is installed]), + [ ac_ssl_includes="$withval"/include + ac_ssl_libraries="$withval"/lib$kdelibsuff + ]) + +want_ssl=yes +AC_ARG_WITH(ssl, + AC_HELP_STRING([--without-ssl],[disable SSL checks]), + [want_ssl=$withval]) + +if test $want_ssl = yes; then + +AC_MSG_CHECKING(for OpenSSL) + +AC_CACHE_VAL(ac_cv_have_ssl, +[#try to guess OpenSSL locations + + ssl_incdirs="/usr/include /usr/local/include /usr/ssl/include /usr/local/ssl/include $prefix/include $kde_extra_includes" + ssl_incdirs="$ac_ssl_includes $ssl_incdirs" + AC_FIND_FILE(openssl/ssl.h, $ssl_incdirs, ssl_incdir) + ac_ssl_includes="$ssl_incdir" + + ssl_libdirs="/usr/lib$kdelibsuff /usr/local/lib$kdelibsuff /usr/ssl/lib$kdelibsuff /usr/local/ssl/lib$kdelibsuff $libdir $prefix/lib$kdelibsuff $exec_prefix/lib$kdelibsuff $kde_extra_libs" + if test ! "$ac_ssl_libraries" = "NO"; then + ssl_libdirs="$ac_ssl_libraries $ssl_libdirs" + fi + + test=NONE + ssl_libdir=NONE + for dir in $ssl_libdirs; do + try="ls -1 $dir/libssl*" + if test=`eval $try 2> /dev/null`; then ssl_libdir=$dir; break; else echo "tried $dir" >&AC_FD_CC ; fi + done + + ac_ssl_libraries="$ssl_libdir" + + ac_ldflags_safe="$LDFLAGS" + ac_libs_safe="$LIBS" + + LDFLAGS="$LDFLAGS -L$ssl_libdir $all_libraries" + LIBS="$LIBS $LIBSSL -lRSAglue -lrsaref" + + AC_TRY_LINK(,void RSAPrivateEncrypt(void);RSAPrivateEncrypt();, + ac_ssl_rsaref="yes" + , + ac_ssl_rsaref="no" + ) + + LDFLAGS="$ac_ldflags_safe" + LIBS="$ac_libs_safe" + + if test "$ac_ssl_includes" = NO || test "$ac_ssl_libraries" = NO; then + have_ssl=no + else + have_ssl=yes; + fi + + ]) + + eval "$ac_cv_have_ssl" + + AC_MSG_RESULT([libraries $ac_ssl_libraries, headers $ac_ssl_includes]) + + AC_MSG_CHECKING([whether OpenSSL uses rsaref]) + AC_MSG_RESULT($ac_ssl_rsaref) + + AC_MSG_CHECKING([for easter eggs]) + AC_MSG_RESULT([none found]) + +else + have_ssl=no +fi + +if test "$have_ssl" = yes; then + AC_MSG_CHECKING(for OpenSSL version) + dnl Check for SSL version + AC_CACHE_VAL(ac_cv_ssl_version, + [ + + cat >conftest.$ac_ext < +#include + int main() { + +#ifndef OPENSSL_VERSION_NUMBER + printf("ssl_version=\\"error\\"\n"); +#else + if (OPENSSL_VERSION_NUMBER < 0x00906000) + printf("ssl_version=\\"old\\"\n"); + else + printf("ssl_version=\\"ok\\"\n"); +#endif + return (0); + } +EOF + + ac_save_CPPFLAGS=$CPPFLAGS + if test "$ac_ssl_includes" != "/usr/include"; then + CPPFLAGS="$CPPFLAGS -I$ac_ssl_includes" + fi + + if AC_TRY_EVAL(ac_link); then + + if eval `./conftest 2>&5`; then + if test $ssl_version = error; then + AC_MSG_ERROR([$ssl_incdir/openssl/opensslv.h doesn't define OPENSSL_VERSION_NUMBER !]) + else + if test $ssl_version = old; then + AC_MSG_WARN([OpenSSL version too old. Upgrade to 0.9.6 at least, see http://www.openssl.org. SSL support disabled.]) + have_ssl=no + fi + fi + ac_cv_ssl_version="ssl_version=$ssl_version" + else + AC_MSG_ERROR([Your system couldn't run a small SSL test program. + Check config.log, and if you can't figure it out, send a mail to + David Faure , attaching your config.log]) + fi + + else + AC_MSG_ERROR([Your system couldn't link a small SSL test program. + Check config.log, and if you can't figure it out, send a mail to + David Faure , attaching your config.log]) + fi + CPPFLAGS=$ac_save_CPPFLAGS + + ]) + + eval "$ac_cv_ssl_version" + AC_MSG_RESULT($ssl_version) +fi + +if test "$have_ssl" != yes; then + LIBSSL=""; +else + AC_DEFINE(HAVE_SSL, 1, [If we are going to use OpenSSL]) + ac_cv_have_ssl="have_ssl=yes \ + ac_ssl_includes=$ac_ssl_includes ac_ssl_libraries=$ac_ssl_libraries ac_ssl_rsaref=$ac_ssl_rsaref" + + + ssl_libraries="$ac_ssl_libraries" + ssl_includes="$ac_ssl_includes" + + if test "$ac_ssl_rsaref" = yes; then + LIBSSL="-lssl -lcrypto -lRSAglue -lrsaref" + fi + + if test $ssl_version = "old"; then + AC_DEFINE(HAVE_OLD_SSL_API, 1, [Define if you have OpenSSL < 0.9.6]) + fi +fi + +SSL_INCLUDES= + +if test "$ssl_includes" = "/usr/include"; then + if test -f /usr/kerberos/include/krb5.h; then + SSL_INCLUDES="-I/usr/kerberos/include" + fi +elif test "$ssl_includes" != "/usr/local/include" && test -n "$ssl_includes"; then + SSL_INCLUDES="-I$ssl_includes" +fi + +if test "$ssl_libraries" = "/usr/lib" || test "$ssl_libraries" = "/usr/local/lib" || test -z "$ssl_libraries" || test "$ssl_libraries" = "NONE"; then + SSL_LDFLAGS="" +else + SSL_LDFLAGS="-L$ssl_libraries -R$ssl_libraries" +fi + +AC_SUBST(SSL_INCLUDES) +AC_SUBST(SSL_LDFLAGS) +AC_SUBST(LIBSSL) +]) + +AC_DEFUN([KDE_CHECK_STRLCPY], +[ + AC_REQUIRE([AC_CHECK_STRLCAT]) + AC_REQUIRE([AC_CHECK_STRLCPY]) + AC_CHECK_SIZEOF(size_t) + AC_CHECK_SIZEOF(unsigned long) + + AC_MSG_CHECKING([sizeof size_t == sizeof unsigned long]) + AC_TRY_COMPILE(,[ + #if SIZEOF_SIZE_T != SIZEOF_UNSIGNED_LONG + choke me + #endif + ],AC_MSG_RESULT([yes]),[ + AC_MSG_RESULT(no) + AC_MSG_ERROR([ + Apparently on your system our assumption sizeof size_t == sizeof unsigned long + does not apply. Please mail kde-devel@kde.org with a description of your system! + ]) + ]) +]) + +AC_DEFUN([KDE_CHECK_BINUTILS], +[ + AC_MSG_CHECKING([if ld supports unversioned version maps]) + + kde_save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -Wl,--version-script=conftest.map" + echo "{ local: extern \"C++\" { foo }; };" > conftest.map + AC_TRY_LINK([int foo;], +[ +#ifdef __INTEL_COMPILER +icc apparently does not support libtools version-info and version-script +at the same time. Dunno where the bug is, but until somebody figured out, +better disable the optional version scripts. +#endif + + foo = 42; +], kde_supports_versionmaps=yes, kde_supports_versionmaps=no) + LDFLAGS="$kde_save_LDFLAGS" + rm -f conftest.map + AM_CONDITIONAL(include_VERSION_SCRIPT, + [test "$kde_supports_versionmaps" = "yes" && test "$kde_use_debug_code" = "no"]) + + AC_MSG_RESULT($kde_supports_versionmaps) +]) + +AC_DEFUN([AM_PROG_OBJC],[ +AC_CHECK_PROGS(OBJC, gcc, gcc) +test -z "$OBJC" && AC_MSG_ERROR([no acceptable objective-c gcc found in \$PATH]) +if test "x${OBJCFLAGS-unset}" = xunset; then + OBJCFLAGS="-g -O2" +fi +AC_SUBST(OBJCFLAGS) +_AM_IF_OPTION([no-dependencies],, [_AM_DEPENDENCIES(OBJC)]) +]) + +AC_DEFUN([KDE_CHECK_PERL], +[ + KDE_FIND_PATH(perl, PERL, [$bindir $exec_prefix/bin $prefix/bin], [ + AC_MSG_ERROR([No Perl found in your $PATH. +We need perl to generate some code.]) + ]) + AC_SUBST(PERL) +]) + +AC_DEFUN([KDE_CHECK_LARGEFILE], +[ +AC_SYS_LARGEFILE +if test "$ac_cv_sys_file_offset_bits" != no; then + CPPFLAGS="$CPPFLAGS -D_FILE_OFFSET_BITS=$ac_cv_sys_file_offset_bits" +fi + +if test "x$ac_cv_sys_large_files" != "xno"; then + CPPFLAGS="$CPPFLAGS -D_LARGE_FILES=1" +fi + +]) + +dnl A small extension to PKG_CHECK_MODULES (defined in pkg.m4.in) +dnl which allows to search for libs that get installed into the KDE prefix. +dnl +dnl Syntax: KDE_PKG_CHECK_MODULES(KSTUFF, libkexif >= 0.2 glib = 1.3.4, action-if, action-not) +dnl defines KSTUFF_LIBS, KSTUFF_CFLAGS, see pkg-config man page +dnl also defines KSTUFF_PKG_ERRORS on error +AC_DEFUN([KDE_PKG_CHECK_MODULES], [ + + PKG_CONFIG_PATH="$prefix/lib${kdelibsuff}/pkgconfig:$PKG_CONFIG_PATH" + if test "$prefix" != "$kde_libs_prefix"; then + PKG_CONFIG_PATH="$kde_libs_prefix/lib${kdelibsuff}/pkgconfig:$PKG_CONFIG_PATH" + fi + export PKG_CONFIG_PATH + PKG_CHECK_MODULES([$1],[$2],[$3],[$4]) +]) + + +dnl Check for PIE support in the compiler and linker +AC_DEFUN([KDE_CHECK_PIE_SUPPORT], +[ + AC_CACHE_CHECK([for PIE support], kde_cv_val_pie_support, + [ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + safe_CXXFLAGS=$CXXFLAGS + safe_LDFLAGS=$LDFLAGS + CXXFLAGS="$CXXFLAGS -fPIE" + LDFLAGS="$LDFLAGS -pie" + + AC_TRY_LINK([int foo;], [], [kde_cv_val_pie_support=yes], [kde_cv_val_pie_support=no]) + + CXXFLAGS=$safe_CXXFLAGS + LDFLAGS=$safe_LDFLAGS + AC_LANG_RESTORE + ]) + + AC_MSG_CHECKING(if enabling -pie/fPIE support) + + AC_ARG_ENABLE(pie, + AC_HELP_STRING([--enable-pie],[platform supports PIE linking [default=detect]]), + [kde_has_pie_support=$enableval], + [kde_has_pie_support=detect]) + + if test "$kde_has_pie_support" = "detect"; then + kde_has_pie_support=$kde_cv_val_pie_support + fi + + AC_MSG_RESULT([$kde_has_pie_support]) + + KDE_USE_FPIE="" + KDE_USE_PIE="" + + AC_SUBST([KDE_USE_FPIE]) + AC_SUBST([KDE_USE_PIE]) + + if test "$kde_has_pie_support" = "yes"; then + KDE_USE_FPIE="-fPIE" + KDE_USE_PIE="-pie" + fi +]) +# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- +## Copyright 1996, 1997, 1998, 1999, 2000, 2001 +## Free Software Foundation, Inc. +## Originally by Gordon Matzigkeit , 1996 +## +## 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 2 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, write to the Free Software +## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +## +## As a special exception to the GNU General Public License, if you +## distribute this file as part of a program that contains a +## configuration script generated by Autoconf, you may include it under +## the same distribution terms that you use for the rest of that program. + +# serial 47 AC_PROG_LIBTOOL + + +# AC_PROVIDE_IFELSE(MACRO-NAME, IF-PROVIDED, IF-NOT-PROVIDED) +# ----------------------------------------------------------- +# If this macro is not defined by Autoconf, define it here. +m4_ifdef([AC_PROVIDE_IFELSE], + [], + [m4_define([AC_PROVIDE_IFELSE], + [m4_ifdef([AC_PROVIDE_$1], + [$2], [$3])])]) + + +# AC_PROG_LIBTOOL +# --------------- +AC_DEFUN([AC_PROG_LIBTOOL], +[AC_REQUIRE([_AC_PROG_LIBTOOL])dnl +dnl If AC_PROG_CXX has already been expanded, run AC_LIBTOOL_CXX +dnl immediately, otherwise, hook it in at the end of AC_PROG_CXX. + AC_PROVIDE_IFELSE([AC_PROG_CXX], + [AC_LIBTOOL_CXX], + [define([AC_PROG_CXX], defn([AC_PROG_CXX])[AC_LIBTOOL_CXX + ])]) +dnl And a similar setup for Fortran 77 support + AC_PROVIDE_IFELSE([AC_PROG_F77], + [AC_LIBTOOL_F77], + [define([AC_PROG_F77], defn([AC_PROG_F77])[AC_LIBTOOL_F77 +])]) + +dnl Quote A][M_PROG_GCJ so that aclocal doesn't bring it in needlessly. +dnl If either AC_PROG_GCJ or A][M_PROG_GCJ have already been expanded, run +dnl AC_LIBTOOL_GCJ immediately, otherwise, hook it in at the end of both. + AC_PROVIDE_IFELSE([AC_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [ifdef([AC_PROG_GCJ], + [define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[AC_LIBTOOL_GCJ])]) + ifdef([A][M_PROG_GCJ], + [define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[AC_LIBTOOL_GCJ])]) + ifdef([LT_AC_PROG_GCJ], + [define([LT_AC_PROG_GCJ], + defn([LT_AC_PROG_GCJ])[AC_LIBTOOL_GCJ])])])]) +])])# AC_PROG_LIBTOOL + + +# _AC_PROG_LIBTOOL +# ---------------- +AC_DEFUN([_AC_PROG_LIBTOOL], +[AC_REQUIRE([AC_LIBTOOL_SETUP])dnl +AC_BEFORE([$0],[AC_LIBTOOL_CXX])dnl +AC_BEFORE([$0],[AC_LIBTOOL_F77])dnl +AC_BEFORE([$0],[AC_LIBTOOL_GCJ])dnl + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool --silent' +AC_SUBST(LIBTOOL)dnl + +# Prevent multiple expansion +define([AC_PROG_LIBTOOL], []) +])# _AC_PROG_LIBTOOL + + +# AC_LIBTOOL_SETUP +# ---------------- +AC_DEFUN([AC_LIBTOOL_SETUP], +[AC_PREREQ(2.50)dnl +AC_REQUIRE([AC_ENABLE_SHARED])dnl +AC_REQUIRE([AC_ENABLE_STATIC])dnl +AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_LD])dnl +AC_REQUIRE([AC_PROG_LD_RELOAD_FLAG])dnl +AC_REQUIRE([AC_PROG_NM])dnl + +AC_REQUIRE([AC_PROG_LN_S])dnl +AC_REQUIRE([AC_DEPLIBS_CHECK_METHOD])dnl +# Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers! +AC_REQUIRE([AC_OBJEXT])dnl +AC_REQUIRE([AC_EXEEXT])dnl +dnl + +AC_LIBTOOL_SYS_MAX_CMD_LEN +AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE +AC_LIBTOOL_OBJDIR + +AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl +_LT_AC_PROG_ECHO_BACKSLASH + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='sed -e s/^X//' +[sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g'] + +# Same as above, but do not quote variable references. +[double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g'] + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +# Constants: +rm="rm -f" + +# Global variables: +default_ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except M$VC, +# which needs '.lib'). +libext=a +ltmain="$ac_aux_dir/ltmain.sh" +ofile="$default_ofile" +with_gnu_ld="$lt_cv_prog_gnu_ld" + +AC_CHECK_TOOL(AR, ar, false) +AC_CHECK_TOOL(RANLIB, ranlib, :) +AC_CHECK_TOOL(STRIP, strip, :) + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$AR" && AR=ar +test -z "$AR_FLAGS" && AR_FLAGS=cru +test -z "$AS" && AS=as +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$DLLTOOL" && DLLTOOL=dlltool +test -z "$LD" && LD=ld +test -z "$LN_S" && LN_S="ln -s" +test -z "$MAGIC_CMD" && MAGIC_CMD=file +test -z "$NM" && NM=nm +test -z "$SED" && SED=sed +test -z "$OBJDUMP" && OBJDUMP=objdump +test -z "$RANLIB" && RANLIB=: +test -z "$STRIP" && STRIP=: +test -z "$ac_objext" && ac_objext=o + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="\$RANLIB -t \$oldlib~$old_postinstall_cmds" + ;; + *) + old_postinstall_cmds="\$RANLIB \$oldlib~$old_postinstall_cmds" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi + +# Only perform the check for file, if the check method requires it +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + AC_PATH_MAGIC + fi + ;; +esac + +AC_PROVIDE_IFELSE([AC_LIBTOOL_DLOPEN], enable_dlopen=yes, enable_dlopen=no) +AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL], +enable_win32_dll=yes, enable_win32_dll=no) + +AC_ARG_ENABLE([libtool-lock], + [AC_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +AC_ARG_WITH([pic], + [AC_HELP_STRING([--with-pic], + [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], + [pic_mode="$withval"], + [pic_mode=default]) +test -z "$pic_mode" && pic_mode=default + +# Use C for the default configuration in the libtool script +tagname= +AC_LIBTOOL_LANG_C_CONFIG +_LT_AC_TAGCONFIG +])# AC_LIBTOOL_SETUP + + +# _LT_AC_SYS_COMPILER +# ------------------- +AC_DEFUN([_LT_AC_SYS_COMPILER], +[AC_REQUIRE([AC_PROG_CC])dnl + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# Allow CC to be a program name with arguments. +compiler=$CC +])# _LT_AC_SYS_COMPILER + + +# _LT_AC_SYS_LIBPATH_AIX +# ---------------------- +# Links a minimal program and checks the executable +# for the system default hardcoded library path. In most cases, +# this is /usr/lib:/lib, but when the MPI compilers are used +# the location of the communication and MPI libs are included too. +# If we don't find anything, use the default library path according +# to the aix ld manual. +AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX], +[AC_LINK_IFELSE(AC_LANG_PROGRAM,[ +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'`; fi],[]) +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi +])# _LT_AC_SYS_LIBPATH_AIX + + +# _LT_AC_SHELL_INIT(ARG) +# ---------------------- +AC_DEFUN([_LT_AC_SHELL_INIT], +[ifdef([AC_DIVERSION_NOTICE], + [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)], + [AC_DIVERT_PUSH(NOTICE)]) +$1 +AC_DIVERT_POP +])# _LT_AC_SHELL_INIT + + +# _LT_AC_PROG_ECHO_BACKSLASH +# -------------------------- +# Add some code to the start of the generated configure script which +# will find an echo command which doesn't interpret backslashes. +AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH], +[_LT_AC_SHELL_INIT([ +# Check that we are running under the correct shell. +SHELL=${CONFIG_SHELL-/bin/sh} + +case X$ECHO in +X*--fallback-echo) + # Remove one level of quotation (which was required for Make). + ECHO=`echo "$ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','` + ;; +esac + +echo=${ECHO-echo} +if test "X[$]1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X[$]1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t' ; then + # Yippee, $echo works! + : +else + # Restart under the correct shell. + exec $SHELL "[$]0" --no-reexec ${1+"[$]@"} +fi + +if test "X[$]1" = X--fallback-echo; then + # used as fallback echo + shift + cat </dev/null && + echo_test_string="`eval $cmd`" && + (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null + then + break + fi + done +fi + +if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + : +else + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. + + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for dir in $PATH /usr/ucb; do + IFS="$lt_save_ifs" + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$dir/echo" + break + fi + done + IFS="$lt_save_ifs" + + if test "X$echo" = Xecho; then + # We didn't find a better echo, so look for alternatives. + if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # This shell has a builtin print -r that does the trick. + echo='print -r' + elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) && + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running configure again with it. + ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"} + else + # Try using printf. + echo='printf %s\n' + if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # Cool, printf works + : + elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL + echo="$CONFIG_SHELL [$]0 --fallback-echo" + elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$CONFIG_SHELL [$]0 --fallback-echo" + else + # maybe with a smaller string... + prev=: + + for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do + if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null + then + break + fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "[$]0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"} + else + # Oops. We lost completely, so just stick with echo. + echo=echo + fi + fi + fi + fi +fi +fi + +# Copy echo and quote the copy suitably for passing to libtool from +# the Makefile, instead of quoting the original, which is used later. +ECHO=$echo +if test "X$ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then + ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo" +fi + +AC_SUBST(ECHO) +])])# _LT_AC_PROG_ECHO_BACKSLASH + + +# _LT_AC_LOCK +# ----------- +AC_DEFUN([_LT_AC_LOCK], +[AC_ARG_ENABLE([libtool-lock], + [AC_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '[#]line __oline__ "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case "`/usr/bin/file conftest.o`" in + *32-bit*) + LINUX_64_MODE="32" + case $host in + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + LINUX_64_MODE="64" + case $host in + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, + [AC_LANG_PUSH(C) + AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) + AC_LANG_POP]) + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL], +[*-*-cygwin* | *-*-mingw* | *-*-pw32*) + AC_CHECK_TOOL(DLLTOOL, dlltool, false) + AC_CHECK_TOOL(AS, as, false) + AC_CHECK_TOOL(OBJDUMP, objdump, false) + ;; + ]) +esac + +need_locks="$enable_libtool_lock" + +])# _LT_AC_LOCK + + +# AC_LIBTOOL_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------------------- +# Check whether the given compiler option works +AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], +[AC_REQUIRE([LT_AC_PROG_SED]) +AC_CACHE_CHECK([$1], [$2], + [$2=no + ifelse([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$3" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test ! -s conftest.err; then + $2=yes + fi + fi + $rm conftest* +]) + +if test x"[$]$2" = xyes; then + ifelse([$5], , :, [$5]) +else + ifelse([$6], , :, [$6]) +fi +])# AC_LIBTOOL_COMPILER_OPTION + + +# AC_LIBTOOL_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [ACTION-SUCCESS], [ACTION-FAILURE]) +# ------------------------------------------------------------ +# Check whether the given compiler option works +AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], +[AC_CACHE_CHECK([$1], [$2], + [$2=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $3" + printf "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&AS_MESSAGE_LOG_FD + else + $2=yes + fi + fi + $rm conftest* + LDFLAGS="$save_LDFLAGS" +]) + +if test x"[$]$2" = xyes; then + ifelse([$4], , :, [$4]) +else + ifelse([$5], , :, [$5]) +fi +])# AC_LIBTOOL_LINKER_OPTION + + +# AC_LIBTOOL_SYS_MAX_CMD_LEN +# -------------------------- +AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], +[# find the maximum length of command line arguments +AC_MSG_CHECKING([the maximum length of command line arguments]) +AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl + i=0 + testring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + *) + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while (test "X"`$CONFIG_SHELL [$]0 --fallback-echo "X$testring" 2>/dev/null` \ + = "XX$testring") >/dev/null 2>&1 && + new_result=`expr "X$testring" : ".*" 2>&1` && + lt_cv_sys_max_cmd_len=$new_result && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + testring=$testring$testring + done + testring= + # Add a significant safety factor because C++ compilers can tack on massive + # amounts of additional arguments before passing them to the linker. + # It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + ;; + esac +]) +if test -n $lt_cv_sys_max_cmd_len ; then + AC_MSG_RESULT($lt_cv_sys_max_cmd_len) +else + AC_MSG_RESULT(none) +fi +])# AC_LIBTOOL_SYS_MAX_CMD_LEN + + +# _LT_AC_CHECK_DLFCN +# -------------------- +AC_DEFUN([_LT_AC_CHECK_DLFCN], +[AC_CHECK_HEADERS(dlfcn.h)dnl +])# _LT_AC_CHECK_DLFCN + + +# _LT_AC_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, +# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) +# ------------------------------------------------------------------ +AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF], +[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl +if test "$cross_compiling" = yes; then : + [$4] +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext < +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +#ifdef __cplusplus +extern "C" void exit (int); +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + + exit (status); +}] +EOF + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) $1 ;; + x$lt_dlneed_uscore) $2 ;; + x$lt_unknown|x*) $3 ;; + esac + else : + # compilation failed + $3 + fi +fi +rm -fr conftest* +])# _LT_AC_TRY_DLOPEN_SELF + + +# AC_LIBTOOL_DLOPEN_SELF +# ------------------- +AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], +[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl +if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ]) + ;; + + *) + AC_CHECK_FUNC([shl_load], + [lt_cv_dlopen="shl_load"], + [AC_CHECK_LIB([dld], [shl_load], + [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"], + [AC_CHECK_FUNC([dlopen], + [lt_cv_dlopen="dlopen"], + [AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], + [AC_CHECK_LIB([svld], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], + [AC_CHECK_LIB([dld], [dld_link], + [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"]) + ]) + ]) + ]) + ]) + ]) + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + AC_CACHE_CHECK([whether a program can dlopen itself], + lt_cv_dlopen_self, [dnl + _LT_AC_TRY_DLOPEN_SELF( + lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, + lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) + ]) + + if test "x$lt_cv_dlopen_self" = xyes; then + LDFLAGS="$LDFLAGS $link_static_flag" + AC_CACHE_CHECK([whether a statically linked program can dlopen itself], + lt_cv_dlopen_self_static, [dnl + _LT_AC_TRY_DLOPEN_SELF( + lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, + lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) + ]) + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi +])# AC_LIBTOOL_DLOPEN_SELF + + +# AC_LIBTOOL_PROG_CC_C_O([TAGNAME]) +# --------------------------------- +# Check to see if options -c and -o are simultaneously supported by compiler +AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O], +[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl +AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], + [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)], + [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no + $rm -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + # According to Tom Tromey, Ian Lance Taylor reported there are C compilers + # that will create temporary files in the current directory regardless of + # the output directory. Thus, making CWD read-only will cause this test + # to fail, enabling locking or at least warning the user not to do parallel + # builds. + chmod -w . + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test ! -s out/conftest.err; then + _LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + fi + fi + chmod u+w . + $rm conftest* out/* + rmdir out + cd .. + rmdir conftest + $rm conftest* +]) +])# AC_LIBTOOL_PROG_CC_C_O + + +# AC_LIBTOOL_SYS_HARD_LINK_LOCKS([TAGNAME]) +# ----------------------------------------- +# Check to see if we can do hard links to lock some files if needed +AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], +[AC_REQUIRE([_LT_AC_LOCK])dnl + +hard_links="nottested" +if test "$_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + AC_MSG_CHECKING([if we can lock with hard links]) + hard_links=yes + $rm conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + AC_MSG_RESULT([$hard_links]) + if test "$hard_links" = no; then + AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) + need_locks=warn + fi +else + need_locks=no +fi +])# AC_LIBTOOL_SYS_HARD_LINK_LOCKS + + +# AC_LIBTOOL_OBJDIR +# ----------------- +AC_DEFUN([AC_LIBTOOL_OBJDIR], +[AC_CACHE_CHECK([for objdir], [lt_cv_objdir], +[rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null]) +objdir=$lt_cv_objdir +])# AC_LIBTOOL_OBJDIR + + +# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH([TAGNAME]) +# ---------------------------------------------- +# Check hardcoding attributes. +AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], +[AC_MSG_CHECKING([how to hardcode library paths into programs]) +_LT_AC_TAGVAR(hardcode_action, $1)= +if test -n "$_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)" || \ + test -n "$_LT_AC_TAGVAR(runpath_var $1)" || \ + test "X$_LT_AC_TAGVAR(hardcode_automatic, $1)"="Xyes" ; then + + # We can hardcode non-existant directories. + if test "$_LT_AC_TAGVAR(hardcode_direct, $1)" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)" != no && + test "$_LT_AC_TAGVAR(hardcode_minus_L, $1)" != no; then + # Linking always hardcodes the temporary library directory. + _LT_AC_TAGVAR(hardcode_action, $1)=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + _LT_AC_TAGVAR(hardcode_action, $1)=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + _LT_AC_TAGVAR(hardcode_action, $1)=unsupported +fi +AC_MSG_RESULT([$_LT_AC_TAGVAR(hardcode_action, $1)]) + +if test "$_LT_AC_TAGVAR(hardcode_action, $1)" = relink; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi +])# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH + + +# AC_LIBTOOL_SYS_LIB_STRIP +# ------------------------ +AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP], +[striplib= +old_striplib= +AC_MSG_CHECKING([whether stripping libraries is possible]) +if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + AC_MSG_RESULT([yes]) +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) +fi + ;; + *) + AC_MSG_RESULT([no]) + ;; + esac +fi +])# AC_LIBTOOL_SYS_LIB_STRIP + + +# AC_LIBTOOL_SYS_DYNAMIC_LINKER +# ----------------------------- +# PORTME Fill in your ld.so characteristics +AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER], +[AC_MSG_CHECKING([dynamic linker characteristics]) +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix4* | aix5*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[[01]] | aix4.[[01]].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "(cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a)"; (cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a) || exit 1; done' + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi4*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32*) + version_type=windows + shrext=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $rm \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | [grep ';[c-zC-Z]:/' >/dev/null]; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext='$(test .$module = .yes && echo .so || echo .dylib)' + # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same. + if test "$GCC" = yes; then + sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"` + else + sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib' + fi + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +kfreebsd*-gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='GNU ld.so' + ;; + +freebsd*) + objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout` + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + *) # from 3.2 on + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case "$host_cpu" in + ia64*) + shrext='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + libsuff= + if test "x$LINUX_64_MODE" = x64; then + # Some platforms are per default 64-bit, so there's no /lib64 + if test -d /lib64 -a ! -h /lib64; then + libsuff=64 + fi + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + sys_lib_dlsearch_path_spec="/lib${libsuff} /usr/lib${libsuff}" + sys_lib_search_path_spec="/lib${libsuff} /usr/lib${libsuff} /usr/local/lib${libsuff}" + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +nto-qnx*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +openbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[[89]] | openbsd2.[[89]].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +sco3.2v5*) + version_type=osf + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + export_dynamic_flag_spec='${wl}-Blargedynsym' + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +AC_MSG_RESULT([$dynamic_linker]) +test "$dynamic_linker" = no && can_build_shared=no +])# AC_LIBTOOL_SYS_DYNAMIC_LINKER + + +# _LT_AC_TAGCONFIG +# ---------------- +AC_DEFUN([_LT_AC_TAGCONFIG], +[AC_ARG_WITH([tags], + [AC_HELP_STRING([--with-tags@<:@=TAGS@:>@], + [include additional configurations @<:@automatic@:>@])], + [tagnames="$withval"]) + +if test -f "$ltmain" && test -n "$tagnames"; then + if test ! -f "${ofile}"; then + AC_MSG_WARN([output file `$ofile' does not exist]) + fi + + if test -z "$LTCC"; then + eval "`$SHELL ${ofile} --config | grep '^LTCC='`" + if test -z "$LTCC"; then + AC_MSG_WARN([output file `$ofile' does not look like a libtool script]) + else + AC_MSG_WARN([using `LTCC=$LTCC', extracted from `$ofile']) + fi + fi + + # Extract list of available tagged configurations in $ofile. + # Note that this assumes the entire list is on one line. + available_tags=`grep "^available_tags=" "${ofile}" | $SED -e 's/available_tags=\(.*$\)/\1/' -e 's/\"//g'` + + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for tagname in $tagnames; do + IFS="$lt_save_ifs" + # Check whether tagname contains only valid characters + case `$echo "X$tagname" | $Xsed -e 's:[[-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890,/]]::g'` in + "") ;; + *) AC_MSG_ERROR([invalid tag name: $tagname]) + ;; + esac + + if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "${ofile}" > /dev/null + then + AC_MSG_ERROR([tag name \"$tagname\" already exists]) + fi + + # Update the list of available tags. + if test -n "$tagname"; then + echo appending configuration tag \"$tagname\" to $ofile + + case $tagname in + CXX) + if test -n "$CXX" && test "X$CXX" != "Xno"; then + AC_LIBTOOL_LANG_CXX_CONFIG + else + tagname="" + fi + ;; + + F77) + if test -n "$F77" && test "X$F77" != "Xno"; then + AC_LIBTOOL_LANG_F77_CONFIG + else + tagname="" + fi + ;; + + GCJ) + if test -n "$GCJ" && test "X$GCJ" != "Xno"; then + AC_LIBTOOL_LANG_GCJ_CONFIG + else + tagname="" + fi + ;; + + RC) + AC_LIBTOOL_LANG_RC_CONFIG + ;; + + *) + AC_MSG_ERROR([Unsupported tag name: $tagname]) + ;; + esac + + # Append the new tag name to the list of available tags. + if test -n "$tagname" ; then + available_tags="$available_tags $tagname" + fi + fi + done + IFS="$lt_save_ifs" + + # Now substitute the updated list of available tags. + if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' \"$ofile\" > \"${ofile}T\""; then + mv "${ofile}T" "$ofile" + chmod +x "$ofile" + else + rm -f "${ofile}T" + AC_MSG_ERROR([unable to update list of available tagged configurations.]) + fi +fi +])# _LT_AC_TAGCONFIG + + +# AC_LIBTOOL_DLOPEN +# ----------------- +# enable checks for dlopen support +AC_DEFUN([AC_LIBTOOL_DLOPEN], + [AC_BEFORE([$0],[AC_LIBTOOL_SETUP]) +])# AC_LIBTOOL_DLOPEN + + +# AC_LIBTOOL_WIN32_DLL +# -------------------- +# declare package support for building win32 dll's +AC_DEFUN([AC_LIBTOOL_WIN32_DLL], +[AC_BEFORE([$0], [AC_LIBTOOL_SETUP]) +])# AC_LIBTOOL_WIN32_DLL + + +# AC_ENABLE_SHARED([DEFAULT]) +# --------------------------- +# implement the --enable-shared flag +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +AC_DEFUN([AC_ENABLE_SHARED], +[define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE([shared], + [AC_HELP_STRING([--enable-shared@<:@=PKGS@:>@], + [build shared libraries @<:@default=]AC_ENABLE_SHARED_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_shared=]AC_ENABLE_SHARED_DEFAULT) +])# AC_ENABLE_SHARED + + +# AC_DISABLE_SHARED +# ----------------- +#- set the default shared flag to --disable-shared +AC_DEFUN([AC_DISABLE_SHARED], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_SHARED(no) +])# AC_DISABLE_SHARED + + +# AC_ENABLE_STATIC([DEFAULT]) +# --------------------------- +# implement the --enable-static flag +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +AC_DEFUN([AC_ENABLE_STATIC], +[define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE([static], + [AC_HELP_STRING([--enable-static@<:@=PKGS@:>@], + [build static libraries @<:@default=]AC_ENABLE_STATIC_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_static=]AC_ENABLE_STATIC_DEFAULT) +])# AC_ENABLE_STATIC + + +# AC_DISABLE_STATIC +# ----------------- +# set the default static flag to --disable-static +AC_DEFUN([AC_DISABLE_STATIC], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_STATIC(no) +])# AC_DISABLE_STATIC + + +# AC_ENABLE_FAST_INSTALL([DEFAULT]) +# --------------------------------- +# implement the --enable-fast-install flag +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +AC_DEFUN([AC_ENABLE_FAST_INSTALL], +[define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE([fast-install], + [AC_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], + [optimize for fast installation @<:@default=]AC_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_fast_install=]AC_ENABLE_FAST_INSTALL_DEFAULT) +])# AC_ENABLE_FAST_INSTALL + + +# AC_DISABLE_FAST_INSTALL +# ----------------------- +# set the default to --disable-fast-install +AC_DEFUN([AC_DISABLE_FAST_INSTALL], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_FAST_INSTALL(no) +])# AC_DISABLE_FAST_INSTALL + + +# AC_LIBTOOL_PICMODE([MODE]) +# -------------------------- +# implement the --with-pic flag +# MODE is either `yes' or `no'. If omitted, it defaults to `both'. +AC_DEFUN([AC_LIBTOOL_PICMODE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +pic_mode=ifelse($#,1,$1,default) +])# AC_LIBTOOL_PICMODE + + +# AC_PROG_EGREP +# ------------- +# This is predefined starting with Autoconf 2.54, so this conditional +# definition can be removed once we require Autoconf 2.54 or later. +m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP], +[AC_CACHE_CHECK([for egrep], [ac_cv_prog_egrep], + [if echo a | (grep -E '(a|b)') >/dev/null 2>&1 + then ac_cv_prog_egrep='grep -E' + else ac_cv_prog_egrep='egrep' + fi]) + EGREP=$ac_cv_prog_egrep + AC_SUBST([EGREP]) +])]) + + +# AC_PATH_TOOL_PREFIX +# ------------------- +# find a file program which can recognise shared library +AC_DEFUN([AC_PATH_TOOL_PREFIX], +[AC_REQUIRE([AC_PROG_EGREP])dnl +AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, +[case $MAGIC_CMD in +[[\\/*] | ?:[\\/]*]) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR +dnl $ac_dummy forces splitting on constant user-supplied paths. +dnl POSIX.2 word splitting is done only on the output of word expansions, +dnl not every word. This closes a longstanding sh security hole. + ac_dummy="ifelse([$2], , $PATH, [$2])" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$1; then + lt_cv_path_MAGIC_CMD="$ac_dir/$1" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`" + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac]) +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + AC_MSG_RESULT($MAGIC_CMD) +else + AC_MSG_RESULT(no) +fi +])# AC_PATH_TOOL_PREFIX + + +# AC_PATH_MAGIC +# ------------- +# find a file program which can recognise a shared library +AC_DEFUN([AC_PATH_MAGIC], +[AC_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + AC_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) + else + MAGIC_CMD=: + fi +fi +])# AC_PATH_MAGIC + + +# AC_PROG_LD +# ---------- +# find the pathname to the GNU or non-GNU linker +AC_DEFUN([AC_PROG_LD], +[AC_ARG_WITH([gnu-ld], + [AC_HELP_STRING([--with-gnu-ld], + [assume the C compiler uses GNU ld @<:@default=no@:>@])], + [test "$withval" = no || with_gnu_ld=yes], + [with_gnu_ld=no]) +AC_REQUIRE([LT_AC_PROG_SED])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by $CC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]]* | ?:[[\\/]]*) + re_direlt='/[[^/]][[^/]]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(lt_cv_path_LD, +[if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD)/i[[3-9]]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case "$host_cpu" in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]'] + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + irix5* | nonstopux*) + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method="file_magic ELF 32-bit MSB dynamic lib MIPS - version 1" + ;; + *) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method="file_magic ELF ${libmagic} MSB mips-[[1234]] dynamic lib MIPS - version 1" + ;; + esac + lt_cv_file_magic_test_file=`echo /lib${libsuff}/libc.so*` + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux*) + case $host_cpu in + alpha* | hppa* | i*86 | ia64* | m68* | mips* | powerpc* | sparc* | s390* | sh* | x86_64* ) + lt_cv_deplibs_check_method=pass_all ;; + # the debian people say, arm and glibc 2.3.1 works for them with pass_all + arm* ) + lt_cv_deplibs_check_method=pass_all ;; + *) + # glibc up to 2.1.1 does not perform some relocations on ARM + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' ;; + esac + lt_cv_file_magic_test_file=`echo /lib/libc.so* /lib/libc-*.so` + ;; + +netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +nto-qnx*) + lt_cv_deplibs_check_method=unknown + ;; + +openbsd*) + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB shared object' + else + lt_cv_deplibs_check_method='file_magic OpenBSD.* shared library' + fi + ;; + +osf3* | osf4* | osf5*) + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method='file_magic COFF format alpha shared library' + lt_cv_file_magic_test_file=/shlib/libc.so + lt_cv_deplibs_check_method=pass_all + ;; + +sco3.2v5*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + lt_cv_file_magic_test_file=/lib/libc.so + ;; + +sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; +esac +]) +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown +])# AC_DEPLIBS_CHECK_METHOD + + +# AC_PROG_NM +# ---------- +# find the pathname to a BSD-compatible name lister +AC_DEFUN([AC_PROG_NM], +[AC_CACHE_CHECK([for BSD-compatible nm], lt_cv_path_NM, +[if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/${ac_tool_prefix}nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + esac + fi + done + IFS="$lt_save_ifs" + test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm +fi]) +NM="$lt_cv_path_NM" +])# AC_PROG_NM + + +# AC_CHECK_LIBM +# ------------- +# check for math library +AC_DEFUN([AC_CHECK_LIBM], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case $host in +*-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*) + # These system don't have libm, or don't need it + ;; +*-ncr-sysv4.3*) + AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") + AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") + ;; +*) + AC_CHECK_LIB(m, cos, LIBM="-lm") + ;; +esac +])# AC_CHECK_LIBM + + +# AC_LIBLTDL_CONVENIENCE([DIRECTORY]) +# ----------------------------------- +# sets LIBLTDL to the link flags for the libltdl convenience library and +# LTDLINCL to the include flags for the libltdl header and adds +# --enable-ltdl-convenience to the configure arguments. Note that LIBLTDL +# and LTDLINCL are not AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called. If +# DIRECTORY is not provided, it is assumed to be `libltdl'. LIBLTDL will +# be prefixed with '${top_builddir}/' and LTDLINCL will be prefixed with +# '${top_srcdir}/' (note the single quotes!). If your package is not +# flat and you're not using automake, define top_builddir and +# top_srcdir appropriately in the Makefiles. +AC_DEFUN([AC_LIBLTDL_CONVENIENCE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl + case $enable_ltdl_convenience in + no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;; + "") enable_ltdl_convenience=yes + ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;; + esac + LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdlc.la + LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) + # For backwards non-gettext consistent compatibility... + INCLTDL="$LTDLINCL" +])# AC_LIBLTDL_CONVENIENCE + + +# AC_LIBLTDL_INSTALLABLE([DIRECTORY]) +# ----------------------------------- +# sets LIBLTDL to the link flags for the libltdl installable library and +# LTDLINCL to the include flags for the libltdl header and adds +# --enable-ltdl-install to the configure arguments. Note that LIBLTDL +# and LTDLINCL are not AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called. If +# DIRECTORY is not provided and an installed libltdl is not found, it is +# assumed to be `libltdl'. LIBLTDL will be prefixed with '${top_builddir}/' +# and LTDLINCL will be prefixed with '${top_srcdir}/' (note the single +# quotes!). If your package is not flat and you're not using automake, +# define top_builddir and top_srcdir appropriately in the Makefiles. +# In the future, this macro may have to be called after AC_PROG_LIBTOOL. +AC_DEFUN([AC_LIBLTDL_INSTALLABLE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl + AC_CHECK_LIB(ltdl, lt_dlinit, + [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no], + [if test x"$enable_ltdl_install" = xno; then + AC_MSG_WARN([libltdl not installed, but installation disabled]) + else + enable_ltdl_install=yes + fi + ]) + if test x"$enable_ltdl_install" = x"yes"; then + ac_configure_args="$ac_configure_args --enable-ltdl-install" + LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdl.la + LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) + else + ac_configure_args="$ac_configure_args --enable-ltdl-install=no" + LIBLTDL="-lltdl" + LTDLINCL= + fi + # For backwards non-gettext consistent compatibility... + INCLTDL="$LTDLINCL" +])# AC_LIBLTDL_INSTALLABLE + + +# AC_LIBTOOL_CXX +# -------------- +# enable support for C++ libraries +AC_DEFUN([AC_LIBTOOL_CXX], +[AC_REQUIRE([_LT_AC_LANG_CXX]) +])# AC_LIBTOOL_CXX + + +# _LT_AC_LANG_CXX +# --------------- +AC_DEFUN([_LT_AC_LANG_CXX], +[AC_REQUIRE([AC_PROG_CXX]) +AC_REQUIRE([AC_PROG_CXXCPP]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}CXX]) +])# _LT_AC_LANG_CXX + + +# AC_LIBTOOL_F77 +# -------------- +# enable support for Fortran 77 libraries +AC_DEFUN([AC_LIBTOOL_F77], +[AC_REQUIRE([_LT_AC_LANG_F77]) +])# AC_LIBTOOL_F77 + + +# _LT_AC_LANG_F77 +# --------------- +AC_DEFUN([_LT_AC_LANG_F77], +[AC_REQUIRE([AC_PROG_F77]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}F77]) +])# _LT_AC_LANG_F77 + + +# AC_LIBTOOL_GCJ +# -------------- +# enable support for GCJ libraries +AC_DEFUN([AC_LIBTOOL_GCJ], +[AC_REQUIRE([_LT_AC_LANG_GCJ]) +])# AC_LIBTOOL_GCJ + + +# _LT_AC_LANG_GCJ +# --------------- +AC_DEFUN([_LT_AC_LANG_GCJ], +[AC_PROVIDE_IFELSE([AC_PROG_GCJ],[], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],[], + [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ],[], + [ifdef([AC_PROG_GCJ],[AC_REQUIRE([AC_PROG_GCJ])], + [ifdef([A][M_PROG_GCJ],[AC_REQUIRE([A][M_PROG_GCJ])], + [AC_REQUIRE([A][C_PROG_GCJ_OR_A][M_PROG_GCJ])])])])])]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}GCJ]) +])# _LT_AC_LANG_GCJ + + +# AC_LIBTOOL_RC +# -------------- +# enable support for Windows resource files +AC_DEFUN([AC_LIBTOOL_RC], +[AC_REQUIRE([LT_AC_PROG_RC]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}RC]) +])# AC_LIBTOOL_RC + + +# AC_LIBTOOL_LANG_C_CONFIG +# ------------------------ +# Ensure that the configuration vars for the C compiler are +# suitably defined. Those variables are subsequently used by +# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. +AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG], [_LT_AC_LANG_C_CONFIG]) +AC_DEFUN([_LT_AC_LANG_C_CONFIG], +[lt_save_CC="$CC" +AC_LANG_PUSH(C) + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +_LT_AC_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;\n" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}\n' + +_LT_AC_SYS_COMPILER + +# +# Check for any special shared library compilation flags. +# +_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)= +if test "$GCC" = no; then + case $host_os in + sco3.2v5*) + _LT_AC_TAGVAR(lt_prog_cc_shlib, $1)='-belf' + ;; + esac +fi +if test -n "$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)"; then + AC_MSG_WARN([`$CC' requires `$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)' to build shared libraries]) + if echo "$old_CC $old_CFLAGS " | grep "[[ ]]$]_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)[[[ ]]" >/dev/null; then : + else + AC_MSG_WARN([add `$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)' to the CC or CFLAGS env variable and reconfigure]) + _LT_AC_TAGVAR(lt_cv_prog_cc_can_build_shared, $1)=no + fi +fi + + +# +# Check to make sure the static flag actually works. +# +AC_LIBTOOL_LINKER_OPTION([if $compiler static flag $_LT_AC_TAGVAR(lt_prog_compiler_static, $1) works], + _LT_AC_TAGVAR(lt_prog_compiler_static_works, $1), + $_LT_AC_TAGVAR(lt_prog_compiler_static, $1), + [], + [_LT_AC_TAGVAR(lt_prog_compiler_static, $1)=]) + + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1) +AC_LIBTOOL_PROG_COMPILER_PIC($1) +AC_LIBTOOL_PROG_CC_C_O($1) +AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) +AC_LIBTOOL_PROG_LD_SHLIBS($1) +AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) +AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) +AC_LIBTOOL_SYS_LIB_STRIP +AC_LIBTOOL_DLOPEN_SELF($1) + +# Report which librarie types wil actually be built +AC_MSG_CHECKING([if libtool supports shared libraries]) +AC_MSG_RESULT([$can_build_shared]) + +AC_MSG_CHECKING([whether to build shared libraries]) +test "$can_build_shared" = "no" && enable_shared=no + +# On AIX, shared libraries and static libraries use the same namespace, and +# are all built from PIC. +case "$host_os" in +aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + +aix4*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + darwin* | rhapsody*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + case "$host_os" in + rhapsody* | darwin1.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-Wl,-undefined -Wl,suppress' + ;; + *) # Darwin 1.3 on + if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-Wl,-flat_namespace -Wl,-undefined -Wl,suppress' + else + case ${MACOSX_DEPLOYMENT_TARGET} in + 10.[012]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-Wl,-flat_namespace -Wl,-undefined -Wl,suppress' + ;; + 10.*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-Wl,-undefined -Wl,dynamic_lookup' + ;; + esac + fi + ;; + esac + output_verbose_link_cmd='echo' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib $allow_undefined_flag -o $lib $compiler_flags $libobjs $deplibs -install_name $rpath/$soname $verstring' + _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $compiler_flags $libobjs $deplibs' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $compiler_flags $libobjs $deplibs -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $compiler_flags $libobjs $deplibs~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_automatic, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-all_load $convenience' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; +esac +AC_MSG_RESULT([$enable_shared]) + +AC_MSG_CHECKING([whether to build static libraries]) +# Make sure either enable_shared or enable_static is yes. +test "$enable_shared" = yes || enable_static=yes +AC_MSG_RESULT([$enable_static]) + +AC_LIBTOOL_CONFIG($1) + +AC_LANG_POP +CC="$lt_save_CC" +])# AC_LIBTOOL_LANG_C_CONFIG + + +# AC_LIBTOOL_LANG_CXX_CONFIG +# -------------------------- +# Ensure that the configuration vars for the C compiler are +# suitably defined. Those variables are subsequently used by +# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. +AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG], [_LT_AC_LANG_CXX_CONFIG(CXX)]) +AC_DEFUN([_LT_AC_LANG_CXX_CONFIG], +[AC_LANG_PUSH(C++) +AC_REQUIRE([AC_PROG_CXX]) +AC_REQUIRE([AC_PROG_CXXCPP]) + +_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_AC_TAGVAR(allow_undefined_flag, $1)= +_LT_AC_TAGVAR(always_export_symbols, $1)=no +_LT_AC_TAGVAR(archive_expsym_cmds, $1)= +_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_AC_TAGVAR(hardcode_direct, $1)=no +_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_AC_TAGVAR(hardcode_libdir_separator, $1)= +_LT_AC_TAGVAR(hardcode_minus_L, $1)=no +_LT_AC_TAGVAR(hardcode_automatic, $1)=no +_LT_AC_TAGVAR(module_cmds, $1)= +_LT_AC_TAGVAR(module_expsym_cmds, $1)= +_LT_AC_TAGVAR(link_all_deplibs, $1)=unknown +_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_AC_TAGVAR(no_undefined_flag, $1)= +_LT_AC_TAGVAR(whole_archive_flag_spec, $1)= +_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Dependencies to place before and after the object being linked: +_LT_AC_TAGVAR(predep_objects, $1)= +_LT_AC_TAGVAR(postdep_objects, $1)= +_LT_AC_TAGVAR(predeps, $1)= +_LT_AC_TAGVAR(postdeps, $1)= +_LT_AC_TAGVAR(compiler_lib_search_path, $1)= + +# Source file extension for C++ test sources. +ac_ext=cc + +# Object file extension for compiled C++ test sources. +objext=o +_LT_AC_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;\n" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(int, char *[]) { return(0); }\n' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_AC_SYS_COMPILER + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_LD=$LD +lt_save_GCC=$GCC +GCC=$GXX +lt_save_with_gnu_ld=$with_gnu_ld +lt_save_path_LD=$lt_cv_path_LD +if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx +else + unset lt_cv_prog_gnu_ld +fi +if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX +else + unset lt_cv_path_LD +fi +test -z "${LDCXX+set}" || LD=$LDCXX +CC=${CXX-"c++"} +compiler=$CC +_LT_AC_TAGVAR(compiler, $1)=$CC +cc_basename=`$echo X"$compiler" | $Xsed -e 's%^.*/%%'` + +# We don't want -fno-exception wen compiling C++ code, so set the +# no_builtin_flag separately +if test "$GXX" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' +else + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= +fi + +if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + AC_PROG_LD + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | \ + grep 'no-whole-archive' > /dev/null; then + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + +else + GXX=no + with_gnu_ld=no + wlarc= +fi + +# PORTME: fill in a description of your system's C++ link characteristics +AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +_LT_AC_TAGVAR(ld_shlibs, $1)=yes +case $host_os in + aix3*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # KDE requires run time linking. Make it the default. + aix_use_runtimelinking=yes + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_AC_TAGVAR(archive_cmds, $1)='' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + if test "$GXX" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + else + # We have old collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= + fi + esac + shared_flag='-shared' + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='-qmkshrobj ${wl}-G' + else + shared_flag='-qmkshrobj' + fi + fi + fi + + # Let the compiler handle the export list. + _LT_AC_TAGVAR(always_export_symbols, $1)=no + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + + _LT_AC_TAGVAR(archive_cmds, $1)="\$CC"' -o $output_objdir/$soname $compiler_flags $libobjs $deplibs `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '" $shared_flag" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $compiler_flags $libobjs $deplibs `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $compiler_flags $libobjs $deplibs ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # -bexpall does not export symbols beginning with underscore (_) + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + # Exported symbols can be pulled into shared objects from archives + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=' ' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds it's shared libraries. + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $compiler_flags $libobjs $deplibs ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=no + _LT_AC_TAGVAR(always_export_symbols, $1)=no + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + darwin* | rhapsody*) + if test "$GXX" = yes; then + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + case "$host_os" in + rhapsody* | darwin1.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-Wl,-undefined -Wl,suppress' + ;; + *) # Darwin 1.3 on + if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-Wl,-flat_namespace -Wl,-undefined -Wl,suppress' + else + case ${MACOSX_DEPLOYMENT_TARGET} in + 10.[012]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-Wl,-flat_namespace -Wl,-undefined -Wl,suppress' + ;; + 10.*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-Wl,-undefined -Wl,dynamic_lookup' + ;; + esac + fi + ;; + esac + lt_int_apple_cc_single_mod=no + output_verbose_link_cmd='echo' + if $CC -dumpspecs 2>&1 | grep 'single_module' >/dev/null ; then + lt_int_apple_cc_single_mod=yes + fi + if test "X$lt_int_apple_cc_single_mod" = Xyes ; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $compiler_flags $libobjs $deplibs -install_name $rpath/$soname $verstring' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $compiler_flags $deplibs -install_name $rpath/$soname $verstring' + fi + _LT_AC_TAGVAR(module_cmds, $1)='$CC ${wl}-bind_at_load $allow_undefined_flag -o $lib -bundle $compiler_flags $libobjs $deplibs' + + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's + if test "X$lt_int_apple_cc_single_mod" = Xyes ; then + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $compiler_flags $libobjs $deplibs -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $compiler_flags $deplibs -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $compiler_flags $libobjs $deplibs~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_automatic, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-all_load $convenience' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + dgux*) + case $cc_basename in + ec++) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + ghcx) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + freebsd[12]*) + # C++ shared libraries reported to be fairly broken before switch to ELF + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + freebsd-elf*) + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + ;; + freebsd* | kfreebsd*-gnu) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + _LT_AC_TAGVAR(ld_shlibs, $1)=yes + ;; + gnu*) + ;; + hpux9*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + aCC) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | egrep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + case "$host_cpu" in + hppa*64*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + ia64*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + ;; + *) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + esac + fi + case "$host_cpu" in + hppa*64*) + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + ia64*) + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + *) + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + aCC) + case "$host_cpu" in + hppa*64*|ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case "$host_cpu" in + ia64*|hppa*64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + irix5* | irix6*) + case $cc_basename in + CC) + # SGI C++ + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` -o $lib' + fi + fi + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + ;; + esac + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + linux*) + case $cc_basename in + KCC) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects --soname $soname -o \$templib; mv \$templib $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | grep "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc) + # Intel C++ + with_gnu_ld=yes + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + cxx) + # Compaq C++ + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + esac + ;; + lynxos*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + m88k*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + mvs*) + case $cc_basename in + cxx) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + osf3*) + case $cc_basename in + KCC) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects --soname $soname -o \$templib; mv \$templib $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + + ;; + RCC) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + cxx) + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + osf4* | osf5*) + case $cc_basename in + KCC) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects --soname $soname -o \$templib; mv \$templib $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' + ;; + RCC) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + cxx) + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects -msym -soname $soname -Wl,-input -Wl,$lib.exp `test -n "$verstring" && echo -set_version $verstring` -update_registry $objdir/so_locations -o $lib~ + $rm $lib.exp' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + psos*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + sco*) + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + case $cc_basename in + CC) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + lcc) + # Lucid + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + solaris*) + case $cc_basename in + CC) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_AC_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -nolib -h$soname -o $lib $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} -nolib ${wl}-M ${wl}$lib.exp -h$soname -o $lib $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects~$rm $lib.exp' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The C++ compiler is used as linker so we must use $wl + # flag to pass the commands to the underlying system + # linker. + # Supported since Solaris 2.6 (maybe 2.5.1?) + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + ;; + esac + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep "\-[[LR]]"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + gcx) + # Green Hills C++ Compiler + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' + if $CC --version | grep -v '^2\.7' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects ${wl}-h $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects~$rm $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd="$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects ${wl}-h $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects~$rm $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd="$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" + fi + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' + fi + ;; + esac + ;; + sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7*) + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + ;; + tandem*) + case $cc_basename in + NCC) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + vxworks*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; +esac +AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)]) +test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +_LT_AC_TAGVAR(GCC, $1)="$GXX" +_LT_AC_TAGVAR(LD, $1)="$LD" + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +AC_LIBTOOL_POSTDEP_PREDEP($1) +AC_LIBTOOL_PROG_COMPILER_PIC($1) +AC_LIBTOOL_PROG_CC_C_O($1) +AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) +AC_LIBTOOL_PROG_LD_SHLIBS($1) +AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) +AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) +AC_LIBTOOL_SYS_LIB_STRIP +AC_LIBTOOL_DLOPEN_SELF($1) + +AC_LIBTOOL_CONFIG($1) + +AC_LANG_POP +CC=$lt_save_CC +LDCXX=$LD +LD=$lt_save_LD +GCC=$lt_save_GCC +with_gnu_ldcxx=$with_gnu_ld +with_gnu_ld=$lt_save_with_gnu_ld +lt_cv_path_LDCXX=$lt_cv_path_LD +lt_cv_path_LD=$lt_save_path_LD +lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld +lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +])# AC_LIBTOOL_LANG_CXX_CONFIG + +# AC_LIBTOOL_POSTDEP_PREDEP([TAGNAME]) +# ------------------------ +# Figure out "hidden" library dependencies from verbose +# compiler output when linking a shared library. +# Parse the compiler output and extract the necessary +# objects, libraries and library flags. +AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP],[ +dnl we can't use the lt_simple_compile_test_code here, +dnl because it contains code intended for an executable, +dnl not a library. It's possible we should let each +dnl tag define a new lt_????_link_test_code variable, +dnl but it's only used here... +ifelse([$1],[],[cat > conftest.$ac_ext < conftest.$ac_ext < conftest.$ac_ext < conftest.$ac_ext <> "$cfgfile" +ifelse([$1], [], +[#! $SHELL + +# `$echo "$cfgfile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001 +# Free Software Foundation, Inc. +# +# This file is part of GNU Libtool: +# Originally by Gordon Matzigkeit , 1996 +# +# 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 2 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, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# A sed program that does not truncate output. +SED=$lt_SED + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="$SED -e s/^X//" + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +if test "X\${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi + +# The names of the tagged configurations supported by this script. +available_tags= + +# ### BEGIN LIBTOOL CONFIG], +[# ### BEGIN LIBTOOL TAG CONFIG: $tagname]) + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$_LT_AC_TAGVAR(archive_cmds_need_lc, $1) + +# Whether or not to disallow shared libs when runtime libs are static +allow_libtool_libs_with_static_runtimes=$_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1) + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A C compiler. +LTCC=$lt_LTCC + +# A language-specific compiler. +CC=$lt_[]_LT_AC_TAGVAR(compiler, $1) + +# Is the compiler the GNU C compiler? +with_gcc=$_LT_AC_TAGVAR(GCC, $1) + +# An ERE matcher. +EGREP=$lt_EGREP + +# The linker used to build libraries. +LD=$lt_[]_LT_AC_TAGVAR(LD, $1) + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS="$AS" + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Shared library suffix (normally ".so"). +shrext='$shrext' + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) +pic_mode=$pic_mode + +# What is the maximum length of a command? +max_cmd_len=$lt_cv_sys_max_cmd_len + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_[]_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1) + +# Must we lock files when doing compilation ? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_static, $1) + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_[]_LT_AC_TAGVAR(export_dynamic_flag_spec, $1) + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_[]_LT_AC_TAGVAR(whole_archive_flag_spec, $1) + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_[]_LT_AC_TAGVAR(thread_safe_flag_spec, $1) + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_cmds, $1) +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_new_cmds, $1) + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) + +# Commands used to build and install a shared archive. +archive_cmds=$lt_[]_LT_AC_TAGVAR(archive_cmds, $1) +archive_expsym_cmds=$lt_[]_LT_AC_TAGVAR(archive_expsym_cmds, $1) +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to build a loadable module (assumed same as above if empty) +module_cmds=$lt_[]_LT_AC_TAGVAR(module_cmds, $1) +module_expsym_cmds=$lt_[]_LT_AC_TAGVAR(module_expsym_cmds, $1) + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Dependencies to place before the objects being linked to create a +# shared library. +predep_objects=$lt_[]_LT_AC_TAGVAR(predep_objects, $1) + +# Dependencies to place after the objects being linked to create a +# shared library. +postdep_objects=$lt_[]_LT_AC_TAGVAR(postdep_objects, $1) + +# Dependencies to place before the objects being linked to create a +# shared library. +predeps=$lt_[]_LT_AC_TAGVAR(predeps, $1) + +# Dependencies to place after the objects being linked to create a +# shared library. +postdeps=$lt_[]_LT_AC_TAGVAR(postdeps, $1) + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_[]_LT_AC_TAGVAR(compiler_lib_search_path, $1) + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_[]_LT_AC_TAGVAR(allow_undefined_flag, $1) + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_[]_LT_AC_TAGVAR(no_undefined_flag, $1) + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$_LT_AC_TAGVAR(hardcode_action, $1) + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) + +# If ld is used when linking, flag to hardcode \$libdir into +# a binary during linking. This must work even if \$libdir does +# not exist. +hardcode_libdir_flag_spec_ld=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1) + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_separator, $1) + +# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$_LT_AC_TAGVAR(hardcode_direct, $1) + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$_LT_AC_TAGVAR(hardcode_minus_L, $1) + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1) + +# Set to yes if building a shared library automatically hardcodes DIR into the library +# and all subsequent libraries and executables linked against it. +hardcode_automatic=$_LT_AC_TAGVAR(hardcode_automatic, $1) + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$_LT_AC_TAGVAR(link_all_deplibs, $1) + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path="$_LT_AC_TAGVAR(fix_srcfile_path, $1)" + +# Set to yes if exported symbols are required. +always_export_symbols=$_LT_AC_TAGVAR(always_export_symbols, $1) + +# The commands to list exported symbols. +export_symbols_cmds=$lt_[]_LT_AC_TAGVAR(export_symbols_cmds, $1) + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_[]_LT_AC_TAGVAR(exclude_expsyms, $1) + +# Symbols that must always be exported. +include_expsyms=$lt_[]_LT_AC_TAGVAR(include_expsyms, $1) + +ifelse([$1],[], +[# ### END LIBTOOL CONFIG], +[# ### END LIBTOOL TAG CONFIG: $tagname]) + +__EOF__ + +ifelse([$1],[], [ + case $host_os in + aix3*) + cat <<\EOF >> "$cfgfile" + +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +EOF + ;; + esac + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '$q' "$ltmain" >> "$cfgfile" || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || \ + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" +]) +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + test -f Makefile && make "$ltmain" +fi +])# AC_LIBTOOL_CONFIG + + +# AC_LIBTOOL_PROG_COMPILER_NO_RTTI([TAGNAME]) +# ------------------------------------------- +AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], +[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl + +_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + +if test "$GCC" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + + AC_LIBTOOL_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], + lt_cv_prog_compiler_rtti_exceptions, + [-fno-rtti -fno-exceptions], [], + [_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) +fi +])# AC_LIBTOOL_PROG_COMPILER_NO_RTTI + + +# AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE +# --------------------------------- +AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], +[AC_REQUIRE([AC_CANONICAL_HOST]) +AC_REQUIRE([AC_PROG_NM]) +AC_REQUIRE([AC_OBJEXT]) +# Check for command to grab the raw symbol name followed by C symbol from nm. +AC_MSG_CHECKING([command to parse $NM output from $compiler object]) +AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], +[ +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[[BCDEGRST]]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' + +# Transform the above into a raw symbol and a C symbol. +symxfrm='\1 \2\3 \3' + +# Transform an extracted symbol line into a proper C declaration +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern int \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[[BCDT]]' + ;; +cygwin* | mingw* | pw32*) + symcode='[[ABCDGISTW]]' + ;; +hpux*) # Its linker distinguishes data from code symbols + if test "$host_cpu" = ia64; then + symcode='[[ABCDEGRST]]' + fi + lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + ;; +irix* | nonstopux*) + symcode='[[BCDEGRST]]' + ;; +osf*) + symcode='[[BCDEGQRST]]' + ;; +solaris* | sysv5*) + symcode='[[BDT]]' + ;; +sysv4) + symcode='[[DFNSTU]]' + ;; +esac + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[[ABCDGISTW]]' ;; +esac + +# Try without a prefix undercore, then with it. +for ac_symprfx in "" "_"; do + + # Write the raw and C identifiers. + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*\($ac_symprfx\)$sympat$opt_cr$/$symxfrm/p'" + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext < $nlist) && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if grep ' nm_test_var$' "$nlist" >/dev/null; then + if grep ' nm_test_func$' "$nlist" >/dev/null; then + cat < conftest.$ac_ext +#ifdef __cplusplus +extern "C" { +#endif + +EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | grep -v main >> conftest.$ac_ext' + + cat <> conftest.$ac_ext +#if defined (__STDC__) && __STDC__ +# define lt_ptr_t void * +#else +# define lt_ptr_t char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + lt_ptr_t address; +} +lt_preloaded_symbols[[]] = +{ +EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (lt_ptr_t) \&\2},/" < "$nlist" | grep -v main >> conftest.$ac_ext + cat <<\EOF >> conftest.$ac_ext + {0, (lt_ptr_t) 0} +}; + +#ifdef __cplusplus +} +#endif +EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_save_LIBS="$LIBS" + lt_save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS="$lt_save_LIBS" + CFLAGS="$lt_save_CFLAGS" + else + echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD + fi + else + echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD + cat conftest.$ac_ext >&5 + fi + rm -f conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done +]) +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + AC_MSG_RESULT(failed) +else + AC_MSG_RESULT(ok) +fi +]) # AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE + + +# AC_LIBTOOL_PROG_COMPILER_PIC([TAGNAME]) +# --------------------------------------- +AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC], +[_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)= +_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= +_LT_AC_TAGVAR(lt_prog_compiler_static, $1)= + +AC_MSG_CHECKING([for $compiler option to produce PIC]) + ifelse([$1],[CXX],[ + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | os2* | pw32*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + sysv4*MP*) + if test -d /usr/nec; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case "$host_cpu" in + hppa*64*|ia64*) + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + case $host_os in + aix4* | aix5*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68) + # Green Hills C++ Compiler + # _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + dgux*) + case $cc_basename in + ec++) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + ghcx) + # Green Hills C++ Compiler + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | kfreebsd*-gnu) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive" + if test "$host_cpu" != ia64; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + fi + ;; + aCC) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive" + case "$host_cpu" in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux*) + case $cc_basename in + KCC) + # KAI C++ Compiler + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + icpc) + # Intel C++ + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + cxx) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd*) + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + ;; + RCC) + # Rational C++ 2.4.1 + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + cxx) + # Digital/Compaq C++ + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + sco*) + case $cc_basename in + CC) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + *) + ;; + esac + ;; + solaris*) + case $cc_basename in + CC) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + gcx) + # Green Hills C++ Compiler + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC) + # Sun C++ 4.x + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + lcc) + # Lucid + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC) + # NonStop-UX NCC 3.20 + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + *) + ;; + esac + ;; + unixware*) + ;; + vxworks*) + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +], +[ + if test "$GCC" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + + beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + enable_shared=no + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case "$host_cpu" in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' + ;; + + hpux9* | hpux10* | hpux11*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case "$host_cpu" in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC (with -KPIC) is the default. + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + newsos6) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + linux*) + case $CC in + icc* | ecc*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + ccc*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All Alpha code is PIC. + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + esac + ;; + + osf3* | osf4* | osf5*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All OSF/1 code is PIC. + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + sco3.2v5*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kpic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-dn' + ;; + + solaris*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sunos4*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + uts4*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *) + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +]) +AC_MSG_RESULT([$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)]) + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)"; then + AC_LIBTOOL_COMPILER_OPTION([if $compiler PIC flag $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) works], + _LT_AC_TAGVAR(lt_prog_compiler_pic_works, $1), + [$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])], [], + [case $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) in + "" | " "*) ;; + *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)" ;; + esac], + [_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) +fi +case "$host_os" in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])" + ;; +esac +]) + + +# AC_LIBTOOL_PROG_LD_SHLIBS([TAGNAME]) +# ------------------------------------ +# See if the linker supports building shared libraries. +AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS], +[AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +ifelse([$1],[CXX],[ + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + case $host_os in + aix4* | aix5*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + else + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + _LT_AC_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" + ;; + cygwin* | mingw*) + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGS]] /s/.* \([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols' + ;; + *) + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac +],[ + runpath_var= + _LT_AC_TAGVAR(allow_undefined_flag, $1)= + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no + _LT_AC_TAGVAR(archive_cmds, $1)= + _LT_AC_TAGVAR(archive_expsym_cmds, $1)= + _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)= + _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1)= + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + _LT_AC_TAGVAR(thread_safe_flag_spec, $1)= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_minus_L, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(link_all_deplibs, $1)=unknown + _LT_AC_TAGVAR(hardcode_automatic, $1)=no + _LT_AC_TAGVAR(module_cmds, $1)= + _LT_AC_TAGVAR(module_expsym_cmds, $1)= + _LT_AC_TAGVAR(always_export_symbols, $1)=no + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + _LT_AC_TAGVAR(include_expsyms, $1)= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + _LT_AC_TAGVAR(exclude_expsyms, $1)="_GLOBAL_OFFSET_TABLE_" + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + openbsd*) + with_gnu_ld=no + ;; + esac + + _LT_AC_TAGVAR(ld_shlibs, $1)=yes + if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # See if GNU ld supports shared libraries. + case $host_os in + aix3* | aix4* | aix5*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + _LT_AC_TAGVAR(ld_shlibs, $1)=no + cat <&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +EOF + fi + ;; + + amigaos*) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + + # Samuel A. Falvo II reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we can't use + # them. + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $compiler_flags $libobjs $deplibs ${wl}-soname $wl$soname -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=no + _LT_AC_TAGVAR(always_export_symbols, $1)=no + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGS]] /s/.* \([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $compiler_flags $libobjs $deplibs -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $compiler_flags $libobjs $deplibs -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' + else + ld_shlibs=no + fi + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $compiler_flags $libobjs $deplibs ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $compiler_flags $libobjs $deplibs ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris* | sysv5*) + if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then + _LT_AC_TAGVAR(ld_shlibs, $1)=no + cat <&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +EOF + elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $compiler_flags $libobjs $deplibs ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $compiler_flags $libobjs $deplibs ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + sunos4*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $compiler_flags $libobjs $deplibs ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $compiler_flags $libobjs $deplibs ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + + if test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = yes; then + runpath_var=LD_RUN_PATH + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + fi + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + if test "$GCC" = yes && test -z "$link_static_flag"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported + fi + ;; + + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + else + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + fi + + # KDE requires run time linking. Make it the default. + aix_use_runtimelinking=yes + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_AC_TAGVAR(archive_cmds, $1)='' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + else + # We have old collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= + fi + esac + shared_flag='-shared' + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='-qmkshrobj ${wl}-G' + else + shared_flag='-qmkshrobj' + fi + fi + fi + + # Let the compiler handle the export list. + _LT_AC_TAGVAR(always_export_symbols, $1)=no + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + _LT_AC_TAGVAR(archive_cmds, $1)="\$CC"' -o $output_objdir/$soname $compiler_flags $libobjs $deplibs `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '" $shared_flag" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $compiler_flags $libobjs $deplibs `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $compiler_flags $libobjs $deplibs ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # -bexpall does not export symbols beginning with underscore (_) + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + # Exported symbols can be pulled into shared objects from archives + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=' ' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds it's shared libraries. + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $compiler_flags $libobjs $deplibs ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + # see comment about different semantics on the GNU ld section + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + + bsdi4*) + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic + ;; + + cygwin* | mingw* | pw32*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=no + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -o $lib $compiler_flags $libobjs `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='true' + # FIXME: Should let the user specify the lib program. + _LT_AC_TAGVAR(old_archive_cmds, $1)='lib /OUT:$oldlib$oldobjs$old_deplibs' + fix_srcfile_path='`cygpath -w "$srcfile"`' + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + + darwin* | rhapsody*) + if test "$GXX" = yes ; then + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + case "$host_os" in + rhapsody* | darwin1.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-Wl,-undefined -Wl,suppress' + ;; + *) # Darwin 1.3 on + if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-Wl,-flat_namespace -Wl,-undefined -Wl,suppress' + else + case ${MACOSX_DEPLOYMENT_TARGET} in + 10.[012]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-Wl,-flat_namespace -Wl,-undefined -Wl,suppress' + ;; + 10.*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-Wl,-undefined -Wl,dynamic_lookup' + ;; + esac + fi + ;; + esac + lt_int_apple_cc_single_mod=no + output_verbose_link_cmd='echo' + if $CC -dumpspecs 2>&1 | grep 'single_module' >/dev/null ; then + lt_int_apple_cc_single_mod=yes + fi + if test "X$lt_int_apple_cc_single_mod" = Xyes ; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $compiler_flags $libobjs $deplibs -install_name $rpath/$soname $verstring' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $compiler_flags $deplibs -install_name $rpath/$soname $verstring' + fi + _LT_AC_TAGVAR(module_cmds, $1)='$CC ${wl}-bind_at_load $allow_undefined_flag -o $lib -bundle $compiler_flags $libobjs $deplibs' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's + if test "X$lt_int_apple_cc_single_mod" = Xyes ; then + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $compiler_flags $libobjs $deplibs -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $compiler_flags $deplibs -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $compiler_flags $libobjs $deplibs~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_automatic, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-all_load $convenience' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + dgux*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + freebsd1*) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | kfreebsd*-gnu) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $compiler_flags $libobjs $deplibs' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + hpux9*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $compiler_flags $libobjs $deplibs~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + + hpux10* | hpux11*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + case "$host_cpu" in + hppa*64*|ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $compiler_flags $libobjs $deplibs' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $compiler_flags $libobjs $deplibs' + ;; + esac + else + case "$host_cpu" in + hppa*64*|ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $libobjs $deplibs $linker_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + ;; + esac + fi + if test "$with_gnu_ld" = no; then + case "$host_cpu" in + hppa*64*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + ia64*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + ;; + *) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $compiler_flags $libobjs $deplibs ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + newsos6) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + openbsd*) + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $compiler_flags $libobjs $deplibs' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + else + case $host_os in + openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $compiler_flags $libobjs $deplibs' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + ;; + esac + fi + ;; + + os2*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(archive_cmds, $1)='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $compiler_flags $libobjs $deplibs$output_objdir/$libname.def' + _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $compiler_flags $libobjs $deplibs ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $compiler_flags $libobjs $deplibs ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + else + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ + $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp' + + # Both c and cxx compiler support -rpath directly + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + fi + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + sco3.2v5*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ;; + + solaris*) + _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text' + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $compiler_flags $libobjs $deplibs' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $compiler_flags $libobjs $deplibs~$rm $lib.exp' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) # Supported since Solaris 2.6 (maybe 2.5.1?) + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;; + esac + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $compiler_flags $libobjs $deplibs' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4) + case $host_vendor in + sni) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' + _LT_AC_TAGVAR(hardcode_direct, $1)=no + ;; + motorola) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4.3*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + _LT_AC_TAGVAR(ld_shlibs, $1)=yes + fi + ;; + + sysv4.2uw2*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + hardcode_runpath_var=yes + runpath_var=LD_RUN_PATH + ;; + + sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7*) + _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z ${wl}text' + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $compiler_flags $libobjs $deplibs' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h ${wl}$soname -o $lib $compiler_flags $libobjs $deplibs' + fi + runpath_var='LD_RUN_PATH' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv5*) + _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text' + # $CC -shared without GNU ld will not create a library from C++ + # object files and a static libstdc++, better avoid it by now + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + ;; + + uts4*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + fi +]) +AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)]) +test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +# +# Do we need to explicitly link libc? +# +case "x$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)" in +x|xyes) + # Assume -lc should be added + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $_LT_AC_TAGVAR(archive_cmds, $1) in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + AC_MSG_CHECKING([whether -lc should be explicitly linked in]) + $rm conftest* + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + if AC_TRY_EVAL(ac_compile) 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$_LT_AC_TAGVAR(allow_undefined_flag, $1) + _LT_AC_TAGVAR(allow_undefined_flag, $1)= + if AC_TRY_EVAL(_LT_AC_TAGVAR(archive_cmds, $1) 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) + then + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + else + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + fi + _LT_AC_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $rm conftest* + AC_MSG_RESULT([$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)]) + ;; + esac + fi + ;; +esac +])# AC_LIBTOOL_PROG_LD_SHLIBS + + +# _LT_AC_FILE_LTDLL_C +# ------------------- +# Be careful that the start marker always follows a newline. +AC_DEFUN([_LT_AC_FILE_LTDLL_C], [ +# /* ltdll.c starts here */ +# #define WIN32_LEAN_AND_MEAN +# #include +# #undef WIN32_LEAN_AND_MEAN +# #include +# +# #ifndef __CYGWIN__ +# # ifdef __CYGWIN32__ +# # define __CYGWIN__ __CYGWIN32__ +# # endif +# #endif +# +# #ifdef __cplusplus +# extern "C" { +# #endif +# BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved); +# #ifdef __cplusplus +# } +# #endif +# +# #ifdef __CYGWIN__ +# #include +# DECLARE_CYGWIN_DLL( DllMain ); +# #endif +# HINSTANCE __hDllInstance_base; +# +# BOOL APIENTRY +# DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved) +# { +# __hDllInstance_base = hInst; +# return TRUE; +# } +# /* ltdll.c ends here */ +])# _LT_AC_FILE_LTDLL_C + + +# _LT_AC_TAGVAR(VARNAME, [TAGNAME]) +# --------------------------------- +AC_DEFUN([_LT_AC_TAGVAR], [ifelse([$2], [], [$1], [$1_$2])]) + + +# old names +AC_DEFUN([AM_PROG_LIBTOOL], [AC_PROG_LIBTOOL]) +AC_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) +AC_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) +AC_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) +AC_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) +AC_DEFUN([AM_PROG_LD], [AC_PROG_LD]) +AC_DEFUN([AM_PROG_NM], [AC_PROG_NM]) + +# This is just to silence aclocal about the macro not being used +ifelse([AC_DISABLE_FAST_INSTALL]) + +AC_DEFUN([LT_AC_PROG_GCJ], +[AC_CHECK_TOOL(GCJ, gcj, no) + test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" + AC_SUBST(GCJFLAGS) +]) + +AC_DEFUN([LT_AC_PROG_RC], +[AC_CHECK_TOOL(RC, windres, no) +]) + +############################################################ +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_SED. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # +############################################################ +# LT_AC_PROG_SED +# -------------- +# Check for a fully-functional sed program, that truncates +# as few characters as possible. Prefer GNU sed if found. +AC_DEFUN([LT_AC_PROG_SED], +[AC_MSG_CHECKING([for a sed that does not truncate output]) +AC_CACHE_VAL(lt_cv_path_SED, +[# Loop through the user's path and test for sed and gsed. +# Then use that list of sed's as ones to test for truncation. +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for lt_ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then + lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" + fi + done + done +done +lt_ac_max=0 +lt_ac_count=0 +# Add /usr/xpg4/bin/sed as it is typically found on Solaris +# along with /bin/sed that truncates output. +for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do + test ! -f $lt_ac_sed && break + cat /dev/null > conftest.in + lt_ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >conftest.in + # Check for GNU sed and select it if it is found. + if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then + lt_cv_path_SED=$lt_ac_sed + break + fi + while true; do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo >>conftest.nl + $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break + cmp -s conftest.out conftest.nl || break + # 10000 chars as input seems more than enough + test $lt_ac_count -gt 10 && break + lt_ac_count=`expr $lt_ac_count + 1` + if test $lt_ac_count -gt $lt_ac_max; then + lt_ac_max=$lt_ac_count + lt_cv_path_SED=$lt_ac_sed + fi + done +done +]) +SED=$lt_cv_path_SED +AC_MSG_RESULT([$SED]) +]) + +dnl PKG_CHECK_MODULES(GSTUFF, gtk+-2.0 >= 1.3 glib = 1.3.4, action-if, action-not) +dnl defines GSTUFF_LIBS, GSTUFF_CFLAGS, see pkg-config man page +dnl also defines GSTUFF_PKG_ERRORS on error +AC_DEFUN([PKG_CHECK_MODULES], [ + succeeded=no + + if test -z "$PKG_CONFIG"; then + AC_PATH_PROG(PKG_CONFIG, pkg-config, no) + fi + + if test "$PKG_CONFIG" = "no" ; then + echo "*** The pkg-config script could not be found. Make sure it is" + echo "*** in your path, or set the PKG_CONFIG environment variable" + echo "*** to the full path to pkg-config." + echo "*** Or see http://www.freedesktop.org/software/pkgconfig to get pkg-config." + else + PKG_CONFIG_MIN_VERSION=0.9.0 + if $PKG_CONFIG --atleast-pkgconfig-version $PKG_CONFIG_MIN_VERSION; then + AC_MSG_CHECKING(for $2) + + if $PKG_CONFIG --exists "$2" ; then + AC_MSG_RESULT(yes) + succeeded=yes + + AC_MSG_CHECKING($1_CFLAGS) + $1_CFLAGS=`$PKG_CONFIG --cflags "$2"` + AC_MSG_RESULT($$1_CFLAGS) + + AC_MSG_CHECKING($1_LIBS) + $1_LIBS=`$PKG_CONFIG --libs "$2"` + AC_MSG_RESULT($$1_LIBS) + else + $1_CFLAGS="" + $1_LIBS="" + ## If we have a custom action on failure, don't print errors, but + ## do set a variable so people can do so. + $1_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"` + ifelse([$4], ,echo $$1_PKG_ERRORS,) + fi + + AC_SUBST($1_CFLAGS) + AC_SUBST($1_LIBS) + else + echo "*** Your version of pkg-config is too old. You need version $PKG_CONFIG_MIN_VERSION or newer." + echo "*** See http://www.freedesktop.org/software/pkgconfig" + fi + fi + + if test $succeeded = yes; then + ifelse([$3], , :, [$3]) + else + ifelse([$4], , AC_MSG_ERROR([Library requirements ($2) not met; consider adjusting the PKG_CONFIG_PATH environment variable if your libraries are in a nonstandard prefix so pkg-config can find them.]), [$4]) + fi +]) + + diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 0000000..c033748 --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,903 @@ +# generated automatically by aclocal 1.10.1 -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +m4_if(AC_AUTOCONF_VERSION, [2.61],, +[m4_warning([this file was generated for autoconf 2.61. +You have another version of autoconf. It may work, but is not guaranteed to. +If you have problems, you may need to regenerate the build system entirely. +To do so, use the procedure documented by the package, typically `autoreconf'.])]) + +# Copyright (C) 2002, 2003, 2005, 2006, 2007 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +# (This private macro should not be called outside this file.) +AC_DEFUN([AM_AUTOMAKE_VERSION], +[am__api_version='1.10' +dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to +dnl require some minimum version. Point them to the right macro. +m4_if([$1], [1.10.1], [], + [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl +]) + +# _AM_AUTOCONF_VERSION(VERSION) +# ----------------------------- +# aclocal traces this macro to find the Autoconf version. +# This is a private macro too. Using m4_define simplifies +# the logic in aclocal, which can simply ignore this definition. +m4_define([_AM_AUTOCONF_VERSION], []) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. +# This function is AC_REQUIREd by AC_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], +[AM_AUTOMAKE_VERSION([1.10.1])dnl +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +_AM_AUTOCONF_VERSION(AC_AUTOCONF_VERSION)]) + +# Figure out how to run the assembler. -*- Autoconf -*- + +# Copyright (C) 2001, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 5 + +# AM_PROG_AS +# ---------- +AC_DEFUN([AM_PROG_AS], +[# By default we simply use the C compiler to build assembly code. +AC_REQUIRE([AC_PROG_CC]) +test "${CCAS+set}" = set || CCAS=$CC +test "${CCASFLAGS+set}" = set || CCASFLAGS=$CFLAGS +AC_ARG_VAR([CCAS], [assembler compiler command (defaults to CC)]) +AC_ARG_VAR([CCASFLAGS], [assembler compiler flags (defaults to CFLAGS)]) +_AM_IF_OPTION([no-dependencies],, [_AM_DEPENDENCIES([CCAS])])dnl +]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to +# `$srcdir', `$srcdir/..', or `$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is `.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[dnl Rely on autoconf to set up CDPATH properly. +AC_PREREQ([2.50])dnl +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 8 + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ(2.52)dnl + ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE])dnl +AC_SUBST([$1_FALSE])dnl +_AM_SUBST_NOTMAKE([$1_TRUE])dnl +_AM_SUBST_NOTMAKE([$1_FALSE])dnl +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 9 + +# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "GCJ", or "OBJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +ifelse([$1], CC, [depcc="$CC" am_compiler_list=], + [$1], CXX, [depcc="$CXX" am_compiler_list=], + [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], UPC, [depcc="$UPC" am_compiler_list=], + [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE(dependency-tracking, +[ --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH])dnl +_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +#serial 3 + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[for mf in $CONFIG_FILES; do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done +done +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking +# is enabled. FIXME. This creates each `.P' file that we will +# need in order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) +]) + +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 8 + +# AM_CONFIG_HEADER is obsolete. It has been replaced by AC_CONFIG_HEADERS. +AU_DEFUN([AM_CONFIG_HEADER], [AC_CONFIG_HEADERS($@)]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 13 + +# This macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.60])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl +dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. +m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,, + [m4_fatal([AC_INIT should be called with package and version arguments])])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) + AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) +AM_MISSING_PROG(AUTOCONF, autoconf) +AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) +AM_MISSING_PROG(AUTOHEADER, autoheader) +AM_MISSING_PROG(MAKEINFO, makeinfo) +AM_PROG_INSTALL_SH +AM_PROG_INSTALL_STRIP +AC_REQUIRE([AM_PROG_MKDIR_P])dnl +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES(CC)], + [define([AC_PROG_CC], + defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES(CXX)], + [define([AC_PROG_CXX], + defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJC], + [_AM_DEPENDENCIES(OBJC)], + [define([AC_PROG_OBJC], + defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl +]) +]) + + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_arg=$1 +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +install_sh=${install_sh-"\$(SHELL) $am_aux_dir/install-sh"} +AC_SUBST(install_sh)]) + +# Copyright (C) 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# Check whether the underlying file-system supports filenames +# with a leading dot. For instance MS-DOS doesn't. +AC_DEFUN([AM_SET_LEADING_DOT], +[rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null +AC_SUBST([am__leading_dot])]) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 3 + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo done +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# We grep out `Entering directory' and `Leaving directory' +# messages which can occur if `w' ends up in MAKEFLAGS. +# In particular we don't look at `^make:' because GNU make might +# be invoked under some other name (usually "gmake"), in which +# case it prints its new name instead of `make'. +if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then + am__include=include + am__quote= + _am_result=GNU +fi +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then + am__include=.include + am__quote="\"" + _am_result=BSD + fi +fi +AC_SUBST([am__include]) +AC_SUBST([am__quote]) +AC_MSG_RESULT([$_am_result]) +rm -f confinc confmf +]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 5 + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it supports --run. +# If it does, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([missing])dnl +test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + AC_MSG_WARN([`missing' script is too old or missing]) +fi +]) + +# Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_MKDIR_P +# --------------- +# Check for `mkdir -p'. +AC_DEFUN([AM_PROG_MKDIR_P], +[AC_PREREQ([2.60])dnl +AC_REQUIRE([AC_PROG_MKDIR_P])dnl +dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P, +dnl while keeping a definition of mkdir_p for backward compatibility. +dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile. +dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of +dnl Makefile.ins that do not define MKDIR_P, so we do our own +dnl adjustment using top_builddir (which is defined more often than +dnl MKDIR_P). +AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl +case $mkdir_p in + [[\\/$]]* | ?:[[\\/]]*) ;; + */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; +esac +]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 3 + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# ------------------------------ +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), 1)]) + +# _AM_SET_OPTIONS(OPTIONS) +# ---------------------------------- +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftest.file +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftest.file` + fi + rm -f conftest.file + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT(yes)]) + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor `install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in `make install-strip', and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be `maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Copyright (C) 2006 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. +# This macro is traced by Automake. +AC_DEFUN([_AM_SUBST_NOTMAKE]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of `v7', `ustar', or `pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. +AM_MISSING_PROG([AMTAR], [tar]) +m4_if([$1], [v7], + [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'], + [m4_case([$1], [ustar],, [pax],, + [m4_fatal([Unknown tar format])]) +AC_MSG_CHECKING([how to create a $1 tar archive]) +# Loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' +_am_tools=${am_cv_prog_tar_$1-$_am_tools} +# Do not fold the above two line into one, because Tru64 sh and +# Solaris sh will not grok spaces in the rhs of `-'. +for _am_tool in $_am_tools +do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; + do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar /dev/null 2>&1 && break + fi +done +rm -rf conftest.dir + +AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) +AC_MSG_RESULT([$am_cv_prog_tar_$1])]) +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + +m4_include([acinclude.m4]) diff --git a/config.h.in b/config.h.in new file mode 100644 index 0000000..9602074 --- /dev/null +++ b/config.h.in @@ -0,0 +1,362 @@ +/* config.h.in. Generated from configure.in by autoheader. */ + +/* defined if K3b should check cdrecord for suid root */ +#undef CDRECORD_SUID_ROOT_CHECK + +/* Define to 1 if your flac library's version is newer than or equal to 1.1.2 + */ +#undef FLAC_NEWER_THAN_1_1_1 + +/* HAL API version 0.4 */ +#undef HAL_0_4 + +/* Define to 1 if you have the header file. */ +#undef HAVE_ARTSC_ARTSC_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_BYTESWAP_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_CARBON_CARBON_H + +/* Define if you have the CoreAudio API */ +#undef HAVE_COREAUDIO + +/* Define to 1 if you have the header file. */ +#undef HAVE_CRT_EXTERNS_H + +/* Defines if your system has the crypt function */ +#undef HAVE_CRYPT + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_DVDREAD_DVD_READER_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_FLAC___DECODER_H + +/* compile in HAL support */ +#undef HAVE_HAL + +/* Define to 1 if you have the header file. */ +#undef HAVE_ICONV_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* defined if K3bSetup is compiled */ +#undef HAVE_K3BSETUP + +/* defined if you have the lame header and lib */ +#undef HAVE_LAME + +/* Define to 1 if you have the header file. */ +#undef HAVE_LAME_LAME_H + +/* Defined if you have libdvdread headers and libs installed. */ +#undef HAVE_LIBDVDREAD + +/* Define if you have libjpeg */ +#undef HAVE_LIBJPEG + +/* defined if you have libmad headers and libraries */ +#undef HAVE_LIBMAD + +/* Define if you have libpng */ +#undef HAVE_LIBPNG + +/* Define if you have a working libpthread (will enable threaded code) */ +#undef HAVE_LIBPTHREAD + +/* defined if you have libsamplerate library and header */ +#undef HAVE_LIBSAMPLERATE + +/* Define if you have libz */ +#undef HAVE_LIBZ + +/* Define if lrint is not supported */ +#undef HAVE_LRINT + +/* Define if lrintf is not supported */ +#undef HAVE_LRINTF + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MPCDEC_MPCDEC_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MUSEPACK_MUSEPACK_H + +/* have MusicBrainz */ +#undef HAVE_MUSICBRAINZ + +/* Define if your system needs _NSGetEnviron to set up the environment */ +#undef HAVE_NSGETENVIRON + +/* Define to 1 if the assembler supports AltiVec instructions. */ +#undef HAVE_PPC_ALTIVEC + +/* defined if you have resmgr libraries and headers */ +#undef HAVE_RESMGR + +/* Define to 1 if you have the header file. */ +#undef HAVE_RESMGR_H + +/* Define if you have res_init */ +#undef HAVE_RES_INIT + +/* Define if you have the res_init prototype */ +#undef HAVE_RES_INIT_PROTO + +/* Define to 1 if you have the header file. */ +#undef HAVE_SAMPLERATE_H + +/* Define if you have a STL implementation by SGI */ +#undef HAVE_SGI_STL + +/* Set to 1 if you have libsndfile. */ +#undef HAVE_SNDFILE + +/* Define to 1 if you have the `snprintf' function. */ +#undef HAVE_SNPRINTF + +/* Define to 1 if you have the `stat64' function. */ +#undef HAVE_STAT64 + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define if you have strlcat */ +#undef HAVE_STRLCAT + +/* Define if you have the strlcat prototype */ +#undef HAVE_STRLCAT_PROTO + +/* Define if you have strlcpy */ +#undef HAVE_STRLCPY + +/* Define if you have the strlcpy prototype */ +#undef HAVE_STRLCPY_PROTO + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_BITYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STATVFS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_VFS_H + +/* have TagLib */ +#undef HAVE_TAGLIB + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the `vsnprintf' function. */ +#undef HAVE_VSNPRINTF + +/* Define to 1 if the assembler supports 3DNOW instructions. */ +#undef HAVE_X86_3DNOW + +/* Define to 1 if the assembler supports MMX instructions. */ +#undef HAVE_X86_MMX + +/* Define to 1 if the assembler supports SSE instructions. */ +#undef HAVE_X86_SSE + +/* Define to 1 if the assembler supports SSE2 instructions. */ +#undef HAVE_X86_SSE2 + +/* K3b additional debugging support */ +#undef K3B_DEBUG + +/* Defined if all ffmpeg codecs should be allowed */ +#undef K3B_FFMPEG_ALL_CODECS + +/* Suffix for lib directories */ +#undef KDELIBSUFF + +/* The header to include for MPC decoding. */ +#undef MPC_HEADER_FILE + +/* Define if you have ogg/vorbis installed */ +#undef OGG_VORBIS + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* The size of `char *', as computed by sizeof. */ +#undef SIZEOF_CHAR_P + +/* The size of `int', as computed by sizeof. */ +#undef SIZEOF_INT + +/* The size of `long', as computed by sizeof. */ +#undef SIZEOF_LONG + +/* The size of `short', as computed by sizeof. */ +#undef SIZEOF_SHORT + +/* The size of `size_t', as computed by sizeof. */ +#undef SIZEOF_SIZE_T + +/* The size of `unsigned long', as computed by sizeof. */ +#undef SIZEOF_UNSIGNED_LONG + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Version number of package */ +#undef VERSION + +/* Defined if compiling without arts */ +#undef WITHOUT_ARTS + +/* defined if arts support is compiled in */ +#undef WITH_ARTS + +/* Define to 1 if your processor stores words with the most significant byte + first (like Motorola and SPARC, unlike Intel and VAX). */ +#undef WORDS_BIGENDIAN + +/* + * jpeg.h needs HAVE_BOOLEAN, when the system uses boolean in system + * headers and I'm too lazy to write a configure test as long as only + * unixware is related + */ +#ifdef _UNIXWARE +#define HAVE_BOOLEAN +#endif + + + +/* + * AIX defines FD_SET in terms of bzero, but fails to include + * that defines bzero. + */ + +#if defined(_AIX) +#include +#endif + + + +#if defined(HAVE_NSGETENVIRON) && defined(HAVE_CRT_EXTERNS_H) +# include +# include +# define environ (*_NSGetEnviron()) +#endif + + + +#if !defined(HAVE_RES_INIT_PROTO) +#ifdef __cplusplus +extern "C" { +#endif +int res_init(void); +#ifdef __cplusplus +} +#endif +#endif + + + +#if !defined(HAVE_STRLCAT_PROTO) +#ifdef __cplusplus +extern "C" { +#endif +unsigned long strlcat(char*, const char*, unsigned long); +#ifdef __cplusplus +} +#endif +#endif + + + +#if !defined(HAVE_STRLCPY_PROTO) +#ifdef __cplusplus +extern "C" { +#endif +unsigned long strlcpy(char*, const char*, unsigned long); +#ifdef __cplusplus +} +#endif +#endif + + + +/* + * On HP-UX, the declaration of vsnprintf() is needed every time ! + */ + +#if !defined(HAVE_VSNPRINTF) || defined(hpux) +#if __STDC__ +#include +#include +#else +#include +#endif +#ifdef __cplusplus +extern "C" +#endif +int vsnprintf(char *str, size_t n, char const *fmt, va_list ap); +#ifdef __cplusplus +extern "C" +#endif +int snprintf(char *str, size_t n, char const *fmt, ...); +#endif + + +/* define to 1 if -fvisibility is supported */ +#undef __KDE_HAVE_GCC_VISIBILITY + + +#if defined(__SVR4) && !defined(__svr4__) +#define __svr4__ 1 +#endif + + +/* type to use in place of socklen_t if not defined */ +#undef kde_socklen_t + +/* type to use in place of socklen_t if not defined (deprecated, use + kde_socklen_t) */ +#undef ksize_t + +/* backwards compatibility stuff */ +#undef mpc_bool_t diff --git a/configure.files b/configure.files new file mode 100644 index 0000000..1225922 --- /dev/null +++ b/configure.files @@ -0,0 +1,26 @@ +./admin/configure.in.min +configure.in.in +./libk3b/configure.in.in +./libk3b/plugin/libsamplerate/configure.in.in +./libk3b/videodvd/configure.in.bot +./libk3b/videodvd/configure.in.in +./libk3bdevice/configure.in.bot +./libk3bdevice/configure.in.in +./plugins/audiooutput/alsa/configure.in.bot +./plugins/audiooutput/alsa/configure.in.in +./plugins/decoder/ffmpeg/configure.in.bot +./plugins/decoder/ffmpeg/configure.in.in +./plugins/decoder/flac/configure.in.bot +./plugins/decoder/flac/configure.in.in +./plugins/decoder/libsndfile/configure.in.bot +./plugins/decoder/libsndfile/configure.in.in +./plugins/decoder/mp3/configure.in.bot +./plugins/decoder/mp3/configure.in.in +./plugins/decoder/musepack/configure.in.bot +./plugins/decoder/musepack/configure.in.in +./plugins/decoder/ogg/configure.in.bot +./plugins/decoder/ogg/configure.in.in +./plugins/encoder/lame/configure.in.bot +./plugins/encoder/lame/configure.in.in +./src/fastscale/configure.in.in +configure.in.bot diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..4bcf6eb --- /dev/null +++ b/configure.in @@ -0,0 +1,1244 @@ +dnl ======================================================= +dnl FILE: ./admin/configure.in.min +dnl ======================================================= + +dnl This file is part of the KDE libraries/packages +dnl Copyright (C) 2001 Stephan Kulow (coolo@kde.org) + +dnl This file is free software; you can redistribute it and/or +dnl modify it under the terms of the GNU Library General Public +dnl License as published by the Free Software Foundation; either +dnl version 2 of the License, or (at your option) any later version. + +dnl This library is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +dnl Library General Public License for more details. + +dnl You should have received a copy of the GNU Library General Public License +dnl along with this library; see the file COPYING.LIB. If not, write to +dnl the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +dnl Boston, MA 02110-1301, USA. + +# Original Author was Kalle@kde.org +# I lifted it in some mater. (Stephan Kulow) +# I used much code from Janos Farkas + +dnl Process this file with autoconf to produce a configure script. + +AC_INIT(acinclude.m4) dnl a source file from your sub dir + +dnl This is so we can use kde-common +AC_CONFIG_AUX_DIR(admin) + +dnl This ksh/zsh feature conflicts with `cd blah ; pwd` +unset CDPATH + +dnl Checking host/target/build systems, for make, install etc. +AC_CANONICAL_SYSTEM +dnl Perform program name transformation +AC_ARG_PROGRAM + +dnl Automake doc recommends to do this only here. (Janos) +AM_INIT_AUTOMAKE(k3b-1.0.5, "3.5.9") dnl searches for some needed programs + +KDE_SET_PREFIX + +dnl generate the config header +AM_CONFIG_HEADER(config.h) dnl at the distribution this done + +dnl Checks for programs. +AC_CHECK_COMPILERS +AC_ENABLE_SHARED(yes) +AC_ENABLE_STATIC(no) +KDE_PROG_LIBTOOL + +dnl for NLS support. Call them in this order! +dnl WITH_NLS is for the po files +AM_KDE_WITH_NLS + +KDE_USE_QT(3.2) +AC_PATH_KDE +dnl ======================================================= +dnl FILE: configure.in.in +dnl ======================================================= + +#MIN_CONFIG(3.2) +#AM_KDE_MIN_VERSION(3.4) + +AC_CHECK_HEADERS(byteswap.h) + +dnl - check the byte order - +dnl this will define WORDS_BIGENDIAN or do nothing +AC_C_BIGENDIAN() + +AC_ARG_WITH( + external-libsamplerate, + [ --with-external-libsamplerate use the libsamplerate provided by the system (default=yes)], + [external_sampletrate=$withval], + [external_sampletrate=yes] +) + +LIBSAMPLERATE="" + +if test x$external_sampletrate != xno; then + +dnl === check for libsamplerate ========== +KDE_CHECK_HEADERS(samplerate.h, [ + KDE_CHECK_LIB(samplerate, src_new, [ + LIBSAMPLERATE="-lsamplerate" + AC_DEFINE(HAVE_LIBSAMPLERATE,1,[defined if you have libsamplerate library and header]) + ]) +]) + +fi + +AC_SUBST(LIBSAMPLERATE) +AM_CONDITIONAL(compile_libsamplerate, [test -z "$LIBSAMPLERATE"]) + + +ARTS_LIBS="" +if test "x$build_arts" = "xyes"; then + dnl Find aRts + KDE_CHECK_HEADERS(artsc/artsc.h, + [arts_available=yes + ARTS_LIBS="-lartsc"], + [arts_available=no] + ) +fi +AC_SUBST(ARTS_LIBS) +AM_CONDITIONAL(include_arts, [test -n "$ARTS_LIBS"]) +if test "x$build_arts" = "xyes" -a "x$arts_available" = "xyes"; then + AC_DEFINE(WITH_ARTS,1,[defined if arts support is compiled in]) +fi + +KDE_CHECK_THREADING + +compile_k3bsetup=yes +AC_ARG_WITH( + k3bsetup, + [ --with-k3bsetup[=ARG] do compile K3bSetup2 KControl Module (default=yes)], + [compile_k3bsetup=$withval] +) + +if test x$compile_k3bsetup = xyes; then + AC_DEFINE(HAVE_K3BSETUP,1,[defined if K3bSetup is compiled]) +fi + +AM_CONDITIONAL(with_k3bsetup1, [test x$compile_k3bsetup = xyes]) + + +cdrecord_suid_root=yes +AC_ARG_WITH( + cdrecord-suid-root, + AS_HELP_STRING( + [--without-cdrecord-suid-root], + [enable or disable K3b's suid root check for cdrecord/cdrdao/wodim (default=enabled)]), + [cdrecord_suid_root=$withval], + [cdrecord_suid_root=yes] +) +if test x$cdrecord_suid_root = xyes; then + AC_DEFINE(CDRECORD_SUID_ROOT_CHECK,1,[defined if K3b should check cdrecord for suid root]) +fi + + +# Extra SCSI support libs can go in CAM_LIB, and are linked into +# libk3bdevice. For Linux, nothing is needed. FreeBSD requires -lcam +# (which is in base, so no test is needed). +case "$host_os" in +freebsd* | dragonfly*) + CAM_LIB="-lcam" + ;; +*) + CAM_LIB="" + ;; +esac +AC_SUBST(CAM_LIB) + + + +dnl ---------- TAGLIB CHECK ---------- + +AC_DEFUN([AC_HAVE_TAGLIB], +[ + AC_DEFINE(HAVE_TAGLIB, 1, [have TagLib]) + taglib_includes=[`$TAGLIB_CONFIG --cflags`] + taglib_libs=[`$TAGLIB_CONFIG --libs`] + have_taglib=true +]) + +AC_DEFUN([AC_NO_TAGLIB], +[ + taglib_includes="" + taglib_libs="" + have_taglib=false +]) + +AC_PATH_PROG(TAGLIB_CONFIG, taglib-config, [no], [$PATH:$prefix/bin]) +if test "x$TAGLIB_CONFIG" = "xno" ; then + AC_NO_TAGLIB +else + AC_HAVE_TAGLIB +fi + +AC_SUBST(taglib_includes) +AC_SUBST(taglib_libs) + +dnl ---------- END TAGLIB CHECK ---------- + + + +dnl ----------- TUNEPIMP/MUSICBRAINZ CHECK ----------- + +AC_ARG_WITH( + musicbrainz, + AS_HELP_STRING( + [--without-musicbrainz], + [build K3b without Musicbrainz support (default=no)]), + [ac_cv_use_musicbrainz=$withval], + [ac_cv_use_musicbrainz=yes] +) + +have_mb=false +MUSICBRAINZ_LIBS="" +if test "$ac_cv_use_musicbrainz" = "yes"; then + KDE_CHECK_HEADER(musicbrainz/mb_c.h, + [ + KDE_CHECK_LIB(musicbrainz,mb_New,[ + AC_DEFINE(HAVE_MUSICBRAINZ, 1, [have MusicBrainz]) + MUSICBRAINZ_LIBS="-lmusicbrainz" + have_mb=true + ]) + ], []) +fi +AC_SUBST(MUSICBRAINZ_LIBS) + +dnl --------- TUNEPIMP/MUSICBRAINZ CHECK END ----------- + + +dnl --------- K3b debugging stuff (only for developers) ---- + +AC_ARG_WITH( + k3b-debug, + AS_HELP_STRING( + [--with-k3b-debug], + [Enable additional K3b debugging output and functionality (default=no)]), + [use_k3b_debug=$withval], + [use_k3b_debug=no] +) +if test "$use_k3b_debug" = "yes"; then + AC_DEFINE(K3B_DEBUG, "1", [K3b additional debugging support]) +fi + +dnl -------------------------------------------------------- + + + + +dnl --------------- libiconv check ------------------------- + +AC_CHECK_HEADERS(iconv.h) + +dnl -------------------------------------------------------- + + +#AC_DEFINE(LIBK3B_VERSION, "0.11.98", [k3b library version]) +#AC_SUBST(LIBK3B_VERSION, 0.11.98) +#AC_CONFIG_FILES([k3b/libk3b/libk3b.pc]) + +KDE_ENABLE_HIDDEN_VISIBILITY +dnl ======================================================= +dnl FILE: ./libk3b/configure.in.in +dnl ======================================================= + +AC_CHECK_FUNCS(stat64) +AC_CHECK_HEADERS(sys/vfs.h) +AC_CHECK_HEADERS(sys/statvfs.h) +dnl ======================================================= +dnl FILE: ./libk3b/plugin/libsamplerate/configure.in.in +dnl ======================================================= + +LIBS="-lm $all_libraries" + +AC_CHECK_DECL(lrint, + AC_DEFINE(HAVE_LRINT,1,[Define if lrint is supported]), + AC_DEFINE(HAVE_LRINT,0,[Define if lrint is not supported]), + [#include ] +) + +AC_CHECK_DECL(lrintf, + AC_DEFINE(HAVE_LRINTF,1,[Define if lrintf is supported]), + AC_DEFINE(HAVE_LRINTF,0,[Define if lrintf is not supported]), + [#include ] +) +dnl ======================================================= +dnl FILE: ./libk3b/videodvd/configure.in.in +dnl ======================================================= + +AC_ARG_WITH( + libdvdread, + AS_HELP_STRING( + [--without-libdvdread], + [build K3b without libdvdread (Video DVD ripping) support (default=no)]), + [ac_cv_use_libdvdread=$withval], + [ac_cv_use_libdvdread=yes] +) + +have_libdvdread=no +if test "$ac_cv_use_libdvdread" = "yes"; then + KDE_CHECK_HEADERS(dvdread/dvd_reader.h, + [ + AC_CHECK_LIB(dvdread, + DVDOpen, + [ + AC_DEFINE(HAVE_LIBDVDREAD,1,[Defined if you have libdvdread headers and libs installed.]) + have_libdvdread=yes + ] + ) + ]) +fi +AM_CONDITIONAL(include_videodvdrip, [test x$have_libdvdread = xyes]) + +#if test "$have_libdvdread" = "no"; then +# AC_MSG_ERROR([Could not find libdvdread. Please install.]) +# DO_NOT_COMPILE="$DO_NOT_COMPILE k3b" +#fi +dnl ======================================================= +dnl FILE: ./libk3bdevice/configure.in.in +dnl ======================================================= + +dnl FIXME: only make the linux header check on linux systems. + +linux_scsi=no +AC_MSG_CHECKING(for linux scsi headers) +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +AC_TRY_COMPILE([ + #include + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,50) + typedef unsigned char u8; + #endif + #include + #include /* cope with silly includes */ + ], + [], + [linux_scsi=yes]) +AC_MSG_RESULT($linux_scsi) + +case "$host_os" in +freebsd*|dragonfly*) + # I'll be damned if lousy coding prevents us from running + # this application. + linux_scsi=yes + ;; +esac + +if test "x$linux_scsi" = "xno" ; then + DO_NOT_COMPILE="$DO_NOT_COMPILE k3b" +fi +AC_LANG_RESTORE + +dnl - find the cam_* functions +AC_CHECK_FUNC(cam_close_device, + [CAM_LIB=""], + [AC_CHECK_LIB(cam, cam_close_device, [CAM_LIB=-lcam], [CAM_LIB=""])] + ) +AC_SUBST(CAM_LIB) + + + +dnl === check for resmgr - begin ============ +AC_ARG_WITH( + resmgr, + AS_HELP_STRING([--without-resmgr], [build K3b without ResMgr support (default=no)]), + [ac_cv_use_resmgr=$withval], + [ac_cv_use_resmgr=yes] +) + +if test "$ac_cv_use_resmgr" = "yes"; then + RESMGR_LIB="" + KDE_CHECK_HEADERS(resmgr.h, [ + KDE_CHECK_LIB(resmgr,rsm_open_device,[ + RESMGR_LIB="-lresmgr" + AC_DEFINE(HAVE_RESMGR,1,[defined if you have resmgr libraries and headers]) + ]) + ]) + AC_SUBST(RESMGR_LIB) +fi +dnl === check for resmgr - end ============ + + + + + +# HAL check from kdebase/kioslave/media + +AC_ARG_WITH( + hal, + AS_HELP_STRING( + [--without-hal], + [build K3b without HAL support (default=no)]), + [ac_cv_use_hal=$withval], + [ac_cv_use_hal=yes] +) + +if test "x$ac_cv_use_hal" = "xyes" ; then + +########### Check for the HAL + + AC_MSG_CHECKING(for the HAL) + + hal_inc=NOTFOUND + hal_lib=NOTFOUND + hal=NOTFOUND + + search_incs="$kde_includes /usr/include /usr/include/hal /usr/local/include /usr/local/include/hal" + AC_FIND_FILE(libhal.h libhal-storage.h, $search_incs, hal_incdir) + + if [test -r $hal_incdir/libhal.h] ; then + HAL_INCS="-I$hal_incdir" + hal_inc=FOUND + fi + + if test -r $hal_incdir/libhal-storage.h ; then + hal_storage_version=4 + grep LibHalVolume $hal_incdir/libhal-storage.h \ + > /dev/null 2>&1 && hal_storage_version=5 + if test $hal_storage_version = 4 ; then + AC_DEFINE(HAL_0_4, , [HAL API version 0.4]) + fi + fi + + search_libs="$kde_libraries /usr/lib64 /usr/lib /usr/local/lib /lib /lib64" + AC_FIND_FILE(libhal.so, $search_libs, hal_libdir) + + if [test -r $hal_libdir/libhal.so] ; then + HAL_LIBS="-L$hal_libdir -lhal" + hal_lib=FOUND + fi + + + if [test $hal_inc = FOUND] && [test $hal_lib = FOUND] ; then + AC_MSG_RESULT(headers $hal_incdir libraries $hal_libdir) + hal=FOUND + else + AC_MSG_RESULT(searched but not found) + fi + + AC_SUBST(HAL_INCS) + AC_SUBST(HAL_LIBS) + + +########### Check for DBus + + AC_MSG_CHECKING(for DBus) + + dbus_inc=NOTFOUND + dbus_lib=NOTFOUND + dbus=NOTFOUND + + search_incs="$kde_includes /usr/include /usr/include/dbus-1.0 /usr/local/include /usr/local/include/dbus-1.0" + AC_FIND_FILE(dbus/dbus.h, $search_incs, dbus_incdir) + + search_incs_arch_deps="$kde_includes /usr/lib64/dbus-1.0/include /usr/lib/dbus-1.0/include /usr/local/lib/dbus-1.0/include" + AC_FIND_FILE(dbus/dbus-arch-deps.h, $search_incs_arch_deps, dbus_incdir_arch_deps) + + if [test -r $dbus_incdir/dbus/dbus.h] && [test -r $dbus_incdir_arch_deps/dbus/dbus-arch-deps.h] ; then + DBUS_INCS="-I$dbus_incdir -I$dbus_incdir_arch_deps" + dbus_inc=FOUND + fi + + search_libs="$kde_libraries /usr/lib64 /usr/lib /usr/local/lib /lib /lib64" + AC_FIND_FILE(libdbus-1.so, $search_libs, dbus_libdir) + + if test -r $dbus_libdir/libdbus-1.so ; then + DBUS_LIBS="-L$dbus_libdir -ldbus-1" + dbus_lib=FOUND + fi + + if [test $dbus_inc = FOUND] && [test $dbus_lib = FOUND] ; then + AC_MSG_RESULT(headers $dbus_incdir $dbus_incdir_arch_deps libraries $dbus_libdir) + dbus=FOUND + else + AC_MSG_RESULT(searched but not found) + fi + + AC_SUBST(DBUS_INCS) + AC_SUBST(DBUS_LIBS) + +########### Check for DBus-Qt bindings + + AC_MSG_CHECKING(for DBus-Qt bindings) + + dbusqt_inc=NOTFOUND + dbusqt_lib=NOTFOUND + dbusqt=NOTFOUND + + search_incs="$kde_includes /usr/include /usr/include/dbus-1.0 /usr/local/include /usr/local/include/dbus-1.0" + AC_FIND_FILE(dbus/connection.h, $search_incs, dbusqt_incdir) + + if test -r $dbusqt_incdir/dbus/connection.h ; then + have_qt_patch=0 + grep dbus_connection_setup_with_qt_main $dbusqt_incdir/dbus/connection.h \ + > /dev/null 2>&1 && have_qt_patch=1 + if test $have_qt_patch = 1 ; then + DBUSQT_INCS="-I$dbusqt_incdir" + dbusqt_inc=FOUND + fi + fi + + search_libs="$kde_libraries /usr/lib /usr/lib64 /usr/local/lib" + AC_FIND_FILE(libdbus-qt-1.so, $search_libs, dbusqt_libdir) + + if test -r $dbusqt_libdir/libdbus-qt-1.so ; then + DBUSQT_LIBS="-L$dbusqt_libdir -ldbus-qt-1" + dbusqt_lib=FOUND + fi + + if [test $dbusqt_inc = FOUND] && [test $dbusqt_lib = FOUND] ; then + AC_MSG_RESULT(headers $dbusqt_incdir libraries $dbusqt_libdir) + dbusqt=FOUND + else + AC_MSG_RESULT(searched but not found) + fi + + AC_SUBST(DBUSQT_INCS) + AC_SUBST(DBUSQT_LIBS) +fi + +########### Check if media HAL backend sould be compiled + +have_hal=no +HAL_DBUS_LIBS="" +if [test "x$hal" = "xFOUND"] && [test "x$dbus" = "xFOUND"] && [test "x$dbusqt" = "xFOUND"] && [ test $hal_storage_version = 5 ] ; then + AC_DEFINE(HAVE_HAL, , [compile in HAL support]) + have_hal=yes + HAL_DBUS_LIBS="$HAL_LIBS $DBUS_LIBS $DBUSQT_LIBS" +fi + +AM_CONDITIONAL(include_HAL, [test x$have_hal = xyes]) +AC_SUBST(HAL_DBUS_LIBS) + +dnl ======================================================= +dnl FILE: ./plugins/audiooutput/alsa/configure.in.in +dnl ======================================================= + +dnl --------- ALSA CHECK BEGIN ------------- + +AC_DEFUN([KDE_CHECK_ALSA], +[ + PKG_CHECK_MODULES([ALSA], [alsa >= 0.9], [have_alsa=yes], [have_alsa=no]) + AC_SUBST([ALSA_CFLAGS]) + AC_SUBST([ALSA_LIBS]) +]) + +AC_ARG_WITH(alsa, + [AS_HELP_STRING(--with-alsa, + [enable support for ALSA output @<:@default=check@:>@])], + [], with_alsa=check) + +have_alsa=no +if test "x$with_alsa" != xno; then + KDE_CHECK_ALSA + + if test "x$with_alsa" != xcheck && test "x$have_alsa" != xyes; then + AC_MSG_FAILURE([--with-alsa was given, but test for ALSA failed]) + fi +fi + +AM_CONDITIONAL(include_ALSA, [test "x$have_alsa" = "xyes"]) + +dnl --------- ALSA CHECK END --------------- +dnl ======================================================= +dnl FILE: ./plugins/decoder/ffmpeg/configure.in.in +dnl ======================================================= + +dnl --------------- FFMPEG CHECK --------------------------------- + +AC_ARG_WITH( + ffmpeg, + AS_HELP_STRING( + [--without-ffmpeg], + [build K3b without ffmpeg audio decoder support (default=no)]), + [ac_cv_use_ffmpeg=$withval], + [ac_cv_use_ffmpeg=yes] +) + +# +# The ffmpeg decoder plugin needs ffmpeg 0.4.9 or higher +# +have_ffmpeg=no +if test "$ac_cv_use_ffmpeg" = "yes"; then + k3b_cxxflags_save="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -D__STDC_CONSTANT_MACROS" + AC_MSG_CHECKING(for ffmpeg >= 0.4.9) + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + AC_COMPILE_IFELSE( + extern "C" { + #include + #include + } + + int main() { + AVFormatContext* fc = 0; + AVPacket* p = 0; + av_register_all(); + return av_read_frame( fc, p ); + }, + [ffmpeg_compiles=yes], [ffmpeg_compiles=no] ) + OLD_LIBS=$LIBS + LIBS="-lavformat -lavcodec $LIBS" + AC_LINK_IFELSE( + extern "C" { + #include + #include + } + + int main() { + AVFormatContext* fc = 0; + AVPacket* p = 0; + av_register_all(); + return av_read_frame( fc, p ); + }, + [ffmpeg_links=yes], [ffmpeg_links=no] ) + AC_LANG_RESTORE + LIBS=$OLD_LIBS + have_ffmpeg=$ffmpeg_links + AC_MSG_RESULT($have_ffmpeg) + CXXFLAGS=$k3b_cxxflags_save +fi +AM_CONDITIONAL(include_FFMPEG, [test x$have_ffmpeg = xyes]) + +dnl --------------- FFMPEG CHECK END ------------------------------ + +AC_ARG_ENABLE( + ffmpeg-all-codecs, + AS_HELP_STRING( + [--enable-ffmpeg-all-codecs], + [Build K3b's ffmeg decoder plugin with all audio codecs enabled (default=disabled)]), + [AC_DEFINE(K3B_FFMPEG_ALL_CODECS, 1, [Defined if all ffmpeg codecs should be allowed]) + enable_ffmpeg_all_codecs=yes], + [enable_ffmpeg_all_codecs=no] +) +dnl ======================================================= +dnl FILE: ./plugins/decoder/flac/configure.in.in +dnl ======================================================= + +dnl === test for FLAC++ and FLAC - begin ==== +AC_ARG_WITH( + flac, + AS_HELP_STRING([--without-flac], [build K3b without FLAC support (default=no)]), + [ac_cv_use_flac=$withval], + [ac_cv_use_flac=yes] +) + +have_flac=no +if test "$ac_cv_use_flac" = "yes"; then + KDE_CHECK_HEADERS(FLAC++/decoder.h, [ + AC_CHECK_LIB(FLAC,FLAC__stream_decoder_process_single, + have_flac=yes,[],$all_libraries)]) + + AC_MSG_CHECKING(for libFLAC newer than 1.1.1) + AC_CACHE_VAL(k3b_flac_new, + [ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + AC_TRY_COMPILE( + [ + #include + ], [ + FLAC::Metadata::VorbisComment* vc; + vc->get_vendor_string().get_field(); + ], k3b_flac_new=no, k3b_flac_new=yes ) + AC_LANG_RESTORE + ]) + AC_MSG_RESULT($k3b_flac_new) + if test $k3b_flac_new = yes; then + AC_DEFINE(FLAC_NEWER_THAN_1_1_1, + 1, + [Define to 1 if your flac library's version is newer than or equal to 1.1.2] + ) + fi +else + have_flac=no +fi + +AM_CONDITIONAL(include_FLAC, [test x$have_flac = xyes]) +dnl === test for FLAC++ and FLAC - end ==== +dnl ======================================================= +dnl FILE: ./plugins/decoder/libsndfile/configure.in.in +dnl ======================================================= + +dnl === test for libsndfile - begin === +dnl +dnl Don't use PKG_CHECK, since if there is no pkg-config installed, +dnl then there is no auto* magic for it either. +dnl +dnl Tests copied from kdebase/kioslave/thumbnail/ +dnl +if test -z "$PKG_CONFIG"; then + AC_PATH_PROG(PKG_CONFIG, pkg-config, no) +fi + +AC_ARG_WITH( + sndfile, + AS_HELP_STRING([--without-sndfile], + [build K3b without libsndfile support (default=no)]), + [ac_cv_use_sndfile=$withval], + [ac_cv_use_sndfile=yes] +) + +if test "$ac_cv_use_sndfile" = "yes"; then + SNDFILE_CFLAGS="" + SNDFILE_LIBS="" + if test "$PKG_CONFIG" = "no" ; then + ac_cv_sndfile=0 + echo "*** The pkg-config script could not be found. Make sure it is" + echo "*** in your path, or set the PKG_CONFIG environment variable" + echo "*** to the full path to pkg-config." + echo "*** Or see http://www.freedesktop.org/software/pkgconfig to get pkg-config." + else + if !(`$PKG_CONFIG --exists sndfile`) ; then + echo "*** sndfile is not installed." + ac_cv_sndfile=0 + else + if !(`$PKG_CONFIG --atleast-version="1.0.2" sndfile`) ; then + echo "*** You need at least version 1.0.2 of sndfile." + ac_cv_sndfile=0 + else + ac_cv_sndfile=1 + SNDFILE_CFLAGS=`$PKG_CONFIG --cflags sndfile` + SNDFILE_LIBS=`$PKG_CONFIG --libs sndfile` + fi + fi + fi + + AC_DEFINE_UNQUOTED([HAVE_SNDFILE],${ac_cv_sndfile}, + [Set to 1 if you have libsndfile.]) + AC_SUBST(SNDFILE_CFLAGS) + AC_SUBST(SNDFILE_LIBS) +fi + +AM_CONDITIONAL(include_AIFF, [test x$ac_cv_sndfile = x1]) +dnl === test for libsndfile - end === +dnl ======================================================= +dnl FILE: ./plugins/decoder/mp3/configure.in.in +dnl ======================================================= + +dnl === libmad MPEG decoder check - begin === +AC_ARG_WITH( + libmad, + AS_HELP_STRING([--without-libmad], [build K3b without libmad support (default=no)]), + [ac_cv_use_libmad=$withval], + [ac_cv_use_libmad=yes] +) + +if test "$ac_cv_use_libmad" = "yes"; then + MAD_LIB="" + KDE_CHECK_HEADER(mad.h, [ + AC_CHECK_LIB(mad, mad_synth_frame, [ + MAD_LIB="-lmad" + AC_DEFINE(HAVE_LIBMAD,1,[defined if you have libmad headers and libraries])], + [], + $all_libraries + ) + ]) + AC_SUBST(MAD_LIB) + +fi + +AM_CONDITIONAL(include_MP3, [test -n "$MAD_LIB"]) +dnl === libmad MPeg decoder check - end === +dnl ======================================================= +dnl FILE: ./plugins/decoder/musepack/configure.in.in +dnl ======================================================= + +dnl --------- MUSEPACK CHECK --------------- + +AC_ARG_WITH( + musepack, + AS_HELP_STRING( + [--without-musepack], + [build K3b without Musepack audio support (default=no)]), + [ac_cv_use_mpc=$withval], + [ac_cv_use_mpc=yes] +) + +have_mpc=no +if test "$ac_cv_use_mpc" = "yes"; then + + dnl - search for both the new and the old naming - + + KDE_CHECK_HEADERS(mpcdec/mpcdec.h, [ + AC_CHECK_LIB(mpcdec, mpc_decoder_setup, [ + have_mpc=yes + MPC_LIBS="-lmpcdec" + AC_DEFINE( + MPC_HEADER_FILE, + , + [The header to include for MPC decoding.]) + ], + [], [], []) + ]) + + if test "$have_mpc" = "no"; then + KDE_CHECK_HEADERS(musepack/musepack.h, [ + AC_CHECK_LIB(musepack, mpc_decoder_setup, [ + have_mpc=yes + MPC_LIBS="-lmusepack" + AC_DEFINE( + MPC_HEADER_FILE, + , + [The header to include for MPC decoding.] + ) + AC_DEFINE( + mpc_bool_t, + BOOL, + [backwards compatibility stuff] + ) + ], [], []) + ]) + fi +fi +AC_SUBST(MPC_LIBS) + +AM_CONDITIONAL(include_MPC, [test x$have_mpc = xyes]) + +dnl --------- MUSEPACK CHECK END ----------- +dnl ======================================================= +dnl FILE: ./plugins/decoder/ogg/configure.in.in +dnl ======================================================= + +dnl === Ogg Vorbis Test - Begin === +AC_ARG_WITH( + oggvorbis, + AS_HELP_STRING([--without-oggvorbis], [build K3b without OggVorbis support (default=no)]), + [ac_cv_use_oggvorbis=$withval], + [ac_cv_use_oggvorbis=yes] +) + +if test "$ac_cv_use_oggvorbis" = "yes"; then + + AC_MSG_CHECKING(for ogg/vorbis headers) + ogg_vorbis=no + AC_TRY_COMPILE([ + #include + #include + ],[ + ],[ + ogg_vorbis=yes + ]) + AC_MSG_RESULT($ogg_vorbis) + if test x$ogg_vorbis = xyes; then + dnl we need the ogg_vorbis_lib because otherwise we override LIBS ! + AC_CHECK_LIB(vorbisfile,ov_open,ogg_vorbis_lib=yes, + ogg_vorbis=no,[$all_libraries -lvorbisfile -lvorbis -logg]) + fi + if test x$ogg_vorbis = xyes; then + AC_DEFINE(OGG_VORBIS,1,[Define if you have ogg/vorbis installed]) + fi +fi + +AM_CONDITIONAL(include_OGG, [test x$ogg_vorbis = xyes]) +dnl === Ogg Vorbis Test - End === +dnl ======================================================= +dnl FILE: ./plugins/encoder/lame/configure.in.in +dnl ======================================================= + +dnl === test for LAME - begin ==== +AC_ARG_WITH( + lame, + AS_HELP_STRING([--without-lame], [build K3b without LAME support (default=no)]), + [ac_cv_use_lame=$withval], + [ac_cv_use_lame=yes] +) + +have_lame=no +if test "$ac_cv_use_lame" = "yes"; then + KDE_CHECK_HEADERS(lame/lame.h, [ + AC_CHECK_LIB(mp3lame, lame_init, [ + have_lame=yes + AC_DEFINE(HAVE_LAME,1,[defined if you have the lame header and lib]) + ], [], $all_libraries -lm) + ]) +fi + +AM_CONDITIONAL(include_LAME, [test x$have_lame = xyes]) +dnl === test for LAME - end ==== +dnl ======================================================= +dnl FILE: ./src/fastscale/configure.in.in +dnl ======================================================= + +# +# Imlib/Mosfet scaling +# +AM_PROG_AS + +# MMX test duped from kdelibs/kdefx - it should be probably moved to admin/ +dnl ----------------------------------------------------- +dnl IA32 checks +dnl ----------------------------------------------------- + +gv_asm_defs= +case $host_cpu in + i*86 ) + AC_MSG_CHECKING(for assembler support for IA32 extensions) + + dnl MMX check + AC_TRY_COMPILE(, [ __asm__("pxor %mm0, %mm0") ], + [ + echo $ECHO_N "MMX yes$ECHO_C" + AC_DEFINE_UNQUOTED(HAVE_X86_MMX, 1, [Define to 1 if the assembler supports MMX instructions.]) + gv_asm_defs="$gv_asm_defs -DHAVE_X86_MMX" + ], [ echo $ECHO_N "MMX no$ECHO_C" ]) + + dnl SSE check + AC_TRY_COMPILE(,[ __asm__("xorps %xmm0, %xmm0") ], + [ + echo $ECHO_N ", SSE yes$ECHO_C" + AC_DEFINE_UNQUOTED(HAVE_X86_SSE, 1, [Define to 1 if the assembler supports SSE instructions.]) + gv_asm_defs="$gv_asm_defs -DHAVE_X86_SSE" + ], [ echo $ECHO_N ", SSE no$ECHO_C" ]) + + dnl SSE2 check + AC_TRY_COMPILE(, [ __asm__("xorpd %xmm0, %xmm0") ], + [ + echo $ECHO_N ", SSE2 yes$ECHO_C" + AC_DEFINE_UNQUOTED(HAVE_X86_SSE2, 1, [Define to 1 if the assembler supports SSE2 instructions.]) + gv_asm_defs="$gv_asm_defs -DHAVE_X86_SSE2" + ], [ echo $ECHO_N ", SSE2 no$ECHO_C" ]) + + dnl 3DNOW check + AC_TRY_COMPILE(, [ __asm__("femms") ], + [ + echo $ECHO_N ", 3DNOW yes$ECHO_C" + AC_DEFINE_UNQUOTED(HAVE_X86_3DNOW, 1, [Define to 1 if the assembler supports 3DNOW instructions.]) + gv_asm_defs="$gv_asm_defs -DHAVE_X86_3DNOW" + ], [ echo $ECHO_N ", 3DNOW no$ECHO_C" ]) + echo + ;; + powerpc ) + AC_MSG_CHECKING(for assembler support for AltiVec instructions) + dnl AltiVec check + AC_TRY_COMPILE(, [ __asm__("mtspr 256, %0\n\t" "vand %%v0, %%v0, %%v0" : : "r"(-1) ) ], + [ + echo $ECHO_N " yes$ECHO_C" + AC_DEFINE_UNQUOTED(HAVE_PPC_ALTIVEC, 1, [Define to 1 if the assembler supports AltiVec instructions.]) + gv_asm_defs="$gv_asm_defs -DHAVE_PPC_ALTIVEC" + ], [ echo $ECHO_N ", AltiVec no$ECHO_C" ]) + echo + ;; +esac + +GV_ASM_DEFS="$gv_asm_defs" +AC_SUBST(GV_ASM_DEFS) +KDE_CREATE_SUBDIRSLIST +AC_CONFIG_FILES([ Makefile ]) +AC_CONFIG_FILES([ doc/Makefile ]) +AC_CONFIG_FILES([ k3bsetup/Makefile ]) +AC_CONFIG_FILES([ kfile-plugins/Makefile ]) +AC_CONFIG_FILES([ kfile-plugins/k3bproject/Makefile ]) +AC_CONFIG_FILES([ kioslaves/Makefile ]) +AC_CONFIG_FILES([ kioslaves/videodvd/Makefile ]) +AC_CONFIG_FILES([ libk3b/Makefile ]) +AC_CONFIG_FILES([ libk3b/cddb/Makefile ]) +AC_CONFIG_FILES([ libk3b/core/Makefile ]) +AC_CONFIG_FILES([ libk3b/jobs/Makefile ]) +AC_CONFIG_FILES([ libk3b/plugin/Makefile ]) +AC_CONFIG_FILES([ libk3b/plugin/libsamplerate/Makefile ]) +AC_CONFIG_FILES([ libk3b/projects/Makefile ]) +AC_CONFIG_FILES([ libk3b/projects/audiocd/Makefile ]) +AC_CONFIG_FILES([ libk3b/projects/datacd/Makefile ]) +AC_CONFIG_FILES([ libk3b/projects/datadvd/Makefile ]) +AC_CONFIG_FILES([ libk3b/projects/mixedcd/Makefile ]) +AC_CONFIG_FILES([ libk3b/projects/movixcd/Makefile ]) +AC_CONFIG_FILES([ libk3b/projects/movixdvd/Makefile ]) +AC_CONFIG_FILES([ libk3b/projects/videocd/Makefile ]) +AC_CONFIG_FILES([ libk3b/projects/videocd/cdi/Makefile ]) +AC_CONFIG_FILES([ libk3b/projects/videocd/extra/Makefile ]) +AC_CONFIG_FILES([ libk3b/projects/videocd/mpeginfo/Makefile ]) +AC_CONFIG_FILES([ libk3b/projects/videodvd/Makefile ]) +AC_CONFIG_FILES([ libk3b/scripts/Makefile ]) +AC_CONFIG_FILES([ libk3b/tools/Makefile ]) +AC_CONFIG_FILES([ libk3b/tools/libisofs/Makefile ]) +AC_CONFIG_FILES([ libk3b/videodvd/Makefile ]) +AC_CONFIG_FILES([ libk3bdevice/Makefile ]) +AC_CONFIG_FILES([ plugins/Makefile ]) +AC_CONFIG_FILES([ plugins/audiooutput/Makefile ]) +AC_CONFIG_FILES([ plugins/audiooutput/alsa/Makefile ]) +AC_CONFIG_FILES([ plugins/audiooutput/arts/Makefile ]) +AC_CONFIG_FILES([ plugins/decoder/Makefile ]) +AC_CONFIG_FILES([ plugins/decoder/ffmpeg/Makefile ]) +AC_CONFIG_FILES([ plugins/decoder/flac/Makefile ]) +AC_CONFIG_FILES([ plugins/decoder/libsndfile/Makefile ]) +AC_CONFIG_FILES([ plugins/decoder/mp3/Makefile ]) +AC_CONFIG_FILES([ plugins/decoder/musepack/Makefile ]) +AC_CONFIG_FILES([ plugins/decoder/ogg/Makefile ]) +AC_CONFIG_FILES([ plugins/decoder/wave/Makefile ]) +AC_CONFIG_FILES([ plugins/encoder/Makefile ]) +AC_CONFIG_FILES([ plugins/encoder/external/Makefile ]) +AC_CONFIG_FILES([ plugins/encoder/lame/Makefile ]) +AC_CONFIG_FILES([ plugins/encoder/ogg/Makefile ]) +AC_CONFIG_FILES([ plugins/encoder/sox/Makefile ]) +AC_CONFIG_FILES([ plugins/project/Makefile ]) +AC_CONFIG_FILES([ plugins/project/audiometainforenamer/Makefile ]) +AC_CONFIG_FILES([ plugins/project/audioprojectcddb/Makefile ]) +AC_CONFIG_FILES([ src/Makefile ]) +AC_CONFIG_FILES([ src/fastscale/Makefile ]) +AC_CONFIG_FILES([ src/icons/Makefile ]) +AC_CONFIG_FILES([ src/icons/actions/Makefile ]) +AC_CONFIG_FILES([ src/konqi/Makefile ]) +AC_CONFIG_FILES([ src/mimetypes/Makefile ]) +AC_CONFIG_FILES([ src/misc/Makefile ]) +AC_CONFIG_FILES([ src/option/Makefile ]) +AC_CONFIG_FILES([ src/pics/Makefile ]) +AC_CONFIG_FILES([ src/pics/73lab/Makefile ]) +AC_CONFIG_FILES([ src/pics/RobsTheme/Makefile ]) +AC_CONFIG_FILES([ src/pics/crystal/Makefile ]) +AC_CONFIG_FILES([ src/pics/quant/Makefile ]) +AC_CONFIG_FILES([ src/projects/Makefile ]) +AC_CONFIG_FILES([ src/projects/kostore/Makefile ]) +AC_CONFIG_FILES([ src/rip/Makefile ]) +AC_CONFIG_FILES([ src/rip/videodvd/Makefile ]) +AC_CONFIG_FILES([ src/sounds/Makefile ]) +AC_OUTPUT +echo "" + +echo "K3b - Include libdvdread (Video DVD ripping) support:" +if test "$have_libdvdread" = "yes"; then + echo "K3b - yes" +else + echo "K3b - no" + if test "$ac_cv_use_libdvdread" = "yes"; then + echo "K3b - You are missing the libdvdread library." + fi +fi +echo "" + +if test -n "$RESMGR_LIB"; then + echo "K3b - Resmgr support: yes" +else + echo "K3b - Resmgr support: no" +fi + +echo "" + + +if test x$have_hal = xyes; then + echo "K3b - Compile HAL support yes" +else + echo "K3b - Compile HAL support no" +if test "x$ac_cv_use_hal" = "xyes" ; then + echo "K3b - You are missing the HAL >= 0.5 headers and libraries" + echo "K3b - or the DBus Qt bindings." +fi +fi +echo "" + +if test "x$have_alsa" = xyes; then + echo "K3b - Audioplayer available (alsa) yes" +else + echo "K3b - Audioplayer available (alsa) no" +fi +echo "" + +echo "K3b - FFMpeg decoder plugin (decodes wma and others):" +if test x$have_ffmpeg = xyes; then + echo "K3b - yes" + if test x$enable_ffmpeg_all_codecs = xyes; then + echo "K3b - WARNING: You enabled all codecs in the ffmpeg decoder plugin." + echo "K3b - Be aware that most are not tested and track lengths" + echo "K3b - will be wrong in many cases." + fi +else + echo "K3b - no" +if test "$ac_cv_use_ffmpeg" = "yes"; then + if test "$ffmpeg_compiles" = "yes"; then + echo "K3b - You are missing the ffmpeg libraries." + echo "K3b - Make sure ffmpeg has been configured as a" + echo "K3b - shared library (which is not the default)." + else + echo "K3b - You are missing the ffmpeg headers and libraries" + echo "K3b - version 0.4.9 or higher." + fi + echo "K3b - The ffmpeg audio decoding plugin (decodes wma and" + echo "K3b - others) won't be compiled." +fi +fi +echo "" + +if test x$have_flac = xyes; then + echo "K3b - FLAC support: yes" +else + echo "K3b - FLAC support: no" +if test "$ac_cv_use_flac" = "yes"; then + if test "$have_flac" = "no"; then + echo "K3b - You are missing the FLAC++ headers and libraries." + echo "K3b - The FLAC decoding plugin won't be compiled." + fi +fi +fi +echo "" + +if $av_cv_sndfile; then + echo "K3b - libsndfile audio decoding support: yes" +else + echo "K3b - libsndfile audio decoding support: no" +if test "$ac_cv_use_sndfile" = "yes"; then + echo "K3b - You are missing the libsndfile headers and libraries." + echo "K3b - The libsndfile audio decoding plugin won't be compiled." +fi +fi +echo "" + +if test -n "$MAD_LIB"; then + echo "K3b - Mp3 decoding support (libmad): yes" +else + echo "K3b - Mp3 decoding support (libmad): no" +if test "$ac_cv_use_libmad" = "yes"; then + echo "K3b - You are missing the libmad headers and libraries." + echo "K3b - The Mp3 decoding plugin won't be compiled." +fi +fi +echo "" + +if test x$have_mpc = xyes; then + echo "K3b - Musepack support: yes" +else + echo "K3b - Musepack support: no" +if test "$ac_cv_use_mpc" = "yes"; then + echo "K3b - You are missing the Musepack headers and libraries >= 1.1." + echo "K3b - The Musepack audio decoding plugin won't be compiled." +fi +fi + +echo "" + +if test x$ogg_vorbis = xyes; then + echo "K3b - Ogg Vorbis support: yes" +else + echo "K3b - Ogg Vorbis support: no" +if test "$ac_cv_use_oggvorbis" = "yes"; then + echo "K3b - You are missing the Ogg-Vorbis headers and libraries." + echo "K3b - The Ogg Vorbis decoding and encoding plugins won't be compiled." +fi +fi +echo "" + +if test x$have_lame = xyes; then + echo "K3b - Lame Mp3 encoder plugin: yes" +else + echo "K3b - Lame Mp3 encoder plugin no" +if test "$ac_cv_use_lame" = "yes"; then + echo "K3b - You are missing the Lame headers and libraries." + echo "K3b - The Lame Mp3 encoding plugin won't be compiled." +fi +fi +echo "" + +if test "$use_k3b_debug" = "yes"; then + echo "" + echo "K3b - K3B DEBUGGING ENABLED! THIS ENABLES ADDITIONAL DEBUGGING OUTPUT" + echo "K3b - AND FUNCTIONALITY WHICH IS ONLY INTENDED FOR K3B DEVELOPERS!" + echo "K3b - THIS MAY EVEN SLOW DOWN K3B IN SOME PLACES!" + echo "" +fi + +if test "$cdrecord_suid_root" != "yes"; then + echo "" + echo "K3b - Suid root test for cdrecord, cdrdao, and wodim deactivated" + echo "K3b - This is NOT recommended although it might work out fine ;)" + echo "" +fi + +if $have_taglib; then + echo "K3b - Audio meta data reading with Taglib: yes" +else + echo "K3b - Audio meta data reading with Taglib: no" + echo "K3b - You are missing the Taglib headers and libraries." + echo "K3b - The mp3 and flac decoder plugins will fall back to" + echo "K3b - using KMetaFileInfo." +fi + +echo "" + +echo "K3b - Audio resampling:" +if test -n "$LIBSAMPLERATE"; then + echo "K3b - using installed version" +else + echo "K3b - using version bundled with K3b" +fi + +echo "" + +if test x$arts_available = xyes; then + echo "K3b - Audioplayer available (aRts) yes" +else + echo "K3b - Audioplayer available (aRts) no" +fi + +echo "" + +if test x$compile_k3bsetup = xyes; then + echo "K3b - Compile K3bSetup 2: yes" +else + echo "K3b - Compile K3bSetup 2: no" +fi + +echo "" + +if $have_mb; then + echo "K3b - Tag guessing using MusicBrainz yes" +else + echo "K3b - Tag guessing using MusicBrainz no" +if test "$ac_cv_use_musicbrainz" = "yes"; then + echo "K3b - You are missing the musicbrainz headers and libraries." + echo "K3b - K3b will be compiled without support for tag guessing." +fi +fi +# Check if KDE_SET_PREFIX was called, and --prefix was passed to configure +if test -n "$kde_libs_prefix" -a -n "$given_prefix"; then + # And if so, warn when they don't match + if test "$kde_libs_prefix" != "$given_prefix"; then + # And if kde doesn't know about the prefix yet + echo ":"`kde-config --path exe`":" | grep ":$given_prefix/bin/:" 2>&1 >/dev/null + if test $? -ne 0; then + echo "" + echo "Warning: you chose to install this package in $given_prefix," + echo "but KDE was found in $kde_libs_prefix." + echo "For this to work, you will need to tell KDE about the new prefix, by ensuring" + echo "that KDEDIRS contains it, e.g. export KDEDIRS=$given_prefix:$kde_libs_prefix" + echo "Then restart KDE." + echo "" + fi + fi +fi + +if test x$GXX = "xyes" -a x$kde_have_gcc_visibility = "xyes" -a x$kde_cv_val_qt_gcc_visibility_patched = "xno"; then + echo "" + echo "Your GCC supports symbol visibility, but the patch for Qt supporting visibility" + echo "was not included. Therefore, GCC symbol visibility support remains disabled." + echo "" + echo "For better performance, consider including the Qt visibility supporting patch" + echo "located at:" + echo "" + echo "http://bugs.kde.org/show_bug.cgi?id=109386" + echo "" + echo "and recompile all of Qt and KDE. Note, this is entirely optional and" + echo "everything will continue to work just fine without it." + echo "" +fi + +if test "$all_tests" = "bad"; then + if test ! "$cache_file" = "/dev/null"; then + echo "" + echo "Please remove the file $cache_file after changing your setup" + echo "so that configure will find the changes next time." + echo "" + fi +else + echo "" + echo "Good - your configure finished. Start make now" + echo "" +fi diff --git a/configure.in.bot b/configure.in.bot new file mode 100644 index 0000000..718d6ba --- /dev/null +++ b/configure.in.bot @@ -0,0 +1,62 @@ +echo "" + +if test "$use_k3b_debug" = "yes"; then + echo "" + echo "K3b - K3B DEBUGGING ENABLED! THIS ENABLES ADDITIONAL DEBUGGING OUTPUT" + echo "K3b - AND FUNCTIONALITY WHICH IS ONLY INTENDED FOR K3B DEVELOPERS!" + echo "K3b - THIS MAY EVEN SLOW DOWN K3B IN SOME PLACES!" + echo "" +fi + +if test "$cdrecord_suid_root" != "yes"; then + echo "" + echo "K3b - Suid root test for cdrecord, cdrdao, and wodim deactivated" + echo "K3b - This is NOT recommended although it might work out fine ;)" + echo "" +fi + +if $have_taglib; then + echo "K3b - Audio meta data reading with Taglib: yes" +else + echo "K3b - Audio meta data reading with Taglib: no" + echo "K3b - You are missing the Taglib headers and libraries." + echo "K3b - The mp3 and flac decoder plugins will fall back to" + echo "K3b - using KMetaFileInfo." +fi + +echo "" + +echo "K3b - Audio resampling:" +if test -n "$LIBSAMPLERATE"; then + echo "K3b - using installed version" +else + echo "K3b - using version bundled with K3b" +fi + +echo "" + +if test x$arts_available = xyes; then + echo "K3b - Audioplayer available (aRts) yes" +else + echo "K3b - Audioplayer available (aRts) no" +fi + +echo "" + +if test x$compile_k3bsetup = xyes; then + echo "K3b - Compile K3bSetup 2: yes" +else + echo "K3b - Compile K3bSetup 2: no" +fi + +echo "" + +if $have_mb; then + echo "K3b - Tag guessing using MusicBrainz yes" +else + echo "K3b - Tag guessing using MusicBrainz no" +if test "$ac_cv_use_musicbrainz" = "yes"; then + echo "K3b - You are missing the musicbrainz headers and libraries." + echo "K3b - K3b will be compiled without support for tag guessing." +fi +fi diff --git a/configure.in.in b/configure.in.in new file mode 100644 index 0000000..27cec92 --- /dev/null +++ b/configure.in.in @@ -0,0 +1,184 @@ +#MIN_CONFIG(3.2) +#AM_KDE_MIN_VERSION(3.4) + +AC_CHECK_HEADERS(byteswap.h) + +dnl - check the byte order - +dnl this will define WORDS_BIGENDIAN or do nothing +AC_C_BIGENDIAN() + +AC_ARG_WITH( + external-libsamplerate, + [ --with-external-libsamplerate use the libsamplerate provided by the system (default=yes)], + [external_sampletrate=$withval], + [external_sampletrate=yes] +) + +LIBSAMPLERATE="" + +if test x$external_sampletrate != xno; then + +dnl === check for libsamplerate ========== +KDE_CHECK_HEADERS(samplerate.h, [ + KDE_CHECK_LIB(samplerate, src_new, [ + LIBSAMPLERATE="-lsamplerate" + AC_DEFINE(HAVE_LIBSAMPLERATE,1,[defined if you have libsamplerate library and header]) + ]) +]) + +fi + +AC_SUBST(LIBSAMPLERATE) +AM_CONDITIONAL(compile_libsamplerate, [test -z "$LIBSAMPLERATE"]) + + +ARTS_LIBS="" +if test "x$build_arts" = "xyes"; then + dnl Find aRts + KDE_CHECK_HEADERS(artsc/artsc.h, + [arts_available=yes + ARTS_LIBS="-lartsc"], + [arts_available=no] + ) +fi +AC_SUBST(ARTS_LIBS) +AM_CONDITIONAL(include_arts, [test -n "$ARTS_LIBS"]) +if test "x$build_arts" = "xyes" -a "x$arts_available" = "xyes"; then + AC_DEFINE(WITH_ARTS,1,[defined if arts support is compiled in]) +fi + +KDE_CHECK_THREADING + +compile_k3bsetup=yes +AC_ARG_WITH( + k3bsetup, + [ --with-k3bsetup[=ARG] do compile K3bSetup2 KControl Module (default=yes)], + [compile_k3bsetup=$withval] +) + +if test x$compile_k3bsetup = xyes; then + AC_DEFINE(HAVE_K3BSETUP,1,[defined if K3bSetup is compiled]) +fi + +AM_CONDITIONAL(with_k3bsetup1, [test x$compile_k3bsetup = xyes]) + + +cdrecord_suid_root=yes +AC_ARG_WITH( + cdrecord-suid-root, + AS_HELP_STRING( + [--without-cdrecord-suid-root], + [enable or disable K3b's suid root check for cdrecord/cdrdao/wodim (default=enabled)]), + [cdrecord_suid_root=$withval], + [cdrecord_suid_root=yes] +) +if test x$cdrecord_suid_root = xyes; then + AC_DEFINE(CDRECORD_SUID_ROOT_CHECK,1,[defined if K3b should check cdrecord for suid root]) +fi + + +# Extra SCSI support libs can go in CAM_LIB, and are linked into +# libk3bdevice. For Linux, nothing is needed. FreeBSD requires -lcam +# (which is in base, so no test is needed). +case "$host_os" in +freebsd* | dragonfly*) + CAM_LIB="-lcam" + ;; +*) + CAM_LIB="" + ;; +esac +AC_SUBST(CAM_LIB) + + + +dnl ---------- TAGLIB CHECK ---------- + +AC_DEFUN([AC_HAVE_TAGLIB], +[ + AC_DEFINE(HAVE_TAGLIB, 1, [have TagLib]) + taglib_includes=[`$TAGLIB_CONFIG --cflags`] + taglib_libs=[`$TAGLIB_CONFIG --libs`] + have_taglib=true +]) + +AC_DEFUN([AC_NO_TAGLIB], +[ + taglib_includes="" + taglib_libs="" + have_taglib=false +]) + +AC_PATH_PROG(TAGLIB_CONFIG, taglib-config, [no], [$PATH:$prefix/bin]) +if test "x$TAGLIB_CONFIG" = "xno" ; then + AC_NO_TAGLIB +else + AC_HAVE_TAGLIB +fi + +AC_SUBST(taglib_includes) +AC_SUBST(taglib_libs) + +dnl ---------- END TAGLIB CHECK ---------- + + + +dnl ----------- TUNEPIMP/MUSICBRAINZ CHECK ----------- + +AC_ARG_WITH( + musicbrainz, + AS_HELP_STRING( + [--without-musicbrainz], + [build K3b without Musicbrainz support (default=no)]), + [ac_cv_use_musicbrainz=$withval], + [ac_cv_use_musicbrainz=yes] +) + +have_mb=false +MUSICBRAINZ_LIBS="" +if test "$ac_cv_use_musicbrainz" = "yes"; then + KDE_CHECK_HEADER(musicbrainz/mb_c.h, + [ + KDE_CHECK_LIB(musicbrainz,mb_New,[ + AC_DEFINE(HAVE_MUSICBRAINZ, 1, [have MusicBrainz]) + MUSICBRAINZ_LIBS="-lmusicbrainz" + have_mb=true + ]) + ], []) +fi +AC_SUBST(MUSICBRAINZ_LIBS) + +dnl --------- TUNEPIMP/MUSICBRAINZ CHECK END ----------- + + +dnl --------- K3b debugging stuff (only for developers) ---- + +AC_ARG_WITH( + k3b-debug, + AS_HELP_STRING( + [--with-k3b-debug], + [Enable additional K3b debugging output and functionality (default=no)]), + [use_k3b_debug=$withval], + [use_k3b_debug=no] +) +if test "$use_k3b_debug" = "yes"; then + AC_DEFINE(K3B_DEBUG, "1", [K3b additional debugging support]) +fi + +dnl -------------------------------------------------------- + + + + +dnl --------------- libiconv check ------------------------- + +AC_CHECK_HEADERS(iconv.h) + +dnl -------------------------------------------------------- + + +#AC_DEFINE(LIBK3B_VERSION, "0.11.98", [k3b library version]) +#AC_SUBST(LIBK3B_VERSION, 0.11.98) +#AC_CONFIG_FILES([k3b/libk3b/libk3b.pc]) + +KDE_ENABLE_HIDDEN_VISIBILITY diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 0000000..6385fe8 --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1,4 @@ + +KDE_LANG = en +KDE_DOCS = k3b + diff --git a/doc/audiocd-howto.docbook b/doc/audiocd-howto.docbook new file mode 100644 index 0000000..b993db5 --- /dev/null +++ b/doc/audiocd-howto.docbook @@ -0,0 +1,96 @@ + + + Quickguide: Burning an Audio-CD in 4 Steps + + + This Quickguide shows you how to create a AudioCD with &k3b;. To reproduce + these steps you need a working &k3b; and a directory in which you have + audiofiles. + + + Step 1 + + When you start &k3b; you should see something like this. + + Here you can select one of four projects &k3b; offers + + + + + + Screenshot + + + + + + + Step 2 + + Now you click on "New Audio CD Project" + + This is a dialog where you can select which files you want to burn on a CD + + + + + + Screenshot + + + + + + The files you see on the top-part of &k3b; can be dropped with the mouse to the bottom-widget. + Another way is to right-click on a file an select Add to Project. In order to rearrange + the order of the audio-tracks you can simply move the tracks with the left mouse-button. The properties + of the tracks can be changed by clicking with the &RMB; and choosing Properties. + As soon as you like the arrangement of the tracks click on Burn... in the right-bottom + corner. + + + + When you burn AudioCD from MP3s or other lossy compressed music, remember that if you encode this CD back to MP3, you'll get poorer quality regardless the bitrate you use. To check whether AudioCD was burnt from lossy format, try auCDtect. + + + + + Step 3 + + This is a dialog where you can decide the settings for the CD. + + + + + + Screenshot + + + + + In this dialog you can control the settings of the burning itself. The default-settings of &k3b; + are probably correct for you. In the top-right corner you can control the speed. One last + step before the actual burning you can give the CD a title by choosing CD-Text and + selecting Write CD-Text. The two which are probably most important for you + are Title and Performer. As soon as you are content with + the settings click on Burn. + + + + Step 4 + + + In this dialog you can see the progress of you burning + + + + + + Screenshot + + + + In this dialog is nothing you can do. Just wait for you computer to finish the session. + + + diff --git a/doc/burndialog_audio.png b/doc/burndialog_audio.png new file mode 100644 index 0000000..936ea3b Binary files /dev/null and b/doc/burndialog_audio.png differ diff --git a/doc/burndialog_progress.png b/doc/burndialog_progress.png new file mode 100644 index 0000000..8a0ac30 Binary files /dev/null and b/doc/burndialog_progress.png differ diff --git a/doc/cdcloning_dialog.png b/doc/cdcloning_dialog.png new file mode 100644 index 0000000..cb93f6e Binary files /dev/null and b/doc/cdcloning_dialog.png differ diff --git a/doc/cdcloning_reading.png b/doc/cdcloning_reading.png new file mode 100644 index 0000000..d7c0b4c Binary files /dev/null and b/doc/cdcloning_reading.png differ diff --git a/doc/cdcopy-howto.docbook b/doc/cdcopy-howto.docbook new file mode 100644 index 0000000..ded1ae0 --- /dev/null +++ b/doc/cdcopy-howto.docbook @@ -0,0 +1,86 @@ + + + Quickguide: Copying a Data-CD in 4 Steps + + + This Quickguide shows you how to create a Data-CD with &k3b;. To reproduce + these steps you need a working &k3b; and the CD you wish to copy inserted in your + CD-ROM. + + + Step 1 + + To copy a Data-CD you select Tools,CDCopy CD... + You will see a dialog where you can set up the burning. + + In this dialog you can select the settings you want to use for the burning. + + + + + + Screenshot + + + + + + + Step 2 + + After you have set up &k3b; click on Start CD Copy. You will get a dialog similar to this: + + In this dialog you can watch to progress of the copying. As soon as the writing of the + image-file is done you will be asked for a emtpy CD on which the data will be burned. + + + + + + Screenshot + + + + + + In this dialog you can watch to progress of the copying. As soon as the writing of the + image-file is done you will be asked for a emtpy CD on which the data will be burned. + + + + Step 3 + + &k3b; is burning the Image file. You have to wait until the Overall process + is at 100% + + + + + + Screenshot + + + + + &k3b; is burning the Image file. You have to wait until the Overall process + is at 100%. + + + + Step 4 + + + In this dialog you can see the result of your burning + + + + + + Screenshot + + + + &k3b; has finished the burning. Click on Close to close the dialog. + + + diff --git a/doc/cdcopy_done.png b/doc/cdcopy_done.png new file mode 100644 index 0000000..20cd3d4 Binary files /dev/null and b/doc/cdcopy_done.png differ diff --git a/doc/cdcopy_reading.png b/doc/cdcopy_reading.png new file mode 100644 index 0000000..d2611ed Binary files /dev/null and b/doc/cdcopy_reading.png differ diff --git a/doc/cdcopy_settings.png b/doc/cdcopy_settings.png new file mode 100644 index 0000000..bb8a1aa Binary files /dev/null and b/doc/cdcopy_settings.png differ diff --git a/doc/cdcopy_writing.png b/doc/cdcopy_writing.png new file mode 100644 index 0000000..6761ea1 Binary files /dev/null and b/doc/cdcopy_writing.png differ diff --git a/doc/commands.docbook b/doc/commands.docbook new file mode 100644 index 0000000..a6f69ae --- /dev/null +++ b/doc/commands.docbook @@ -0,0 +1,700 @@ + + + + The Menu Entries + + + The <guimenu>File</guimenu> Menu + + + + + + + &Ctrl;N + + + File + New Project + + + + + Creates a new project. + You have to choose the project type (Audio CD, Data DVD, ...). + + + + + + + + &Ctrl;O + + + File + Open... + + + + + Opens an existing project which + can be selected with KDE's Open File dialog. + + + + + + + + &Ctrl;R + + + File + Open Recent + + + + + This is a shortcut to re-open recently opened + projects. The sub-menu belonging to this item + contains a list of these projects, clicking on a specific file + will open it again. + + + + + + + + &Ctrl;S + + + File + Save + + + + + Saves the current project. + If there has already been a save of the document then this + will overwrite the previously saved file without asking + for the user's consent. If it is the first save of a new + document the Save As dialog will be invoked. + + + + + + + File + Save As... + + + + + Saves the current project with a new + file name. KDE's Save As dialog appears to specify + name and directory of the new project file. + + + + + + + File + Save All + + + + + Saves all open projects. + This is the same as selecting + + File + Save + for each of them. + + + + + + + + &Ctrl;C + + + File + Close + + + + + Closes the current project. + If a project has been modified but not yet saved + then &k3b; will ask what to do. + You can choose to save or discard the changes, + and you also have the opportunity to cancel closing + and keep the project open. + + + + + + + File + Close All + + + + + Closes all open projects. For each unsaved + project &k3b; will ask what to do, just like it does when + + File + Close + is selected. + + + + + + + + &Ctrl;Q + + + File + Quit + + + + + Quits &k3b; after closing all of its open + projects. For every unsaved project &k3b; will ask what to do, + just like it does when + + File + Close + is selected. + + + + + + + + + + The <guimenu>Project</guimenu> Menu + + + + + + Project + Add Files... + + + + + When this item is selected, the appearing dialog + lets you choose one or more files to be added + to the project. This has the same effect as dragging + files directly from the Contents View into the Project View. + If the current project is a data disc project, + the added files will appear in the disc's root directory. + + + + + + + Project + Clear Project + + + + + Removes all files and directories + from the current project. + The project itself remains open. + + + + + + + + &Ctrl;B + + + Project + Burn... + + + + + Opens the Burn dialog for the current project. + This is in fact the same as the Properties dialog - the only + difference is that there is an additional Burn button which + causes &k3b; to burn a disc from project data. The Burn dialog + won't open if the project does not contain any files. + + + + + + + + &Ctrl;P + + + Project + Properties... + + + + + Opens the Properties dialog for the current project. + Here you can specify a lot of options concerning + the project. Every project type has got a different set of + options, most of them can be explained by using What's This + (accessible by right-mouse-clicking). + + + + + + + Project + Import Session + + + + + This Item only appears if a Data CD/DVD or Video DVD project + is active. It causes K3b to import the file entries + from the previous session to the current project. + You can use this when compiling files for multi-session discs. + Hence that data from the previous session is always included, + even if you don't choose to make use of this command. + It just helps to know what's on the disc already. + + + + + + + Project + Clear Imported Session + + + + + This Item only appears if a Data CD/DVD or Video DVD project + is active. It causes K3b to remove the file entries + from the current project that were imported by + + Project + Import Session + while keeping all of the other data + in the project. Hence that making use of this command doesn't + actually remove anything from the disc that will be burned, + it just hides these files again. + + + + + + + Project + Edit Boot Images + + + + + This Item only appears if a Data CD/DVD or Video DVD project + is active. Here you can specify boot images + in order to create bootable CDs or DVDs. A boot image can be + a direct copy of a floppy or hard disk (for example, created + by the dd shell command) as well as another disc's boot image. + In any case it's a single file containing a complete, bootable + system that is burned as a normal file. In order to let the + computer know that the disc contains a boot image, the burning + application creates a boot catalog file whose name can be + determined in the dialog window. + + + + + + + + + + + + + The <guimenu>Tools</guimenu> Menu + + + + + + Tools + Copy CD... + + + + + Opens the CD Copy dialog. + Without the need of a project file, it provides + the ability to copy a CD's content to another disc. + Alternatively, you can choose only to create an image + of the source CD which can be burned anytime. There is + also an option to clone the CD instead of normal + copying, which should be preferred when copying CDs + with defective sectors or Video CDs. + + + + + + + Tools + Copy DVD... + + + + + Opens the DVD Copy dialog. + Without the need of a project file, it provides + the ability to copy a DVD's content to another disc. + Alternatively, you can choose only to create an image + of the source DVD which can be burned anytime. + Video transcoding within the DVD Copy dialog + is not yet supported, so the destination disc + has to be large enough to contain all of the + source disc's (video) data in its original form. + + + + + + + Tools + Erase CD-RW... + + + + + Opens the Erase CD-RW dialog. + With its help you can clear the contents of a CD-RW, + or part of it. + + + + + + + Tools + Format DVD±RW... + + + + + Opens the DVD Formatting dialog. + With its help you can format a DVD-R(W) or DVD+R(W), + which causes the disc's contents to be deleted. + &k3b; gives the choice between the "Overwrite" and + "Incremental" writing modes. + + + + + + + Tools + Burn CD Image... + + + + + Burns a previously created CD image. + The Burn CD Image dialog asks to select an + *.iso, + *.cue or + *.toc file + as data source that you can instantly burn by pressing + the Start button. + (Nero *.nrg files + are currently not supported, so you have to make use + of other tools like + Nrg2Iso.) + + + + + + + Tools + Burn DVD ISO Image... + + + + + Burns a previously created DVD image. + The Burn Iso9660 Image dialog asks to select an + *.iso file as data + source that you can instantly burn by pressing + the Start button. + + + + + + + Tools + Encode Video... + + + + + A DVD video that has already been ripped can be + encoded with a little help from the Encoding Video + dialog. This dialog box normally opens after ripping the DVD + from within the Contents View, but can also be used standalone. + It contains information about the ripped DVD video, encoding + options and even video resizing and cropping abilities. + + + + + + + Tools + Diskinfo + + + + + Shows information about the inserted disk. + This information will be displayed in the Contents View and + covers disk properties like type, size and track length + of the CD or DVD in your drive. + + + + + + + + + + The <guimenu>Settings</guimenu> Menu + + + + + + Settings + Toolbars + + + + + Pops up a list of &k3b;'s toolbars. + If a toolbar entry is checked, it means that + the toolbar is currently visible. + + + + + + + Settings + Show/Hide Statusbar + + + + + This enables you to show or hide the small bar + at the bottom of the main window containing + various information about &k3b;'s status and activities. + + + + + + + Settings + Show Directories + + + + + Toggles the visibility of the Directory View. + This view enables you to select directories and disc drives. + When selected, their contents will appear in the Contents View. + Disc drives have also got a context menu providing functions + like Disk Info, (un)mounting the drive or ejecting the medium. + + + + + + + Settings + Show Contents + + + + + Toggles the visibility of the Contents View. + This view enables you to select files that can be dragged + into the Project View in order to add them to the project. + The Contents View also acts as an interface to rip + audio CDs and video discs when a disc drive containing + an appropriate CD/DVD is selected in the Directory View. + + + + + + + Settings + Show Document Header + + + + + Toggles the visibility of the document header + belonging to the Project View. This is a small bar that is + only visible if the Project View contains any open projects. + The document header has no functionality, yet it's nice + eye candy and improves clarity by separating + the Project View from the other views. + + + + + + + Settings + Configure Shortcuts... + + + + + This command opens a dialog box where the key bindings + for &k3b;'s menu commands may be changed. + After selecting one of the available commands + from the upper part of the dialog, the shortcut + for this action can be changed in the lower part. + + + + + + + Settings + Configure Toolbars... + + + + + This command opens a dialog box where the toolbars + can be customized. The drop down box on top + of the dialog determines which toolbar can be edited + at the moment. The Available Actions list on the left contains + all commands that can be added to the toolbar, + the Current Actions list on the right shows the ones + that are already there. Items can be added by selecting + the appropriate command out of the Available Actions list and + pressing the right button to move it to the Current Actions + list. Removing an item works the other way round. + The up and down buttons change the commands's position + within the toolbar. + + + + + + + Settings + &k3b; Setup + + + + + This opens &k3bsetup; which helps setting the + right permissions needed by &k3b; in order to burn + CDs and DVDs. Linux' user rights management permits program + execution and access to disc drives if no permissions have + been granted by the administrator. &k3bsetup; cannot set + permissions without administrator privileges, so you have + to enter the root password when starting up. + + + + + + + Settings + Configure &k3b;... + + + + + Opens the Options dialog + where general program settings can be configured. + Although most of &k3b;'s functionality should work out + of the box, this dialog allows to customize and fine-tune + the program. + + + + + + + + + + The <guimenu>Help</guimenu> Menu +&help.menu.documentation; + + + + \ No newline at end of file diff --git a/doc/dcop.docbook b/doc/dcop.docbook new file mode 100644 index 0000000..82b05a6 --- /dev/null +++ b/doc/dcop.docbook @@ -0,0 +1,104 @@ + + The &k3b; &DCOP; Interface + &k3b; features, like many other &kde; applications as well, a + &DCOP; interface which makes it possible to control a part of it's + functionality from ⪚ a shellscript. + To use these &DCOP; functions you can either use the + dcop commandline program or the more convenient + Kdcop application. Both provide the same + functionality so it's mostly a matter of taste and context of usage when + deciding which way to choose. + This chapter assumes that you're using the dcop + commandline program. To access &k3b;'s &DCOP; functions, make sure that + &k3b; is started and then enter something like this at a console: + +# dcop [function] + + + +Besides the generic &DCOP; functions available to all &kde; +applications, &k3b;'s DCOP interface mainly consists of two parts as described below. + + +The default K3bInterface + +The default K3b DCOP interface provides functionality like copyCD, formatDVD, and methods for creating new projects. + + +DCOPRef createDataCDProject() +DCOPRef createAudioCDProject() +DCOPRef createMixedCDProject() +DCOPRef createVideoCDProject() +DCOPRef createMovixCDProject() +DCOPRef createDataDVDProject() +DCOPRef createVideoDVDProject() +DCOPRef createMovixDVDProject() +DCOPRef openProject(KURL url) +QValueList<DCOPRef> projects() +DCOPRef currentProject() +void copyCd() +void copyDvd() +void eraseCdrw() +void formatDvd() +void burnCdImage(KURL url) +void burnDvdImage(KURL url) + + +As result from one of the createXXXProject methods one gets a DCOP reference to the newly created project: + +DCOPRef(k3b,K3bProject-0) + +Alternatively you may create a project using the command line: + + +# k3b --audiocd + + +and then retrieve a reference to this project with + + +# dcop currentProject + + +Using this reference it is possible to manipulate the project using the K3bProjectInterface. + + + + +K3bProjectInterface + + +void addUrls(KURL::List urls) +void addUrl(KURL url) +void burn() + + +K3b offers the K3bProjectInterface as listed above or the more powerful K3bDataProjectInterface which only applies to data projects (CD and DVD): + + +void createFolder(QString name) +void createFolder(QString name,QString parent) +void addUrl(KURL url,QString parent) +void addUrls(KURL::List urls,QString parent) +void removeItem(QString path) +void renameItem(QString path,QString newName) +void setVolumeID(QString id) + + + +Using this it is possible to fill a data project with files and folders from a script. +The following script for example creates a new data project, adds several folders to the project, and adds files to the newly created folders: + + +#!/bin/bash +PROJECT=$(dcop k3b K3bInterface createDataCDProject) +dcop $PROJECT createFolder test +dcop $PROJECT createFolder foo +dcop $PROJECT createFolder bar /foo +dcop $PROJECT addUrl /home/trueg/somefile.txt /foo/bar + + + + + + diff --git a/doc/index.docbook b/doc/index.docbook new file mode 100644 index 0000000..fcb6f96 --- /dev/null +++ b/doc/index.docbook @@ -0,0 +1,340 @@ + +K3b"> +cdrdao"> +DVD+RW-Tools"> +mkisofs"> +cdrecord"> +K3bSetup"> + + + + + + + + +]> + + + + +The &k3b; Handbook + + + + Carsten + Niehaus + + + Jakob + Petsovits + + + + + + + + + 2003-2004 +Carsten Niehaus + + +&FDLNotice; + +2005-06-21 +0.03.00 + + + + + + &k3b; is a CD and DVD burning application for &kde; with a comfortable user interface. + + + + +KDE +kdeextragear +cdrecord +DVD +CD +burning +ripping +iso +K3b + + + + + +Introduction + + + &k3b; is a CD and DVD burning application for Linux systems + optimized for &kde;. It provides a comfortable user interface + to perform most CD/DVD burning tasks like creating an Audio CD + from a set of audio files or copying a CD. + While the experienced user can take influence in all steps + of the burning process, the beginner may find comfort + in the automatic settings and the reasonable &k3b; defaults + which allow a quick start. The actual burning in K3b is done + by the command line utilities + cdrecord, + cdrdao, and + growisofs. + + + + +&k3b-commands; + + + HOWTOs for a quickstart to &k3b; + + &k3b-audiocd-howto; + &k3b-cdcopy-howto; + + + + +&k3b-dcop; + + + +Questions and Answers + + + +&reporting.bugs; +&updating.documentation; + + + + + + Compiling &k3b; fails with undefined type "struct KComboBox". + + + + + The QTDesigner tool uic is not able to find the kde widget plugins. + To solve this run qtconfig and add + $KDEDIR/lib/kde3/plugins to the + plugin search path (replace $KDEDIR with your kde base dir). + + + + + + + + + + + +Credits and License + + +&k3b; + + + Program copyright 1999-2005 Sebastian Trueg trueg@k3b.org + and the K3b team + + +Contributors: + + Thomas Froescher tfroescher@k3b.org + +Christian Kvasny chris@k3b.org + +Klaus-Dieter Krannich kd@k3b.org + + + + + + Documentation Copyright © 2003-2004 Carsten Niehaus cniehaus@kde.org + + + + +&underFDL; + + + +&underGPL; + + + +Installation + + +How to obtain &k3b; + + + + + + The main information site for &k3b; is + www.k3b.org. + For the most current version of &k3b;, feedback and + community help as well as &k3b; news and other information, + this is the place to go. + + + + + +Requirements + + + In order to successfully use &k3b;, you need &kde; >= 3.1 and &Qt; >= 3.1. + + + &cdrdao;: Records audio or data CD-Rs in disk-at-once (DAO) + mode based on a textual description of the CD contents (toc-file). + + + &cdrecord;/&mkisofs;: Records any kind of CD-Rs. &cdrecord; contains all of &cdrdao;'s features and extended functionality and therefore is &k3b;'s standard choice for CD burning. In some cases, &cdrdao; reaches better audio CD burning quality though. + + + &dvdtools;: The &dvdtools; are used to burn and format DVD+R(W) and DVD-R(W) media. + + + + Optionally &k3b; can make use of all these libraries: + + + +cdparanoia: A Compact Disc Digital Audio (CDDA) extraction tool, +commonly known on the net as a 'ripper'. + + + +Ogg Vorbis library: Ogg Vorbis is a completely open, patent-free, +professional audio encoding and streaming technology with all the benefits +of Open Source, and in direct competition with the MP3 format. +Used by the Ogg Vorbis Decoder and Encoder plugins. + + + +MAD (MPEG Audio Decoder) Library: A high-quality MPEG audio decoder, +supporting the MPEG-1, MPEG-2 and MPEG 2.5 formats. All three audio +layers Layer I, Layer II, and Layer III (i.e. MP3) are fully implemented. +Used by the MP3 Decoder plugin. + + + +LAME: A highly evolved MP3 encoder, with quality and speed able to rival +state of the art commercial encoders. Used by the MP3 Encoder plugin. + + + +FLAC: A free, open source codec for lossless audio compression and +decompression. Used by the FLAC Decoder plugin and the +External Audio Encoder plugin, so you can read and write FLAC files. + + + +Libsndfile, FFmpeg, FLAC, Musepack decoders: Other libraries for processing a +broad range of audio file formats. For example, with FFmpeg it is possible to +decode WMA files in order to burn them onto audio CDs. +Used by the respective plugins. + + + +SoX: A utility that can convert between various audio file formats. +Used by the SoX Audio Encoder plugin. + + + +transcode: A Linux text-console utility for video stream processing. +You need this if you want to rip DVD video. + + + +VCDImager: A full-featured mastering suite for authoring, +disassembling and analyzing Video CDs and Super Video CDs. + + + +Normalize: A tool for adjusting the volume of audio files to a standard level. +This is useful for things like creating mixed CDs and MP3 collections, where +different recording levels on different albums can cause the volume to vary +greatly from song to song. + + + +eMovix: A tiny Linux distribution that is burned on CD together with video +files. eMovix contains all the software to boot from a CD and automatically +play every video file localized in the CD root. + + + + +You can find a list of changes to &k3b; at http://www.k3b.org. + + + + +Compilation and Installation + + + + + +&install.compile.documentation; + + + + + +&documentation.index; + + + diff --git a/doc/select_audiofiles.png b/doc/select_audiofiles.png new file mode 100644 index 0000000..b50a8a9 Binary files /dev/null and b/doc/select_audiofiles.png differ diff --git a/doc/select_project.png b/doc/select_project.png new file mode 100644 index 0000000..9cedf35 Binary files /dev/null and b/doc/select_project.png differ diff --git a/k3b.lsm b/k3b.lsm new file mode 100644 index 0000000..ad825b8 --- /dev/null +++ b/k3b.lsm @@ -0,0 +1,14 @@ +Begin3 +Title: K3b +Version: 1.0 +Entered-date: +Description: CD writing software for KDE 3.2 and above +Keywords: CD-Writing, Ripping, CD-Audio, CDDA +Author: Sebastian Trueg +Maintained-by: Sebastian Trueg +Primary-site: +Home-page: http://www.k3b.org +Original-site: +Platforms: Linux +Copying-policy: GNU Public License +End diff --git a/k3bsetup/Makefile.am b/k3bsetup/Makefile.am new file mode 100644 index 0000000..42d3bee --- /dev/null +++ b/k3bsetup/Makefile.am @@ -0,0 +1,18 @@ +AM_CPPFLAGS = -I$(srcdir)/../src -I$(srcdir)/../libk3b/core -I$(srcdir)/../libk3b/tools -I$(srcdir)/../libk3bdevice $(all_includes) + +METASOURCES = AUTO + +# Install this plugin in the KDE modules directory +kde_module_LTLIBRARIES = kcm_k3bsetup2.la + +kcm_k3bsetup2_la_SOURCES = base_k3bsetup2.ui k3bsetup2.cpp +kcm_k3bsetup2_la_LIBADD = $(LIB_KDEUI) ../libk3b/libk3b.la +kcm_k3bsetup2_la_LDFLAGS = -module -avoid-version $(all_libraries) -no-undefined + +k3bsetup2_DATA = k3bsetup2.desktop +k3bsetup2dir = $(kde_appsdir)/Settings/System + +bin_SCRIPTS = k3bsetup + +messages: rc.cpp + $(XGETTEXT) *.cpp -o $(podir)/k3bsetup.pot diff --git a/k3bsetup/base_k3bsetup2.ui b/k3bsetup/base_k3bsetup2.ui new file mode 100644 index 0000000..05af5fd --- /dev/null +++ b/k3bsetup/base_k3bsetup2.ui @@ -0,0 +1,380 @@ + +base_K3bSetup2 + + + Form1 + + + + 0 + 0 + 500 + 450 + + + + + unnamed + + + 0 + + + + layout6 + + + + unnamed + + + + groupBox3 + + + Settings + + + + unnamed + + + + layout1 + + + + unnamed + + + + m_checkUseBurningGroup + + + Use burning group: + + + <p>If this option is checked, only the users in the specified group will be able to burn CDs and DVDs, since only they will have access to the devices and the CD recording programs used by K3b.</p> +<p>Otherwise all users on the system have access to the devices and to all K3b functionality. + + + + + m_editBurningGroup + + + false + + + burning + + + + + + + layout2 + + + + unnamed + + + + spacer1 + + + Horizontal + + + Fixed + + + + 20 + 10 + + + + + + textLabel2 + + + Users allowed to burn (separated by space): + + + + + m_editUsers + + + false + + + + + + + + + groupBox1 + + + Devices + + + + unnamed + + + + textLabel1_2 + + + Check the devices whose permissions you want to be changed + + + + + + Device + + + true + + + true + + + + + Devicenode + + + true + + + true + + + + + Permissions + + + true + + + true + + + + + New Permissions + + + true + + + true + + + + m_viewDevices + + + + + layout3 + + + + unnamed + + + + spacer2 + + + Horizontal + + + Expanding + + + + 40 + 20 + + + + + + m_buttonAddDevice + + + Add Device... + + + + + + + + + groupBox2 + + + External Programs + + + + unnamed + + + + tabWidget2 + + + + tab + + + Found Programs + + + + unnamed + + + + textLabel1 + + + Check the programs whose permissions you want to be changed + + + + + + Program + + + true + + + true + + + + + Version + + + true + + + true + + + + + Path + + + true + + + true + + + + + Permissions + + + true + + + true + + + + + New Permissions + + + true + + + true + + + + m_viewPrograms + + + + + + + tab + + + Search Path + + + + unnamed + + + + m_editSearchPath + + + Search Path + + + false + + + + + textLabel1_3 + + + <qt><b>Hint:</b> to force K3b to use another than the default name for the executable specify it in the search path.</qt> + + + + + + + + + + + + + + m_checkUseBurningGroup + toggled(bool) + m_editBurningGroup + setEnabled(bool) + + + m_checkUseBurningGroup + toggled(bool) + m_editUsers + setEnabled(bool) + + + + + klistview.h + klistview.h + keditlistbox.h + klineedit.h + + diff --git a/k3bsetup/k3bsetup b/k3bsetup/k3bsetup new file mode 100644 index 0000000..0851430 --- /dev/null +++ b/k3bsetup/k3bsetup @@ -0,0 +1,20 @@ +# +# $Id: k3bsetup 476230 2005-10-31 23:05:34Z thiago $ +# Copyright (C) 2003 Sebastian Trueg +# +# This file is part of the K3b project. +# Copyright (C) 1998-2003 Sebastian Trueg +# +# 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 2 of the License, or +# (at your option) any later version. +# See the file "COPYING" for the exact licensing terms. +# + + +#!/usr/bin/sh + +#TODO: if kdesu not found and not currently root use kdialog to display an error message + +kdesu kcmshell k3bsetup2 diff --git a/k3bsetup/k3bsetup2.cpp b/k3bsetup/k3bsetup2.cpp new file mode 100644 index 0000000..37c23a1 --- /dev/null +++ b/k3bsetup/k3bsetup2.cpp @@ -0,0 +1,560 @@ +/* + * + * $Id: k3bsetup2.cpp 623771 2007-01-15 13:47:39Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "k3bsetup2.h" +#include "base_k3bsetup2.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + + +static bool shouldRunSuidRoot( K3bExternalBin* bin ) +{ + // + // Since kernel 2.6.8 older cdrecord versions are not able to use the SCSI subsystem when running suid root anymore + // So for we ignore the suid root issue with kernel >= 2.6.8 and cdrecord < 2.01.01a02 + // + // Some kernel version 2.6.16.something again introduced a problem here. Since I do not know the exact version + // and a workaround was introduced in cdrecord 2.01.01a05 just use that version as the first for suid root. + // + // Seems as if cdrdao never had problems with suid root... + // + + if( bin->name() == "cdrecord" ) { + return ( K3b::simpleKernelVersion() < K3bVersion( 2, 6, 8 ) || + bin->version >= K3bVersion( 2, 1, 1, "a05" ) || + bin->hasFeature( "wodim" ) ); + } + else if( bin->name() == "cdrdao" ) { + return true; + } + else if( bin->name() == "growisofs" ) { + // + // starting with 6.0 growiofs raises it's priority using nice(-20) + // BUT: newer kernels have ridiculously low default memorylocked resource limit, which prevents privileged + // users from starting growisofs 6.0 with "unable to anonymously mmap 33554432: Resource temporarily unavailable" + // error message. Until Andy releases a version including a workaround we simply never configure growisofs suid root + return false; // bin->version >= K3bVersion( 6, 0 ); + } + else + return false; +} + + +class K3bSetup2::Private +{ +public: + K3bDevice::DeviceManager* deviceManager; + K3bExternalBinManager* externalBinManager; + + bool changesNeeded; + + QMap listDeviceMap; + QMap deviceListMap; + + QMap listBinMap; + QMap binListMap; + + KConfig* config; +}; + + + +K3bSetup2::K3bSetup2( QWidget *parent, const char *, const QStringList& ) + : KCModule( parent, "k3bsetup" ) +{ + d = new Private(); + d->config = new KConfig( "k3bsetup2rc" ); + + m_aboutData = new KAboutData("k3bsetup2", + "K3bSetup 2", + 0, 0, KAboutData::License_GPL, + "(C) 2003-2007 Sebastian Trueg"); + m_aboutData->addAuthor("Sebastian Trueg", 0, "trueg@k3b.org"); + + setButtons( KCModule::Apply|KCModule::Cancel|KCModule::Ok|KCModule::Default ); + + QHBoxLayout* box = new QHBoxLayout( this ); + box->setAutoAdd(true); + box->setMargin(0); + box->setSpacing( KDialog::spacingHint() ); + + KTextEdit* label = new KTextEdit( this ); + label->setText( "

K3bSetup

" + + i18n("

This simple setup assistant is able to set the permissions needed by K3b in order to " + "burn CDs and DVDs. " + "

It does not take things like devfs or resmgr into account. In most cases this is not a " + "problem but on some systems the permissions may be altered the next time you login or restart " + "your computer. In those cases it is best to consult the distribution documentation." + "

Caution: Although K3bSetup 2 should not be able " + "to mess up your system no guarantee can be given.") ); + label->setReadOnly( true ); + label->setFixedWidth( 200 ); + + w = new base_K3bSetup2( this ); + + // TODO: enable this and let root specify users + w->m_editUsers->hide(); + w->textLabel2->hide(); + + + connect( w->m_checkUseBurningGroup, SIGNAL(toggled(bool)), + this, SLOT(updateViews()) ); + connect( w->m_editBurningGroup, SIGNAL(textChanged(const QString&)), + this, SLOT(updateViews()) ); + connect( w->m_editSearchPath, SIGNAL(changed()), + this, SLOT(slotSearchPrograms()) ); + connect( w->m_buttonAddDevice, SIGNAL(clicked()), + this, SLOT(slotAddDevice()) ); + + + d->externalBinManager = new K3bExternalBinManager( this ); + d->deviceManager = new K3bDevice::DeviceManager( this ); + + // these are the only programs that need special permissions + d->externalBinManager->addProgram( new K3bCdrdaoProgram() ); + d->externalBinManager->addProgram( new K3bCdrecordProgram(false) ); + d->externalBinManager->addProgram( new K3bGrowisofsProgram() ); + + d->externalBinManager->search(); + d->deviceManager->scanBus(); + + load(); + + // + // This is a hack to work around a kcm bug which makes the faulty assumption that + // every module starts without anything to apply + // + QTimer::singleShot( 0, this, SLOT(updateViews()) ); + + if( getuid() != 0 || !d->config->checkConfigFilesWritable( true ) ) + makeReadOnly(); +} + + +K3bSetup2::~K3bSetup2() +{ + delete d->config; + delete d; + delete m_aboutData; +} + + +void K3bSetup2::updateViews() +{ + d->changesNeeded = false; + + updatePrograms(); + updateDevices(); + + emit changed( ( getuid() != 0 ) ? false : d->changesNeeded ); +} + + +void K3bSetup2::updatePrograms() +{ + // first save which were checked + QMap checkMap; + QListViewItemIterator listIt( w->m_viewPrograms ); + for( ; listIt.current(); ++listIt ) + checkMap.insert( d->listBinMap[(QCheckListItem*)*listIt], ((QCheckListItem*)*listIt)->isOn() ); + + w->m_viewPrograms->clear(); + d->binListMap.clear(); + d->listBinMap.clear(); + + // load programs + const QMap& map = d->externalBinManager->programs(); + for( QMap::const_iterator it = map.begin(); it != map.end(); ++it ) { + K3bExternalProgram* p = it.data(); + + QPtrListIterator binIt( p->bins() ); + for( ; binIt.current(); ++binIt ) { + K3bExternalBin* b = *binIt; + + QFileInfo fi( b->path ); + // we need the uid bit which is not supported by QFileInfo + struct stat s; + if( ::stat( QFile::encodeName(b->path), &s ) ) { + kdDebug() << "(K3bSetup2) unable to stat " << b->path << endl; + } + else { + // create a checkviewitem + QCheckListItem* bi = new QCheckListItem( w->m_viewPrograms, b->name(), QCheckListItem::CheckBox ); + bi->setText( 1, b->version ); + bi->setText( 2, b->path ); + + d->listBinMap.insert( bi, b ); + d->binListMap.insert( b, bi ); + + // check the item on first insertion or if it was checked before + bi->setOn( checkMap.contains(b) ? checkMap[b] : true ); + + int perm = s.st_mode & 0007777; + + QString wantedGroup("root"); + if( w->m_checkUseBurningGroup->isChecked() ) + wantedGroup = burningGroup(); + + int wantedPerm = 0; + if( shouldRunSuidRoot( b ) ) { + if( w->m_checkUseBurningGroup->isChecked() ) + wantedPerm = 0004710; + else + wantedPerm = 0004711; + } + else { + if( w->m_checkUseBurningGroup->isChecked() ) + wantedPerm = 0000750; + else + wantedPerm = 0000755; + } + + bi->setText( 3, QString::number( perm, 8 ).rightJustify( 4, '0' ) + " " + fi.owner() + "." + fi.group() ); + if( perm != wantedPerm || + fi.owner() != "root" || + fi.group() != wantedGroup ) { + bi->setText( 4, QString("%1 root.%2").arg(wantedPerm,0,8).arg(wantedGroup) ); + if( bi->isOn() ) + d->changesNeeded = true; + } + else + bi->setText( 4, i18n("no change") ); + } + } + } +} + + +void K3bSetup2::updateDevices() +{ + // first save which were checked + QMap checkMap; + QListViewItemIterator listIt( w->m_viewDevices ); + for( ; listIt.current(); ++listIt ) + checkMap.insert( d->listDeviceMap[(QCheckListItem*)*listIt], ((QCheckListItem*)*listIt)->isOn() ); + + w->m_viewDevices->clear(); + d->listDeviceMap.clear(); + d->deviceListMap.clear(); + + QPtrListIterator it( d->deviceManager->allDevices() ); + for( ; it.current(); ++it ) { + K3bDevice::Device* device = *it; + // check the item on first insertion or if it was checked before + QCheckListItem* item = createDeviceItem( device->blockDeviceName() ); + item->setOn( checkMap.contains(device->blockDeviceName()) ? checkMap[device->blockDeviceName()] : true ); + item->setText( 0, device->vendor() + " " + device->description() ); + + if( !device->genericDevice().isEmpty() ) { + QCheckListItem* item = createDeviceItem( device->genericDevice() ); + item->setOn( checkMap.contains(device->genericDevice()) ? checkMap[device->genericDevice()] : true ); + item->setText( 0, device->vendor() + " " + device->description() + " (" + i18n("Generic SCSI Device") + ")" ); + } + } +} + + +QCheckListItem* K3bSetup2::createDeviceItem( const QString& deviceNode ) +{ + QFileInfo fi( deviceNode ); + struct stat s; + if( ::stat( QFile::encodeName(deviceNode), &s ) ) { + kdDebug() << "(K3bSetup2) unable to stat " << deviceNode << endl; + return 0; + } + else { + // create a checkviewitem + QCheckListItem* bi = new QCheckListItem( w->m_viewDevices, + deviceNode, + QCheckListItem::CheckBox ); + + d->listDeviceMap.insert( bi, deviceNode ); + d->deviceListMap.insert( deviceNode, bi ); + + bi->setText( 1, deviceNode ); + + int perm = s.st_mode & 0000777; + + bi->setText( 2, QString::number( perm, 8 ).rightJustify( 3, '0' ) + " " + fi.owner() + "." + fi.group() ); + if( w->m_checkUseBurningGroup->isChecked() ) { + // we ignore the device's owner here + if( perm != 0000660 || + fi.group() != burningGroup() ) { + bi->setText( 3, "660 " + fi.owner() + "." + burningGroup() ); + if( bi->isOn() ) + d->changesNeeded = true; + } + else + bi->setText( 3, i18n("no change") ); + } + else { + // we ignore the device's owner and group here + if( perm != 0000666 ) { + bi->setText( 3, "666 " + fi.owner() + "." + fi.group() ); + if( bi->isOn() ) + d->changesNeeded = true; + } + else + bi->setText( 3, i18n("no change") ); + } + + return bi; + } +} + + +void K3bSetup2::load() +{ + if( d->config->hasGroup("External Programs") ) { + d->config->setGroup( "External Programs" ); + d->externalBinManager->readConfig( d->config ); + } + if( d->config->hasGroup("Devices") ) { + d->config->setGroup( "Devices" ); + d->deviceManager->readConfig( d->config ); + } + + d->config->setGroup( "General Settings" ); + w->m_checkUseBurningGroup->setChecked( d->config->readBoolEntry( "use burning group", false ) ); + w->m_editBurningGroup->setText( d->config->readEntry( "burning group", "burning" ) ); + + + // load search path + w->m_editSearchPath->clear(); + w->m_editSearchPath->insertStringList( d->externalBinManager->searchPath() ); + + updateViews(); +} + + +void K3bSetup2::defaults() +{ + w->m_checkUseBurningGroup->setChecked(false); + w->m_editBurningGroup->setText( "burning" ); + + // + // This is a hack to work around a kcm bug which makes the faulty assumption that + // every module defaults to a state where nothing is to be applied + // + QTimer::singleShot( 0, this, SLOT(updateViews()) ); +} + + +void K3bSetup2::save() +{ + d->config->setGroup( "General Settings" ); + d->config->writeEntry( "use burning group", w->m_checkUseBurningGroup->isChecked() ); + d->config->writeEntry( "burning group", burningGroup() ); + d->config->setGroup( "External Programs"); + d->externalBinManager->saveConfig( d->config ); + d->config->setGroup( "Devices"); + d->deviceManager->saveConfig( d->config ); + + + bool success = true; + + struct group* g = 0; + if( w->m_checkUseBurningGroup->isChecked() ) { + // TODO: create the group if it's not there + g = getgrnam( burningGroup().local8Bit() ); + if( !g ) { + KMessageBox::error( this, i18n("There is no group %1.").arg(burningGroup()) ); + return; + } + } + + + // save the device permissions + QListViewItemIterator listIt( w->m_viewDevices ); + for( ; listIt.current(); ++listIt ) { + + QCheckListItem* checkItem = (QCheckListItem*)listIt.current(); + + if( checkItem->isOn() ) { + QString dev = d->listDeviceMap[checkItem]; + + if( w->m_checkUseBurningGroup->isChecked() ) { + if( ::chmod( QFile::encodeName(dev), S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP ) ) + success = false; + + if( ::chown( QFile::encodeName(dev), (gid_t)-1, g->gr_gid ) ) + success = false; + } + else { + if( ::chmod( QFile::encodeName(dev), S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH ) ) + success = false; + } + } + } + + + // save the program permissions + listIt = QListViewItemIterator( w->m_viewPrograms ); + for( ; listIt.current(); ++listIt ) { + + QCheckListItem* checkItem = (QCheckListItem*)listIt.current(); + + if( checkItem->isOn() ) { + + K3bExternalBin* bin = d->listBinMap[checkItem]; + + if( w->m_checkUseBurningGroup->isChecked() ) { + if( ::chown( QFile::encodeName(bin->path), (gid_t)0, g->gr_gid ) ) + success = false; + + int perm = 0; + if( shouldRunSuidRoot( bin ) ) + perm = S_ISUID|S_IRWXU|S_IXGRP; + else + perm = S_IRWXU|S_IXGRP|S_IRGRP; + + if( ::chmod( QFile::encodeName(bin->path), perm ) ) + success = false; + } + else { + if( ::chown( QFile::encodeName(bin->path), 0, 0 ) ) + success = false; + + int perm = 0; + if( shouldRunSuidRoot( bin ) ) + perm = S_ISUID|S_IRWXU|S_IXGRP|S_IXOTH; + else + perm = S_IRWXU|S_IXGRP|S_IRGRP|S_IXOTH|S_IROTH; + + if( ::chmod( QFile::encodeName(bin->path), perm ) ) + success = false; + } + } + } + + + if( success ) + KMessageBox::information( this, i18n("Successfully updated all permissions.") ); + else { + if( getuid() ) + KMessageBox::error( this, i18n("Could not update all permissions. You should run K3bSetup 2 as root.") ); + else + KMessageBox::error( this, i18n("Could not update all permissions.") ); + } + + // WE MAY USE "newgrp -" to reinitialize the environment if we add users to a group + + updateViews(); +} + + +QString K3bSetup2::quickHelp() const +{ + return i18n("

K3bSetup 2

" + "

This simple setup assistant is able to set the permissions needed by K3b in order to " + "burn CDs and DVDs." + "

It does not take into account devfs or resmgr, or similar. In most cases this is not a " + "problem, but on some systems the permissions may be altered the next time you login or restart " + "your computer. In these cases it is best to consult the distribution's documentation." + "

The important task that K3bSetup 2 performs is grant write access to the CD and DVD devices." + "

Caution: Although K3bSetup 2 should not be able " + "to damage your system, no guarantee can be given."); +} + + +QString K3bSetup2::burningGroup() const +{ + QString g = w->m_editBurningGroup->text(); + return g.isEmpty() ? QString("burning") : g; +} + + +void K3bSetup2::slotSearchPrograms() +{ + d->externalBinManager->setSearchPath( w->m_editSearchPath->items() ); + d->externalBinManager->search(); + updatePrograms(); + + emit changed( d->changesNeeded ); +} + + +void K3bSetup2::slotAddDevice() +{ + bool ok; + QString newDevicename = KInputDialog::getText( i18n("Location of New Drive"), + i18n("Please enter the device name where K3b should search\n" + "for a new drive (example: /dev/mebecdrom):"), + "/dev/", &ok, this ); + + if( ok ) { + if( d->deviceManager->addDevice( newDevicename ) ) { + updateDevices(); + + emit changed( d->changesNeeded ); + } + else + KMessageBox::error( this, i18n("Could not find an additional device at\n%1").arg(newDevicename), + i18n("Error"), false ); + } +} + +void K3bSetup2::makeReadOnly() +{ + w->m_checkUseBurningGroup->setEnabled( false ); + w->m_editBurningGroup->setEnabled( false ); + w->m_editUsers->setEnabled( false ); + w->m_viewDevices->setEnabled( false ); + w->m_buttonAddDevice->setEnabled( false ); + w->m_viewPrograms->setEnabled( false ); + w->m_editSearchPath->setEnabled( false ); +} + + +typedef KGenericFactory K3bSetup2Factory; +K_EXPORT_COMPONENT_FACTORY( kcm_k3bsetup2, K3bSetup2Factory("k3bsetup") ) + + +#include "k3bsetup2.moc" diff --git a/k3bsetup/k3bsetup2.desktop b/k3bsetup/k3bsetup2.desktop new file mode 100644 index 0000000..5f73b03 --- /dev/null +++ b/k3bsetup/k3bsetup2.desktop @@ -0,0 +1,148 @@ +[Desktop Entry] +Encoding=UTF-8 +Comment=K3bSetup 2 - modify permission for CD/DVD burning with K3b +Comment[af]=K3bSetup 2 - verander regte vir CD/DVD skryf met K3b +Comment[ar]= اعداد K3B 2 - غيًر الصلاحيات (الاذون ) كي تستطيع كتابة الاقراص المدمجة (CD) او الاقراص المرئية الرقمية (DVD) بواسطة K3B +Comment[bg]=Настройване на K3b (2) - промяна на правата за запис на CD/DVD с K3b +Comment[bn]=কে-থ্রি-বি ব্যবস্থাপনা ২ - কে-থ্রি-বি দিয়ে সিডি/ডিভিডি লিখনের জন্য অনুমতি পরিবর্তন করে +Comment[bs]=K3bSetup 2 - promijenite privilegije za CD/DVD prženje sa K3b-om +Comment[ca]=K3bSetup 2 - modifica els permisos per a cremar CD i DVD amb K3b +Comment[cs]=K3bSetup 2 - změna oprávnění pro vypalování CD/DVD s K3b +Comment[da]=K3bSetup 2 - ændring af tilladelser for cd/dvd-brænding med K3b +Comment[de]=K3b Einrichtungsassistent - Zugriffsrechte zum Brennen mit K3b anpassen +Comment[el]=Ρύθμιση K3b 2 - τροποποίηση δικαιωμάτων για εγγραφή CD/DVD με το K3b +Comment[eo]=K3bAgordo 2 - ŝanĝu rajtojn por KD/DVD enskribo per K3b +Comment[es]=K3bSetup 2 - modifica los permisos para la grabación de CD o DVD con K3b +Comment[et]=K3b seadistamine - võimalus muuta õigusi CD/DVD kirjutamiseks K3b-ga +Comment[fa]=K3bSetup 2 - تغییر مجوز برای سوزاندن دیسک فشرده/دی وی دی با K3b +Comment[fi]=K3bSetup 2 - aseta K3b:n poltto-oikeudet +Comment[fr]=K3bSetup 2 - Modification des permissions pour la gravure de CD / DVD avec K3b +Comment[gl]=K3bSetup 2 - modifica os permisos para gravar CDs/DVDs con K3b +Comment[he]=K3bSetup 2 - שינוי הרשאות עבור צריבת תקליטורי CD/DVD עם K3b +Comment[hi]=के3बी-सेटअप 2 - के3बी के साथ सीडी/डीवीडी बर्निंग हेतु आज्ञाएँ परिवर्धित करें +Comment[hu]=K3bSetup 2 - jogosultságbeállítás CD/DVD-íráshoz a K3b-ben +Comment[is]=K3b uppsetning 2 - breyta aðgangsheimildum á CD/DVD skrifun með K3b +Comment[it]=Impostazioni di K3b 2 - modifica i permessi per CD/DVD per scrivere con K3b +Comment[ja]=K3bSetup 2 - K3b で CD/DVD に書き込むための権限を設定 +Comment[ka]=K3bSetup 2 - K3b-ით CD/DVD-ის ჩაწერის უფლების შეცვლა +Comment[km]=K3bSetup 2 - កែប្រែ​សិទ្ធិ​ដើម្បី​ដុត​ស៊ីឌី ឬ ឌីវីឌី​​ដោយ​ប្រើ K3b +Comment[lt]=K3bSetup 2 – pakeiskite leidimus CD/DVD kūrimui su K3b +Comment[mk]=K3bSetup 2 - менување на дозволите за снимање на CD/DVD со K3b +Comment[ms]=K3bSetup2 - mengubahsuai kebenaran untuk membakar CD/DVD dengan K3b +Comment[nb]=K3bSetup 2 – endre tillatelser for CD-/DVD-brenning med K3b +Comment[nds]=K3b-Inrichthölper - Verlöven för't Brennen vun CD/DVD mit K3b ännern +Comment[ne]=K3bSetup 2 - ले K3b सँग सीडी/डीभीडी बर्निङका लागि अनुमति परिमार्जन गर्दछ +Comment[nl]=K3bSetup 2 - stelt de toegangsrechten in voor cd/dvd-branden met K3b +Comment[nn]=K3b-oppsett 2 – endra løyve for CD- og DVD-brenning med K3b +Comment[pa]=K3bSetup 2 - K3b ਨਾਲ CD/DVD ਲਿਖਣ ਲਈ ਅਧਿਕਾਰ ਸੋਧ +Comment[pl]=K3bSetup 2 - modyfikacja uprawnień do nagrywania płyt CD/DVD za pomocą K3b +Comment[pt]=K3bSetup 2 - modificar as permissões para a gravação de CDs/DVDs com o K3b +Comment[pt_BR]=Configurações Avançadas do K3b - modificar as permissões para a queima de CD/DVD com o K3b +Comment[ru]=K3bSetup 2 - настроить права для записи при помощи K3b +Comment[sk]=K3bSetup 2 - zmena práv pre napaľovanie CD/DVD s K3b +Comment[sl]=K3bSetup - spremeni dovoljenja za pisanje CD/DVD-jev s K3b +Comment[sr]=K3bSetup 2 — мења дозволе за резање CD/DVD-а помоћу K3b-а +Comment[sr@Latn]=K3bSetup 2 — menja dozvole za rezanje CD/DVD-a pomoću K3b-a +Comment[sv]=Ställ in K3b 2: ändra rättigheter för att bränna cd/dvd med K3b +Comment[ta]= K3bஅமைவு2 - K3b ஐ CD/DVD களோடு எழுதுவதற்காக அனுமதி மாற்றுவதற்காக +Comment[tg]=K3bSetup 2 - танзим кардани иҷозат барои сабт бо ёрии K3b +Comment[tr]=K3bSetup 2 - K3b ile CD/DVD kaydetme izinlerini ayarlama +Comment[uk]=K3bSetup 2 - зміна прав доступу для запису КД/DVD за допомогою K3b +Comment[uz]=K3bSetup 2 - K3b yordamida CD/DVD'ga yozish huquqini moslash +Comment[uz@cyrillic]=K3bSetup 2 - K3b ёрдамида CD/DVD'га ёзиш ҳуқуқини мослаш +Comment[zh_CN]=K3b 设置 2 - 修改使用 K3b 烧录 CD/DVD 的权限 +Comment[zh_TW]=K3bSetup 2 - 為 K3b 燒錄 CD/DVD 修改權限 +Exec=k3bsetup +Keywords=K3bSetup2,k3bsetup2 +Keywords[ar]=اعداد K3b , K3b2 +Keywords[bg]=K3bSetup2,k3bsetup2,Настройване на K3b (2) +Keywords[de]=K3b, Einrichtungsassistent, Rechte +Keywords[el]=Ρύθμιση K3b 2,k3bsetup2 +Keywords[eo]=K3bAgordo2,k3bagordo2 +Keywords[et]=K3bSetup2,k3bsetup2,k3b seadistamine +Keywords[hi]=के3बी-सेटअप 2,के3बी-सेटअप2 +Keywords[nds]=K3bSetup2,k3bsetup2,K3b-Inrichthölper +Keywords[nl]=K3bSetup2,k3bsetup2,branden,cd branden,dvd,dvd branden +Keywords[nn]=K3b-oppsett 2,k3b-oppsett 2 +Keywords[pl]=K3bSetup2,k3bsetup2,k3b,ustawienia,uprawnienia +Keywords[pt_BR]=Configurações Avançadas do K3b,configurações avançadas do K3b +Keywords[sv]=Ställ in K3b 2,k3bsetup2 +Keywords[ta]=K3bஅமைவு2,K3bஅமைவு2 +Keywords[tg]=ТанзимиK3b2,танзимиk3b2 +Keywords[uz]=K3bSetup2,k3bsetup2,CD,kompakt-disk +Keywords[uz@cyrillic]=K3bSetup2,k3bsetup2,CD,компакт-диск +Name=K3bSetup +Name[ar]= اعداد K3b +Name[bg]=Настройване на K3b +Name[bn]=কে-থ্রি-বি ব্যবস্থাপনা +Name[de]=K3b Einrichtungsassistent +Name[eo]=K3bAgordo +Name[et]=K3b seadistamine +Name[hi]=के3बी-सेटअप +Name[is]=K3b uppsetning +Name[it]=Impostazioni di K3b +Name[nds]=K3b-Inrichthölper +Name[nn]=K3b-oppsett +Name[pa]=K3b-ਸੈੱਟਅੱਪ +Name[pt_BR]=Configurar K3b +Name[sv]=Ställ in K3b +Name[ta]=K3b அமைவு +Name[tg]=ТанзимиK3b +Name[zh_TW]=K3b 設定 +Terminal=false +Type=Application +Icon=k3b +X-KDE-FactoryName=k3bsetup2 +X-KDE-Library=k3bsetup2 +X-KDE-ModuleType=Library +X-KDE-RootOnly=true +Categories=Application;System;X-KDE-System; +GenericName=CD & DVD Burning Setup +GenericName[af]=CD & DVD Skryf Opstelling +GenericName[ar]=العام اعداد كتابة القرص المدمج (CD) و القرص المرئي الرقمي (DVD) +GenericName[bg]=Настройване записа на CD и DVD +GenericName[bn]=সিডি এবং ডিভিডি লিখন ব্যবস্থাপনা +GenericName[ca]=Programa per gravar CDs i DVDs +GenericName[cs]=Nastavení vypalování CD a DVD +GenericName[da]=Cd & dvd opsætning til brænding +GenericName[de]=CD & DVD-Brennen einrichten +GenericName[el]=Ρύθμιση εγγραφής CD & DVD +GenericName[eo]=KD & DVD Enskriba agordo +GenericName[es]=Configurar grabación de CD y DVD +GenericName[et]=CD ja DVD kirjutamise seadistamine +GenericName[fa]=برپایی سوزاندن دیسک فشرده و دی وی دی +GenericName[fi]=K3b-poltto-ohjelman asetusten määritys +GenericName[fr]=Configuration de la gravure de CD et de DVD +GenericName[gl]=Configurazón da Grabazón de CDs e DVDs +GenericName[hu]=CD- és DVD-írási beállítások +GenericName[is]=Uppsetning á CD og DVD brennslu +GenericName[it]=Impostazioni di masterizzazione CD e DVD +GenericName[ja]=CD / DVD 作成の設定 +GenericName[ka]=CD-ის და DVD-ის ჩაწერის გამართვა +GenericName[km]=រៀបចំ​ការ​ដុត​ស៊ីឌី & ឌីវីឌី +GenericName[lt]=CD & DVD kūrimo parinktys +GenericName[mk]=Поставувања за снимање на CD и DVD +GenericName[ms]=Tetapan Membakar CD & DVD +GenericName[nb]=Oppsett av CD- og DVD-brenning +GenericName[nds]=Brennen vun CD & DVD instellen +GenericName[ne]=सीडी र डीभीडी बर्निङ सेटअप +GenericName[nl]=CD- en dvd-branden instellen +GenericName[nn]=Oppsett av CD- og DVD-brenning +GenericName[pa]=CD & DVD ਲਿਖਣ ਸੈਟਅੱਪ +GenericName[pl]=Konfiguracja nagrywania płyt CD i DVD +GenericName[pt]=Configuração da Gravação de CDs e DVDs +GenericName[pt_BR]=Configuração da Queima de CD & DVD +GenericName[ru]=Настройка записи CD и DVD +GenericName[sk]=Nastavenie CD & DVD napaľovania +GenericName[sl]=Nastavitve za pisanje CD-jev in DVD-jev +GenericName[sr]=Подешавање резања CD-а и DVD-а +GenericName[sr@Latn]=Podešavanje rezanja CD-a i DVD-a +GenericName[sv]=Cd och dvd-bränninställning +GenericName[ta]=சிடி & DVD நகல் எடுக்கும் அமைப்பு +GenericName[tg]=Танзимоти сабткунии CD ва DVD +GenericName[tr]=CD ve DVD Kaydetme Kurulumu +GenericName[uk]=Налажтування запису КД та DVD +GenericName[uz]=CD va DVD diskka yozishni moslash +GenericName[uz@cyrillic]=CD ва DVD дискка ёзишни мослаш +GenericName[zh_CN]=CD & DVD 刻录程序设置 +GenericName[zh_TW]=CD & DVD 燒錄設定 diff --git a/k3bsetup/k3bsetup2.h b/k3bsetup/k3bsetup2.h new file mode 100644 index 0000000..ea86664 --- /dev/null +++ b/k3bsetup/k3bsetup2.h @@ -0,0 +1,65 @@ +/* + * + * $Id: k3bsetup2.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3BSETUP2_H_ +#define _K3BSETUP2_H_ + +#include +#include + + +class base_K3bSetup2; +class QCheckListItem; + + +class K3bSetup2: public KCModule +{ + Q_OBJECT + + public: + K3bSetup2( QWidget* parent = 0, const char* name = 0, const QStringList& args = QStringList() ); + ~K3bSetup2(); + + QString quickHelp() const; + const KAboutData* aboutData() { return m_aboutData; }; + + void load(); + void save(); + void defaults(); + + public slots: + void updateViews(); + + private slots: + void slotSearchPrograms(); + void slotAddDevice(); + + private: + void updatePrograms(); + void updateDevices(); + QString burningGroup() const; + void makeReadOnly(); + QCheckListItem* createDeviceItem( const QString& deviceNode ); + + class Private; + Private* d; + + base_K3bSetup2* w; + + KAboutData* m_aboutData; +}; + +#endif diff --git a/kfile-plugins/Makefile.am b/kfile-plugins/Makefile.am new file mode 100644 index 0000000..c1ba442 --- /dev/null +++ b/kfile-plugins/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = k3bproject \ No newline at end of file diff --git a/kfile-plugins/k3bproject/Makefile.am b/kfile-plugins/k3bproject/Makefile.am new file mode 100644 index 0000000..d229c41 --- /dev/null +++ b/kfile-plugins/k3bproject/Makefile.am @@ -0,0 +1,27 @@ +AM_CPPFLAGS = -I$(srcdir)/../../libk3b/core \ + -I$(srcdir)/../../libk3b/core \ + -I$(srcdir)/../../libk3b/plugin \ + -I$(srcdir)/../../libk3b/tools \ + -I$(srcdir)/../../libk3b/projects \ + -I$(srcdir)/../../libk3b/projects/datacd \ + -I$(srcdir)/../../libk3bdevice \ + -I$(srcdir)/../../src/projects \ + $(all_includes) + +# these are the headers for your project +noinst_HEADERS = kfile_k3bprojectfileplugin.h + +kde_module_LTLIBRARIES = kfile_k3b.la + +kfile_k3b_la_SOURCES = kfile_k3bprojectfileplugin.cpp +kfile_k3b_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kfile_k3b_la_LIBADD = $(LIB_KIO) ../../libk3b/libk3b.la ../../src/projects/kostore/libkostore.la + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +services_DATA = kfile_k3b.desktop +servicesdir = $(kde_servicesdir) + +messages: + $(XGETTEXT) *.cpp -o $(podir)/kfile_k3b.pot diff --git a/kfile-plugins/k3bproject/kfile_k3b.desktop b/kfile-plugins/k3bproject/kfile_k3b.desktop new file mode 100644 index 0000000..b0156d0 --- /dev/null +++ b/kfile-plugins/k3bproject/kfile_k3b.desktop @@ -0,0 +1,53 @@ +[Desktop Entry] +Encoding=UTF-8 +Type=Service +Name=K3b Project Info +Name[af]=K3b Projek Informasie +Name[ar]= معلومات عن مشروع K3B +Name[bg]=Информация за K3b проект +Name[bn]=কে-থ্রি-বি প্রকল্প তথ্য +Name[br]=Titouroù raktres K3b +Name[ca]=Informació sobre el projecte de K3b +Name[cs]=Info o K3b projektu +Name[da]=K3b Projektinformation +Name[de]=K3b Projektinformationen +Name[el]=Πληροφορίες έργου K3b +Name[eo]=K3b projekta informo +Name[es]=Información de proyecto K3b +Name[et]=K3b projekti info +Name[fa]= اطلاعات پروژۀ K3b +Name[fi]=K3b-projektin kuvaus +Name[fr]=Information sur le projet K3b +Name[ga]=Eolas faoin Tionscadal K3b +Name[gl]=Informazón de Proxecto K3b +Name[hu]=K3b-projektinformáció +Name[is]=K3b verkefnisupplýsingar +Name[it]=Informazioni progetto K3b +Name[ja]=K3b プロジェクト情報 +Name[km]=ព័ត៌មាន​របស់​​គម្រោង K3b +Name[lt]=K3b projekto informacija +Name[mk]=Информации за проект од K3b +Name[nb]=K3b-prosjektinformasjon +Name[nds]=K3b-Projektinformatschonen +Name[nl]=K3b-projectinformatie +Name[nn]=K3b-prosjektinfo +Name[pa]=K3b ਪ੍ਰੋਜੈੱਕਟ ਜਾਣਕਾਰੀ +Name[pl]=Informacja dla projektu K3b +Name[pt]=Informação do Projecto do K3b +Name[pt_BR]=Informações do Projeto do K3b +Name[ru]=Свдения о проекте K3b +Name[sk]=K3b informácie o projekte +Name[sr]=Инфо о K3b пројекту +Name[sr@Latn]=Info o K3b projektu +Name[sv]=K3b-projektinformation +Name[tr]=K3b Proje Bilgisi +Name[uk]=Інформація проекту K3b +Name[uz]=K3b loyihasi haqida maʼlumot +Name[uz@cyrillic]=K3b лойиҳаси ҳақида маълумот +Name[zh_CN]=K3b 方案信息 +Name[zh_TW]=K3b 專案資訊 +ServiceTypes=KFilePlugin +X-KDE-Library=kfile_k3b +MimeType=application/x-k3b +PreferredGroups=General +PreferredItems=documenttype diff --git a/kfile-plugins/k3bproject/kfile_k3bprojectfileplugin.cpp b/kfile-plugins/k3bproject/kfile_k3bprojectfileplugin.cpp new file mode 100644 index 0000000..b868c94 --- /dev/null +++ b/kfile-plugins/k3bproject/kfile_k3bprojectfileplugin.cpp @@ -0,0 +1,135 @@ +/* + * + * $Id: sourceheader,v 1.3 2005/01/19 13:03:46 trueg Exp $ + * Copyright (C) 2005 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include + +#include "kfile_k3bprojectfileplugin.h" +#include "kostore/koStore.h" +#include "kostore/koStoreDevice.h" + +#include + +#include + +#include +#include +#include + + + +K_EXPORT_COMPONENT_FACTORY(kfile_k3b, KGenericFactory("kfile_k3b")) + + +K3bProjectFilePlugin::K3bProjectFilePlugin( QObject *parent, const char *name, + const QStringList &args) + : KFilePlugin(parent, name, args) +{ + KFileMimeTypeInfo* info = addMimeTypeInfo( "application/x-k3b" ); + + KFileMimeTypeInfo::GroupInfo* group = addGroupInfo( info, "General", i18n("General") ); + + addItemInfo( group, "documenttype", i18n("Document Type"), QVariant::String ); +} + + +bool K3bProjectFilePlugin::readInfo( KFileMetaInfo& info, uint /*what*/) +{ + if( !info.url().isLocalFile() ) { + kdDebug() << "(K3bProjectFilePluginInfo) no local file." << endl; + return false; + } + + // open the file + bool success = false; + QDomDocument xmlDoc; + + // try opening a store + KoStore* store = KoStore::createStore( info.url().path(), KoStore::Read ); + if( store && !store->bad() && store->open( "maindata.xml" ) ) { + QIODevice* dev = store->device(); + dev->open( IO_ReadOnly ); + if( xmlDoc.setContent( dev ) ) + success = true; + dev->close(); + store->close(); + } + else + kdDebug() << "(K3bProjectFilePluginInfo) failed to open the store." << endl; + + if( success ) { + // check the documents DOCTYPE + K3bDoc::DocType type = K3bDoc::AUDIO; + if( xmlDoc.doctype().name() == "k3b_audio_project" ) + type = K3bDoc::AUDIO; + else if( xmlDoc.doctype().name() == "k3b_data_project" ) + type = K3bDoc::DATA; + else if( xmlDoc.doctype().name() == "k3b_vcd_project" ) + type = K3bDoc::VCD; + else if( xmlDoc.doctype().name() == "k3b_mixed_project" ) + type = K3bDoc::MIXED; + else if( xmlDoc.doctype().name() == "k3b_movix_project" ) + type = K3bDoc::MOVIX; + else if( xmlDoc.doctype().name() == "k3b_movixdvd_project" ) + type = K3bDoc::MOVIX_DVD; + else if( xmlDoc.doctype().name() == "k3b_dvd_project" ) + type = K3bDoc::DVD; + else if( xmlDoc.doctype().name() == "k3b_video_dvd_project" ) + type = K3bDoc::VIDEODVD; + else { + kdDebug() << "(K3bDoc) unknown doc type: " << xmlDoc.doctype().name() << endl; + success = false; + } + + QString stringType; + switch( type ) { + case K3bDoc::AUDIO: + stringType = i18n("Audio CD"); + break; + case K3bDoc::DATA: + stringType = i18n("Data CD"); + break; + case K3bDoc::MIXED: + stringType = i18n("Mixed Mode CD"); + break; + case K3bDoc::VCD: + stringType = i18n("Video CD"); + break; + case K3bDoc::MOVIX: + stringType = i18n("eMovix CD"); + break; + case K3bDoc::MOVIX_DVD: + stringType = i18n("eMovix DVD"); + break; + case K3bDoc::DVD: + stringType = i18n("Data DVD"); + break; + case K3bDoc::VIDEODVD: + stringType = i18n("Video DVD"); + break; + } + + // and finally display it! + KFileMetaInfoGroup group = appendGroup(info, "General"); + appendItem( group, "documenttype", stringType ); + } + + delete store; + + return success; +} + +#include "kfile_k3bprojectfileplugin.moc" + diff --git a/kfile-plugins/k3bproject/kfile_k3bprojectfileplugin.h b/kfile-plugins/k3bproject/kfile_k3bprojectfileplugin.h new file mode 100644 index 0000000..c90b678 --- /dev/null +++ b/kfile-plugins/k3bproject/kfile_k3bprojectfileplugin.h @@ -0,0 +1,37 @@ +/* + * + * $Id: sourceheader,v 1.3 2005/01/19 13:03:46 trueg Exp $ + * Copyright (C) 2005 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef __KFILE_K3BPROJECTFILEPLUGIN_H__ +#define __KFILE_K3BPROJECTFILEPLUGIN_H__ + +/** + * Note: For further information look into <$KDEDIR/include/kfilemetainfo.h> + */ +#include + +class QStringList; + +class K3bProjectFilePlugin: public KFilePlugin +{ + Q_OBJECT + + public: + K3bProjectFilePlugin( QObject *parent, const char *name, const QStringList& args ); + + virtual bool readInfo( KFileMetaInfo& info, uint what); +}; + +#endif + diff --git a/kioslaves/Makefile.am b/kioslaves/Makefile.am new file mode 100644 index 0000000..55ab08d --- /dev/null +++ b/kioslaves/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = videodvd diff --git a/kioslaves/videodvd/Makefile.am b/kioslaves/videodvd/Makefile.am new file mode 100644 index 0000000..d8dca0e --- /dev/null +++ b/kioslaves/videodvd/Makefile.am @@ -0,0 +1,19 @@ +INCLUDES = -I$(srcdir)/../../libk3b/tools \ + -I$(srcdir)/../../libk3b/core \ + -I$(srcdir)/../../libk3bdevice \ + $(all_includes) + +kde_module_LTLIBRARIES = kio_videodvd.la + +kio_videodvd_la_SOURCES = videodvd.cpp +kio_videodvd_la_LIBADD = -lkio ../../libk3b/libk3b.la +kio_videodvd_la_LDFLAGS = -avoid-version -module $(all_libraries) $(KDE_PLUGIN) + +protocol_DATA = videodvd.protocol +protocoldir = $(kde_servicesdir) + +konq_sidebartree_init_services_data_DATA = videodvd.desktop +konq_sidebartree_init_services_datadir = $(kde_datadir)/konqsidebartng/virtual_folders/services + +messages: + $(XGETTEXT) *.cpp -o $(podir)/kio_videodvd.pot diff --git a/kioslaves/videodvd/videodvd.cpp b/kioslaves/videodvd/videodvd.cpp new file mode 100644 index 0000000..b453037 --- /dev/null +++ b/kioslaves/videodvd/videodvd.cpp @@ -0,0 +1,407 @@ +/* + * + * $Id: sourceheader 380067 2005-01-19 13:03:46Z trueg $ + * Copyright (C) 2005 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include "videodvd.h" + +using namespace KIO; + +extern "C" +{ + LIBK3B_EXPORT int kdemain( int argc, char **argv ) + { + KInstance instance( "kio_videodvd" ); + + kdDebug(7101) << "*** Starting kio_videodvd " << endl; + + if (argc != 4) + { + kdDebug(7101) << "Usage: kio_videodvd protocol domain-socket1 domain-socket2" << endl; + exit(-1); + } + + kio_videodvdProtocol slave(argv[2], argv[3]); + slave.dispatchLoop(); + + kdDebug(7101) << "*** kio_videodvd Done" << endl; + return 0; + } +} + + + +// FIXME: Does it really make sense to use a static device manager? Are all instances +// of videodvd started in another process? +K3bDevice::DeviceManager* kio_videodvdProtocol::s_deviceManager = 0; +int kio_videodvdProtocol::s_instanceCnt = 0; + +kio_videodvdProtocol::kio_videodvdProtocol(const QCString &pool_socket, const QCString &app_socket) + : SlaveBase("kio_videodvd", pool_socket, app_socket) +{ + kdDebug() << "kio_videodvdProtocol::kio_videodvdProtocol()" << endl; + if( !s_deviceManager ) + { + s_deviceManager = new K3bDevice::DeviceManager(); + s_deviceManager->setCheckWritingModes( false ); + s_deviceManager->scanBus(); + } + s_instanceCnt++; +} + + +kio_videodvdProtocol::~kio_videodvdProtocol() +{ + kdDebug() << "kio_videodvdProtocol::~kio_videodvdProtocol()" << endl; + s_instanceCnt--; + if( s_instanceCnt == 0 ) + { + delete s_deviceManager; + s_deviceManager = 0; + } +} + + +KIO::UDSEntry kio_videodvdProtocol::createUDSEntry( const K3bIso9660Entry* e ) const +{ + KIO::UDSEntry uds; + KIO::UDSAtom a; + + a.m_uds = KIO::UDS_NAME; + a.m_str = e->name(); + uds.append( a ); + + a.m_uds = KIO::UDS_ACCESS; + a.m_long = e->permissions(); + uds.append( a ); + + a.m_uds = KIO::UDS_CREATION_TIME; + a.m_long = e->date(); + uds.append( a ); + + a.m_uds = KIO::UDS_MODIFICATION_TIME; + a.m_long = e->date(); + uds.append( a ); + + if( e->isDirectory() ) + { + a.m_uds = KIO::UDS_FILE_TYPE; + a.m_long = S_IFDIR; + uds.append( a ); + + a.m_uds = KIO::UDS_MIME_TYPE; + a.m_str = "inode/directory"; + uds.append( a ); + } + else + { + const K3bIso9660File* file = static_cast( e ); + + a.m_uds = KIO::UDS_SIZE; + a.m_long = file->size(); + uds.append( a ); + + a.m_uds = KIO::UDS_FILE_TYPE; + a.m_long = S_IFREG; + uds.append( a ); + + a.m_uds = KIO::UDS_MIME_TYPE; + if( e->name().endsWith( "VOB" ) ) + a.m_str = "video/mpeg"; + else + a.m_str = "unknown"; + uds.append( a ); + } + + return uds; +} + + +// FIXME: remember the iso instance for quicker something and search for the videodvd +// in the available devices. +K3bIso9660* kio_videodvdProtocol::openIso( const KURL& url, QString& plainIsoPath ) +{ + // get the volume id from the url + QString volumeId = url.path().section( '/', 1, 1 ); + + kdDebug() << "(kio_videodvdProtocol) searching for Video dvd: " << volumeId << endl; + + // now search the devices for this volume id + // FIXME: use the cache created in listVideoDVDs + for( QPtrListIterator it( s_deviceManager->dvdReader() ); *it; ++it ) { + K3bDevice::Device* dev = *it; + K3bDevice::DiskInfo di = dev->diskInfo(); + + // we search for a DVD with a single track. + // this time let K3bIso9660 decide if we need dvdcss or not + // FIXME: check for encryption and libdvdcss and report an error + if( di.isDvdMedia() && di.numTracks() == 1 ) { + K3bIso9660* iso = new K3bIso9660( dev ); + iso->setPlainIso9660( true ); + if( iso->open() && iso->primaryDescriptor().volumeId == volumeId ) { + plainIsoPath = url.path().section( "/", 2, -1 ) + "/"; + kdDebug() << "(kio_videodvdProtocol) using iso path: " << plainIsoPath << endl; + return iso; + } + delete iso; + } + } + + error( ERR_SLAVE_DEFINED, i18n("No VideoDVD found") ); + return 0; +} + + +void kio_videodvdProtocol::get(const KURL& url ) +{ + kdDebug() << "kio_videodvd::get(const KURL& url)" << endl ; + + QString isoPath; + if( K3bIso9660* iso = openIso( url, isoPath ) ) + { + const K3bIso9660Entry* e = iso->firstIsoDirEntry()->entry( isoPath ); + if( e && e->isFile() ) + { + const K3bIso9660File* file = static_cast( e ); + totalSize( file->size() ); + QByteArray buffer( 10*2048 ); + int read = 0; + int cnt = 0; + KIO::filesize_t totalRead = 0; + while( (read = file->read( totalRead, buffer.data(), buffer.size() )) > 0 ) + { + buffer.resize( read ); + data(buffer); + ++cnt; + totalRead += read; + if( cnt == 10 ) + { + cnt = 0; + processedSize( totalRead ); + } + } + + delete iso; + + data(QByteArray()); // empty array means we're done sending the data + + if( read == 0 ) + finished(); + else + error( ERR_SLAVE_DEFINED, i18n("Read error.") ); + } + else + error( ERR_DOES_NOT_EXIST, url.path() ); + } +} + + +void kio_videodvdProtocol::listDir( const KURL& url ) +{ + if( url.path() == "/" ) { + listVideoDVDs(); + } + else { + QString isoPath; + K3bIso9660* iso = openIso( url, isoPath ); + if( iso ) { + const K3bIso9660Directory* mainDir = iso->firstIsoDirEntry(); + const K3bIso9660Entry* e = mainDir->entry( isoPath ); + if( e ) { + if( e->isDirectory() ) { + const K3bIso9660Directory* dir = static_cast(e); + QStringList el = dir->entries(); + el.remove( "." ); + el.remove( ".." ); + UDSEntryList udsl; + for( QStringList::const_iterator it = el.begin(); it != el.end(); ++it ) + udsl.append( createUDSEntry( dir->entry( *it ) ) ); + listEntries( udsl ); + finished(); + } + else { + error( ERR_CANNOT_ENTER_DIRECTORY, url.path() ); + } + } + else { + error( ERR_CANNOT_ENTER_DIRECTORY, url.path() ); + } + + // for testing we always do the whole thing + delete iso; + } + } +} + + +void kio_videodvdProtocol::listVideoDVDs() +{ + int cnt = 0; + + for( QPtrListIterator it( s_deviceManager->dvdReader() ); *it; ++it ) { + K3bDevice::Device* dev = *it; + K3bDevice::DiskInfo di = dev->diskInfo(); + + // we search for a DVD with a single track. + if( di.isDvdMedia() && di.numTracks() == 1 ) { + // + // now do a quick check for VideoDVD. + // - no dvdcss for speed + // - only a check for the VIDEO_TS dir + // + K3bIso9660 iso( new K3bIso9660DeviceBackend(dev) ); + iso.setPlainIso9660( true ); + if( iso.open() && iso.firstIsoDirEntry()->entry( "VIDEO_TS" ) ) { + // FIXME: cache the entry for speedup + + UDSEntryList udsl; + KIO::UDSEntry uds; + KIO::UDSAtom a; + + a.m_uds = KIO::UDS_NAME; + a.m_str = iso.primaryDescriptor().volumeId; + uds.append( a ); + + a.m_uds = KIO::UDS_FILE_TYPE; + a.m_long = S_IFDIR; + uds.append( a ); + + a.m_uds = KIO::UDS_MIME_TYPE; + a.m_str = "inode/directory"; + uds.append( a ); + + a.m_uds = KIO::UDS_ICON_NAME; + a.m_str = "dvd_unmount"; + uds.append( a ); + + udsl.append( uds ); + + listEntries( udsl ); + + ++cnt; + } + } + } + + if( cnt ) + finished(); + else + error( ERR_SLAVE_DEFINED, i18n("No VideoDVD found") ); +} + + +void kio_videodvdProtocol::stat( const KURL& url ) +{ + if( url.path() == "/" ) { + // + // stat the root path + // + KIO::UDSEntry uds; + KIO::UDSAtom a; + + a.m_uds = KIO::UDS_NAME; + a.m_str = "/"; + uds.append( a ); + + a.m_uds = KIO::UDS_FILE_TYPE; + a.m_long = S_IFDIR; + uds.append( a ); + + a.m_uds = KIO::UDS_MIME_TYPE; + a.m_str = "inode/directory"; + uds.append( a ); + + statEntry( uds ); + finished(); + } + else { + QString isoPath; + K3bIso9660* iso = openIso( url, isoPath ); + if( iso ) { + const K3bIso9660Entry* e = iso->firstIsoDirEntry()->entry( isoPath ); + if( e ) { + statEntry( createUDSEntry( e ) ); + finished(); + } + else + error( ERR_DOES_NOT_EXIST, url.path() ); + + delete iso; + } + } +} + + +// FIXME: when does this get called? It seems not to be used for the files. +void kio_videodvdProtocol::mimetype( const KURL& url ) +{ + if( url.path() == "/" ) { + error( ERR_UNSUPPORTED_ACTION, "mimetype(/)" ); + return; + } + + QString isoPath; + K3bIso9660* iso = openIso( url, isoPath ); + if( iso ) + { + const K3bIso9660Entry* e = iso->firstIsoDirEntry()->entry( isoPath ); + if( e ) + { + if( e->isDirectory() ) + mimeType( "inode/directory" ); + else if( e->name().endsWith( ".VOB" ) ) + { + mimetype( "video/mpeg" ); + } + else + { + // send some data + const K3bIso9660File* file = static_cast( e ); + QByteArray buffer( 10*2048 ); + int read = file->read( 0, buffer.data(), buffer.size() ); + if( read > 0 ) + { + buffer.resize( read ); + data(buffer); + data(QByteArray()); + finished(); + // FIXME: do we need to emit finished() after emitting the end of data()? + } + else + error( ERR_SLAVE_DEFINED, i18n("Read error.") ); + } + } + delete iso; + } +} diff --git a/kioslaves/videodvd/videodvd.desktop b/kioslaves/videodvd/videodvd.desktop new file mode 100644 index 0000000..942e860 --- /dev/null +++ b/kioslaves/videodvd/videodvd.desktop @@ -0,0 +1,48 @@ +[Desktop Entry] +Encoding=UTF-8 +Type=Link +URL=videodvd:/ +Icon=dvd_unmount +Name=Video DVD Browser +Name[af]=Video DVD Blaaier +Name[ar]= قارىء القرص المدمج المرئي الرقمي DVD +Name[bg]=Браузър за видео DVD +Name[br]=Furcher DVD Video +Name[ca]=Navegador de DVDs de vídeo +Name[cs]=Prohlížeč Video DVD +Name[da]=Video-dvd browser +Name[de]=Video-DVD-Browser +Name[el]=Περιηγητής Video DVD +Name[eo]=Videa DVD foliumilo +Name[es]=Navegador de DVD de vídeo +Name[et]=Video DVD sirvija +Name[fa]= مرورگر دی وی دی ویدئویی +Name[fi]=Video-dvd selain +Name[fr]=Navigateur de DVD +Name[gl]=Explorador de Vídeo DVD +Name[hu]=Video DVD-böngésző +Name[is]=Vídeó DVD flakkari +Name[it]=Navigatore DVD video +Name[ja]=ビデオ DVD ブラウザ +Name[ka]=ვიდეო DVD-ის ბროუზერი +Name[km]=កម្មវិធី​រុករក​ឌីវីឌី​វីដេអូ +Name[lt]=Video DVD naršyklė +Name[nds]=Video-DVD-Kieker +Name[nn]=Film-DVD-lesar +Name[pa]=ਵੀਡਿਓ DVD ਝਲਕਾਰਾ +Name[pl]=Przeglądarka płyt DVD Video +Name[pt]=Navegador de DVD de Vídeo +Name[pt_BR]=Navegador de DVD de Vídeo +Name[sk]=Video DVD prehliadač +Name[sr]=Прегледач видео DVD-а +Name[sr@Latn]=Pregledač video DVD-a +Name[sv]=Video-dvd bläddrare +Name[tr]=Görüntü DVD'si Gezgini +Name[uk]=Навігатор відео-DVD +Name[uz]=Video-DVD brauzeri +Name[uz@cyrillic]=Видео-DVD браузери +Name[zh_CN]=视频 DVD 浏览器 +Name[zh_TW]=Video DVD 瀏覽器 +Open=false +X-KDE-TreeModule=Directory +X-KDE-KonqSidebarModule=konqsidebar_tree diff --git a/kioslaves/videodvd/videodvd.h b/kioslaves/videodvd/videodvd.h new file mode 100644 index 0000000..e27e54f --- /dev/null +++ b/kioslaves/videodvd/videodvd.h @@ -0,0 +1,55 @@ +/* + * + * $Id: sourceheader 380067 2005-01-19 13:03:46Z trueg $ + * Copyright (C) 2005 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _videodvd_H_ +#define _videodvd_H_ + +#include +#include + +#include +#include +#include + +class QCString; +class K3bIso9660Entry; +class K3bIso9660; +namespace K3bDevice +{ + class DeviceManager; +} + +class kio_videodvdProtocol : public KIO::SlaveBase +{ +public: + kio_videodvdProtocol(const QCString &pool_socket, const QCString &app_socket); + ~kio_videodvdProtocol(); + + void mimetype( const KURL& url ); + void stat( const KURL& url ); + void get( const KURL& url ); + void listDir( const KURL& url ); + +private: + K3bIso9660* openIso( const KURL&, QString& plainIsoPath ); + KIO::UDSEntry createUDSEntry( const K3bIso9660Entry* e ) const; + void listVideoDVDs(); + + static K3bDevice::DeviceManager* s_deviceManager; + static int s_instanceCnt; +}; + +#endif diff --git a/kioslaves/videodvd/videodvd.protocol b/kioslaves/videodvd/videodvd.protocol new file mode 100644 index 0000000..6337443 --- /dev/null +++ b/kioslaves/videodvd/videodvd.protocol @@ -0,0 +1,52 @@ +[Protocol] +exec=kio_videodvd +protocol=videodvd +input=none +output=filesystem +reading=true +listing=Name,Type,Size,Date +Icon=dvd_unmount +Class=:local +Description=A kioslave that allows files to be copied from a Video DVD (including decryption) +Description[af]='n 'Kioslave' wat jou toelaat om lêers vanaf 'n Video DVD te kopiëer. Dit doen ook die nodige dekripsie. +Description[ar]= يسمح هذا ال-kioslave بنسخ الملفات من قرص مدمج مرئي رقمي DVD ( بما فيه فك التشفير ) +Description[bg]=kioslave, позволяващ ви да копирате файлове от видео DVD (включително разшифроването) +Description[bn]=একটি কে-আই-ও স্লেভ যেটি একটি ভিডিও ডিভিডি থেকে ফাইল কপি করতে অনুমতিদেয় (ডিক্রিপশন সহ) +Description[ca]=Un kioslave que permet que es copiïn fitxers des d'un DVD de vídeo (incloent el desxifrat) +Description[cs]=Kioslave umožňující kopírování video DVD (včetně dekódování) +Description[da]=En kioslave som gør det muligt at kopiere filer fra en video-dvd (inklusive afkodning) +Description[de]=Ein-/Ausgabemodul, mit dem man Dateien von einer Video-DVD kopieren kann (inkl. Entschlüsselung) +Description[el]=Ένα kioslave που επιτρέπει την αντιγραφή αρχείων από ένα DVD βίντεο (δυνατότητα αποκρυπτογράφησης) +Description[eo]=Kioslave kiu permesas kopii dosierojn el videa DVD (inklude malĉifro) +Description[es]=Un kioslave que permite copiar archivos de un DVD de vídeo (incluye descifrado) +Description[et]=KIO-moodul, mis võimaldab kopeerida faile video DVD-lt (vajadusel dekrüpteerib) +Description[fa]=یک kioslave که اجازه می‌دهد پرونده‌ها از یک دی وی دی ویدئویی )شامل سرگشایی( رونوشت شوند +Description[fi]=Kioslave-palvelu, joka mahdollistaa tiedostojen purkamisen dvd-levyltä. +Description[fr]=Un kioslave qui permet de copier des fichiers depuis un DVD Vidéo (incluant le déchiffrement) +Description[gl]=Un kioslave que permite copiar ficheiros dun Video DVD (incluindo descifrar) +Description[he]=עבד קלט/פלט של KDE המאפשר לקבצים להיות מועתקים מתקליטור וידאו של DVD (כולל פענוח) +Description[hu]=Kioslave, amellyel fájlokat lehet másolni Video DVD-ről (dekódolással együtt) +Description[is]=Kioslave sem leyfir afritun af skrám frá vídeó DVD (með afkóðun) +Description[it]=Un kioslave che permette ai file di essere copiati da un DVD video (incluso decifrazione) +Description[ja]=ビデオ DVD からファイルをコピーすることを可能にする kioslave (暗号解除も含む) +Description[ka]=Kioslave, რომელიც იძლევა Video DVD-დან ასლის ფაილების მიღების საშუელებას (გაშიფრვასთან ერთად) +Description[km]=​kioslave ដែល​អនុញ្ញាត​ឲ្យ​ចម្លង​​ឯកសារ​ពី​ឌីវីឌី​វីដេអូ(រួម​ទាំង​ការ​ឌិគ្រីប) +Description[lt]=Priedas (kioslave) leidžiantis kopijuoti bylas iš Video DVD (taip pat ir atšifruoti) +Description[ms]=kioslave yang membenarkan fail untuk disalin dari DVD Video (termasuk nyahenkripsi) +Description[nb]=En kioslave som gjør det mulig å kopiere filer fra en Video-DVD (medregnet dekryptering) +Description[nds]=En In-/Utgaavmoduul, mit dat sik Dateien vun en Video-DVD koperen laat (ok mit Opslöteln) +Description[nl]=Een kioslave waarmee u bestanden van een video-dvd kunt kopiëren (inclusief versleuteling) +Description[nn]=Ein kioslave som gjer det mogleg å kopiera filer frå ein film-DVD (inkludert kryptering) +Description[pa]=ਇੱਕ kioslave ਹੈ, ਜੋ ਕਿ ਫਾਇਲਾਂ ਨੂੰ ਇੱਕ DVD (ਡਿਸਕਰਿਪਸ਼ਨ ਸਮੇ) ਤੋਂ ਨਕਲ ਕਰਨ ਲਈ ਸਹਾਇਕ ਹੈ +Description[pl]=Wtyczka protokołu pozwalająca kopiować pliki z płyt DVD Video (łącznie z odszyfrowywaniem) +Description[pt]=Um 'kioslave' que permite copiar ficheiros de um DVD Vídeo (incluindo decifrar) +Description[pt_BR]=Um kioslave que permite que arquivos sejam copiados de um DVD de Vídeo (incluindo a quebra da proteção) +Description[ru]=Позволяет копировать файлы с Video DVD (с дешифровкой) +Description[sk]=kioslave, ktorý umožňuje kopírovať súbory z Video DVD (vrátane dešifrovania) +Description[sr]=kioslave који омогућава копирање фајлова са видео DVD-а (укључујући дешифровање) +Description[sr@Latn]=kioslave koji omogućava kopiranje fajlova sa video DVD-a (uključujući dešifrovanje) +Description[sv]=En I/O-slav som gör det möjligt att kopiera filer från en video-dvd (inklusive avkodning) +Description[tr]= Bir Görüntü DVD'sinden dosyaların kopyalanmasını (ve kodunun çözülmesini) sağlayan kioslave +Description[uk]=Підлеглий В/В, який дає змогу копіювати файли з Відео DVD (включаючи розшифрування) +Description[zh_CN]=允许从视频 DVD(包括加密影碟)中复制文件的 kioslave +Description[zh_TW]=允許直接從 Video DVD 複製檔案的 kioslave(會自動解密) diff --git a/libk3b/Makefile.am b/libk3b/Makefile.am new file mode 100644 index 0000000..4c74f7d --- /dev/null +++ b/libk3b/Makefile.am @@ -0,0 +1,28 @@ +if include_videodvdrip +VIDEODVDDIR = videodvd +VIDEODVDLIB = videodvd/libvideodvd.la +endif + + +lib_LTLIBRARIES = libk3b.la + +libk3b_la_SOURCES = dummy.cpp + +libk3b_la_LIBADD = core/libk3bcore.la \ + cddb/libcddb.la \ + projects/libk3bproject.la \ + plugin/libk3bplugin.la \ + tools/libk3btools.la \ + jobs/libjobs.la \ + $(VIDEODVDLIB) \ + ../libk3bdevice/libk3bdevice.la + +libk3b_la_LDFLAGS = $(all_libraries) -version-info 3:0:0 -no-undefined + +SUBDIRS = core plugin tools projects cddb jobs $(VIDEODVDDIR) + +#pkgconfigdir = $(libdir)/pkgconfig +#pkgconfig_DATA = libk3b.pc + +messages: + $(XGETTEXT) `find -name "*.cpp" -o -name "*.h"` -o $(podir)/libk3b.pot diff --git a/libk3b/README b/libk3b/README new file mode 100644 index 0000000..a1ba273 --- /dev/null +++ b/libk3b/README @@ -0,0 +1,29 @@ +libk3b +========================= + +This is the k3b library which provides a lot of CD/DVD writing classes. + +If you want to use it please be aware that the API is far from stable and +there will be no binary compatibility (or even source compatibility) before +K3b 1.0. + +But you are welcome to help fix the API and improve it whereever it is needed. + + +Usage +========================== + +Just a very basic scetch how to create an audio cd: + +1. create a k3bcore instance (this provides all the stuff that is needed by the lib) +1.1 K3bCore::init() to initialize the core. + +2. create a K3bAudioDoc object and add urls to it + +3. create a K3bJobHandler derived class (for example a widget which displays the progress) + +4. call K3bAudioDoc::newBurnJob or create a K3bAudioJob manually. + +5. modify the doc's settings. + +6. call K3bAudioJob::start() to start the burning process. diff --git a/libk3b/cddb/Makefile.am b/libk3b/cddb/Makefile.am new file mode 100644 index 0000000..e73c5ce --- /dev/null +++ b/libk3b/cddb/Makefile.am @@ -0,0 +1,9 @@ +AM_CPPFLAGS = -I$(srcdir)/../core -I$(srcdir)/../../libk3bdevice -I$(srcdir)/../../src $(all_includes) + +METASOURCES = AUTO + +noinst_LTLIBRARIES = libcddb.la + +libcddb_la_SOURCES = k3bcddbquery.cpp k3bcddb.cpp k3bcddbresult.cpp k3bcddbhttpquery.cpp k3bcddbpquery.cpp k3bcddblocalquery.cpp k3bcddbsubmit.cpp k3bcddblocalsubmit.cpp k3bcddbmultientriesdialog.cpp + +include_HEADERS = k3bcddb.h k3bcddbresult.h diff --git a/libk3b/cddb/k3bcddb.cpp b/libk3b/cddb/k3bcddb.cpp new file mode 100644 index 0000000..a0e4fe1 --- /dev/null +++ b/libk3b/cddb/k3bcddb.cpp @@ -0,0 +1,280 @@ +/* + * + * $Id: k3bcddb.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "k3bcddb.h" +#include "k3bcddbhttpquery.h" +#include "k3bcddbpquery.h" +#include "k3bcddblocalquery.h" +#include "k3bcddblocalsubmit.h" + +#include +#include +#include "k3bcddbmultientriesdialog.h" + + +K3bCddb::K3bCddb( QObject* parent, const char* name ) + : QObject( parent, name ) +{ + m_httpQuery = 0; + m_cddbpQuery = 0; + m_localQuery = 0; + m_localSubmit = 0; + + m_lastUsedQuery = 0; +} + + +K3bCddb::~K3bCddb() +{ +} + + +void K3bCddb::readConfig( KConfig* c ) +{ + c->setGroup( "Cddb" ); + + m_bRemoteCddbQuery = c->readBoolEntry( "use remote cddb", true ); + m_bLocalCddbQuery = c->readBoolEntry( "use local cddb query", false ); + + // old config <= 0.7.3 + QStringList cddbpServer = c->readListEntry( "cddbp server" ); + QStringList httpServer = c->readListEntry( "http server" ); + + // new config + m_cddbServer = c->readListEntry( "cddb server" ); + + m_localCddbDirs = c->readPathListEntry( "local cddb dirs" ); + + m_bUseManualCgiPath = c->readBoolEntry( "use manual cgi path", false ); + m_cgiPath = c->readEntry( "cgi path", "/~cddb/cddb.cgi" ); + + if( m_localCddbDirs.isEmpty() ) + m_localCddbDirs.append( "~/.cddb/" ); + + // old config <= 0.7.3 + if( !httpServer.isEmpty() ) { + for( QStringList::iterator it = httpServer.begin(); it != httpServer.end(); ++it ) { + m_cddbServer.append( "Http " + *it ); + } + } + if( !cddbpServer.isEmpty() ) { + for( QStringList::iterator it = cddbpServer.begin(); it != cddbpServer.end(); ++it ) { + m_cddbServer.append( "Cddbp " + *it ); + } + } + + if( m_cddbServer.isEmpty() ) + m_cddbServer.append( "Http freedb2.org:80" ); +} + + +void K3bCddb::query( const K3bDevice::Toc& toc ) +{ + m_toc = toc; + + if( m_bLocalCddbQuery ) { + m_iCurrentQueriedLocalDir = 0; + QTimer::singleShot( 0, this, SLOT(localQuery()) ); + } + else if( m_bRemoteCddbQuery ) { + m_iCurrentQueriedServer = 0; + QTimer::singleShot( 0, this, SLOT(remoteQuery()) ); + } + else { + QTimer::singleShot( 0, this, SLOT(slotNoEntry()) ); + } +} + + +void K3bCddb::slotNoEntry() +{ + emit queryFinished( K3bCddbQuery::NO_ENTRY_FOUND ); +} + + +void K3bCddb::remoteQuery() +{ + K3bCddbQuery* q = getQuery( m_cddbServer[m_iCurrentQueriedServer] ); + q->query(m_toc); +} + + +void K3bCddb::slotMultibleMatches( K3bCddbQuery* query ) +{ + K3bCddbResultHeader hdr = K3bCddbMultiEntriesDialog::selectCddbEntry( query, 0 ); + if( !hdr.discid.isEmpty() ) + query->queryMatch( hdr ); + else + emit queryFinished( K3bCddbQuery::CANCELED ); +} + + +void K3bCddb::slotQueryFinished( K3bCddbQuery* query ) +{ + m_lastUsedQuery = query; + + if( query->error() == K3bCddbQuery::SUCCESS ) { + m_lastResult = m_lastUsedQuery->result(); + + // make sure the result has the requested discid since otherwise local saving does not make much sense + m_lastResult.discid = QString::number( m_toc.discId(), 16 ).rightJustify( 8, '0' ); + + emit queryFinished( K3bCddbQuery::SUCCESS ); + } + else if( query == m_localQuery ) { + m_iCurrentQueriedLocalDir++; + if( m_iCurrentQueriedLocalDir < m_localCddbDirs.size() ) + localQuery(); + else if( m_bRemoteCddbQuery ) { + m_iCurrentQueriedServer = 0; + remoteQuery(); + } + else { + emit queryFinished( query->error() ); + } + } + else { + m_iCurrentQueriedServer++; + if( m_iCurrentQueriedServer < m_cddbServer.size() ) { + remoteQuery(); + } + else { + emit queryFinished( query->error() ); + } + } +} + + +K3bCddbQuery* K3bCddb::getQuery( const QString& s ) +{ + QStringList buf = QStringList::split( ":", s.mid( s.find(" ")+1 ) ); + QString server = buf[0]; + int port = buf[1].toInt(); + + if( s.startsWith("Http") ) { + if( !m_httpQuery ) { + m_httpQuery = new K3bCddbHttpQuery( this ); + connect( m_httpQuery, SIGNAL(infoMessage(const QString&)), + this, SIGNAL(infoMessage(const QString&)) ); + connect( m_httpQuery, SIGNAL(queryFinished(K3bCddbQuery*)), + this, SLOT(slotQueryFinished(K3bCddbQuery*)) ); + connect( m_httpQuery, SIGNAL(inexactMatches(K3bCddbQuery*)), + this, SLOT(slotMultibleMatches(K3bCddbQuery*)) ); + } + + m_httpQuery->setServer( server, port ); + m_httpQuery->setCgiPath( m_bUseManualCgiPath ? m_cgiPath : QString::fromLatin1("/~cddb/cddb.cgi") ); + + return m_httpQuery; + } + else { + if( !m_cddbpQuery ) { + m_cddbpQuery = new K3bCddbpQuery( this ); + connect( m_cddbpQuery, SIGNAL(infoMessage(const QString&)), + this, SIGNAL(infoMessage(const QString&)) ); + connect( m_cddbpQuery, SIGNAL(queryFinished(K3bCddbQuery*)), + this, SLOT(slotQueryFinished(K3bCddbQuery*)) ); + connect( m_cddbpQuery, SIGNAL(inexactMatches(K3bCddbQuery*)), + this, SLOT(slotMultibleMatches(K3bCddbQuery*)) ); + } + + m_cddbpQuery->setServer( server, port ); + + return m_cddbpQuery; + } +} + + +void K3bCddb::localQuery() +{ + if( !m_localQuery ) { + m_localQuery = new K3bCddbLocalQuery( this ); + connect( m_localQuery, SIGNAL(infoMessage(const QString&)), + this, SIGNAL(infoMessage(const QString&)) ); + connect( m_localQuery, SIGNAL(queryFinished(K3bCddbQuery*)), + this, SLOT(slotQueryFinished(K3bCddbQuery*)) ); + connect( m_localQuery, SIGNAL(inexactMatches(K3bCddbQuery*)), + this, SLOT(slotMultibleMatches(K3bCddbQuery*)) ); + } + + m_localQuery->setCddbDir( m_localCddbDirs[m_iCurrentQueriedLocalDir] ); + + m_localQuery->query( m_toc ); +} + + +QString K3bCddb::errorString() const +{ + if( !m_lastUsedQuery ) + return "no query"; + + switch( m_lastUsedQuery->error() ) { + case K3bCddbQuery::SUCCESS: + return i18n("Found freedb entry."); + case K3bCddbQuery::NO_ENTRY_FOUND: + return i18n("No entry found"); + case K3bCddbQuery::CONNECTION_ERROR: + return i18n("Error while connecting to host."); + case K3bCddbQuery::WORKING: + return i18n("Working..."); + case K3bCddbQuery::QUERY_ERROR: + case K3bCddbQuery::READ_ERROR: + case K3bCddbQuery::FAILURE: + default: + return i18n("Communication error."); + } +} + + +const K3bCddbResultEntry& K3bCddb::result() const +{ + // return m_lastUsedQuery->result(); + return m_lastResult; +} + + +void K3bCddb::saveEntry( const K3bCddbResultEntry& entry ) +{ + if( !m_localSubmit ) { + m_localSubmit = new K3bCddbLocalSubmit( this ); + connect( m_localSubmit, SIGNAL(submitFinished(K3bCddbSubmit*)), + this, SLOT(slotSubmitFinished(K3bCddbSubmit*)) ); + } + + m_localSubmit->setCddbDir( m_localCddbDirs[0] ); + + m_localSubmit->submit( entry ); +} + + +void K3bCddb::slotSubmitFinished( K3bCddbSubmit* s ) +{ + emit submitFinished( s->error() == K3bCddbSubmit::SUCCESS ); +} + +#include "k3bcddb.moc" + diff --git a/libk3b/cddb/k3bcddb.h b/libk3b/cddb/k3bcddb.h new file mode 100644 index 0000000..86b67c5 --- /dev/null +++ b/libk3b/cddb/k3bcddb.h @@ -0,0 +1,103 @@ +/* + * + * $Id: k3bcddb.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BCDDB_H +#define K3BCDDB_H + +#include +#include +#include + +#include + +#include "k3bcddbresult.h" +#include "k3b_export.h" + +class KConfig; +class K3bCddbQuery; +class K3bCddbHttpQuery; +class K3bCddbpQuery; +class K3bCddbLocalQuery; +class K3bCddbSubmit; +class K3bCddbLocalSubmit; + + +class LIBK3B_EXPORT K3bCddb : public QObject +{ + Q_OBJECT + + public: + K3bCddb( QObject* parent = 0, const char* name = 0 ); + ~K3bCddb(); + + QString errorString() const; + + /** + * Do NOT call this before queryResult has + * been emitted + */ + const K3bCddbResultEntry& result() const; + + public slots: + /** query a cd and connect to the queryFinished signal */ + void query( const K3bDevice::Toc& ); + void readConfig( KConfig* c ); + void saveEntry( const K3bCddbResultEntry& ); + + signals: + void queryFinished( int error ); + void submitFinished( bool success ); + void infoMessage( const QString& ); + + private slots: + void localQuery(); + void remoteQuery(); + void slotQueryFinished( K3bCddbQuery* ); + void slotSubmitFinished( K3bCddbSubmit* ); + void slotMultibleMatches( K3bCddbQuery* ); + void slotNoEntry(); + + private: + K3bCddbQuery* getQuery( const QString& ); + + K3bCddbHttpQuery* m_httpQuery; + K3bCddbpQuery* m_cddbpQuery; + K3bCddbLocalQuery* m_localQuery; + K3bCddbLocalSubmit* m_localSubmit; + + K3bDevice::Toc m_toc; + unsigned int m_iCurrentQueriedServer; + unsigned int m_iCurrentQueriedLocalDir; + + const K3bCddbQuery* m_lastUsedQuery; + K3bCddbResultEntry m_lastResult; + + // config + QStringList m_cddbServer; + QString m_proxyServer; + int m_proxyPort; + QString m_cgiPath; + bool m_bUseProxyServer; + bool m_bUseKdeSettings; + QStringList m_localCddbDirs; + bool m_bSaveCddbEntriesLocally; + bool m_bUseManualCgiPath; + bool m_bRemoteCddbQuery; + bool m_bLocalCddbQuery; +}; + + +#endif diff --git a/libk3b/cddb/k3bcddbhttpquery.cpp b/libk3b/cddb/k3bcddbhttpquery.cpp new file mode 100644 index 0000000..a453c3e --- /dev/null +++ b/libk3b/cddb/k3bcddbhttpquery.cpp @@ -0,0 +1,233 @@ +/* + * + * $Id: k3bcddbhttpquery.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + + +#include "k3bcddbhttpquery.h" + +#include "k3bcddbresult.h" + +#include +#include +#include + +#include +#include +#include +#include + + +K3bCddbHttpQuery::K3bCddbHttpQuery( QObject* parent, const char* name ) + : K3bCddbQuery( parent, name ) +{ + m_server = "freedb.org"; + m_port = 80; + m_cgiPath = "/~cddb/cddb.cgi"; +} + + +K3bCddbHttpQuery::~K3bCddbHttpQuery() +{ +} + + +void K3bCddbHttpQuery::doQuery() +{ + setError( WORKING ); + m_state = QUERY; + + performCommand( queryString() ); +} + + +void K3bCddbHttpQuery::doMatchQuery() +{ + setError( WORKING ); + m_state = READ; + m_parsingBuffer.truncate(0); + + performCommand( QString( "cddb read %1 %2").arg( header().category ).arg( header().discid ) ); +} + + +void K3bCddbHttpQuery::performCommand( const QString& cmd ) +{ + KURL url; + url.setProtocol( "http" ); + url.setHost( m_server ); + url.setPort( m_port ); + url.setPath( m_cgiPath ); + + url.addQueryItem( "cmd", cmd ); + url.addQueryItem( "hello", handshakeString() ); + url.addQueryItem( "proto", "6" ); + + m_data.truncate(0); + + kdDebug() << "(K3bCddbHttpQuery) getting url: " << url.prettyURL() << endl; + + KIO::TransferJob* job = KIO::get( url, false, false ); + + if( !job ) { + setError( CONNECTION_ERROR ); + emit infoMessage( i18n("Could not connect to host %1").arg(m_server) ); + emitQueryFinished(); + return; + } + + connect( job, SIGNAL(data(KIO::Job*, const QByteArray&)), + SLOT(slotData(KIO::Job*, const QByteArray&)) ); + connect( job, SIGNAL(result(KIO::Job*)), + SLOT(slotResult(KIO::Job*)) ); +} + + + +void K3bCddbHttpQuery::slotData( KIO::Job*, const QByteArray& data ) +{ + if( data.size() ) { + QDataStream stream( m_data, IO_WriteOnly | IO_Append ); + stream.writeRawBytes( data.data(), data.size() ); + } +} + + +void K3bCddbHttpQuery::slotResult( KIO::Job* job ) +{ + if( job->error() ) { + emit infoMessage( job->errorString() ); + setError( CONNECTION_ERROR ); + emitQueryFinished(); + return; + } + + QStringList lines = QStringList::split( "\n", QString::fromUtf8( m_data.data(), m_data.size() ) ); + + for( QStringList::const_iterator it = lines.begin(); it != lines.end(); ++it ) { + QString line = *it; + + // kdDebug() << "(K3bCddbHttpQuery) line: " << line << endl; + + switch( m_state ) { + + case QUERY: + if( getCode( line ) == 200 ) { + // parse exact match and send a read command + K3bCddbResultHeader header; + parseMatchHeader( line.mid(4), header ); + + queryMatch( header ); + } + + else if( getCode( line ) == 210 ) { + // TODO: perhaps add an "exact" field to K3bCddbEntry + kdDebug() << "(K3bCddbHttpQuery) Found multiple exact matches" << endl; + + emit infoMessage( i18n("Found multiple exact matches") ); + + m_state = QUERY_DATA; + } + + else if( getCode( line ) == 211 ) { + kdDebug() << "(K3bCddbHttpQuery) Found inexact matches" << endl; + + emit infoMessage( i18n("Found inexact matches") ); + + m_state = QUERY_DATA; + } + + else if( getCode( line ) == 202 ) { + kdDebug() << "(K3bCddbHttpQuery) no match found" << endl; + emit infoMessage( i18n("No match found") ); + setError(NO_ENTRY_FOUND); + m_state = FINISHED; + emitQueryFinished(); + return; + } + + else { + kdDebug() << "(K3bCddbHttpQuery) Error while querying: " << line << endl; + emit infoMessage( i18n("Error while querying") ); + setError(QUERY_ERROR); + m_state = FINISHED; + emitQueryFinished(); + return; + } + break; + + case QUERY_DATA: + if( line.startsWith( "." ) ) { + // finished query + // go on reading + + + // here we have the inexact matches headers and should emit the + // inexactMatches signal + emit inexactMatches( this ); + } + else { + kdDebug() << "(K3bCddbHttpQuery) inexact match: " << line << endl; + + // create a new resultHeader + K3bCddbResultHeader header; + parseMatchHeader( line, header ); + m_inexactMatches.append(header); + } + break; + + case READ: + if( getCode( line ) == 210 ) { + + // we just start parsing the read data + m_state = READ_DATA; + } + + else { + emit infoMessage( i18n("Could not read match") ); + setError(READ_ERROR); + m_state = FINISHED; + emitQueryFinished(); + return; + } + break; + + + case READ_DATA: + + // kdDebug() << "parsing line: " << line << endl; + + if( line.startsWith( "." ) ) { + + kdDebug() << "(K3bCddbHttpQuery query finished." << endl; + + QTextStream strStream( m_parsingBuffer, IO_ReadOnly ); + parseEntry( strStream, result() ); + + setError(SUCCESS); + m_state = FINISHED; + emitQueryFinished(); + return; + } + + else { + m_parsingBuffer.append(line + "\n"); + } + break; + } + } +} + + +#include "k3bcddbhttpquery.moc" diff --git a/libk3b/cddb/k3bcddbhttpquery.h b/libk3b/cddb/k3bcddbhttpquery.h new file mode 100644 index 0000000..b1e544e --- /dev/null +++ b/libk3b/cddb/k3bcddbhttpquery.h @@ -0,0 +1,64 @@ +/* + * + * $Id: k3bcddbhttpquery.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BCDDB_HTTP_QUERY_H +#define K3BCDDB_HTTP_QUERY_H + +#include "k3bcddbquery.h" +#include "k3bcddbresult.h" + +#include + +namespace KIO { + class Job; +} + +class K3bCddbHttpQuery : public K3bCddbQuery +{ + Q_OBJECT + + public: + K3bCddbHttpQuery( QObject* parent = 0, const char* name = 0 ); + ~K3bCddbHttpQuery(); + + public slots: + void setServer( const QString& s, int port = 80 ) { m_server = s; m_port = port; } + void setCgiPath( const QString& p ) { m_cgiPath = p; } + + protected slots: + void doQuery(); + void doMatchQuery(); + void slotResult( KIO::Job* ); + void slotData( KIO::Job*, const QByteArray& data ); + + private: + void performCommand( const QString& ); + + enum State { QUERY, QUERY_DATA, READ, READ_DATA, FINISHED }; + + int m_state; + QString m_server; + int m_port; + QString m_cgiPath; + + QString m_currentlyConnectingServer; + + QByteArray m_data; + QString m_parsingBuffer; +}; + +#endif + diff --git a/libk3b/cddb/k3bcddblocalquery.cpp b/libk3b/cddb/k3bcddblocalquery.cpp new file mode 100644 index 0000000..b3a1264 --- /dev/null +++ b/libk3b/cddb/k3bcddblocalquery.cpp @@ -0,0 +1,129 @@ +/* + * + * $Id: k3bcddblocalquery.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bcddblocalquery.h" + +#include +#include +#include + +#include +#include +#include + + +K3bCddbLocalQuery::K3bCddbLocalQuery( QObject* parent , const char* name ) + : K3bCddbQuery( parent, name ) +{ +} + + +K3bCddbLocalQuery::~K3bCddbLocalQuery() +{ +} + + +void K3bCddbLocalQuery::doQuery() +{ + emit infoMessage( i18n("Searching entry in %1").arg( m_cddbDir ) ); + kapp->processEvents(); //BAD! + + QString path = preparePath( m_cddbDir ); + + kdDebug() << "(K3bCddbLocalQuery) searching in dir " << path << " for " + << QString::number( toc().discId(), 16 ).rightJustify( 8, '0' ) << endl; + + for( QStringList::const_iterator it = categories().begin(); + it != categories().end(); ++it ) { + + QString file = path + *it + "/" + QString::number( toc().discId(), 16 ).rightJustify( 8, '0' ); + + if( QFile::exists( file ) ) { + // found file + + QFile f( file ); + if( !f.open( IO_ReadOnly ) ) { + kdDebug() << "(K3bCddbLocalQuery) Could not open file" << endl; + } + else { + QTextStream t( &f ); + + K3bCddbResultEntry entry; + parseEntry( t, entry ); + K3bCddbResultHeader header; + header.discid = QString::number( toc().discId(), 16 ).rightJustify( 8, '0' ); + header.category = *it; + header.title = entry.cdTitle; + header.artist = entry.cdArtist; + m_inexactMatches.append(header); + } + } + else { + kdDebug() << "(K3bCddbLocalQuery) Could not find local entry in category " << *it << endl; + } + } + + if( m_inexactMatches.count() > 0 ) { + setError( SUCCESS ); + if( m_inexactMatches.count() == 1 ) { + queryMatch( m_inexactMatches.first() ); + } + else { + emit inexactMatches( this ); + } + } + else { + setError( NO_ENTRY_FOUND ); + emit queryFinished( this ); + } +} + + +void K3bCddbLocalQuery::doMatchQuery() +{ + QString path = preparePath( m_cddbDir ) + header().category + "/" + header().discid; + + QFile f( path ); + if( !f.open( IO_ReadOnly ) ) { + kdDebug() << "(K3bCddbLocalQuery) Could not open file" << endl; + setError( READ_ERROR ); + } + else { + QTextStream t( &f ); + + parseEntry( t, result() ); + result().discid = header().discid; + result().category = header().category; + setError( SUCCESS ); + } + emit queryFinished( this ); +} + + +QString K3bCddbLocalQuery::preparePath( const QString& p ) +{ + QString path = p; + if( path.startsWith( "~" ) ) + path.replace( 0, 1, QDir::homeDirPath() ); + else if( !path.startsWith( "/" ) ) + path.prepend( QDir::homeDirPath() ); + if( path[path.length()-1] != '/' ) + path.append( "/" ); + + return path; +} + +#include "k3bcddblocalquery.moc" diff --git a/libk3b/cddb/k3bcddblocalquery.h b/libk3b/cddb/k3bcddblocalquery.h new file mode 100644 index 0000000..d68d379 --- /dev/null +++ b/libk3b/cddb/k3bcddblocalquery.h @@ -0,0 +1,48 @@ +/* + * + * $Id: k3bcddblocalquery.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + + +#ifndef K3BCDDB_LOCAL_QUERY_H +#define K3BCDDB_LOCAL_QUERY_H + +#include "k3bcddbquery.h" +#include "k3bcddbresult.h" + +#include + + +class K3bCddbLocalQuery : public K3bCddbQuery +{ + Q_OBJECT + + public: + K3bCddbLocalQuery( QObject* parent = 0, const char* name = 0 ); + ~K3bCddbLocalQuery(); + + public slots: + void setCddbDir( const QString& dir ) { m_cddbDir = dir; } + + protected: + void doQuery(); + void doMatchQuery(); + + private: + QString preparePath( const QString& p ); + + QString m_cddbDir; +}; + +#endif diff --git a/libk3b/cddb/k3bcddblocalsubmit.cpp b/libk3b/cddb/k3bcddblocalsubmit.cpp new file mode 100644 index 0000000..f2d1e69 --- /dev/null +++ b/libk3b/cddb/k3bcddblocalsubmit.cpp @@ -0,0 +1,102 @@ +/* + * + * $Id: k3bcddblocalsubmit.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + + +#include "k3bcddblocalsubmit.h" + +#include +#include +#include + +#include +#include + + +K3bCddbLocalSubmit::K3bCddbLocalSubmit( QObject* parent, const char* name ) + : K3bCddbSubmit( parent, name ) +{ +} + + +K3bCddbLocalSubmit::~K3bCddbLocalSubmit() +{ +} + + +void K3bCddbLocalSubmit::doSubmit() +{ + QString path = m_cddbDir; + if( path.startsWith( "~" ) ) + path.replace( 0, 1, QDir::homeDirPath() + "/" ); + else if( !path.startsWith( "/" ) ) + path.prepend( QDir::homeDirPath() + "/" ); + if( path[path.length()-1] != '/' ) + path.append( "/" ); + + if( !QFile::exists( path ) && !QDir().mkdir( path ) ) { + kdDebug() << "(K3bCddbLocalSubmit) could not create directory: " << path << endl; + setError( IO_ERROR ); + emit submitFinished( this ); + return; + } + + if( QFile::exists( path ) ) { + // if the category dir does not exists + // create it + + path += resultEntry().category; + + if( !QFile::exists( path ) ) { + if( !QDir().mkdir( path ) ) { + kdDebug() << "(K3bCddbLocalSubmit) could not create directory: " << path << endl; + setError( IO_ERROR ); + emit submitFinished( this ); + return; + } + } + + // we always overwrite existing entries + path += "/" + resultEntry().discid; + QFile entryFile( path ); + if( entryFile.exists() ) { + kdDebug() << "(K3bCddbLocalSubmit) file already exists: " << path << endl; + } + + if( !entryFile.open( IO_WriteOnly ) ) { + kdDebug() << "(K3bCddbLocalSubmit) could not create file: " << path << endl; + setError( IO_ERROR ); + emit submitFinished( this ); + } + else { + kdDebug() << "(K3bCddbLocalSubmit) creating file: " << path << endl; + QTextStream entryStream( &entryFile ); + entryStream.setEncoding( QTextStream::UnicodeUTF8 ); + entryStream << resultEntry().rawData; + entryFile.close(); + + setError( SUCCESS ); + emit submitFinished( this ); + } + } + else { + kdDebug() << "(K3bCddbLocalSubmit) could not find directory: " << path << endl; + setError( IO_ERROR ); + emit infoMessage( i18n("Could not find directory: %1").arg(path) ); + emit submitFinished( this ); + } +} + +#include "k3bcddblocalsubmit.moc" diff --git a/libk3b/cddb/k3bcddblocalsubmit.h b/libk3b/cddb/k3bcddblocalsubmit.h new file mode 100644 index 0000000..8b7ea91 --- /dev/null +++ b/libk3b/cddb/k3bcddblocalsubmit.h @@ -0,0 +1,43 @@ +/* + * + * $Id: k3bcddblocalsubmit.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BCDDB_LOCAL_SUBMIT_H +#define K3BCDDB_LOCAL_SUBMIT_H + +#include "k3bcddbsubmit.h" + +#include + + +class K3bCddbLocalSubmit : public K3bCddbSubmit +{ + Q_OBJECT + + public: + K3bCddbLocalSubmit( QObject* parent = 0, const char* name = 0 ); + ~K3bCddbLocalSubmit(); + + public slots: + void setCddbDir( const QString& dir ) { m_cddbDir = dir; } + + protected slots: + void doSubmit(); + + private: + QString m_cddbDir; +}; + +#endif diff --git a/libk3b/cddb/k3bcddbmultientriesdialog.cpp b/libk3b/cddb/k3bcddbmultientriesdialog.cpp new file mode 100644 index 0000000..094176a --- /dev/null +++ b/libk3b/cddb/k3bcddbmultientriesdialog.cpp @@ -0,0 +1,74 @@ +/* + * + * $Id: k3bcddbmultientriesdialog.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bcddbmultientriesdialog.h" + +#include +#include +#include + +#include +#include + + + +K3bCddbMultiEntriesDialog::K3bCddbMultiEntriesDialog( QWidget* parent, const char* name ) + : KDialogBase( Plain, i18n("CDDB Database Entry"), Ok|Cancel, Ok, parent, name ) +{ + QFrame* frame = plainPage(); + QVBoxLayout* layout = new QVBoxLayout( frame ); + layout->setAutoAdd( true ); + layout->setSpacing( spacingHint() ); + layout->setMargin( 0 ); + + QLabel* infoLabel = new QLabel( i18n("K3b found multiple inexact CDDB entries. Please select one."), frame ); + infoLabel->setAlignment( WordBreak ); + + m_listBox = new KListBox( frame, "list_box"); + + setMinimumSize( 280, 200 ); +} + +K3bCddbResultHeader K3bCddbMultiEntriesDialog::selectCddbEntry( K3bCddbQuery* query, QWidget* parent ) +{ + K3bCddbMultiEntriesDialog d( parent ); + + const QValueList headers = query->getInexactMatches(); + + int i = 1; + for( QValueListConstIterator it = headers.begin(); + it != headers.end(); ++it ) { + d.m_listBox->insertItem( QString::number(i) + " " + + (*it).artist + " - " + + (*it).title + " (" + + (*it).category + ")" ); + ++i; + } + + d.m_listBox->setSelected( 0, true ); + + if( d.exec() == QDialog::Accepted ) + return headers[ d.m_listBox->currentItem() >= 0 ? d.m_listBox->currentItem() : 0 ]; + else + return K3bCddbResultHeader(); +} + + +K3bCddbMultiEntriesDialog::~K3bCddbMultiEntriesDialog(){ +} + + +#include "k3bcddbmultientriesdialog.moc" diff --git a/libk3b/cddb/k3bcddbmultientriesdialog.h b/libk3b/cddb/k3bcddbmultientriesdialog.h new file mode 100644 index 0000000..15cc6f8 --- /dev/null +++ b/libk3b/cddb/k3bcddbmultientriesdialog.h @@ -0,0 +1,48 @@ +/* + * + * $Id: k3bcddbmultientriesdialog.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BCDDBMULTIENTRIESDIALOG_H +#define K3BCDDBMULTIENTRIESDIALOG_H + +#include + +#include "k3bcddbquery.h" +#include "k3bcddbresult.h" + + +class QStringList; +class KListBox; + +/** + *@author Sebastian Trueg + */ +class K3bCddbMultiEntriesDialog : public KDialogBase +{ + Q_OBJECT + + public: + ~K3bCddbMultiEntriesDialog(); + + static K3bCddbResultHeader selectCddbEntry( K3bCddbQuery* query, QWidget* parent = 0 ); + + protected: + K3bCddbMultiEntriesDialog( QWidget* parent = 0, const char* name = 0); + + private: + KListBox *m_listBox; +}; + +#endif diff --git a/libk3b/cddb/k3bcddbpquery.cpp b/libk3b/cddb/k3bcddbpquery.cpp new file mode 100644 index 0000000..fefc8e4 --- /dev/null +++ b/libk3b/cddb/k3bcddbpquery.cpp @@ -0,0 +1,278 @@ +/* + * + * $Id: k3bcddbpquery.cpp 619556 2007-01-03 17:38:12Z trueg $ + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bcddbpquery.h" + +#include +#include +#include + +#include +#include + + + + +K3bCddbpQuery::K3bCddbpQuery( QObject* parent, const char* name ) + :K3bCddbQuery( parent, name ) +{ + m_socket = new QSocket( this ); + m_stream.setDevice( m_socket ); + m_stream.setEncoding( QTextStream::UnicodeUTF8 ); + + connect( m_socket, SIGNAL(connected()), this, SLOT(slotConnected()) ); + connect( m_socket, SIGNAL(hostFound()), this, SLOT(slotHostFound()) ); + connect( m_socket, SIGNAL(connectionClosed()), this, SLOT(slotConnectionClosed()) ); + connect( m_socket, SIGNAL(error(int)), this, SLOT(slotError(int)) ); + connect( m_socket, SIGNAL(readyRead()), this, SLOT(slotReadyRead()) ); +} + + +K3bCddbpQuery::~K3bCddbpQuery() +{ + delete m_socket; +} + +void K3bCddbpQuery::doQuery() +{ + setError( WORKING ); + + m_state = GREETING; + + // connect to the server + + m_socket->connectToHost( m_server, m_port ); + emit infoMessage( i18n("Searching %1 on port %2").arg(m_server).arg(m_port) ); +} + + +void K3bCddbpQuery::doMatchQuery() +{ + // we should still be connected + // TODO: check this + + QString read = QString( "cddb read %1 %2").arg( header().category ).arg( header().discid ); + + m_state = READ; + m_parsingBuffer = ""; + + kdDebug() << "(K3bCddbpQuery) Read: " << read << endl; + + m_stream << read << endl << flush; +} + + +void K3bCddbpQuery::slotHostFound() +{ + emit infoMessage( i18n("Host found") ); +} + + +void K3bCddbpQuery::slotConnected() +{ + emit infoMessage( i18n("Connected") ); +} + + +void K3bCddbpQuery::slotConnectionClosed() +{ + emit infoMessage( i18n("Connection closed") ); + emitQueryFinished(); +} + + +void K3bCddbpQuery::cddbpQuit() +{ + m_state = QUIT; + m_stream << "quit" << endl << flush; +} + + +void K3bCddbpQuery::slotReadyRead() +{ + while( m_socket->canReadLine() ) { + QString line = m_stream.readLine(); + + // kdDebug() << "(K3bCddbpQuery) line: " << line << endl; + + switch( m_state ) { + case GREETING: + if( getCode( line ) == 200 || getCode( line ) == 201) { + emit infoMessage( i18n("OK, read access") ); + m_state = HANDSHAKE; + + m_stream << "cddb hello " << handshakeString() << endl << flush; + } + + else { + emit infoMessage( i18n("Connection refused") ); + setError( CONNECTION_ERROR ); + m_socket->close(); + } + break; + + case HANDSHAKE: + if( getCode( line ) == 200 ) { + emit infoMessage( i18n("Handshake successful") ); + + m_state = PROTO; + + m_stream << "proto 6" << endl << flush; + } + + else { + emit infoMessage( i18n("Handshake failed") ); // server closes connection + setError( CONNECTION_ERROR ); + m_socket->close(); // just to be sure + } + break; + + case PROTO: + { + if( getCode( line ) == 501 ) { + kdDebug() << "(K3bCddbpQuery) illigal protocol level!" << endl; + } + + // just ignore the reply since it's not important for the functionality + m_state = QUERY; + + m_stream << queryString() << endl << flush; + break; + } + + case QUERY: + if( getCode( line ) == 200 ) { + // parse exact match and send a read command + K3bCddbResultHeader header; + parseMatchHeader( line.mid( 4 ), header ); + + emit infoMessage( i18n("Found exact match") ); + + queryMatch( header ); + } + + else if( getCode( line ) == 210 ) { + // TODO: perhaps add an "exact" field to K3bCddbEntry + kdDebug() << "(K3bCddbpQuery) Found multiple exact matches" << endl; + + emit infoMessage( i18n("Found multiple exact matches") ); + + m_state = QUERY_DATA; + } + + else if( getCode( line ) == 211 ) { + kdDebug() << "(K3bCddbpQuery) Found inexact matches" << endl; + + emit infoMessage( i18n("Found inexact matches") ); + + m_state = QUERY_DATA; + } + + else if( getCode( line ) == 202 ) { + kdDebug() << "(K3bCddbpQuery) no match found" << endl; + emit infoMessage( i18n("No match found") ); + setError( NO_ENTRY_FOUND ); + cddbpQuit(); + } + + else { + kdDebug() << "(K3bCddbpQuery) Error while querying: " << line << endl; + emit infoMessage( i18n("Error while querying") ); + setError( QUERY_ERROR ); + cddbpQuit(); + } + break; + + case QUERY_DATA: + if( line.startsWith( "." ) ) { + // finished query + // go on reading + + emit inexactMatches( this ); + return; + } + else { + kdDebug() << "(K3bCddbpQuery) inexact match: " << line << endl; + K3bCddbResultHeader header; + parseMatchHeader( line, header ); + m_inexactMatches.append( header ); + } + break; + + case READ: + if( getCode( line ) == 210 ) { + + // we just start parsing the read data + m_state = READ_DATA; + } + + else { + emit infoMessage( i18n("Could not read match") ); + setError( READ_ERROR ); + cddbpQuit(); + } + break; + + + case READ_DATA: + + // kdDebug() << "(K3bCddbpQuery) parsing line: " << line << endl; + + if( line.startsWith( "." ) ) { + + kdDebug() << "(K3bCddbpQuery) query finished." << endl; + + QTextStream strStream( m_parsingBuffer, IO_ReadOnly ); + parseEntry( strStream, result() ); + + setError( SUCCESS ); + cddbpQuit(); + } + + else { + m_parsingBuffer.append(line + "\n"); + } + break; + + case QUIT: + // no parsing needed + break; + } + } +} + + +void K3bCddbpQuery::slotError( int e ) +{ + switch(e) { + case QSocket::ErrConnectionRefused: + kdDebug() << i18n("Connection to %1 refused").arg( m_server ) << endl; + emit infoMessage( i18n("Connection to %1 refused").arg( m_server ) ); + break; + case QSocket::ErrHostNotFound: + kdDebug() << i18n("Could not find host %1").arg( m_server ) << endl; + emit infoMessage( i18n("Could not find host %1").arg( m_server ) ); + break; + case QSocket::ErrSocketRead: + kdDebug() << i18n("Error while reading from %1").arg( m_server ) << endl; + emit infoMessage( i18n("Error while reading from %1").arg( m_server ) ); + break; + } + + m_socket->close(); + emitQueryFinished(); +} + +#include "k3bcddbpquery.moc" diff --git a/libk3b/cddb/k3bcddbpquery.h b/libk3b/cddb/k3bcddbpquery.h new file mode 100644 index 0000000..78fe5df --- /dev/null +++ b/libk3b/cddb/k3bcddbpquery.h @@ -0,0 +1,62 @@ +/* + * + * $Id: k3bcddbpquery.h 619556 2007-01-03 17:38:12Z trueg $ + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BCDDBP_QUERY_H +#define K3BCDDBP_QUERY_H + +#include "k3bcddbquery.h" +#include "k3bcddbresult.h" + +#include +#include +#include + +class QSocket; + +class K3bCddbpQuery : public K3bCddbQuery +{ + Q_OBJECT + + public: + K3bCddbpQuery( QObject* parent = 0, const char* name = 0 ); + ~K3bCddbpQuery(); + + public slots: + void setServer( const QString& s, int port = 8080 ) { m_server = s; m_port = port; } + + protected slots: + void slotHostFound(); + void slotConnected(); + void slotConnectionClosed(); + void slotReadyRead(); + void slotError( int e ); + void doQuery(); + void doMatchQuery(); + + private: + void cddbpQuit(); + enum State { GREETING, HANDSHAKE, PROTO, QUERY, QUERY_DATA, READ, READ_DATA, QUIT }; + + int m_state; + QString m_server; + int m_port; + + QSocket* m_socket; + QTextStream m_stream; + + QString m_parsingBuffer; +}; + +#endif diff --git a/libk3b/cddb/k3bcddbquery.cpp b/libk3b/cddb/k3bcddbquery.cpp new file mode 100644 index 0000000..783f9a4 --- /dev/null +++ b/libk3b/cddb/k3bcddbquery.cpp @@ -0,0 +1,275 @@ +/* + * + * $Id: k3bcddbquery.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + + +#include "k3bcddbquery.h" + +#include "k3bcddbresult.h" + +#include +#include +#include +#include + + +#include +#include +#include +#include + +#include + + + + +K3bCddbQuery::K3bCddbQuery( QObject* parent, const char* name ) + : QObject(parent, name) +{ + m_bQueryFinishedEmited = false; +} + + +K3bCddbQuery::~K3bCddbQuery() +{ +} + + +void K3bCddbQuery::query( const K3bDevice::Toc& toc ) +{ + m_bQueryFinishedEmited = false; + m_toc = toc; + m_inexactMatches.clear(); + + QTimer::singleShot( 0, this, SLOT(doQuery()) ); +} + + +void K3bCddbQuery::queryMatch( const K3bCddbResultHeader& header ) +{ + m_header = header; + m_result = K3bCddbResultEntry(); + m_result.category = header.category; + m_result.discid = header.discid; + + QTimer::singleShot( 0, this, SLOT(doMatchQuery()) ); +} + + +const QStringList& K3bCddbQuery::categories() +{ + static QStringList s_cat = QStringList::split( ",", "rock,blues,misc,classical," + "country,data,folk,jazz,newage,reggae,soundtrack" ); + return s_cat; +} + + +bool K3bCddbQuery::parseEntry( QTextStream& stream, K3bCddbResultEntry& entry ) +{ + entry.rawData = ""; + + stream.setEncoding( QTextStream::UnicodeUTF8 ); + + // parse data + QString line; + while( !(line = stream.readLine()).isNull() ) { + entry.rawData.append(line + "\n"); + + // !all fields may be splitted into several lines! + + if( line.startsWith( "DISCID" ) ) { + // TODO: this could be several discids separated by comma! + } + + else if( line.startsWith( "DYEAR" ) ) { + QString year = line.mid( 6 ); + if( year.length() == 4 ) + entry.year = year.toInt(); + } + + else if( line.startsWith( "DGENRE" ) ) { + entry.genre = line.mid( 7 ); + } + + else if( line.startsWith( "DTITLE" ) ) { + entry.cdTitle += line.mid( 7 ); + } + + else if( line.startsWith( "TTITLE" ) ) { + int eqSgnPos = line.find( "=" ); + bool ok; + uint trackNum = (uint)line.mid( 6, eqSgnPos - 6 ).toInt( &ok ); + if( !ok ) + kdDebug() << "(K3bCddbQuery) !!! PARSE ERROR: " << line << endl; + else { + // kdDebug() << "(K3bCddbQuery) Track title for track " << trackNum << endl; + + // make sure the list is big enough + while( entry.titles.count() <= trackNum ) + entry.titles.append( "" ); + + entry.titles[trackNum] += line.mid( eqSgnPos+1 ); + } + } + + else if( line.startsWith( "EXTD" ) ) { + entry.cdExtInfo += line.mid( 5 ); + } + + else if( line.startsWith( "EXTT" ) ) { + int eqSgnPos = line.find( "=" ); + bool ok; + uint trackNum = (uint)line.mid( 4, eqSgnPos - 4 ).toInt( &ok ); + if( !ok ) + kdDebug() << "(K3bCddbQuery) !!! PARSE ERROR: " << line << endl; + else { + // kdDebug() << "(K3bCddbQuery) Track extr track " << trackNum << endl; + + // make sure the list is big enough + while( entry.extInfos.count() <= trackNum ) + entry.extInfos.append( "" ); + + entry.extInfos[trackNum] += line.mid( eqSgnPos+1 ); + } + } + + else if( line.startsWith( "#" ) ) { + // kdDebug() << "(K3bCddbQuery) comment: " << line << endl; + } + + else { + kdDebug() << "(K3bCddbQuery) Unknown field: " << line << endl; + } + } + + // now split the titles in the last added match + // if no " / " delimiter is present title and artist are the same + // ------------------------------------------------------------------- + QString fullTitle = entry.cdTitle; + int splitPos = fullTitle.find( " / " ); + if( splitPos < 0 ) + entry.cdArtist = fullTitle; + else { + // split + entry.cdTitle = fullTitle.mid( splitPos + 3 ); + entry.cdArtist = fullTitle.left( splitPos ); + } + + + for( QStringList::iterator it = entry.titles.begin(); + it != entry.titles.end(); ++it ) { + QString fullTitle = *it; + int splitPos = fullTitle.find( " / " ); + if( splitPos < 0 ) + entry.artists.append( entry.cdArtist ); + else { + // split + *it = fullTitle.mid( splitPos + 3 ); + entry.artists.append( fullTitle.left( splitPos ) ); + } + } + + + // replace all "\\n" with "\n" + for( QStringList::iterator it = entry.titles.begin(); + it != entry.titles.end(); ++it ) { + (*it).replace( "\\\\\\\\n", "\\n" ); + } + + for( QStringList::iterator it = entry.artists.begin(); + it != entry.artists.end(); ++it ) { + (*it).replace( "\\\\\\\\n", "\\n" ); + } + + for( QStringList::iterator it = entry.extInfos.begin(); + it != entry.extInfos.end(); ++it ) { + (*it).replace( "\\\\\\\\n", "\\n" ); + } + + entry.cdTitle.replace( "\\\\\\\\n", "\\n" ); + entry.cdArtist.replace( "\\\\\\\\n", "\\n" ); + entry.cdExtInfo.replace( "\\\\\\\\n", "\\n" ); + entry.genre.replace( "\\\\\\\\n", "\\n" ); + + return true; +} + + +int K3bCddbQuery::getCode( const QString& line ) +{ + bool ok; + int code = line.left( 3 ).toInt( &ok ); + if( !ok ) + code = -1; + return code; +} + + +QString K3bCddbQuery::handshakeString() const +{ + QString user( getenv("USER") ); + QString host( getenv("HOST") ); + if( user.isEmpty() ) + user = "kde-user"; + if( host.isEmpty() ) + host = "kde-host"; + + return QString("%1 %2 K3b %3").arg(user).arg(host).arg(kapp->aboutData()->version()); +} + + +QString K3bCddbQuery::queryString() const +{ + QString query = "cddb query " + + QString::number( m_toc.discId(), 16 ).rightJustify( 8, '0' ) + + " " + + QString::number( (unsigned int)m_toc.count() ); + + for( K3bDevice::Toc::const_iterator it = m_toc.begin(); it != m_toc.end(); ++it ) { + query.append( QString( " %1" ).arg( (*it).firstSector().lba() ) ); + } + + query.append( QString( " %1" ).arg( m_toc.length().lba() / 75 ) ); + + return query; +} + + +bool K3bCddbQuery::parseMatchHeader( const QString& line, K3bCddbResultHeader& header ) +{ + // format: category id title + // where title could be artist and title splitted with a / + header.category = line.section( ' ', 0, 0 ); + header.discid = line.section( ' ', 1, 1 ); + header.title = line.mid( header.category.length() + header.discid.length() + 2 ); + int slashPos = header.title.find( "/" ); + if( slashPos > 0 ) { + header.artist = header.title.left(slashPos).stripWhiteSpace(); + header.title = header.title.mid( slashPos+1 ).stripWhiteSpace(); + } + return true; +} + + +void K3bCddbQuery::emitQueryFinished() +{ + if( !m_bQueryFinishedEmited ) { + m_bQueryFinishedEmited = true; + emit queryFinished( this ); + } +} + + +#include "k3bcddbquery.moc" diff --git a/libk3b/cddb/k3bcddbquery.h b/libk3b/cddb/k3bcddbquery.h new file mode 100644 index 0000000..569e882 --- /dev/null +++ b/libk3b/cddb/k3bcddbquery.h @@ -0,0 +1,115 @@ +/* + * + * $Id: k3bcddbquery.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BCDDB_QUERY_H +#define K3BCDDB_QUERY_H + +#include +#include +#include + +#include "k3bcddbresult.h" + +#include +#include "k3b_export.h" + + +class LIBK3B_EXPORT K3bCddbQuery : public QObject +{ + Q_OBJECT + + public: + K3bCddbQuery( QObject* parent = 0, const char* name = 0 ); + virtual ~K3bCddbQuery(); + + void query( const K3bDevice::Toc& ); + + /** + * Use this if the query returned multiple matches + */ + void queryMatch( const K3bCddbResultHeader& ); + + const K3bCddbResultEntry& result() const { return m_result; } + + /** + * After emitting the signal inexactMatches one has to choose one + * of these entries and query it with queryInexactMatch + */ + const QValueList& getInexactMatches() const { return m_inexactMatches; } + + static const QStringList& categories(); + + enum Error { SUCCESS = 0, + CANCELED, + NO_ENTRY_FOUND, + CONNECTION_ERROR, + QUERY_ERROR, + READ_ERROR, + FAILURE, + WORKING }; + + int error() const { return m_error; } + + signals: + /** + * This gets emitted if a single entry has been found or + * no entry has been found. + */ + void queryFinished( K3bCddbQuery* ); + + /** + * This gets emitted if multiple entries have been found. + * Call queryInexactMatch() after receiving it. + */ + void inexactMatches( K3bCddbQuery* ); + + void infoMessage( const QString& ); + + protected slots: + virtual void doQuery() = 0; + virtual void doMatchQuery() = 0; + + protected: + const K3bDevice::Toc& toc() const { return m_toc; } + K3bCddbResultHeader& header() { return m_header; } + K3bCddbResultEntry& result() { return m_result; } + void setError( int e ) { m_error = e; } + + bool parseEntry( QTextStream&, K3bCddbResultEntry& ); + int getCode( const QString& ); + QString handshakeString() const; + QString queryString() const; + bool parseMatchHeader( const QString& line, K3bCddbResultHeader& header ); + + /** + * since I'm not quite sure when the socket will emit connectionClosed + * this method makes sure the queryFinished signal + * gets emited only once. + */ + void emitQueryFinished(); + + QValueList m_inexactMatches; + + private: + K3bDevice::Toc m_toc; + K3bCddbResultEntry m_result; + K3bCddbResultHeader m_header; + int m_error; + + bool m_bQueryFinishedEmited; +}; + +#endif diff --git a/libk3b/cddb/k3bcddbresult.cpp b/libk3b/cddb/k3bcddbresult.cpp new file mode 100644 index 0000000..b33b16e --- /dev/null +++ b/libk3b/cddb/k3bcddbresult.cpp @@ -0,0 +1,49 @@ +/* + * + * $Id: k3bcddbresult.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + + +#include "k3bcddbresult.h" + + +K3bCddbResult::K3bCddbResult() +{ +} + + +void K3bCddbResult::clear() +{ + m_entries.clear(); +} + + +int K3bCddbResult::foundEntries() const +{ + return m_entries.count(); +} + +const K3bCddbResultEntry& K3bCddbResult::entry( unsigned int number ) const +{ + if( number >= m_entries.count() ) + return m_emptyEntry; + + return m_entries[number]; +} + + +void K3bCddbResult::addEntry( const K3bCddbResultEntry& entry ) +{ + m_entries.append( entry ); +} diff --git a/libk3b/cddb/k3bcddbresult.h b/libk3b/cddb/k3bcddbresult.h new file mode 100644 index 0000000..46dcb9a --- /dev/null +++ b/libk3b/cddb/k3bcddbresult.h @@ -0,0 +1,79 @@ +/* + * + * $Id: k3bcddbresult.h 768492 2008-01-30 08:39:42Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + + +#ifndef K3B_CDDB_RESULT_H +#define K3B_CDDB_RESULT_H + + +#include +#include "k3b_export.h" + + +class LIBK3B_EXPORT K3bCddbResultHeader +{ + public: + QString category; + QString title; + QString artist; + QString discid; +}; + + +class LIBK3B_EXPORT K3bCddbResultEntry +{ + public: + // just to set a default + K3bCddbResultEntry() + : category("misc"), + year(0) { + } + + QStringList titles; + QStringList artists; + QStringList extInfos; + + QString cdTitle; + QString cdArtist; + QString cdExtInfo; + + QString genre; + QString category; + int year; + QString discid; + + QString rawData; +}; + + +class LIBK3B_EXPORT K3bCddbResult +{ + public: + K3bCddbResult(); + // K3bCddbQuery( const K3bCddbQuery& ); + + void clear(); + void addEntry( const K3bCddbResultEntry& = K3bCddbResultEntry() ); + const K3bCddbResultEntry& entry( unsigned int number = 0 ) const; + int foundEntries() const; + + private: + QValueList m_entries; + + K3bCddbResultEntry m_emptyEntry; +}; + +#endif diff --git a/libk3b/cddb/k3bcddbsubmit.cpp b/libk3b/cddb/k3bcddbsubmit.cpp new file mode 100644 index 0000000..a04dbcb --- /dev/null +++ b/libk3b/cddb/k3bcddbsubmit.cpp @@ -0,0 +1,84 @@ +/* + * + * $Id: k3bcddbsubmit.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bcddbsubmit.h" + +#include + + +K3bCddbSubmit::K3bCddbSubmit( QObject* parent, const char* name ) + : QObject( parent, name ) +{ +} + + +K3bCddbSubmit::~K3bCddbSubmit() +{ +} + + +void K3bCddbSubmit::submit( const K3bCddbResultEntry& entry ) +{ + m_resultEntry = entry; + + if( m_resultEntry.rawData.isEmpty() ) + createDataStream( m_resultEntry ); + + QTimer::singleShot( 0, this, SLOT(doSubmit()) ); +} + + +void K3bCddbSubmit::createDataStream( K3bCddbResultEntry& entry ) +{ + entry.rawData.truncate(0); + + QTextStream ts( &entry.rawData, IO_WriteOnly ); + + ts << "#" << endl + << "# Submitted via: K3b" << endl + << "#" << endl; + + ts << "DISCID=" << entry.discid << endl + << "DTITLE=" << entry.cdArtist << " / " << entry.cdTitle << endl + << "DYEAR="; + if( entry.year > 0 ) + ts << entry.year; + ts << endl; + ts << "DGENRE=" << entry.genre << endl; + + bool allEqualArtist = true; + for( unsigned int i = 0; i < entry.artists.count(); ++i ) + if( entry.artists[i] != entry.cdArtist && + !entry.artists[i].isEmpty() ) { + allEqualArtist = false; + break; + } + + for( unsigned int i = 0; i < entry.titles.count(); ++i ) { + ts << "TTITLE" << i << "="; + if( !allEqualArtist ) + ts << entry.artists[i] << " / "; + ts << entry.titles[i] << endl; + } + + ts << "EXTD=" << entry.cdExtInfo << endl; + + for( unsigned int i = 0; i < entry.titles.count(); ++i ) { + ts << "EXTT" << i << "=" << entry.extInfos[i] << endl; + } +} + +#include "k3bcddbsubmit.moc" diff --git a/libk3b/cddb/k3bcddbsubmit.h b/libk3b/cddb/k3bcddbsubmit.h new file mode 100644 index 0000000..ff57101 --- /dev/null +++ b/libk3b/cddb/k3bcddbsubmit.h @@ -0,0 +1,60 @@ +/* + * + * $Id: k3bcddbsubmit.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BCDDB_SUBMIT_H +#define K3BCDDB_SUBMIT_H + +#include +#include + +#include "k3bcddbresult.h" + + + +class K3bCddbSubmit : public QObject +{ + Q_OBJECT + + public: + K3bCddbSubmit( QObject* parent = 0, const char* name = 0 ); + virtual ~K3bCddbSubmit(); + + int error() const { return m_error; } + + enum State { SUCCESS, WORKING, IO_ERROR, CONNECTION_ERROR }; + + public slots: + void submit( const K3bCddbResultEntry& ); + + signals: + void infoMessage( const QString& ); + void submitFinished( K3bCddbSubmit* ); + + protected slots: + virtual void doSubmit() = 0; + void setError( int e ) { m_error = e; } + + protected: + K3bCddbResultEntry& resultEntry() { return m_resultEntry; } + + private: + void createDataStream( K3bCddbResultEntry& entry ); + + int m_error; + K3bCddbResultEntry m_resultEntry; +}; + +#endif diff --git a/libk3b/configure.in.in b/libk3b/configure.in.in new file mode 100644 index 0000000..af0c8f5 --- /dev/null +++ b/libk3b/configure.in.in @@ -0,0 +1,3 @@ +AC_CHECK_FUNCS(stat64) +AC_CHECK_HEADERS(sys/vfs.h) +AC_CHECK_HEADERS(sys/statvfs.h) diff --git a/libk3b/core/Makefile.am b/libk3b/core/Makefile.am new file mode 100644 index 0000000..3764d86 --- /dev/null +++ b/libk3b/core/Makefile.am @@ -0,0 +1,19 @@ +AM_CPPFLAGS = -I$(srcdir)/../../libk3bdevice -I$(srcdir)/../plugin -I$(srcdir)/../tools $(all_includes) + +noinst_LTLIBRARIES = libk3bcore.la + +libk3bcore_la_LIBADD = $(LIB_KIO) $(ARTSC_LIB) + +libk3bcore_la_LDFLAGS = $(all_libraries) + +libk3bcore_la_SOURCES = k3bcore.cpp k3bglobals.cpp k3bdefaultexternalprograms.cpp \ + k3bexternalbinmanager.cpp k3bversion.cpp k3bprocess.cpp k3bjob.cpp \ + k3bthread.cpp k3bthreadjob.cpp k3bglobalsettings.cpp k3bsimplejobhandler.cpp + +include_HEADERS = k3bcore.h k3bdefaultexternalprograms.h k3bexternalbinmanager.h \ + k3bprocess.h k3bversion.h k3bglobals.h k3bjob.h k3bthread.h \ + k3bthreadjob.h k3bglobalsettings.h k3bjobhandler.h \ + k3b_export.h k3bjobhandler.h k3bsimplejobhandler.h + +METASOURCES = AUTO + diff --git a/libk3b/core/k3b_export.h b/libk3b/core/k3b_export.h new file mode 100644 index 0000000..b6272f1 --- /dev/null +++ b/libk3b/core/k3b_export.h @@ -0,0 +1,33 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (c) 2005 Laurent Montel + * Copyright (C) 2005-2007 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_EXPORT_H_ +#define _K3B_EXPORT_H_ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef __KDE_HAVE_GCC_VISIBILITY +#define LIBK3B_NO_EXPORT __attribute__ ((visibility("hidden"))) +#define LIBK3B_EXPORT __attribute__ ((visibility("default"))) +#else +#define LIBK3B_NO_EXPORT +#define LIBK3B_EXPORT +#endif + +#endif + diff --git a/libk3b/core/k3bcore.cpp b/libk3b/core/k3bcore.cpp new file mode 100644 index 0000000..c10fec0 --- /dev/null +++ b/libk3b/core/k3bcore.cpp @@ -0,0 +1,375 @@ +/* + * + * $Id: k3bcore.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include + +#include "k3bcore.h" +#include "k3bjob.h" + +#include +#ifdef HAVE_HAL +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + + +static Qt::HANDLE s_guiThreadHandle = QThread::currentThread(); + +// We cannot use QWaitCondition here since the event might be handled faster +// than the thread starts the waiting +class DeviceBlockingEventDoneCondition { +public: + DeviceBlockingEventDoneCondition() + : m_done(false) { + } + + void done() { + m_doneMutex.lock(); + m_done = true; + m_doneMutex.unlock(); + } + + void wait() { + while( true ) { + m_doneMutex.lock(); + bool done = m_done; + m_doneMutex.unlock(); + if( done ) + return; + } + } + +private: + QMutex m_doneMutex; + bool m_done; +}; + +class DeviceBlockingEvent : public QCustomEvent +{ +public: + DeviceBlockingEvent( bool block_, K3bDevice::Device* dev, DeviceBlockingEventDoneCondition* cond_, bool* success_ ) + : QCustomEvent( QEvent::User + 33 ), + block(block_), + device(dev), + cond(cond_), + success(success_) { + } + + bool block; + K3bDevice::Device* device; + DeviceBlockingEventDoneCondition* cond; + bool* success; +}; + + +class K3bCore::Private { +public: + Private() + : version( LIBK3B_VERSION ), + config(0), + deleteConfig(false), + deviceManager(0), + externalBinManager(0), + pluginManager(0), + globalSettings(0) { + } + + K3bVersion version; + KConfig* config; + bool deleteConfig; + K3bDevice::DeviceManager* deviceManager; + K3bExternalBinManager* externalBinManager; + K3bPluginManager* pluginManager; + K3bGlobalSettings* globalSettings; + + QValueList runningJobs; + QValueList blockedDevices; +}; + + + +K3bCore* K3bCore::s_k3bCore = 0; + + + +K3bCore::K3bCore( QObject* parent, const char* name ) + : QObject( parent, name ) +{ + d = new Private(); + + if( s_k3bCore ) + qFatal("ONLY ONE INSTANCE OF K3BCORE ALLOWED!"); + s_k3bCore = this; + + // create the thread widget instance in the GUI thread + K3bThreadWidget::instance(); +} + + +K3bCore::~K3bCore() +{ + s_k3bCore = 0; + + delete d->globalSettings; + delete d; +} + + +K3bDevice::DeviceManager* K3bCore::deviceManager() const +{ + const_cast(this)->initDeviceManager(); + return d->deviceManager; +} + + +K3bExternalBinManager* K3bCore::externalBinManager() const +{ + const_cast(this)->initExternalBinManager(); + return d->externalBinManager; +} + + +K3bPluginManager* K3bCore::pluginManager() const +{ + const_cast(this)->initPluginManager(); + return d->pluginManager; +} + + +K3bGlobalSettings* K3bCore::globalSettings() const +{ + const_cast(this)->initGlobalSettings(); + return d->globalSettings; +} + + +const K3bVersion& K3bCore::version() const +{ + return d->version; +} + + +KConfig* K3bCore::config() const +{ + if( !d->config ) { + kdDebug() << "(K3bCore) opening k3b config file." << endl; + kdDebug() << "(K3bCore) while I am a " << className() << endl; + d->deleteConfig = true; + d->config = new KConfig( "k3brc" ); + } + + return d->config; +} + + +void K3bCore::init() +{ + initGlobalSettings(); + initExternalBinManager(); + initDeviceManager(); + initPluginManager(); + + // load the plugins before doing anything else + // they might add external bins + pluginManager()->loadAll(); + + externalBinManager()->search(); + +#ifdef HAVE_HAL + connect( K3bDevice::HalConnection::instance(), SIGNAL(deviceAdded(const QString&)), + deviceManager(), SLOT(addDevice(const QString&)) ); + connect( K3bDevice::HalConnection::instance(), SIGNAL(deviceRemoved(const QString&)), + deviceManager(), SLOT(removeDevice(const QString&)) ); + QStringList devList = K3bDevice::HalConnection::instance()->devices(); + if( devList.isEmpty() ) + deviceManager()->scanBus(); + else + for( unsigned int i = 0; i < devList.count(); ++i ) + deviceManager()->addDevice( devList[i] ); +#else + deviceManager()->scanBus(); +#endif +} + + +void K3bCore::initGlobalSettings() +{ + if( !d->globalSettings ) + d->globalSettings = new K3bGlobalSettings(); +} + + +void K3bCore::initExternalBinManager() +{ + if( !d->externalBinManager ) { + d->externalBinManager = new K3bExternalBinManager( this ); + K3b::addDefaultPrograms( d->externalBinManager ); + } +} + + +void K3bCore::initDeviceManager() +{ + if( !d->deviceManager ) + d->deviceManager = new K3bDevice::DeviceManager( this ); +} + + +void K3bCore::initPluginManager() +{ + if( !d->pluginManager ) + d->pluginManager = new K3bPluginManager( this ); +} + + +void K3bCore::readSettings( KConfig* cnf ) +{ + KConfig* c = cnf; + if( !c ) + c = config(); + + QString oldGrp = c->group(); + + globalSettings()->readSettings( c ); + deviceManager()->readConfig( c ); + externalBinManager()->readConfig( c ); + + c->setGroup( oldGrp ); +} + + +void K3bCore::saveSettings( KConfig* cnf ) +{ + KConfig* c = cnf; + if( !c ) + c = config(); + + QString oldGrp = c->group(); + + c->setGroup( "General Options" ); + c->writeEntry( "config version", version() ); + + deviceManager()->saveConfig( c ); + externalBinManager()->saveConfig( c ); + d->globalSettings->saveSettings( c ); + + c->setGroup( oldGrp ); +} + + +void K3bCore::registerJob( K3bJob* job ) +{ + d->runningJobs.append( job ); + emit jobStarted( job ); + if( K3bBurnJob* bj = dynamic_cast( job ) ) + emit burnJobStarted( bj ); +} + + +void K3bCore::unregisterJob( K3bJob* job ) +{ + d->runningJobs.remove( job ); + emit jobFinished( job ); + if( K3bBurnJob* bj = dynamic_cast( job ) ) + emit burnJobFinished( bj ); +} + + +bool K3bCore::jobsRunning() const +{ + return !d->runningJobs.isEmpty(); +} + + +const QValueList& K3bCore::runningJobs() const +{ + return d->runningJobs; +} + + +bool K3bCore::blockDevice( K3bDevice::Device* dev ) +{ + if( QThread::currentThread() == s_guiThreadHandle ) { + return internalBlockDevice( dev ); + } + else { + bool success = false; + DeviceBlockingEventDoneCondition w; + QApplication::postEvent( this, new DeviceBlockingEvent( true, dev, &w, &success ) ); + w.wait(); + return success; + } +} + + +void K3bCore::unblockDevice( K3bDevice::Device* dev ) +{ + if( QThread::currentThread() == s_guiThreadHandle ) { + internalUnblockDevice( dev ); + } + else { + DeviceBlockingEventDoneCondition w; + QApplication::postEvent( this, new DeviceBlockingEvent( false, dev, &w, 0 ) ); + w.wait(); + } +} + + +bool K3bCore::internalBlockDevice( K3bDevice::Device* dev ) +{ + if( !d->blockedDevices.contains( dev ) ) { + d->blockedDevices.append( dev ); + return true; + } + else + return false; +} + + +void K3bCore::internalUnblockDevice( K3bDevice::Device* dev ) +{ + d->blockedDevices.remove( dev ); +} + + +void K3bCore::customEvent( QCustomEvent* e ) +{ + if( DeviceBlockingEvent* de = dynamic_cast(e) ) { + if( de->block ) + *de->success = internalBlockDevice( de->device ); + else + internalUnblockDevice( de->device ); + de->cond->done(); + } +} + +#include "k3bcore.moc" diff --git a/libk3b/core/k3bcore.h b/libk3b/core/k3bcore.h new file mode 100644 index 0000000..ce73e32 --- /dev/null +++ b/libk3b/core/k3bcore.h @@ -0,0 +1,181 @@ +/* + * + * $Id: k3bcore.h 733470 2007-11-06 12:10:29Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_CORE_H_ +#define _K3B_CORE_H_ + +#include +#include + +#include "k3b_export.h" + + +#define LIBK3B_VERSION "1.0.5" + +#define k3bcore K3bCore::k3bCore() + + +class K3bExternalBinManager; +class K3bVersion; +class KConfig; +class KAboutData; +class K3bJob; +class K3bBurnJob; +class K3bGlobalSettings; +class K3bPluginManager; +class QCustomEvent; + + +namespace K3bDevice { + class DeviceManager; + class Device; +} + + +/** + * The K3b core takes care of the managers. + * This has been separated from K3bApplication to + * make creating a K3bPart easy. + * This is the heart of the K3b system. Every plugin may use this + * to get the information it needs. + */ +class LIBK3B_EXPORT K3bCore : public QObject +{ + Q_OBJECT + + public: + /** + * Although K3bCore is a singlelton it's constructor is not private to make inheritance + * possible. Just make sure to only create one instance. + */ + K3bCore( QObject* parent = 0, const char* name = 0 ); + virtual ~K3bCore(); + + const QValueList& runningJobs() const; + + /** + * Equals to !runningJobs().isEmpty() + */ + bool jobsRunning() const; + + /** + * The default implementation calls add four initXXX() methods, + * scans for devices, applications, and reads the global settings. + */ + virtual void init(); + + /** + * @param c if 0 K3bCore uses the K3b configuration + */ + virtual void readSettings( KConfig* c = 0 ); + + /** + * @param c if 0 K3bCore uses the K3b configuration + */ + virtual void saveSettings( KConfig* c = 0 ); + + /** + * If this is reimplemented it is recommended to also reimplement + * init(). + */ + virtual K3bDevice::DeviceManager* deviceManager() const; + + /** + * Returns the external bin manager from K3bCore. + * + * By default K3bCore only adds the default programs: + * cdrecord, cdrdao, growisofs, mkisofs, dvd+rw-format, readcd + * + * If you need other programs you have to add them manually like this: + *

externalBinManager()->addProgram( new K3bNormalizeProgram() );
+ */ + K3bExternalBinManager* externalBinManager() const; + K3bPluginManager* pluginManager() const; + + /** + * Global settings used throughout libk3b. Change the settings directly in the + * K3bGlobalSettings object. They will be saved by K3bCore::saveSettings + */ + K3bGlobalSettings* globalSettings() const; + + /** + * returns the version of the library as defined by LIBK3B_VERSION + */ + const K3bVersion& version() const; + + /** + * Default implementation returns the K3b configuration from k3brc. + * Normally this should not be used. + */ + virtual KConfig* config() const; + + /** + * Used by the writing jobs to block a device. + * This makes sure no device is used twice within libk3b + * + * When using this method in a job be aware that reimplementations might + * open dialogs and resulting in a blocking call. + * + * This method calls internalBlockDevice() to do the actual work. + */ + bool blockDevice( K3bDevice::Device* ); + void unblockDevice( K3bDevice::Device* ); + + static K3bCore* k3bCore() { return s_k3bCore; } + + signals: + /** + * Emitted once a new job has been started. This includes burn jobs. + */ + void jobStarted( K3bJob* ); + void burnJobStarted( K3bBurnJob* ); + void jobFinished( K3bJob* ); + void burnJobFinished( K3bBurnJob* ); + + public slots: + /** + * Every running job registers itself with the core. + * For now this is only used to determine if some job + * is running. + */ + void registerJob( K3bJob* job ); + void unregisterJob( K3bJob* job ); + + protected: + /** + * Reimplement this to add additonal checks. + * + * This method is thread safe. blockDevice makes sure + * it is only executed in the GUI thread. + */ + virtual bool internalBlockDevice( K3bDevice::Device* ); + virtual void internalUnblockDevice( K3bDevice::Device* ); + + virtual void initGlobalSettings(); + virtual void initExternalBinManager(); + virtual void initDeviceManager(); + virtual void initPluginManager(); + + virtual void customEvent( QCustomEvent* e ); + + private: + class Private; + Private* d; + + static K3bCore* s_k3bCore; +}; + +#endif diff --git a/libk3b/core/k3bdataevent.h b/libk3b/core/k3bdataevent.h new file mode 100644 index 0000000..b6a4334 --- /dev/null +++ b/libk3b/core/k3bdataevent.h @@ -0,0 +1,48 @@ +/* + * + * $Id: k3bdataevent.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef K3B_DATA_EVENT_H +#define K3B_DATA_EVENT_H + +#include + + +/** + * Custom event class for posting events corresponding to the + * K3bJob signals. This is useful for a threaded job since + * in that case it's not possible to emit signals that directly + * change the GUI (see QThread docu). + */ +class K3bDataEvent : public QCustomEvent +{ + public: + // make sure we get not in the way of K3bProgressInfoEvent + static const int EVENT_TYPE = QEvent::User + 100; + + K3bDataEvent( const char* data, int len ) + : QCustomEvent( EVENT_TYPE ), + m_data(data), + m_length(len) + {} + + const char* data() const { return m_data; } + int length() const { return m_length; } + + private: + const char* m_data; + int m_length; +}; + +#endif diff --git a/libk3b/core/k3bdefaultexternalprograms.cpp b/libk3b/core/k3bdefaultexternalprograms.cpp new file mode 100644 index 0000000..b654d22 --- /dev/null +++ b/libk3b/core/k3bdefaultexternalprograms.cpp @@ -0,0 +1,1030 @@ +/* + * + * $Id: k3bdefaultexternalprograms.cpp 731898 2007-11-02 08:22:18Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bdefaultexternalprograms.h" +#include "k3bexternalbinmanager.h" +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + + + +void K3b::addDefaultPrograms( K3bExternalBinManager* m ) +{ + m->addProgram( new K3bCdrecordProgram(false) ); + m->addProgram( new K3bMkisofsProgram() ); + m->addProgram( new K3bReadcdProgram() ); + m->addProgram( new K3bCdrdaoProgram() ); + m->addProgram( new K3bGrowisofsProgram() ); + m->addProgram( new K3bDvdformatProgram() ); + // m->addProgram( new K3bDvdBooktypeProgram() ); +} + + +void K3b::addTranscodePrograms( K3bExternalBinManager* m ) +{ + static const char* transcodeTools[] = { "transcode", + 0, // K3b 1.0 only uses the transcode binary + "tcprobe", + "tccat", + "tcscan", + "tcextract", + "tcdecode", + 0 }; + + for( int i = 0; transcodeTools[i]; ++i ) + m->addProgram( new K3bTranscodeProgram( transcodeTools[i] ) ); +} + + +void K3b::addVcdimagerPrograms( K3bExternalBinManager* m ) +{ + // don't know if we need more vcdTools in the future (vcdxrip) + static const char* vcdTools[] = { "vcdxbuild", + "vcdxminfo", + "vcdxrip", + 0 }; + + for( int i = 0; vcdTools[i]; ++i ) + m->addProgram( new K3bVcdbuilderProgram( vcdTools[i] ) ); +} + + +K3bCdrecordProgram::K3bCdrecordProgram( bool dvdPro ) + : K3bExternalProgram( dvdPro ? "cdrecord-prodvd" : "cdrecord" ), + m_dvdPro(dvdPro) +{ +} + + +// +// This is a hack for Debian based systems which use +// a wrapper cdrecord script to call cdrecord.mmap or cdrecord.shm +// depending on the kernel version. +// For 2.0.x and 2.2.x kernels the shm version is used. In all +// other cases it's the mmap version. +// +// But since it may be that someone manually installed cdrecord +// replacing the wrapper we check if cdrecord is a script. +// +static QString& debianWeirdnessHack( QString& path ) +{ + if( QFile::exists( path + ".mmap" ) ) { + kdDebug() << "(K3bCdrecordProgram) checking for Debian cdrecord wrapper script." << endl; + if( QFileInfo( path ).size() < 1024 ) { + kdDebug() << "(K3bCdrecordProgram) Debian Wrapper script size fits. Checking file." << endl; + QFile f( path ); + f.open( IO_ReadOnly ); + QString s = QTextStream( &f ).read(); + if( s.contains( "cdrecord.mmap" ) && s.contains( "cdrecord.shm" ) ) { + kdDebug() << "(K3bCdrecordProgram) Found Debian Wrapper script." << endl; + QString ext; + if( K3b::kernelVersion().versionString().left(3) > "2.2" ) + ext = ".mmap"; + else + ext = ".shm"; + + kdDebug() << "(K3bCdrecordProgram) Using cdrecord" << ext << endl; + + path += ext; + } + } + } + + return path; +} + + +bool K3bCdrecordProgram::scan( const QString& p ) +{ + if( p.isEmpty() ) + return false; + + bool wodim = false; + QString path = p; + QFileInfo fi( path ); + if( fi.isDir() ) { + if( path[path.length()-1] != '/' ) + path.append("/"); + + if( QFile::exists( path + "wodim" ) ) { + wodim = true; + path += "wodim"; + } + else if( QFile::exists( path + "cdrecord" ) ) { + path += "cdrecord"; + } + else + return false; + } + + debianWeirdnessHack( path ); + + K3bExternalBin* bin = 0; + + // probe version + KProcess vp; + K3bProcessOutputCollector out( &vp ); + + vp << path << "-version"; + if( vp.start( KProcess::Block, KProcess::AllOutput ) ) { + int pos = -1; + if( wodim ) { + pos = out.output().find( "Wodim" ); + } + else if( m_dvdPro ) { + pos = out.output().find( "Cdrecord-ProDVD" ); + } + else { + pos = out.output().find( "Cdrecord" ); + } + + if( pos < 0 ) + return false; + + pos = out.output().find( QRegExp("[0-9]"), pos ); + if( pos < 0 ) + return false; + + int endPos = out.output().find( QRegExp("\\s"), pos+1 ); + if( endPos < 0 ) + return false; + + bin = new K3bExternalBin( this ); + bin->path = path; + bin->version = out.output().mid( pos, endPos-pos ); + + if( wodim ) + bin->addFeature( "wodim" ); + + pos = out.output().find( "Copyright") + 14; + endPos = out.output().find( "\n", pos ); + + // cdrecord does not use local encoding for the copyright statement but plain latin1 + bin->copyright = QString::fromLatin1( out.output().mid( pos, endPos-pos ).local8Bit() ).stripWhiteSpace(); + } + else { + kdDebug() << "(K3bCdrecordProgram) could not start " << path << endl; + return false; + } + + if( !m_dvdPro && bin->version.suffix().endsWith( "-dvd" ) ) { + bin->addFeature( "dvd-patch" ); + bin->version = QString(bin->version.versionString()).remove("-dvd"); + } + + // probe features + KProcess fp; + out.setProcess( &fp ); + fp << path << "-help"; + if( fp.start( KProcess::Block, KProcess::AllOutput ) ) { + if( out.output().contains( "gracetime" ) ) + bin->addFeature( "gracetime" ); + if( out.output().contains( "-overburn" ) ) + bin->addFeature( "overburn" ); + if( out.output().contains( "-text" ) ) + bin->addFeature( "cdtext" ); + if( out.output().contains( "-clone" ) ) + bin->addFeature( "clone" ); + if( out.output().contains( "-tao" ) ) + bin->addFeature( "tao" ); + if( out.output().contains( "cuefile=" ) && + ( wodim || bin->version > K3bVersion( 2, 1, -1, "a14") ) ) // cuefile handling was still buggy in a14 + bin->addFeature( "cuefile" ); + + // new mode 2 options since cdrecord 2.01a12 + // we use both checks here since the help was not updated in 2.01a12 yet (well, I + // just double-checked and the help page is proper but there is no harm in having + // two checks) + // and the version check does not handle versions like 2.01-dvd properly + if( out.output().contains( "-xamix" ) || + bin->version >= K3bVersion( 2, 1, -1, "a12" ) || + wodim ) + bin->addFeature( "xamix" ); + + // check if we run cdrecord as root + struct stat s; + if( !::stat( QFile::encodeName(path), &s ) ) { + if( (s.st_mode & S_ISUID) && s.st_uid == 0 ) + bin->addFeature( "suidroot" ); + } + } + else { + kdDebug() << "(K3bCdrecordProgram) could not start " << bin->path << endl; + delete bin; + return false; + } + + if( bin->version < K3bVersion( 2, 0 ) && !wodim ) + bin->addFeature( "outdated" ); + + // FIXME: are these version correct? + if( bin->version >= K3bVersion("1.11a38") || wodim ) + bin->addFeature( "plain-atapi" ); + if( bin->version > K3bVersion("1.11a17") || wodim ) + bin->addFeature( "hacked-atapi" ); + + if( bin->version >= K3bVersion( 2, 1, 1, "a02" ) || wodim ) + bin->addFeature( "short-track-raw" ); + + if( bin->version >= K3bVersion( 2, 1, -1, "a13" ) || wodim ) + bin->addFeature( "audio-stdin" ); + + if( bin->version >= K3bVersion( "1.11a02" ) || wodim ) + bin->addFeature( "burnfree" ); + else + bin->addFeature( "burnproof" ); + + addBin( bin ); + return true; +} + + + +K3bMkisofsProgram::K3bMkisofsProgram() + : K3bExternalProgram( "mkisofs" ) +{ +} + +bool K3bMkisofsProgram::scan( const QString& p ) +{ + if( p.isEmpty() ) + return false; + + bool genisoimage = false; + QString path = p; + QFileInfo fi( path ); + if( fi.isDir() ) { + if( path[path.length()-1] != '/' ) + path.append("/"); + + if( QFile::exists( path + "genisoimage" ) ) { + genisoimage = true; + path += "genisoimage"; + } + else if( QFile::exists( path + "mkisofs" ) ) { + path += "mkisofs"; + } + else + return false; + } + + K3bExternalBin* bin = 0; + + // probe version + KProcess vp; + vp << path << "-version"; + K3bProcessOutputCollector out( &vp ); + if( vp.start( KProcess::Block, KProcess::AllOutput ) ) { + int pos = -1; + if( genisoimage ) + pos = out.output().find( "genisoimage" ); + else + pos = out.output().find( "mkisofs" ); + + if( pos < 0 ) + return false; + + pos = out.output().find( QRegExp("[0-9]"), pos ); + if( pos < 0 ) + return false; + + int endPos = out.output().find( ' ', pos+1 ); + if( endPos < 0 ) + return false; + + bin = new K3bExternalBin( this ); + bin->path = path; + bin->version = out.output().mid( pos, endPos-pos ); + + if( genisoimage ) + bin->addFeature( "genisoimage" ); + } + else { + kdDebug() << "(K3bMkisofsProgram) could not start " << path << endl; + return false; + } + + + + // probe features + KProcess fp; + fp << path << "-help"; + out.setProcess( &fp ); + if( fp.start( KProcess::Block, KProcess::AllOutput ) ) { + if( out.output().contains( "-udf" ) ) + bin->addFeature( "udf" ); + if( out.output().contains( "-dvd-video" ) ) + bin->addFeature( "dvd-video" ); + if( out.output().contains( "-joliet-long" ) ) + bin->addFeature( "joliet-long" ); + if( out.output().contains( "-xa" ) ) + bin->addFeature( "xa" ); + if( out.output().contains( "-sectype" ) ) + bin->addFeature( "sectype" ); + + // check if we run mkisofs as root + struct stat s; + if( !::stat( QFile::encodeName(path), &s ) ) { + if( (s.st_mode & S_ISUID) && s.st_uid == 0 ) + bin->addFeature( "suidroot" ); + } + } + else { + kdDebug() << "(K3bMkisofsProgram) could not start " << bin->path << endl; + delete bin; + return false; + } + + if( bin->version < K3bVersion( 1, 14) && !genisoimage ) + bin->addFeature( "outdated" ); + + if( bin->version >= K3bVersion( 1, 15, -1, "a40" ) || genisoimage ) + bin->addFeature( "backslashed_filenames" ); + + if ( genisoimage && bin->version >= K3bVersion( 1, 1, 4 ) ) + bin->addFeature( "no-4gb-limit" ); + + if ( !genisoimage && bin->version >= K3bVersion( 2, 1, 1, "a32" ) ) + bin->addFeature( "no-4gb-limit" ); + + addBin(bin); + return true; +} + + +K3bReadcdProgram::K3bReadcdProgram() + : K3bExternalProgram( "readcd" ) +{ +} + +bool K3bReadcdProgram::scan( const QString& p ) +{ + if( p.isEmpty() ) + return false; + + bool readom = false; + QString path = p; + QFileInfo fi( path ); + if( fi.isDir() ) { + if( path[path.length()-1] != '/' ) + path.append("/"); + + if( QFile::exists( path + "readom" ) ) { + readom = true; + path += "readom"; + } + else if( QFile::exists( path + "readcd" ) ) { + path += "readcd"; + } + else + return false; + } + + if( !QFile::exists( path ) ) + return false; + + K3bExternalBin* bin = 0; + + // probe version + KProcess vp; + vp << path << "-version"; + K3bProcessOutputCollector out( &vp ); + if( vp.start( KProcess::Block, KProcess::AllOutput ) ) { + int pos = -1; + if( readom ) + pos = out.output().find( "readom" ); + else + pos = out.output().find( "readcd" ); + if( pos < 0 ) + return false; + + pos = out.output().find( QRegExp("[0-9]"), pos ); + if( pos < 0 ) + return false; + + int endPos = out.output().find( ' ', pos+1 ); + if( endPos < 0 ) + return false; + + bin = new K3bExternalBin( this ); + bin->path = path; + bin->version = out.output().mid( pos, endPos-pos ); + + if( readom ) + bin->addFeature( "readom" ); + } + else { + kdDebug() << "(K3bMkisofsProgram) could not start " << path << endl; + return false; + } + + + + // probe features + KProcess fp; + fp << path << "-help"; + out.setProcess( &fp ); + if( fp.start( KProcess::Block, KProcess::AllOutput ) ) { + if( out.output().contains( "-clone" ) ) + bin->addFeature( "clone" ); + + // check if we run mkisofs as root + struct stat s; + if( !::stat( QFile::encodeName(path), &s ) ) { + if( (s.st_mode & S_ISUID) && s.st_uid == 0 ) + bin->addFeature( "suidroot" ); + } + } + else { + kdDebug() << "(K3bReadcdProgram) could not start " << bin->path << endl; + delete bin; + return false; + } + + + // FIXME: are these version correct? + if( bin->version >= K3bVersion("1.11a38") || readom ) + bin->addFeature( "plain-atapi" ); + if( bin->version > K3bVersion("1.11a17") || readom ) + bin->addFeature( "hacked-atapi" ); + + addBin(bin); + return true; +} + + +K3bCdrdaoProgram::K3bCdrdaoProgram() + : K3bExternalProgram( "cdrdao" ) +{ +} + +bool K3bCdrdaoProgram::scan( const QString& p ) +{ + if( p.isEmpty() ) + return false; + + QString path = p; + QFileInfo fi( path ); + if( fi.isDir() ) { + if( path[path.length()-1] != '/' ) + path.append("/"); + path.append("cdrdao"); + } + + if( !QFile::exists( path ) ) + return false; + + K3bExternalBin* bin = 0; + + // probe version + KProcess vp; + vp << path ; + K3bProcessOutputCollector out( &vp ); + if( vp.start( KProcess::Block, KProcess::AllOutput ) ) { + int pos = out.output().find( "Cdrdao version" ); + if( pos < 0 ) + return false; + + pos = out.output().find( QRegExp("[0-9]"), pos ); + if( pos < 0 ) + return false; + + int endPos = out.output().find( ' ', pos+1 ); + if( endPos < 0 ) + return false; + + bin = new K3bExternalBin( this ); + bin->path = path; + bin->version = out.output().mid( pos, endPos-pos ); + + pos = out.output().find( "(C)", endPos+1 ) + 4; + endPos = out.output().find( '\n', pos ); + bin->copyright = out.output().mid( pos, endPos-pos ); + } + else { + kdDebug() << "(K3bCdrdaoProgram) could not start " << path << endl; + return false; + } + + + + // probe features + KProcess fp; + fp << path << "write" << "-h"; + out.setProcess( &fp ); + if( fp.start( KProcess::Block, KProcess::AllOutput ) ) { + if( out.output().contains( "--overburn" ) ) + bin->addFeature( "overburn" ); + if( out.output().contains( "--multi" ) ) + bin->addFeature( "multisession" ); + + if( out.output().contains( "--buffer-under-run-protection" ) ) + bin->addFeature( "disable-burnproof" ); + + // check if we run cdrdao as root + struct stat s; + if( !::stat( QFile::encodeName(path), &s ) ) { + if( (s.st_mode & S_ISUID) && s.st_uid == 0 ) + bin->addFeature( "suidroot" ); + } + } + else { + kdDebug() << "(K3bCdrdaoProgram) could not start " << bin->path << endl; + delete bin; + return false; + } + + + // SuSE 9.0 ships with a patched cdrdao 1.1.7 which contains an updated libschily + // Gentoo ships with a patched cdrdao 1.1.7 which contains scglib support + if( bin->version > K3bVersion( 1, 1, 7 ) || + bin->version == K3bVersion( 1, 1, 7, "-gentoo" ) || + bin->version == K3bVersion( 1, 1, 7, "-suse" ) ) { + // bin->addFeature( "plain-atapi" ); + bin->addFeature( "hacked-atapi" ); + } + + if( bin->version >= K3bVersion( 1, 1, 8 ) ) + bin->addFeature( "plain-atapi" ); + + addBin(bin); + return true; +} + + +K3bTranscodeProgram::K3bTranscodeProgram( const QString& transcodeProgram ) + : K3bExternalProgram( transcodeProgram ), + m_transcodeProgram( transcodeProgram ) +{ +} + +bool K3bTranscodeProgram::scan( const QString& p ) +{ + if( p.isEmpty() ) + return false; + + QString path = p; + if( path[path.length()-1] != '/' ) + path.append("/"); + + QString appPath = path + m_transcodeProgram; + + if( !QFile::exists( appPath ) ) + return false; + + K3bExternalBin* bin = 0; + + // probe version + KProcess vp; + vp << appPath << "-v"; + K3bProcessOutputCollector out( &vp ); + if( vp.start( KProcess::Block, KProcess::AllOutput ) ) { + int pos = out.output().find( "transcode v" ); + if( pos < 0 ) + return false; + + pos += 11; + + int endPos = out.output().find( QRegExp("[\\s\\)]"), pos+1 ); + if( endPos < 0 ) + return false; + + bin = new K3bExternalBin( this ); + bin->path = appPath; + bin->version = out.output().mid( pos, endPos-pos ); + } + else { + kdDebug() << "(K3bTranscodeProgram) could not start " << appPath << endl; + return false; + } + + // + // Check features + // + QString modInfoBin = path + "tcmodinfo"; + KProcess modp; + modp << modInfoBin << "-p"; + out.setProcess( &modp ); + if( modp.start( KProcess::Block, KProcess::AllOutput ) ) { + QString modPath = out.output().stripWhiteSpace(); + QDir modDir( modPath ); + if( !modDir.entryList( "*export_xvid*", QDir::Files ).isEmpty() ) + bin->addFeature( "xvid" ); + if( !modDir.entryList( "*export_lame*", QDir::Files ).isEmpty() ) + bin->addFeature( "lame" ); + if( !modDir.entryList( "*export_ffmpeg*", QDir::Files ).isEmpty() ) + bin->addFeature( "ffmpeg" ); + if( !modDir.entryList( "*export_ac3*", QDir::Files ).isEmpty() ) + bin->addFeature( "ac3" ); + } + + addBin(bin); + return true; +} + + + +K3bVcdbuilderProgram::K3bVcdbuilderProgram( const QString& p ) + : K3bExternalProgram( p ), + m_vcdbuilderProgram( p ) +{ +} + +bool K3bVcdbuilderProgram::scan( const QString& p ) +{ + if( p.isEmpty() ) + return false; + + QString path = p; + QFileInfo fi( path ); + if( fi.isDir() ) { + if( path[path.length()-1] != '/' ) + path.append("/"); + path.append(m_vcdbuilderProgram); + } + + if( !QFile::exists( path ) ) + return false; + + K3bExternalBin* bin = 0; + + // probe version + KProcess vp; + vp << path << "-V"; + K3bProcessOutputCollector out( &vp ); + if( vp.start( KProcess::Block, KProcess::AllOutput ) ) { + int pos = out.output().find( "GNU VCDImager" ); + if( pos < 0 ) + return false; + + pos += 14; + + int endPos = out.output().find( QRegExp("[\\n\\)]"), pos+1 ); + if( endPos < 0 ) + return false; + + bin = new K3bExternalBin( this ); + bin->path = path; + bin->version = out.output().mid( pos, endPos-pos ).stripWhiteSpace(); + + pos = out.output().find( "Copyright" ) + 14; + endPos = out.output().find( "\n", pos ); + bin->copyright = out.output().mid( pos, endPos-pos ).stripWhiteSpace(); + } + else { + kdDebug() << "(K3bVcdbuilderProgram) could not start " << path << endl; + return false; + } + + addBin(bin); + return true; +} + + +K3bNormalizeProgram::K3bNormalizeProgram() + : K3bExternalProgram( "normalize-audio" ) +{ +} + + +bool K3bNormalizeProgram::scan( const QString& p ) +{ + if( p.isEmpty() ) + return false; + + QString path = p; + QFileInfo fi( path ); + if( fi.isDir() ) { + if( path[path.length()-1] != '/' ) + path.append("/"); + path.append("normalize-audio"); + } + + if( !QFile::exists( path ) ) + return false; + + K3bExternalBin* bin = 0; + + // probe version + KProcess vp; + K3bProcessOutputCollector out( &vp ); + + vp << path << "--version"; + if( vp.start( KProcess::Block, KProcess::AllOutput ) ) { + int pos = out.output().find( "normalize" ); + if( pos < 0 ) + return false; + + pos = out.output().find( QRegExp("\\d"), pos ); + if( pos < 0 ) + return false; + + int endPos = out.output().find( QRegExp("\\s"), pos+1 ); + if( endPos < 0 ) + return false; + + bin = new K3bExternalBin( this ); + bin->path = path; + bin->version = out.output().mid( pos, endPos-pos ); + + pos = out.output().find( "Copyright" )+14; + endPos = out.output().find( "\n", pos ); + bin->copyright = out.output().mid( pos, endPos-pos ).stripWhiteSpace(); + } + else { + kdDebug() << "(K3bCdrecordProgram) could not start " << path << endl; + return false; + } + + addBin( bin ); + return true; +} + + +K3bGrowisofsProgram::K3bGrowisofsProgram() + : K3bExternalProgram( "growisofs" ) +{ +} + +bool K3bGrowisofsProgram::scan( const QString& p ) +{ + if( p.isEmpty() ) + return false; + + QString path = p; + QFileInfo fi( path ); + if( fi.isDir() ) { + if( path[path.length()-1] != '/' ) + path.append("/"); + path.append("growisofs"); + } + + if( !QFile::exists( path ) ) + return false; + + K3bExternalBin* bin = 0; + + // probe version + KProcess vp; + K3bProcessOutputCollector out( &vp ); + + vp << path << "-version"; + if( vp.start( KProcess::Block, KProcess::AllOutput ) ) { + int pos = out.output().find( "growisofs" ); + if( pos < 0 ) + return false; + + pos = out.output().find( QRegExp("\\d"), pos ); + if( pos < 0 ) + return false; + + int endPos = out.output().find( ",", pos+1 ); + if( endPos < 0 ) + return false; + + bin = new K3bExternalBin( this ); + bin->path = path; + bin->version = out.output().mid( pos, endPos-pos ); + } + else { + kdDebug() << "(K3bGrowisofsProgram) could not start " << path << endl; + return false; + } + + // fixed Copyright: + bin->copyright = "Andy Polyakov "; + + // check if we run growisofs as root + struct stat s; + if( !::stat( QFile::encodeName(path), &s ) ) { + if( (s.st_mode & S_ISUID) && s.st_uid == 0 ) + bin->addFeature( "suidroot" ); + } + + addBin( bin ); + return true; +} + + +K3bDvdformatProgram::K3bDvdformatProgram() + : K3bExternalProgram( "dvd+rw-format" ) +{ +} + +bool K3bDvdformatProgram::scan( const QString& p ) +{ + if( p.isEmpty() ) + return false; + + QString path = p; + QFileInfo fi( path ); + if( fi.isDir() ) { + if( path[path.length()-1] != '/' ) + path.append("/"); + path.append("dvd+rw-format"); + } + + if( !QFile::exists( path ) ) + return false; + + K3bExternalBin* bin = 0; + + // probe version + KProcess vp; + K3bProcessOutputCollector out( &vp ); + + vp << path; + if( vp.start( KProcess::Block, KProcess::AllOutput ) ) { + // different locales make searching for the +- char difficult + // so we simply ignore it. + int pos = out.output().find( QRegExp("DVD.*RAM format utility") ); + if( pos < 0 ) + return false; + + pos = out.output().find( "version", pos ); + if( pos < 0 ) + return false; + + pos += 8; + + // the version ends in a dot. + int endPos = out.output().find( QRegExp("\\.\\D"), pos ); + if( endPos < 0 ) + return false; + + bin = new K3bExternalBin( this ); + bin->path = path; + bin->version = out.output().mid( pos, endPos-pos ); + } + else { + kdDebug() << "(K3bDvdformatProgram) could not start " << path << endl; + return false; + } + + // fixed Copyright: + bin->copyright = "Andy Polyakov "; + + // check if we run dvd+rw-format as root + struct stat s; + if( !::stat( QFile::encodeName(path), &s ) ) { + if( (s.st_mode & S_ISUID) && s.st_uid == 0 ) + bin->addFeature( "suidroot" ); + } + + addBin( bin ); + return true; +} + + +K3bDvdBooktypeProgram::K3bDvdBooktypeProgram() + : K3bExternalProgram( "dvd+rw-booktype" ) +{ +} + +bool K3bDvdBooktypeProgram::scan( const QString& p ) +{ + if( p.isEmpty() ) + return false; + + QString path = p; + QFileInfo fi( path ); + if( fi.isDir() ) { + if( path[path.length()-1] != '/' ) + path.append("/"); + path.append("dvd+rw-booktype"); + } + + if( !QFile::exists( path ) ) + return false; + + K3bExternalBin* bin = 0; + + // probe version + KProcess vp; + K3bProcessOutputCollector out( &vp ); + + vp << path; + if( vp.start( KProcess::Block, KProcess::AllOutput ) ) { + int pos = out.output().find( "dvd+rw-booktype" ); + if( pos < 0 ) + return false; + + bin = new K3bExternalBin( this ); + bin->path = path; + // No version information. Create dummy version + bin->version = K3bVersion( 1, 0, 0 ); + } + else { + kdDebug() << "(K3bDvdBooktypeProgram) could not start " << path << endl; + return false; + } + + addBin( bin ); + return true; +} + + + +K3bCdda2wavProgram::K3bCdda2wavProgram() + : K3bExternalProgram( "cdda2wav" ) +{ +} + +bool K3bCdda2wavProgram::scan( const QString& p ) +{ + if( p.isEmpty() ) + return false; + + QString path = p; + QFileInfo fi( path ); + if( fi.isDir() ) { + if( path[path.length()-1] != '/' ) + path.append("/"); + path.append("cdda2wav"); + } + + if( !QFile::exists( path ) ) + return false; + + K3bExternalBin* bin = 0; + + // probe version + KProcess vp; + K3bProcessOutputCollector out( &vp ); + + vp << path << "-h"; + if( vp.start( KProcess::Block, KProcess::AllOutput ) ) { + int pos = out.output().find( "cdda2wav" ); + if( pos < 0 ) + return false; + + pos = out.output().find( "Version", pos ); + if( pos < 0 ) + return false; + + pos += 8; + + // the version does not end in a space but the kernel info + int endPos = out.output().find( QRegExp("[^\\d\\.]"), pos ); + if( endPos < 0 ) + return false; + + bin = new K3bExternalBin( this ); + bin->path = path; + bin->version = out.output().mid( pos, endPos-pos ); + + // features (we do this since the cdda2wav help says that the short + // options will disappear soon) + if( out.output().find( "-info-only" ) ) + bin->addFeature( "info-only" ); // otherwise use the -J option + if( out.output().find( "-no-infofile" ) ) + bin->addFeature( "no-infofile" ); // otherwise use the -H option + if( out.output().find( "-gui" ) ) + bin->addFeature( "gui" ); // otherwise use the -g option + if( out.output().find( "-bulk" ) ) + bin->addFeature( "bulk" ); // otherwise use the -B option + if( out.output().find( "dev=" ) ) + bin->addFeature( "dev" ); // otherwise use the -B option + } + else { + kdDebug() << "(K3bCdda2wavProgram) could not start " << path << endl; + return false; + } + + // check if we run as root + struct stat s; + if( !::stat( QFile::encodeName(path), &s ) ) { + if( (s.st_mode & S_ISUID) && s.st_uid == 0 ) + bin->addFeature( "suidroot" ); + } + + addBin( bin ); + return true; +} + diff --git a/libk3b/core/k3bdefaultexternalprograms.h b/libk3b/core/k3bdefaultexternalprograms.h new file mode 100644 index 0000000..3212727 --- /dev/null +++ b/libk3b/core/k3bdefaultexternalprograms.h @@ -0,0 +1,143 @@ +/* + * + * $Id: k3bdefaultexternalprograms.h 623768 2007-01-15 13:33:55Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + + +#ifndef _K3B_DEFAULT_EXTERNAL_BIN_PROGRAMS_H_ +#define _K3B_DEFAULT_EXTERNAL_BIN_PROGRAMS_H_ + +#include "k3bexternalbinmanager.h" +#include "k3b_export.h" +class K3bExternalBinManager; + +namespace K3b +{ + LIBK3B_EXPORT void addDefaultPrograms( K3bExternalBinManager* ); + LIBK3B_EXPORT void addTranscodePrograms( K3bExternalBinManager* ); + LIBK3B_EXPORT void addVcdimagerPrograms( K3bExternalBinManager* ); +} + + +class LIBK3B_EXPORT K3bCdrecordProgram : public K3bExternalProgram +{ + public: + K3bCdrecordProgram( bool dvdPro ); + + bool scan( const QString& ); + + private: + bool m_dvdPro; +}; + + +class LIBK3B_EXPORT K3bMkisofsProgram : public K3bExternalProgram +{ + public: + K3bMkisofsProgram(); + + bool scan( const QString& ); +}; + + +class LIBK3B_EXPORT K3bReadcdProgram : public K3bExternalProgram +{ + public: + K3bReadcdProgram(); + + bool scan( const QString& ); +}; + + +class LIBK3B_EXPORT K3bCdrdaoProgram : public K3bExternalProgram +{ + public: + K3bCdrdaoProgram(); + + bool scan( const QString& ); +}; + + +class LIBK3B_EXPORT K3bTranscodeProgram : public K3bExternalProgram +{ + public: + K3bTranscodeProgram( const QString& transcodeProgram ); + + bool scan( const QString& ); + + // no user parameters (yet) + bool supportsUserParameters() const { return false; } + + private: + QString m_transcodeProgram; +}; + + +class LIBK3B_EXPORT K3bVcdbuilderProgram : public K3bExternalProgram +{ + public: + K3bVcdbuilderProgram( const QString& ); + + bool scan( const QString& ); + + private: + QString m_vcdbuilderProgram; +}; + + +class LIBK3B_EXPORT K3bNormalizeProgram : public K3bExternalProgram +{ + public: + K3bNormalizeProgram(); + + bool scan( const QString& ); +}; + + +class LIBK3B_EXPORT K3bGrowisofsProgram : public K3bExternalProgram +{ + public: + K3bGrowisofsProgram(); + + bool scan( const QString& ); +}; + + +class LIBK3B_EXPORT K3bDvdformatProgram : public K3bExternalProgram +{ + public: + K3bDvdformatProgram(); + + bool scan( const QString& ); +}; + + +class LIBK3B_EXPORT K3bDvdBooktypeProgram : public K3bExternalProgram +{ + public: + K3bDvdBooktypeProgram(); + + bool scan( const QString& ); +}; + + +class LIBK3B_EXPORT K3bCdda2wavProgram : public K3bExternalProgram +{ + public: + K3bCdda2wavProgram(); + + bool scan( const QString& ); +}; + +#endif diff --git a/libk3b/core/k3bexternalbinmanager.cpp b/libk3b/core/k3bexternalbinmanager.cpp new file mode 100644 index 0000000..2b21a85 --- /dev/null +++ b/libk3b/core/k3bexternalbinmanager.cpp @@ -0,0 +1,389 @@ +/* + * + * $Id: k3bexternalbinmanager.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bexternalbinmanager.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + + + +QString K3bExternalBinManager::m_noPath = ""; + + +// /////////////////////////////////////////////////////////// +// +// K3BEXTERNALBIN +// +// /////////////////////////////////////////////////////////// + +K3bExternalBin::K3bExternalBin( K3bExternalProgram* p ) + : m_program(p) +{ +} + + +bool K3bExternalBin::isEmpty() const +{ + return !version.isValid(); +} + + +const QString& K3bExternalBin::name() const +{ + return m_program->name(); +} + + +bool K3bExternalBin::hasFeature( const QString& f ) const +{ + return m_features.contains( f ); +} + + +void K3bExternalBin::addFeature( const QString& f ) +{ + m_features.append( f ); +} + + +const QStringList& K3bExternalBin::userParameters() const +{ + return m_program->userParameters(); +} + + + +// /////////////////////////////////////////////////////////// +// +// K3BEXTERNALPROGRAM +// +// /////////////////////////////////////////////////////////// + + +K3bExternalProgram::K3bExternalProgram( const QString& name ) + : m_name( name ) +{ + m_bins.setAutoDelete( true ); +} + + +K3bExternalProgram::~K3bExternalProgram() +{ +} + + +const K3bExternalBin* K3bExternalProgram::mostRecentBin() const +{ + QPtrListIterator it( m_bins ); + K3bExternalBin* bin = *it; + ++it; + while( *it ) { + if( it.current()->version > bin->version ) + bin = *it; + ++it; + } + return bin; +} + + +void K3bExternalProgram::addBin( K3bExternalBin* bin ) +{ + if( !m_bins.contains( bin ) ) { + // insertion sort + // the first bin in the list is always the one used + // so we default to using the newest one + K3bExternalBin* oldBin = m_bins.first(); + while( oldBin && oldBin->version > bin->version ) + oldBin = m_bins.next(); + + m_bins.insert( oldBin ? m_bins.at() : m_bins.count(), bin ); + } +} + +void K3bExternalProgram::setDefault( const K3bExternalBin* bin ) +{ + if( m_bins.contains( bin ) ) + m_bins.take( m_bins.find( bin ) ); + + // the first bin in the list is always the one used + m_bins.insert( 0, bin ); +} + + +void K3bExternalProgram::setDefault( const QString& path ) +{ + for( QPtrListIterator it( m_bins ); it.current(); ++it ) { + if( it.current()->path == path ) { + setDefault( it.current() ); + return; + } + } +} + + +void K3bExternalProgram::addUserParameter( const QString& p ) +{ + if( !m_userParameters.contains( p ) ) + m_userParameters.append(p); +} + + + +// /////////////////////////////////////////////////////////// +// +// K3BEXTERNALBINMANAGER +// +// /////////////////////////////////////////////////////////// + + +K3bExternalBinManager::K3bExternalBinManager( QObject* parent, const char* name ) + : QObject( parent, name ) +{ +} + + +K3bExternalBinManager::~K3bExternalBinManager() +{ + clear(); +} + + +bool K3bExternalBinManager::readConfig( KConfig* c ) +{ + loadDefaultSearchPath(); + + c->setGroup( "External Programs" ); + + if( c->hasKey( "search path" ) ) + setSearchPath( c->readPathListEntry( "search path" ) ); + + search(); + + for ( QMap::iterator it = m_programs.begin(); it != m_programs.end(); ++it ) { + K3bExternalProgram* p = it.data(); + if( c->hasKey( p->name() + " default" ) ) { + p->setDefault( c->readEntry( p->name() + " default" ) ); + } + if( c->hasKey( p->name() + " user parameters" ) ) { + QStringList list = c->readListEntry( p->name() + " user parameters" ); + for( QStringList::iterator strIt = list.begin(); strIt != list.end(); ++strIt ) + p->addUserParameter( *strIt ); + } + if( c->hasKey( p->name() + " last seen newest version" ) ) { + K3bVersion lastMax( c->readEntry( p->name() + " last seen newest version" ) ); + // now search for a newer version and use it (because it was installed after the last + // K3b run and most users would probably expect K3b to use a newly installed version) + const K3bExternalBin* newestBin = p->mostRecentBin(); + if( newestBin && newestBin->version > lastMax ) + p->setDefault( newestBin ); + } + } + + return true; +} + +bool K3bExternalBinManager::saveConfig( KConfig* c ) +{ + c->setGroup( "External Programs" ); + c->writePathEntry( "search path", m_searchPath ); + + for ( QMap::iterator it = m_programs.begin(); it != m_programs.end(); ++it ) { + K3bExternalProgram* p = it.data(); + if( p->defaultBin() ) + c->writeEntry( p->name() + " default", p->defaultBin()->path ); + + c->writeEntry( p->name() + " user parameters", p->userParameters() ); + + const K3bExternalBin* newestBin = p->mostRecentBin(); + if( newestBin ) + c->writeEntry( p->name() + " last seen newest version", newestBin->version ); + } + + return true; +} + + +bool K3bExternalBinManager::foundBin( const QString& name ) +{ + if( m_programs.find( name ) == m_programs.end() ) + return false; + else + return (m_programs[name]->defaultBin() != 0); +} + + +const QString& K3bExternalBinManager::binPath( const QString& name ) +{ + if( m_programs.find( name ) == m_programs.end() ) + return m_noPath; + + if( m_programs[name]->defaultBin() != 0 ) + return m_programs[name]->defaultBin()->path; + else + return m_noPath; +} + + +const K3bExternalBin* K3bExternalBinManager::binObject( const QString& name ) +{ + if( m_programs.find( name ) == m_programs.end() ) + return 0; + + return m_programs[name]->defaultBin(); +} + + +void K3bExternalBinManager::addProgram( K3bExternalProgram* p ) +{ + m_programs.insert( p->name(), p ); +} + + +void K3bExternalBinManager::clear() +{ + for( QMap::Iterator it = m_programs.begin(); it != m_programs.end(); ++it ) + delete it.data(); + m_programs.clear(); +} + + +void K3bExternalBinManager::search() +{ + if( m_searchPath.isEmpty() ) + loadDefaultSearchPath(); + + for( QMap::iterator it = m_programs.begin(); it != m_programs.end(); ++it ) { + it.data()->clear(); + } + + // do not search one path twice + QStringList paths; + for( QStringList::const_iterator it = m_searchPath.begin(); it != m_searchPath.end(); ++it ) { + QString p = *it; + if( p[p.length()-1] == '/' ) + p.truncate( p.length()-1 ); + if( !paths.contains( p ) && !paths.contains( p + "/" ) ) + paths.append(p); + } + + // get the environment path variable + char* env_path = ::getenv("PATH"); + if( env_path ) { + QStringList env_pathList = QStringList::split(":", QString::fromLocal8Bit(env_path)); + for( QStringList::const_iterator it = env_pathList.begin(); it != env_pathList.end(); ++it ) { + QString p = *it; + if( p[p.length()-1] == '/' ) + p.truncate( p.length()-1 ); + if( !paths.contains( p ) && !paths.contains( p + "/" ) ) + paths.append(p); + } + } + + + for( QStringList::const_iterator it = paths.begin(); it != paths.end(); ++it ) + for( QMap::iterator pit = m_programs.begin(); pit != m_programs.end(); ++pit ) + pit.data()->scan(*it); + + // TESTING + // ///////////////////////// + const K3bExternalBin* bin = program("cdrecord")->defaultBin(); + + if( !bin ) { + kdDebug() << "(K3bExternalBinManager) Probing cdrecord failed" << endl; + } + else { + kdDebug() << "(K3bExternalBinManager) Cdrecord " << bin->version << " features: " + << bin->features().join( ", " ) << endl; + + if( bin->version >= K3bVersion("1.11a02") ) + kdDebug() << "(K3bExternalBinManager) " + << bin->version.majorVersion() << " " << bin->version.minorVersion() << " " << bin->version.patchLevel() + << " " << bin->version.suffix() + << " seems to be cdrecord version >= 1.11a02, using burnfree instead of burnproof" << endl; + if( bin->version >= K3bVersion("1.11a31") ) + kdDebug() << "(K3bExternalBinManager) seems to be cdrecord version >= 1.11a31, support for Just Link via burnfree " + << "driveroption" << endl; + } +} + + +K3bExternalProgram* K3bExternalBinManager::program( const QString& name ) const +{ + if( m_programs.find( name ) == m_programs.end() ) + return 0; + else + return m_programs[name]; +} + + +void K3bExternalBinManager::loadDefaultSearchPath() +{ + static const char* defaultSearchPaths[] = { "/usr/bin/", + "/usr/local/bin/", + "/usr/sbin/", + "/usr/local/sbin/", + "/opt/schily/bin/", + "/sbin", + 0 }; + + m_searchPath.clear(); + for( int i = 0; defaultSearchPaths[i]; ++i ) { + m_searchPath.append( defaultSearchPaths[i] ); + } +} + + +void K3bExternalBinManager::setSearchPath( const QStringList& list ) +{ + loadDefaultSearchPath(); + + for( QStringList::const_iterator it = list.begin(); it != list.end(); ++it ) { + if( !m_searchPath.contains( *it ) ) + m_searchPath.append( *it ); + } +} + + +void K3bExternalBinManager::addSearchPath( const QString& path ) +{ + if( !m_searchPath.contains( path ) ) + m_searchPath.append( path ); +} + + + +const K3bExternalBin* K3bExternalBinManager::mostRecentBinObject( const QString& name ) +{ + if( K3bExternalProgram* p = program( name ) ) + return p->mostRecentBin(); + else + return 0; +} + +#include "k3bexternalbinmanager.moc" + diff --git a/libk3b/core/k3bexternalbinmanager.h b/libk3b/core/k3bexternalbinmanager.h new file mode 100644 index 0000000..e7fe601 --- /dev/null +++ b/libk3b/core/k3bexternalbinmanager.h @@ -0,0 +1,162 @@ +/* + * + * $Id: k3bexternalbinmanager.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef K3B_EXTERNAL_BIN_MANAGER_H +#define K3B_EXTERNAL_BIN_MANAGER_H + +#include +#include +#include +#include +#include +#include "k3b_export.h" +#include "k3bversion.h" + +class KConfig; +class KProcess; + + +class K3bExternalProgram; + + +/** + * A K3bExternalBin represents an installed version of a program. + * All K3bExternalBin objects are managed by K3bExternalPrograms. + * + * A bin may have certain features that are represented by a string. + */ +class LIBK3B_EXPORT K3bExternalBin +{ + public: + K3bExternalBin( K3bExternalProgram* ); + virtual ~K3bExternalBin() {} + + K3bVersion version; + QString path; + QString copyright; + + const QString& name() const; + bool isEmpty() const; + const QStringList& userParameters() const; + const QStringList& features() const { return m_features; } + + bool hasFeature( const QString& ) const; + void addFeature( const QString& ); + + K3bExternalProgram* program() const { return m_program; } + + private: + QStringList m_features; + K3bExternalProgram* m_program; +}; + + +/** + * This is the main class that represents a program + * It's scan method has to be reimplemented for every program + * It manages a list of K3bExternalBin-objects that each represent + * one installed version of the program. + */ +class LIBK3B_EXPORT K3bExternalProgram +{ + public: + K3bExternalProgram( const QString& name ); + virtual ~K3bExternalProgram(); + + const K3bExternalBin* defaultBin() const { return m_bins.getFirst(); } + const K3bExternalBin* mostRecentBin() const; + + void addUserParameter( const QString& ); + void setUserParameters( const QStringList& list ) { m_userParameters = list; } + + const QStringList& userParameters() const { return m_userParameters; } + const QString& name() const { return m_name; } + + void addBin( K3bExternalBin* ); + void clear() { m_bins.clear(); } + void setDefault( const K3bExternalBin* ); + void setDefault( const QString& path ); + + const QPtrList& bins() const { return m_bins; } + + /** + * this scans for the program in the given path, + * adds the found bin object to the list and returnes true. + * if nothing could be found false is returned. + */ + virtual bool scan( const QString& ) {return false;}//= 0; + + /** + * reimplement this if it does not make sense to have the user be able + * to specify additional parameters + */ + virtual bool supportsUserParameters() const { return true; } + + private: + QString m_name; + QStringList m_userParameters; + QPtrList m_bins; +}; + + +class LIBK3B_EXPORT K3bExternalBinManager : public QObject +{ + Q_OBJECT + + public: + K3bExternalBinManager( QObject* parent = 0, const char* name = 0 ); + ~K3bExternalBinManager(); + + void search(); + + /** + * read config and add changes to current map. + * Takes care of setting the config group + */ + bool readConfig( KConfig* ); + + /** + * Takes care of setting the config group + */ + bool saveConfig( KConfig* ); + + bool foundBin( const QString& name ); + const QString& binPath( const QString& name ); + const K3bExternalBin* binObject( const QString& name ); + const K3bExternalBin* mostRecentBinObject( const QString& name ); + + K3bExternalProgram* program( const QString& ) const; + const QMap& programs() const { return m_programs; } + + /** always extends the default searchpath */ + void setSearchPath( const QStringList& ); + void addSearchPath( const QString& ); + void loadDefaultSearchPath(); + + const QStringList& searchPath() const { return m_searchPath; } + + void addProgram( K3bExternalProgram* ); + void clear(); + + private: + QMap m_programs; + QStringList m_searchPath; + + static QString m_noPath; // used for binPath() to return const string + + QString m_gatheredOutput; +}; + +#endif diff --git a/libk3b/core/k3bglobals.cpp b/libk3b/core/k3bglobals.cpp new file mode 100644 index 0000000..fc5a4e1 --- /dev/null +++ b/libk3b/core/k3bglobals.cpp @@ -0,0 +1,634 @@ +/* + * + * $Id: k3bglobals.cpp 659634 2007-04-30 14:51:32Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include + + +#include "k3bglobals.h" +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#if defined(__FreeBSD__) || defined(__NetBSD__) +# include +# include +# include +# define bswap_16(x) bswap16(x) +# define bswap_32(x) bswap32(x) +# define bswap_64(x) bswap64(x) +#else +# include +#endif +#ifdef HAVE_SYS_STATVFS_H +# include +#endif +#ifdef HAVE_SYS_VFS_H +# include +#endif + + +/* +struct Sample { + unsigned char msbLeft; + unsigned char lsbLeft; + unsigned char msbRight; + unsigned char lsbRight; + + short left() const { + return ( msbLeft << 8 ) | lsbLeft; + } + short right() const { + return ( msbRight << 8 ) | lsbRight; + } + void left( short d ) { + msbLeft = d >> 8; + lsbLeft = d; + } + void right( short d ) { + msbRight = d >> 8; + lsbRight = d; + } +}; +*/ + +QString K3b::framesToString( int h, bool showFrames ) +{ + int m = h / 4500; + int s = (h % 4500) / 75; + int f = h % 75; + + QString str; + + if( showFrames ) { + // cdrdao needs the MSF format where 1 second has 75 frames! + str.sprintf( "%.2i:%.2i:%.2i", m, s, f ); + } + else + str.sprintf( "%.2i:%.2i", m, s ); + + return str; +} + +/*QString K3b::sizeToTime(long size) +{ + int h = size / sizeof(Sample) / 588; + return framesToString(h, false); +}*/ + + +Q_INT16 K3b::swapByteOrder( const Q_INT16& i ) +{ + return bswap_16( i ); + //((i << 8) & 0xff00) | ((i >> 8 ) & 0xff); +} + + +Q_INT32 K3b::swapByteOrder( const Q_INT32& i ) +{ + //return ((i << 24) & 0xff000000) | ((i << 8) & 0xff0000) | ((i >> 8) & 0xff00) | ((i >> 24) & 0xff ); + return bswap_32( i ); +} + + +Q_INT64 K3b::swapByteOrder( const Q_INT64& i ) +{ + return bswap_64( i ); +} + + +int K3b::round( double d ) +{ + return (int)( floor(d) + 0.5 <= d ? ceil(d) : floor(d) ); +} + + +QString K3b::findUniqueFilePrefix( const QString& _prefix, const QString& path ) +{ + QString url; + if( path.isEmpty() || !QFile::exists(path) ) + url = defaultTempPath(); + else + url = prepareDir( path ); + + QString prefix = _prefix; + if( prefix.isEmpty() ) + prefix = "k3b_"; + + // now create the unique prefix + QDir dir( url ); + QStringList entries = dir.entryList( QDir::DefaultFilter, QDir::Name ); + int i = 0; + for( QStringList::iterator it = entries.begin(); + it != entries.end(); ++it ) { + if( (*it).startsWith( prefix + QString::number(i) ) ) { + i++; + it = entries.begin(); + } + } + + return url + prefix + QString::number(i); +} + + +QString K3b::findTempFile( const QString& ending, const QString& d ) +{ + return findUniqueFilePrefix( "k3b_", d ) + ( ending.isEmpty() ? QString::null : (QString::fromLatin1(".") + ending) ); +} + + +QString K3b::defaultTempPath() +{ + QString oldGroup = kapp->config()->group(); + kapp->config()->setGroup( "General Options" ); + QString url = kapp->config()->readPathEntry( "Temp Dir", KGlobal::dirs()->resourceDirs( "tmp" ).first() ); + kapp->config()->setGroup( oldGroup ); + return prepareDir(url); +} + + +QString K3b::prepareDir( const QString& dir ) +{ + return (dir + (dir[dir.length()-1] != '/' ? "/" : "")); +} + + +QString K3b::parentDir( const QString& path ) +{ + QString parent = path; + if( path[path.length()-1] == '/' ) + parent.truncate( parent.length()-1 ); + + int pos = parent.findRev( '/' ); + if( pos >= 0 ) + parent.truncate( pos+1 ); + else // relative path, do anything... + parent = "/"; + + return parent; +} + + +QString K3b::fixupPath( const QString& path ) +{ + QString s; + bool lastWasSlash = false; + for( unsigned int i = 0; i < path.length(); ++i ) { + if( path[i] == '/' ) { + if( !lastWasSlash ) { + lastWasSlash = true; + s.append( "/" ); + } + } + else { + lastWasSlash = false; + s.append( path[i] ); + } + } + + return s; +} + + +K3bVersion K3b::kernelVersion() +{ + // initialize kernel version + K3bVersion v; + utsname unameinfo; + if( ::uname(&unameinfo) == 0 ) { + v = QString::fromLocal8Bit( unameinfo.release ); + kdDebug() << "kernel version: " << v << endl; + } + else + kdError() << "could not determine kernel version." << endl; + return v; +} + + +K3bVersion K3b::simpleKernelVersion() +{ + return kernelVersion().simplify(); +} + + +QString K3b::systemName() +{ + QString v; + utsname unameinfo; + if( ::uname(&unameinfo) == 0 ) { + v = QString::fromLocal8Bit( unameinfo.sysname ); + } + else + kdError() << "could not determine system name." << endl; + return v; +} + + +bool K3b::kbFreeOnFs( const QString& path, unsigned long& size, unsigned long& avail ) +{ + struct statvfs fs; + if( ::statvfs( QFile::encodeName(path), &fs ) == 0 ) { + unsigned long kBfak = fs.f_frsize/1024; + + size = fs.f_blocks*kBfak; + avail = fs.f_bavail*kBfak; + + return true; + } + else + return false; +} + + +KIO::filesize_t K3b::filesize( const KURL& url ) +{ + if( url.isLocalFile() ) { + k3b_struct_stat buf; + if ( !k3b_stat( QFile::encodeName( url.path() ), &buf ) ) { + return (KIO::filesize_t)buf.st_size; + } + } + + KIO::UDSEntry uds; + KIO::NetAccess::stat( url, uds, 0 ); + for( KIO::UDSEntry::const_iterator it = uds.begin(); it != uds.end(); ++it ) { + if( (*it).m_uds == KIO::UDS_SIZE ) { + return (*it).m_long; + } + } + + return ( KIO::filesize_t )0; +} + + +KIO::filesize_t K3b::imageFilesize( const KURL& url ) +{ + KIO::filesize_t size = K3b::filesize( url ); + int cnt = 0; + while( KIO::NetAccess::exists( KURL::fromPathOrURL( url.url() + '.' + QString::number(cnt).rightJustify( 3, '0' ) ), true ) ) + size += K3b::filesize( KURL::fromPathOrURL( url.url() + '.' + QString::number(cnt++).rightJustify( 3, '0' ) ) ); + return size; +} + + +QString K3b::cutFilename( const QString& name, unsigned int len ) +{ + if( name.length() > len ) { + QString ret = name; + + // determine extension (we think of an extension to be at most 5 chars in length) + int pos = name.find( '.', -6 ); + if( pos > 0 ) + len -= (name.length() - pos); + + ret.truncate( len ); + + if( pos > 0 ) + ret.append( name.mid( pos ) ); + + return ret; + } + else + return name; +} + + +QString K3b::removeFilenameExtension( const QString& name ) +{ + QString v = name; + int dotpos = v.findRev( '.' ); + if( dotpos > 0 ) + v.truncate( dotpos ); + return v; +} + + +QString K3b::appendNumberToFilename( const QString& name, int num, unsigned int maxlen ) +{ + // determine extension (we think of an extension to be at most 5 chars in length) + QString result = name; + QString ext; + int pos = name.find( '.', -6 ); + if( pos > 0 ) { + ext = name.mid(pos); + result.truncate( pos ); + } + + ext.prepend( QString::number(num) ); + result.truncate( maxlen - ext.length() ); + + return result + ext; +} + + +bool K3b::plainAtapiSupport() +{ + // FIXME: what about BSD? + return ( K3b::simpleKernelVersion() >= K3bVersion( 2, 5, 40 ) ); +} + + +bool K3b::hackedAtapiSupport() +{ + // IMPROVEME!!! + // FIXME: since when does the kernel support this? + return ( K3b::simpleKernelVersion() >= K3bVersion( 2, 4, 0 ) ); +} + + +QString K3b::externalBinDeviceParameter( K3bDevice::Device* dev, const K3bExternalBin* bin ) +{ +#ifdef Q_OS_LINUX + // + // experimental: always use block devices on 2.6 kernels + // + if( simpleKernelVersion() >= K3bVersion( 2, 6, 0 ) ) + return dev->blockDeviceName(); + else +#endif + if( dev->interfaceType() == K3bDevice::SCSI ) + return dev->busTargetLun(); + else if( (plainAtapiSupport() && bin->hasFeature("plain-atapi") ) ) + return dev->blockDeviceName(); + else + return QString("ATAPI:%1").arg(dev->blockDeviceName()); +} + + +int K3b::writingAppFromString( const QString& s ) +{ + if( s.lower() == "cdrdao" ) + return K3b::CDRDAO; + else if( s.lower() == "cdrecord" ) + return K3b::CDRECORD; + else if( s.lower() == "dvdrecord" ) + return K3b::DVDRECORD; + else if( s.lower() == "growisofs" ) + return K3b::GROWISOFS; + else if( s.lower() == "dvd+rw-format" ) + return K3b::DVD_RW_FORMAT; + else + return K3b::DEFAULT; +} + + +QString K3b::writingModeString( int mode ) +{ + if( mode == WRITING_MODE_AUTO ) + return i18n("Auto"); + else + return K3bDevice::writingModeString( mode ); +} + + +QString K3b::resolveLink( const QString& file ) +{ + QFileInfo f( file ); + QStringList steps( f.absFilePath() ); + while( f.isSymLink() ) { + QString p = f.readLink(); + if( !p.startsWith( "/" ) ) + p.prepend( f.dirPath(true) + "/" ); + f.setFile( p ); + if( steps.contains( f.absFilePath() ) ) { + kdDebug() << "(K3b) symlink loop detected." << endl; + break; + } + else + steps.append( f.absFilePath() ); + } + return f.absFilePath(); +} + + +K3bDevice::Device* K3b::urlToDevice( const KURL& deviceUrl ) +{ + if( deviceUrl.protocol() == "media" || deviceUrl.protocol() == "system" ) { + kdDebug() << "(K3b) Asking mediamanager for " << deviceUrl.fileName() << endl; + DCOPRef mediamanager("kded", "mediamanager"); + DCOPReply reply = mediamanager.call("properties(QString)", deviceUrl.fileName()); + QStringList properties = reply; + if( !reply.isValid() || properties.count() < 6 ) { + kdError() << "(K3b) Invalid reply from mediamanager" << endl; + return 0; + } + else { + kdDebug() << "(K3b) Reply from mediamanager " << properties[5] << endl; + return k3bcore->deviceManager()->findDevice( properties[5] ); + } + } + + return k3bcore->deviceManager()->findDevice( deviceUrl.path() ); +} + + +KURL K3b::convertToLocalUrl( const KURL& url ) +{ + if( !url.isLocalFile() ) { +#if KDE_IS_VERSION(3,4,91) + return KIO::NetAccess::mostLocalURL( url, 0 ); +#else +#ifndef UDS_LOCAL_PATH +#define UDS_LOCAL_PATH (72 | KIO::UDS_STRING) +#else + using namespace KIO; +#endif + KIO::UDSEntry e; + if( KIO::NetAccess::stat( url, e, 0 ) ) { + const KIO::UDSEntry::ConstIterator end = e.end(); + for( KIO::UDSEntry::ConstIterator it = e.begin(); it != end; ++it ) { + if( (*it).m_uds == UDS_LOCAL_PATH && !(*it).m_str.isEmpty() ) + return KURL::fromPathOrURL( (*it).m_str ); + } + } +#endif + } + + return url; +} + + +KURL::List K3b::convertToLocalUrls( const KURL::List& urls ) +{ + KURL::List r; + for( KURL::List::const_iterator it = urls.constBegin(); it != urls.constEnd(); ++it ) + r.append( convertToLocalUrl( *it ) ); + return r; +} + + +Q_INT16 K3b::fromLe16( char* data ) +{ +#ifdef WORDS_BIGENDIAN // __BYTE_ORDER == __BIG_ENDIAN + return swapByteOrder( *((Q_INT16*)data) ); +#else + return *((Q_INT16*)data); +#endif +} + + +Q_INT32 K3b::fromLe32( char* data ) +{ +#ifdef WORDS_BIGENDIAN // __BYTE_ORDER == __BIG_ENDIAN + return swapByteOrder( *((Q_INT32*)data) ); +#else + return *((Q_INT32*)data); +#endif +} + + +Q_INT64 K3b::fromLe64( char* data ) +{ +#ifdef WORDS_BIGENDIAN // __BYTE_ORDER == __BIG_ENDIAN + return swapByteOrder( *((Q_INT64*)data) ); +#else + return *((Q_INT64*)data); +#endif +} + + +QString K3b::findExe( const QString& name ) +{ + // first we search the path + QString bin = KStandardDirs::findExe( name ); + + // then go on with our own little list + if( bin.isEmpty() ) + bin = KStandardDirs::findExe( name, k3bcore->externalBinManager()->searchPath().join(":") ); + + return bin; +} + + +bool K3b::isMounted( K3bDevice::Device* dev ) +{ + if( !dev ) + return false; + + return !KIO::findDeviceMountPoint( dev->blockDeviceName() ).isEmpty(); +} + + +bool K3b::unmount( K3bDevice::Device* dev ) +{ + if( !dev ) + return false; + + QString mntDev = dev->blockDeviceName(); + +#if KDE_IS_VERSION(3,4,0) + // first try to unmount it the standard way + if( KIO::NetAccess::synchronousRun( KIO::unmount( mntDev, false ), 0 ) ) + return true; +#endif + + QString umountBin = K3b::findExe( "umount" ); + if( !umountBin.isEmpty() ) { + KProcess p; + p << umountBin; + p << "-l"; // lazy unmount + p << dev->blockDeviceName(); + p.start( KProcess::Block ); + if( !p.exitStatus() ) + return true; + } + + // now try pmount + QString pumountBin = K3b::findExe( "pumount" ); + if( !pumountBin.isEmpty() ) { + KProcess p; + p << pumountBin; + p << "-l"; // lazy unmount + p << dev->blockDeviceName(); + p.start( KProcess::Block ); + return !p.exitStatus(); + } + else { +#ifdef HAVE_HAL + return !K3bDevice::HalConnection::instance()->unmount( dev ); +#else + return false; +#endif + } +} + + +bool K3b::mount( K3bDevice::Device* dev ) +{ + if( !dev ) + return false; + + QString mntDev = dev->blockDeviceName(); + +#if KDE_IS_VERSION(3,4,0) + // first try to mount it the standard way + if( KIO::NetAccess::synchronousRun( KIO::mount( true, 0, mntDev, false ), 0 ) ) + return true; +#endif + +#ifdef HAVE_HAL + if( !K3bDevice::HalConnection::instance()->mount( dev ) ) + return true; +#endif + + // now try pmount + QString pmountBin = K3b::findExe( "pmount" ); + if( !pmountBin.isEmpty() ) { + KProcess p; + p << pmountBin; + p << mntDev; + p.start( KProcess::Block ); + return !p.exitStatus(); + } + return false; +} + + +bool K3b::eject( K3bDevice::Device* dev ) +{ +#ifdef HAVE_HAL + if( !K3bDevice::HalConnection::instance()->eject( dev ) ) + return true; +#endif + + if( K3b::isMounted( dev ) ) + K3b::unmount( dev ); + + return dev->eject(); +} diff --git a/libk3b/core/k3bglobals.h b/libk3b/core/k3bglobals.h new file mode 100644 index 0000000..2795630 --- /dev/null +++ b/libk3b/core/k3bglobals.h @@ -0,0 +1,257 @@ +/* + * + * $Id: k3bglobals.h 630384 2007-02-05 09:33:17Z mlaurent $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BGLOBALS_H +#define K3BGLOBALS_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include "k3b_export.h" + +class KConfig; +class K3bVersion; +class K3bExternalBin; + + +#include + + +#ifdef HAVE_STAT64 +#define k3b_struct_stat struct stat64 +#define k3b_stat ::stat64 +#define k3b_lstat ::lstat64 +#else +#define k3b_struct_stat struct stat +#define k3b_stat ::stat +#define k3b_lstat ::lstat +#endif + + +namespace K3bDevice { + class Device; +} + +namespace K3b +{ + enum WritingApp { + DEFAULT = 1, + CDRECORD = 2, + CDRDAO = 4, + DVDRECORD = 8, + GROWISOFS = 16, + DVD_RW_FORMAT = 32 + }; + + LIBK3B_EXPORT int writingAppFromString( const QString& ); + + /** + * DATA_MODE_AUTO - let K3b determine the best mode + * MODE1 - refers to the default Yellow book mode1 + * MODE2 - refers to CDROM XA mode2 form1 + */ + enum DataMode { + DATA_MODE_AUTO, + MODE1, + MODE2 + }; + + /** + * The sector size denotes the number of bytes K3b provides per sector. + * This is based on the sizes cdrecord's -data, -xa, and -xamix parameters + * demand. + */ + enum SectorSize { + SECTORSIZE_AUDIO = 2352, + SECTORSIZE_DATA_2048 = 2048, + SECTORSIZE_DATA_2048_SUBHEADER = 2056, + SECTORSIZE_DATA_2324 = 2324, + SECTORSIZE_DATA_2324_SUBHEADER = 2332, + SECTORSIZE_RAW = 2448 + }; + + /** + * AUTO - let K3b determine the best mode + * TAO - Track at once + * DAO - Disk at once (or session at once) + * RAW - Raw mode + * + * may be or'ed together (except for WRITING_MODE_AUTO of course) + */ + enum WritingMode { + WRITING_MODE_AUTO = 0, + TAO = K3bDevice::WRITINGMODE_TAO, + DAO = K3bDevice::WRITINGMODE_SAO, + RAW = K3bDevice::WRITINGMODE_RAW, + WRITING_MODE_INCR_SEQ = K3bDevice::WRITINGMODE_INCR_SEQ, // Incremental Sequential + WRITING_MODE_RES_OVWR = K3bDevice::WRITINGMODE_RES_OVWR // Restricted Overwrite + }; + + LIBK3B_EXPORT QString writingModeString( int ); + + LIBK3B_EXPORT QString framesToString( int h, bool showFrames = true ); + /*LIBK3B_EXPORT QString sizeToTime( long size );*/ + + LIBK3B_EXPORT Q_INT16 swapByteOrder( const Q_INT16& i ); + LIBK3B_EXPORT Q_INT32 swapByteOrder( const Q_INT32& i ); + LIBK3B_EXPORT Q_INT64 swapByteOrder( const Q_INT64& i ); + + int round( double ); + + /** + * This checks the free space on the filesystem path is in. + * We use this since we encountered problems with the KDE version. + * @returns true on success. + */ + LIBK3B_EXPORT bool kbFreeOnFs( const QString& path, unsigned long& size, unsigned long& avail ); + + /** + * Cut a filename preserving the extension + */ + LIBK3B_EXPORT QString cutFilename( const QString& name, unsigned int len ); + + LIBK3B_EXPORT QString removeFilenameExtension( const QString& name ); + + /** + * Append a number to a filename preserving the extension. + * The resulting name's length will not exceed @p maxlen + */ + LIBK3B_EXPORT QString appendNumberToFilename( const QString& name, int num, unsigned int maxlen ); + + LIBK3B_EXPORT QString findUniqueFilePrefix( const QString& _prefix = QString::null, const QString& path = QString::null ); + + /** + * Find a unique filename in directory d (if d is empty the method uses the defaultTempPath) + */ + LIBK3B_EXPORT QString findTempFile( const QString& ending = QString::null, const QString& d = QString::null ); + + /** + * Wrapper around KStandardDirs::findExe which searches the PATH and some additional + * directories to find system tools which are normally only in root's PATH. + */ + LIBK3B_EXPORT QString findExe( const QString& name ); + + /** + * get the default K3b temp path to store image files + */ + LIBK3B_EXPORT QString defaultTempPath(); + + /** + * makes sure a path ends with a "/" + */ + LIBK3B_EXPORT QString prepareDir( const QString& dir ); + + /** + * returns the parent dir of a path. + * CAUTION: this does only work well with absolut paths. + * + * Example: /usr/share/doc -> /usr/share/ + */ + QString parentDir( const QString& path ); + + /** + * For now this just replaces multiple occurrences of / with a single / + */ + LIBK3B_EXPORT QString fixupPath( const QString& ); + + /** + * resolves a symlinks completely. Meaning it also handles links to links to links... + */ + LIBK3B_EXPORT QString resolveLink( const QString& ); + + LIBK3B_EXPORT K3bVersion kernelVersion(); + + /** + * Kernel version stripped of all suffixes + */ + LIBK3B_EXPORT K3bVersion simpleKernelVersion(); + + QString systemName(); + + LIBK3B_EXPORT KIO::filesize_t filesize( const KURL& ); + + /** + * Calculate the total size of an image file. This also includes + * images splitted by a K3bFileSplitter. + * + * \returns the total size of the image file at url + */ + LIBK3B_EXPORT KIO::filesize_t imageFilesize( const KURL& url ); + + /** + * true if the kernel supports ATAPI devices without SCSI emulation. + * use in combination with the K3bExternalProgram feature "plain-atapi" + */ + LIBK3B_EXPORT bool plainAtapiSupport(); + + /** + * true if the kernel supports ATAPI devices without SCSI emulation + * via the ATAPI: pseudo stuff + * use in combination with the K3bExternalProgram feature "hacked-atapi" + */ + LIBK3B_EXPORT bool hackedAtapiSupport(); + + /** + * Used to create a parameter for cdrecord, cdrdao or readcd. + * Takes care of SCSI and ATAPI. + */ + QString externalBinDeviceParameter( K3bDevice::Device* dev, const K3bExternalBin* ); + + /** + * Convert an url pointing to a local device to a K3bDevice. + * Supports media:// and system::// urls. + */ + LIBK3B_EXPORT K3bDevice::Device* urlToDevice( const KURL& deviceUrl ); + + /** + * Tries to convert urls from local protocols != "file" to file (for now supports media:/) + */ + LIBK3B_EXPORT KURL convertToLocalUrl( const KURL& url ); + LIBK3B_EXPORT KURL::List convertToLocalUrls( const KURL::List& l ); + + LIBK3B_EXPORT Q_INT16 fromLe16( char* ); + LIBK3B_EXPORT Q_INT32 fromLe32( char* ); + LIBK3B_EXPORT Q_INT64 fromLe64( char* ); + + LIBK3B_EXPORT bool isMounted( K3bDevice::Device* ); + + /** + * Tries to unmount the device ignoring its actual mounting state. + * This method uses both KIO::unmount and pumount if available. + */ + LIBK3B_EXPORT bool unmount( K3bDevice::Device* ); + + /** + * Tries to mount the medium. Since K3b does not gather any information + * about mount points the only methods used are pmount and HAL::mount + */ + LIBK3B_EXPORT bool mount( K3bDevice::Device* ); + + /** + * Ejects the medium in the device or simply opens the tray. + * This method improves over K3bDevice::Device::eject in that it + * unmounts before ejecting and introduces HAL support. + */ + LIBK3B_EXPORT bool eject( K3bDevice::Device* ); +} + +#endif diff --git a/libk3b/core/k3bglobalsettings.cpp b/libk3b/core/k3bglobalsettings.cpp new file mode 100644 index 0000000..6f58592 --- /dev/null +++ b/libk3b/core/k3bglobalsettings.cpp @@ -0,0 +1,61 @@ +/* + * + * $Id: k3bglobalsettings.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2005 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bglobalsettings.h" + +#include + + +K3bGlobalSettings::K3bGlobalSettings() + : m_eject(true), + m_burnfree(true), + m_overburn(false), + m_useManualBufferSize(false), + m_bufferSize(4), + m_force(false) +{ +} + + +void K3bGlobalSettings::readSettings( KConfig* c ) +{ + QString lastG = c->group(); + c->setGroup( "General Options" ); + + m_eject = !c->readBoolEntry( "No cd eject", false ); + m_burnfree = c->readBoolEntry( "burnfree", true ); + m_overburn = c->readBoolEntry( "Allow overburning", false ); + m_useManualBufferSize = c->readBoolEntry( "Manual buffer size", false ); + m_bufferSize = c->readNumEntry( "Fifo buffer", 4 ); + m_force = c->readBoolEntry( "Force unsafe operations", false ); + + c->setGroup( lastG ); +} + + +void K3bGlobalSettings::saveSettings( KConfig* c ) +{ + QString lastG = c->group(); + c->setGroup( "General Options" ); + + c->writeEntry( "No cd eject", !m_eject ); + c->writeEntry( "burnfree", m_burnfree ); + c->writeEntry( "Allow overburning", m_overburn ); + c->writeEntry( "Manual buffer size", m_useManualBufferSize ); + c->writeEntry( "Fifo buffer", m_bufferSize ); + c->writeEntry( "Force unsafe operations", m_force ); + + c->setGroup( lastG ); +} diff --git a/libk3b/core/k3bglobalsettings.h b/libk3b/core/k3bglobalsettings.h new file mode 100644 index 0000000..1194789 --- /dev/null +++ b/libk3b/core/k3bglobalsettings.h @@ -0,0 +1,70 @@ +/* + * + * $Id: k3bglobalsettings.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2005 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_GLOBAL_SETTINGS_H_ +#define _K3B_GLOBAL_SETTINGS_H_ +#include "k3b_export.h" +class KConfig; + +/** + * Some global settings used throughout K3b. + */ +class LIBK3B_EXPORT K3bGlobalSettings +{ + public: + K3bGlobalSettings(); + + /** + * This method takes care of settings the config group + */ + void readSettings( KConfig* ); + + /** + * This method takes care of settings the config group + */ + void saveSettings( KConfig* ); + + bool ejectMedia() const { return m_eject; } + bool burnfree() const { return m_burnfree; } + bool overburn() const { return m_overburn; } + bool useManualBufferSize() const { return m_useManualBufferSize; } + int bufferSize() const { return m_bufferSize; } + + /** + * If force is set to true K3b will continue in certain "unsafe" situations. + * The most common being a medium not suitable for the writer in terms of + * writing speed. + * Compare cdrecord's parameter -force + */ + bool force() const { return m_force; } + + void setEjectMedia( bool b ) { m_eject = b; } + void setBurnfree( bool b ) { m_burnfree = b; } + void setOverburn( bool b ) { m_overburn = b; } + void setUseManualBufferSize( bool b ) { m_useManualBufferSize = b; } + void setBufferSize( int size ) { m_bufferSize = size; } + void setForce( bool b ) { m_force = b; } + + private: + bool m_eject; + bool m_burnfree; + bool m_overburn; + bool m_useManualBufferSize; + int m_bufferSize; + bool m_force; +}; + + +#endif diff --git a/libk3b/core/k3bjob.cpp b/libk3b/core/k3bjob.cpp new file mode 100644 index 0000000..b545107 --- /dev/null +++ b/libk3b/core/k3bjob.cpp @@ -0,0 +1,253 @@ +/* + * + * $Id: k3bjob.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bjob.h" +#include +#include + +#include +#include + +#include +#include + + +class K3bJob::Private +{ +public: +}; + + +const char* K3bJob::DEFAULT_SIGNAL_CONNECTION = "K3bJobDefault"; + + +K3bJob::K3bJob( K3bJobHandler* handler, QObject* parent, const char* name ) + : QObject( parent, name ), + m_jobHandler( handler ), + m_canceled(false), + m_active(false) +{ + connect( this, SIGNAL(canceled()), + this, SLOT(slotCanceled()) ); +} + +K3bJob::~K3bJob() +{ + // + // Normally a job (or the user of a job should take care of this + // but we do this here for security reasons. + // + if( m_active ) + jobFinished( false ); +} + + +void K3bJob::setJobHandler( K3bJobHandler* jh ) +{ + m_jobHandler = jh; +} + + +void K3bJob::jobStarted() +{ + m_canceled = false; + m_active = true; + + if( jobHandler() && jobHandler()->isJob() ) + static_cast(jobHandler())->registerSubJob( this ); + else + k3bcore->registerJob( this ); + + emit started(); +} + + +void K3bJob::jobFinished( bool success ) +{ + m_active = false; + + if( jobHandler() && jobHandler()->isJob() ) + static_cast(jobHandler())->unregisterSubJob( this ); + else + k3bcore->unregisterJob( this ); + + emit finished( success ); +} + + +void K3bJob::slotCanceled() +{ + m_canceled = true; +} + + +int K3bJob::waitForMedia( K3bDevice::Device* device, + int mediaState, + int mediaType, + const QString& message ) +{ + // TODO: What about: emit newSubTask( i18n("Waiting for media") ); + return m_jobHandler->waitForMedia( device, mediaState, mediaType, message ); +} + + +bool K3bJob::questionYesNo( const QString& text, + const QString& caption, + const QString& yesText, + const QString& noText ) +{ + return m_jobHandler->questionYesNo( text, caption, yesText, noText ); +} + + +void K3bJob::blockingInformation( const QString& text, + const QString& caption ) +{ + return m_jobHandler->blockingInformation( text, caption ); +} + + +void K3bJob::connectSubJob( K3bJob* subJob, + const char* finishedSlot, + bool connectProgress, + const char* progressSlot, + const char* subProgressSlot, + const char* processedSizeSlot, + const char* processedSubSizeSlot ) +{ + connect( subJob, SIGNAL(newTask(const QString&)), this, SIGNAL(newSubTask(const QString&)) ); + connect( subJob, SIGNAL(newSubTask(const QString&)), this, SLOT(slotNewSubTask(const QString&)) ); + connect( subJob, SIGNAL(debuggingOutput(const QString&, const QString&)), + this, SIGNAL(debuggingOutput(const QString&, const QString&)) ); + connect( subJob, SIGNAL(infoMessage(const QString&, int)), + this, SIGNAL(infoMessage(const QString&, int)) ); + connect( subJob, SIGNAL(finished(bool)), this, finishedSlot ); + + if( connectProgress ) { + connect( subJob, SIGNAL(percent(int)), + this, progressSlot != 0 ? progressSlot : SIGNAL(subPercent(int)) ); + if( subProgressSlot ) + connect( subJob, SIGNAL(subPercent(int)), this, subProgressSlot ); + connect( subJob, SIGNAL(processedSize(int, int)), + this, processedSizeSlot != 0 ? processedSizeSlot : SIGNAL(processedSubSize(int, int)) ); + if( processedSubSizeSlot ) + connect( subJob, SIGNAL(processedSubSize(int, int)), this, processedSubSizeSlot ); + } +} + + +void K3bJob::connectSubJob( K3bJob* subJob, + const char* finishedSlot, + const char* newTaskSlot, + const char* newSubTaskSlot, + const char* progressSlot, + const char* subProgressSlot, + const char* processedSizeSlot, + const char* processedSubSizeSlot ) +{ + // standard connections + connect( subJob, SIGNAL(debuggingOutput(const QString&, const QString&)), + this, SIGNAL(debuggingOutput(const QString&, const QString&)) ); + connect( subJob, SIGNAL(infoMessage(const QString&, int)), + this, SIGNAL(infoMessage(const QString&, int)) ); + + // task connections + if( newTaskSlot == DEFAULT_SIGNAL_CONNECTION ) + connect( subJob, SIGNAL(newTask(const QString&)), this, SIGNAL(newSubTask(const QString&)) ); + else if( newTaskSlot ) + connect( subJob, SIGNAL(newTask(const QString&)), this, newTaskSlot ); + + if( newSubTaskSlot == DEFAULT_SIGNAL_CONNECTION ) + connect( subJob, SIGNAL(newSubTask(const QString&)), this, SLOT(slotNewSubTask(const QString&)) ); + else if( newSubTaskSlot ) + connect( subJob, SIGNAL(newSubTask(const QString&)), this, newSubTaskSlot ); + + if( finishedSlot && finishedSlot != DEFAULT_SIGNAL_CONNECTION ) + connect( subJob, SIGNAL(finished(bool)), this, finishedSlot ); + + // progress + if( progressSlot == DEFAULT_SIGNAL_CONNECTION ) + connect( subJob, SIGNAL(percent(int)), this, SIGNAL(subPercent(int)) ); + else if( progressSlot ) + connect( subJob, SIGNAL(percent(int)), this, progressSlot ); + + if( subProgressSlot && subProgressSlot != DEFAULT_SIGNAL_CONNECTION ) + connect( subJob, SIGNAL(subPercent(int)), this, subProgressSlot ); + + // processed size + if( processedSizeSlot == DEFAULT_SIGNAL_CONNECTION ) + connect( subJob, SIGNAL(processedSize(int, int)), this, SIGNAL(processedSubSize(int, int)) ); + else if( processedSizeSlot ) + connect( subJob, SIGNAL(processedSize(int, int)), this, processedSizeSlot ); + + if( processedSubSizeSlot && processedSubSizeSlot != DEFAULT_SIGNAL_CONNECTION ) + connect( subJob, SIGNAL(processedSubSize(int, int)), this, processedSubSizeSlot ); +} + + +unsigned int K3bJob::numRunningSubJobs() const +{ + return m_runningSubJobs.count(); +} + + +void K3bJob::slotNewSubTask( const QString& str ) +{ + emit infoMessage( str, INFO ); +} + + +void K3bJob::registerSubJob( K3bJob* job ) +{ + m_runningSubJobs.append( job ); +} + + +void K3bJob::unregisterSubJob( K3bJob* job ) +{ + m_runningSubJobs.removeRef( job ); +} + + + + +class K3bBurnJob::Private +{ +public: +}; + + + +K3bBurnJob::K3bBurnJob( K3bJobHandler* handler, QObject* parent, const char* name ) + : K3bJob( handler, parent, name ), + m_writeMethod( K3b::DEFAULT ) +{ + d = new Private; +} + + +K3bBurnJob::~K3bBurnJob() +{ + delete d; +} + + +int K3bBurnJob::supportedWritingApps() const +{ + return K3b::DEFAULT | K3b::CDRDAO | K3b::CDRECORD; +} + +#include "k3bjob.moc" diff --git a/libk3b/core/k3bjob.h b/libk3b/core/k3bjob.h new file mode 100644 index 0000000..59e1f9b --- /dev/null +++ b/libk3b/core/k3bjob.h @@ -0,0 +1,311 @@ +/* + * + * $Id: k3bjob.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BJOB_H +#define K3BJOB_H + +#include +#include +#include "k3bjobhandler.h" +#include "k3b_export.h" + +class K3bDoc; +namespace K3bDevice { + class Device; +} + + +/** + * This is the baseclass for all the jobs in K3b which actually do the work like burning a cd! + * The K3bJob object takes care of registering with the k3bcore or with a parent K3bJob. + * + * Every job has a jobhandler which can be another job (in which case the job is handled as + * a subjob) or an arbitrary class implementing the K3bJobHandler interface. + * + * A Job should never create any widgets. User interaction should be done through the methods + * questionYesNo, waitForMedia. + * + * @author Sebastian Trueg + */ +class LIBK3B_EXPORT K3bJob : public QObject, public K3bJobHandler +{ + Q_OBJECT + + public: + virtual ~K3bJob(); + + /** + * \reimplemented from K3bJobHandler + */ + bool isJob() const { return true; } + + K3bJobHandler* jobHandler() const { return m_jobHandler; } + + /** + * Is the job active? + * The default implementation is based on the jobStarted() and jobFinished() + * methods and there is normally no need to reimplement this. + */ + virtual bool active() const { return m_active; } + + /** + * The default implementation is based on the canceled() signal. + * + * This means that one cannot count on this value being valid + * in a slot connected to the canceled() signal. It is, however, save + * to call this method from a slot connected to the finished() signal + * in case the job makes proper usage of the jobStarted/jobFinished + * methods. + */ + virtual bool hasBeenCanceled() const { return m_canceled; } + + virtual QString jobDescription() const { return "K3bJob"; } + virtual QString jobDetails() const { return QString::null; } + + /** + * @returns the number of running subjobs. + * this is useful for proper cancellation of jobs. + */ + unsigned int numRunningSubJobs() const; + + const QPtrList& runningSubJobs() const { return m_runningSubJobs; } + + /** + * \deprecated + */ + virtual void connectSubJob( K3bJob* subJob, + const char* finishedSlot = 0, + bool progress = false, + const char* progressSlot = 0, + const char* subProgressSot = 0, + const char* processedSizeSlot = 0, + const char* processedSubSizeSlot = 0 ); + + static const char* DEFAULT_SIGNAL_CONNECTION; + + /** + * \param newTaskSlot If DEFAULT_SIGNAL_CONNECTION the newTask signal from the subjob will + * be connected to the newSubTask signal + * \param newSubTaskSlot If DEFAULT_SIGNAL_CONNECTION the newSubTask signal from the subjob + * will create an infoMessage signal + * \param progressSlot If DEFAULT_SIGNAL_CONNECTION the percent signal of the subjob will be + * connected to the subPercent signal. + * debuggingOutput and infoMessage will always be direcctly connected. + * + * If a parameter is set to 0 it will not be connected at all + */ + virtual void connectSubJob( K3bJob* subJob, + const char* finishedSlot = DEFAULT_SIGNAL_CONNECTION, + const char* newTaskSlot = DEFAULT_SIGNAL_CONNECTION, + const char* newSubTaskSlot = DEFAULT_SIGNAL_CONNECTION, + const char* progressSlot = DEFAULT_SIGNAL_CONNECTION, + const char* subProgressSlot = DEFAULT_SIGNAL_CONNECTION, + const char* processedSizeSlot = DEFAULT_SIGNAL_CONNECTION, + const char* processedSubSizeSlot = DEFAULT_SIGNAL_CONNECTION ); + + /** + * Message types to be used in combination with the infoMessage signal. + * + * \see infoMessage() + */ + enum MessageType { + INFO, /**< Informational message. For example a message that informs the user about what is + currently going on */ + WARNING, /**< A warning message. Something did not go perfectly but the job may continue. */ + ERROR, /**< An error. Only use this message type if the job will actually fail afterwards + with a call to jobFinished( false ) */ + SUCCESS /**< This message type may be used to inform the user that a sub job has + been successfully finished. */ + }; + + /** + * reimplemented from K3bJobHandler + */ + int waitForMedia( K3bDevice::Device*, + int mediaState = K3bDevice::STATE_EMPTY, + int mediaType = K3bDevice::MEDIA_WRITABLE_CD, + const QString& message = QString::null ); + + /** + * reimplemented from K3bJobHandler + */ + bool questionYesNo( const QString& text, + const QString& caption = QString::null, + const QString& yesText = QString::null, + const QString& noText = QString::null ); + + /** + * reimplemented from K3bJobHandler + */ + void blockingInformation( const QString& text, + const QString& caption = QString::null ); + + public slots: + /** + * This is the slot that starts the job. The first call should always + * be jobStarted(). + * + * Once the job has finished it has to call jobFinished() with the result as + * a parameter. + * + * \see jobStarted() + * \see jobFinished() + */ + virtual void start() = 0; + + /** + * This slot should cancel the job. The job has to emit the canceled() signal and make a call + * to jobFinished(). + * It is not important to do any of those two directly in this slot though. + */ + virtual void cancel() = 0; + + void setJobHandler( K3bJobHandler* ); + + signals: + void infoMessage( const QString& msg, int type ); + void percent( int p ); + void subPercent( int p ); + void processedSize( int processed, int size ); + void processedSubSize( int processed, int size ); + void newTask( const QString& job ); + void newSubTask( const QString& job ); + void debuggingOutput(const QString&, const QString&); + void data( const char* data, int len ); + void nextTrack( int track, int numTracks ); + + void canceled(); + + /** + * Emitted once the job has been started. Never emit this signal directly. + * Use jobStarted() instead, otherwise the job will not be properly registered + */ + void started(); + + /** + * Emitted once the job has been finshed. Never emit this signal directly. + * Use jobFinished() instead, otherwise the job will not be properly deregistered + */ + void finished( bool success ); + + protected: + /** + * \param hdl the handler of the job. This allows for some user interaction without + * specifying any details (like the GUI). + * The job handler can also be another job. In that case this job is a sub job + * and will be part of the parents running sub jobs. + * + * \see runningSubJobs() + * \see numRunningSubJobs() + */ + K3bJob( K3bJobHandler* hdl, QObject* parent = 0, const char* name = 0 ); + + /** + * Call this in start() to properly register the job and emit the started() signal. + * Do never emit the started() signal manually. + * + * Always call K3bJob::jobStarted in reimplementations. + */ + virtual void jobStarted(); + + /** + * Call this at the end of the job to properly deregister the job and emit the finished() signal. + * Do never emit the started() signal manually. + * + * Always call K3bJob::jobFinished in reimplementations. + */ + virtual void jobFinished( bool success ); + + private slots: + void slotCanceled(); + void slotNewSubTask( const QString& str ); + + private: + void registerSubJob( K3bJob* ); + void unregisterSubJob( K3bJob* ); + + K3bJobHandler* m_jobHandler; + QPtrList m_runningSubJobs; + + bool m_canceled; + bool m_active; + + class Private; + Private* d; +}; + + +/** + * Every job used to actually burn a medium is derived from K3bBurnJob. + * This class implements additional signals like buffer status or writing speed + * as well as a handling of the used writing application. + */ +class LIBK3B_EXPORT K3bBurnJob : public K3bJob +{ + Q_OBJECT + + public: + K3bBurnJob( K3bJobHandler* hdl, QObject* parent = 0, const char* name = 0 ); + virtual ~K3bBurnJob(); + + /** + * The writing device used by this job. + */ + virtual K3bDevice::Device* writer() const { return 0; } + + /** + * use K3b::WritingApp + */ + int writingApp() const { return m_writeMethod; } + + /** + * K3b::WritingApp "ored" together + */ + virtual int supportedWritingApps() const; + + public slots: + /** + * use K3b::WritingApp + */ + void setWritingApp( int w ) { m_writeMethod = w; } + + signals: + void bufferStatus( int ); + + void deviceBuffer( int ); + + /** + * @param speed current writing speed in Kb + * @param multiplicator use 150 for CDs and 1380 for DVDs + * FIXME: maybe one should be able to ask the burnjob if it burns a CD or a DVD and remove the + * multiplicator parameter) + */ + void writeSpeed( int speed, int multiplicator ); + + /** + * This signal may be used to inform when the burning starts or ends + * The BurningProgressDialog for example uses it to enable and disable + * the buffer and writing speed displays. + */ + void burning(bool); + + private: + int m_writeMethod; + + class Private; + Private* d; +}; +#endif diff --git a/libk3b/core/k3bjobhandler.h b/libk3b/core/k3bjobhandler.h new file mode 100644 index 0000000..1262e0e --- /dev/null +++ b/libk3b/core/k3bjobhandler.h @@ -0,0 +1,64 @@ +/* + * + * $Id: k3bjobhandler.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_JOB_HANDLER_H_ +#define _K3B_JOB_HANDLER_H_ + + +#include +#include + + +/** + * See @p K3bJobProgressDialog as an example for the usage of + * the K3bJobHandler interface. + */ +class K3bJobHandler +{ + public: + K3bJobHandler() {} + virtual ~K3bJobHandler() {} + + /** + * \return true if the handler itself is also a job + */ + virtual bool isJob() const { return false; } + + /** + * @return K3bDevice::MediaType on success, + * 0 if forced (no media info available), + * and -1 on error (canceled) + */ + virtual int waitForMedia( K3bDevice::Device*, + int mediaState = K3bDevice::STATE_EMPTY, + int mediaType = K3bDevice::MEDIA_WRITABLE_CD, + const QString& message = QString::null ) = 0; + + // FIXME: use KGuiItem + virtual bool questionYesNo( const QString& text, + const QString& caption = QString::null, + const QString& yesText = QString::null, + const QString& noText = QString::null ) = 0; + + /** + * Use this if you need the user to do something before the job is able to continue. + * In all other cases an infoMessage should be used. + */ + virtual void blockingInformation( const QString& text, + const QString& caption = QString::null ) = 0; + +}; + +#endif diff --git a/libk3b/core/k3bprocess.cpp b/libk3b/core/k3bprocess.cpp new file mode 100644 index 0000000..35ddff4 --- /dev/null +++ b/libk3b/core/k3bprocess.cpp @@ -0,0 +1,452 @@ +/* + * + * $Id: k3bprocess.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + + +#include "k3bprocess.h" +#include "k3bexternalbinmanager.h" + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + + +class K3bProcess::Data +{ +public: + QString unfinishedStdoutLine; + QString unfinishedStderrLine; + + int dupStdoutFd; + int dupStdinFd; + + bool rawStdin; + bool rawStdout; + + int in[2]; + int out[2]; + + bool suppressEmptyLines; +}; + + +K3bProcess::K3bProcess() + : KProcess(), + m_bSplitStdout(false) +{ + d = new Data(); + d->dupStdinFd = d->dupStdoutFd = -1; + d->rawStdout = d->rawStdin = false; + d->in[0] = d->in[1] = -1; + d->out[0] = d->out[1] = -1; + d->suppressEmptyLines = true; +} + +K3bProcess::~K3bProcess() +{ + delete d; +} + + +K3bProcess& K3bProcess::operator<<( const K3bExternalBin* bin ) +{ + return this->operator<<( bin->path ); +} + +K3bProcess& K3bProcess::operator<<( const QString& arg ) +{ + static_cast(this)->operator<<( arg ); + return *this; +} + +K3bProcess& K3bProcess::operator<<( const char* arg ) +{ + static_cast(this)->operator<<( arg ); + return *this; +} + +K3bProcess& K3bProcess::operator<<( const QCString& arg ) +{ + static_cast(this)->operator<<( arg ); + return *this; +} + +K3bProcess& K3bProcess::operator<<( const QStringList& args ) +{ + static_cast(this)->operator<<( args ); + return *this; +} + + +bool K3bProcess::start( RunMode run, Communication com ) +{ + if( com & Stderr ) { + connect( this, SIGNAL(receivedStderr(KProcess*, char*, int)), + this, SLOT(slotSplitStderr(KProcess*, char*, int)) ); + } + if( com & Stdout ) { + connect( this, SIGNAL(receivedStdout(KProcess*, char*, int)), + this, SLOT(slotSplitStdout(KProcess*, char*, int)) ); + } + + return KProcess::start( run, com ); +} + + +void K3bProcess::slotSplitStdout( KProcess*, char* data, int len ) +{ + if( m_bSplitStdout ) { + QStringList lines = splitOutput( data, len, d->unfinishedStdoutLine, d->suppressEmptyLines ); + + for( QStringList::iterator it = lines.begin(); it != lines.end(); ++it ) { + QString& str = *it; + + // just to be sure since something in splitOutput does not do this right + if( d->suppressEmptyLines && str.isEmpty() ) + continue; + + emit stdoutLine( str ); + } + } +} + + +void K3bProcess::slotSplitStderr( KProcess*, char* data, int len ) +{ + QStringList lines = splitOutput( data, len, d->unfinishedStderrLine, d->suppressEmptyLines ); + + for( QStringList::iterator it = lines.begin(); it != lines.end(); ++it ) { + QString& str = *it; + + // just to be sure since something in splitOutput does not do this right + if( d->suppressEmptyLines && str.isEmpty() ) + continue; + + emit stderrLine( str ); + } +} + + +QStringList K3bProcess::splitOutput( char* data, int len, + QString& unfinishedLine, bool suppressEmptyLines ) +{ + // + // The stderr splitting is mainly used for parsing of messages + // That's why we simplify the data before proceeding + // + + QString buffer; + for( int i = 0; i < len; i++ ) { + if( data[i] == '\b' ) { + while( data[i] == '\b' ) // we replace multiple backspaces with a single line feed + i++; + buffer += '\n'; + } + if( data[i] == '\r' ) + buffer += '\n'; + else if( data[i] == '\t' ) // replace tabs with a single space + buffer += " "; + else + buffer += data[i]; + } + + QStringList lines = QStringList::split( '\n', buffer, !suppressEmptyLines ); + + // in case we suppress empty lines we need to handle the following separately + // to make sure we join unfinished lines correctly + if( suppressEmptyLines && buffer[0] == '\n' ) + lines.prepend( QString::null ); + + if( !unfinishedLine.isEmpty() ) { + lines.first().prepend( unfinishedLine ); + unfinishedLine.truncate(0); + + kdDebug() << "(K3bProcess) joined line: '" << (lines.first()) << "'" << endl; + } + + QStringList::iterator it; + + // check if line ends with a newline + // if not save the last line because it is not finished + QChar c = buffer.right(1).at(0); + bool hasUnfinishedLine = ( c != '\n' && c != '\r' && c != QChar(46) ); // What is unicode 46?? It is printed as a point + if( hasUnfinishedLine ) { + kdDebug() << "(K3bProcess) found unfinished line: '" << lines.last() << "'" << endl; + kdDebug() << "(K3bProcess) last char: '" << buffer.right(1) << "'" << endl; + unfinishedLine = lines.last(); + it = lines.end(); + --it; + lines.remove(it); + } + + return lines; +} + + +int K3bProcess::setupCommunication( Communication comm ) +{ + if( KProcess::setupCommunication( comm ) ) { + + // + // Setup our own socketpair + // + + if( d->rawStdin ) { + if( socketpair(AF_UNIX, SOCK_STREAM, 0, d->in) == 0 ) { + fcntl(d->in[0], F_SETFD, FD_CLOEXEC); + fcntl(d->in[1], F_SETFD, FD_CLOEXEC); + } + else + return 0; + } + + if( d->rawStdout ) { + if( socketpair(AF_UNIX, SOCK_STREAM, 0, d->out) == 0 ) { + fcntl(d->out[0], F_SETFD, FD_CLOEXEC); + fcntl(d->out[1], F_SETFD, FD_CLOEXEC); + } + else { + if( d->rawStdin || d->dupStdinFd ) { + close(d->in[0]); + close(d->in[1]); + } + return 0; + } + } + + return 1; + } + else + return 0; +} + + +void K3bProcess::commClose() +{ + if( d->rawStdin ) { + close(d->in[1]); + d->in[1] = -1; + } + if( d->rawStdout ) { + close(d->out[0]); + d->out[0] = -1; + } + + KProcess::commClose(); +} + + +int K3bProcess::commSetupDoneP() +{ + int ok = KProcess::commSetupDoneP(); + + if( d->rawStdin ) + close(d->in[0]); + if( d->rawStdout ) + close(d->out[1]); + + d->in[0] = d->out[1] = -1; + + return ok; +} + + +int K3bProcess::commSetupDoneC() +{ + int ok = KProcess::commSetupDoneC(); + + if( d->dupStdoutFd != -1 ) { + // + // make STDOUT_FILENO a duplicate of d->dupStdoutFd such that writes to STDOUT_FILENO are "redirected" + // to d->dupStdoutFd + // + if( ::dup2( d->dupStdoutFd, STDOUT_FILENO ) < 0 ) { + kdDebug() << "(K3bProcess) Error while dup( " << d->dupStdoutFd << ", " << STDOUT_FILENO << endl; + ok = 0; + } + } + else if( d->rawStdout ) { + if( ::dup2( d->out[1], STDOUT_FILENO ) < 0 ) { + kdDebug() << "(K3bProcess) Error while dup( " << d->out[1] << ", " << STDOUT_FILENO << endl; + ok = 0; + } + } + + if( d->dupStdinFd != -1 ) { + if( ::dup2( d->dupStdinFd, STDIN_FILENO ) < 0 ) { + kdDebug() << "(K3bProcess) Error while dup( " << d->dupStdinFd << ", " << STDIN_FILENO << endl; + ok = 0; + } + } + else if( d->rawStdin ) { + if( ::dup2( d->in[0], STDIN_FILENO ) < 0 ) { + kdDebug() << "(K3bProcess) Error while dup( " << d->in[0] << ", " << STDIN_FILENO << endl; + ok = 0; + } + } + + return ok; +} + + + +int K3bProcess::stdinFd() const +{ + if( d->rawStdin ) + return d->in[1]; + else if( d->dupStdinFd != -1 ) + return d->dupStdinFd; + else + return -1; +} + +int K3bProcess::stdoutFd() const +{ + if( d->rawStdout ) + return d->out[0]; + else if( d->dupStdoutFd != -1 ) + return d->dupStdoutFd; + else + return -1; +} + + +void K3bProcess::dupStdout( int fd ) +{ + writeToFd( fd ); +} + +void K3bProcess::dupStdin( int fd ) +{ + readFromFd( fd ); +} + + +void K3bProcess::writeToFd( int fd ) +{ + d->dupStdoutFd = fd; + if( fd != -1 ) + d->rawStdout = false; +} + +void K3bProcess::readFromFd( int fd ) +{ + d->dupStdinFd = fd; + if( fd != -1 ) + d->rawStdin = false; +} + + +void K3bProcess::setRawStdin(bool b) +{ + if( b ) { + d->rawStdin = true; + d->dupStdinFd = -1; + } + else + d->rawStdin = false; +} + + +void K3bProcess::setRawStdout(bool b) +{ + if( b ) { + d->rawStdout = true; + d->dupStdoutFd = -1; + } + else + d->rawStdout = false; +} + + +void K3bProcess::setSuppressEmptyLines( bool b ) +{ + d->suppressEmptyLines = b; +} + + +bool K3bProcess::closeStdin() +{ + if( d->rawStdin ) { + close(d->in[1]); + d->in[1] = -1; + return true; + } + else + return KProcess::closeStdin(); +} + + +bool K3bProcess::closeStdout() +{ + if( d->rawStdout ) { + close(d->out[0]); + d->out[0] = -1; + return true; + } + else + return KProcess::closeStdout(); +} + + +K3bProcessOutputCollector::K3bProcessOutputCollector( KProcess* p ) + : m_process(0) +{ + setProcess( p ); +} + +void K3bProcessOutputCollector::setProcess( KProcess* p ) +{ + if( m_process ) + m_process->disconnect( this ); + + m_process = p; + if( p ) { + connect( p, SIGNAL(receivedStdout(KProcess*, char*, int)), + this, SLOT(slotGatherStdout(KProcess*, char*, int)) ); + connect( p, SIGNAL(receivedStderr(KProcess*, char*, int)), + this, SLOT(slotGatherStderr(KProcess*, char*, int)) ); + } + + m_gatheredOutput.truncate( 0 ); + m_stderrOutput.truncate( 0 ); + m_stdoutOutput.truncate( 0 ); +} + +void K3bProcessOutputCollector::slotGatherStderr( KProcess*, char* data, int len ) +{ + m_gatheredOutput.append( QString::fromLocal8Bit( data, len ) ); + m_stderrOutput.append( QString::fromLocal8Bit( data, len ) ); +} + +void K3bProcessOutputCollector::slotGatherStdout( KProcess*, char* data, int len ) +{ + m_gatheredOutput.append( QString::fromLocal8Bit( data, len ) ); + m_stdoutOutput.append( QString::fromLocal8Bit( data, len ) ); +} + + +#include "k3bprocess.moc" diff --git a/libk3b/core/k3bprocess.h b/libk3b/core/k3bprocess.h new file mode 100644 index 0000000..959bda1 --- /dev/null +++ b/libk3b/core/k3bprocess.h @@ -0,0 +1,204 @@ +/* + * + * $Id: k3bprocess.h 621644 2007-01-09 12:53:09Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3B_PROCESS_H +#define K3B_PROCESS_H + + +#include +#include +#include "k3b_export.h" + +class K3bExternalBin; + + +/** + * This is an enhanced KProcess. + * It splits the stderr output to lines making sure the client gets every line as it + * was written by the process. + * Aditionally one may set raw stdout and stdin handling using the stdin() and stdout() methods + * to get the process' file descriptors. + * Last but not least K3bProcess is able to duplicate stdout making it possible to connect two + * K3bProcesses like used in K3bDataJob to duplicate mkisofs' stdout to the stdin of the writer + * (cdrecord or cdrdao) + */ +class LIBK3B_EXPORT K3bProcess : public KProcess +{ + Q_OBJECT + + public: + class OutputCollector; + + public: + K3bProcess(); + ~K3bProcess(); + + /** + * In the future this might also set the nice value + */ + K3bProcess& operator<<( const K3bExternalBin* ); + + K3bProcess& operator<<( const QString& arg ); + K3bProcess& operator<<( const char* arg ); + K3bProcess& operator<<( const QCString& arg ); + K3bProcess& operator<<( const QStringList& args ); + + bool start( RunMode run = NotifyOnExit, Communication com = NoCommunication ); + + /** + * get stdin file descriptor + * Only makes sense while process is running. + * + * Only use with setRawStdin + */ + int stdinFd() const; + + /** + * get stdout file descriptor + * Only makes sense while process is running. + * + * Only use with setRawStdout + */ + int stdoutFd() const; + + /** + * @deprecated use writeToFd + */ + void dupStdout( int fd ); + + /** + * @deprecated use readFromFd + */ + void dupStdin( int fd ); + + /** + * Make the process write to @fd instead of Stdout. + * This means you won't get any stdoutReady() or receivedStdout() + * signals anymore. + * + * Only use this before starting the process. + */ + void writeToFd( int fd ); + + /** + * Make the process read from @fd instead of Stdin. + * This means you won't get any wroteStdin() + * signals anymore. + * + * Only use this before starting the process. + */ + void readFromFd( int fd ); + + /** + * If set true the process' stdin fd will be available + * through @stdinFd. + * Be aware that you will not get any wroteStdin signals + * anymore. + * + * Only use this before starting the process. + */ + void setRawStdin(bool b); + + /** + * If set true the process' stdout fd will be available + * through @stdoutFd. + * Be aware that you will not get any stdoutReady or receivedStdout + * signals anymore. + * + * Only use this before starting the process. + */ + void setRawStdout(bool b); + + public slots: + void setSplitStdout( bool b ) { m_bSplitStdout = b; } + + /** + * default is true + */ + void setSuppressEmptyLines( bool b ); + + bool closeStdin(); + bool closeStdout(); + + private slots: + void slotSplitStderr( KProcess*, char*, int ); + void slotSplitStdout( KProcess*, char*, int ); + + signals: + void stderrLine( const QString& line ); + void stdoutLine( const QString& line ); + + /** + * Gets emitted if raw stdout mode has been requested + * The data has to be read from @p fd. + */ + void stdoutReady( int fd ); + + protected: + /** + * reimplemeted from KProcess + */ + int commSetupDoneP(); + + /** + * reimplemeted from KProcess + */ + int commSetupDoneC(); + + /** + * reimplemeted from KProcess + */ + int setupCommunication( Communication comm ); + + /** + * reimplemeted from KProcess + */ + void commClose(); + + private: + static QStringList splitOutput( char*, int, QString&, bool ); + + class Data; + Data* d; + + bool m_bSplitStdout; +}; + +class LIBK3B_EXPORT K3bProcessOutputCollector: public QObject +{ + Q_OBJECT + + public: + K3bProcessOutputCollector( KProcess* ); + void setProcess( KProcess* ); + + const QString& output() const { return m_gatheredOutput; } + const QString& stderrOutput() const { return m_stderrOutput; } + const QString& stdoutOutput() const { return m_stdoutOutput; } + + private slots: + void slotGatherStderr( KProcess*, char*, int ); + void slotGatherStdout( KProcess*, char*, int ); + + private: + QString m_gatheredOutput; + QString m_stderrOutput; + QString m_stdoutOutput; + KProcess* m_process; +}; + + +#endif diff --git a/libk3b/core/k3bprogressinfoevent.h b/libk3b/core/k3bprogressinfoevent.h new file mode 100644 index 0000000..0e77718 --- /dev/null +++ b/libk3b/core/k3bprogressinfoevent.h @@ -0,0 +1,85 @@ +/* + * + * $Id: k3bprogressinfoevent.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef K3B_PROGRESS_INFO_EVENT_H +#define K3B_PROGRESS_INFO_EVENT_H + +#include +#include + + +/** + * Custom event class for posting events corresponding to the + * K3bJob signals. This is useful for a threaded job since + * in that case it's not possible to emit signals that directly + * change the GUI (see QThread docu). + */ +class K3bProgressInfoEvent : public QCustomEvent +{ + public: + K3bProgressInfoEvent( int type ) + : QCustomEvent( type ), + m_type(type) + {} + + K3bProgressInfoEvent( int type, const QString& v1, const QString& v2 = QString::null, + int value1 = 0, int value2 = 0 ) + : QCustomEvent( type ), + m_type( type), + m_firstValue(value1), + m_secondValue(value2), + m_firstString(v1), + m_secondString(v2) + {} + + K3bProgressInfoEvent( int type, int value1, int value2 = 0 ) + : QCustomEvent( type ), + m_type( type), + m_firstValue(value1), + m_secondValue(value2) + {} + + int type() const { return m_type; } + const QString& firstString() const { return m_firstString; } + const QString& secondString() const { return m_secondString; } + int firstValue() const { return m_firstValue; } + int secondValue() const { return m_secondValue; } + + enum K3bProgressInfoEventType { + Progress = QEvent::User + 1, + SubProgress, + ProcessedSize, + ProcessedSubSize, + InfoMessage, + Started, + Canceled, + Finished, + NewTask, + NewSubTask, + DebuggingOutput, + BufferStatus, + WriteSpeed, + NextTrack + }; + + private: + int m_type; + int m_firstValue; + int m_secondValue; + QString m_firstString; + QString m_secondString; +}; + +#endif diff --git a/libk3b/core/k3bsimplejobhandler.cpp b/libk3b/core/k3bsimplejobhandler.cpp new file mode 100644 index 0000000..eaf7cd6 --- /dev/null +++ b/libk3b/core/k3bsimplejobhandler.cpp @@ -0,0 +1,62 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bsimplejobhandler.h" + + +K3bSimpleJobHandler::K3bSimpleJobHandler( QObject* parent ) + : QObject( parent ), + K3bJobHandler() +{ +} + +K3bSimpleJobHandler::~K3bSimpleJobHandler() +{ +} + +int K3bSimpleJobHandler::waitForMedia( K3bDevice::Device* dev, + int mediaState, + int mediaType, + const QString& message ) +{ + Q_UNUSED( dev ); + Q_UNUSED( mediaState ); + Q_UNUSED( mediaType ); + Q_UNUSED( message ); + + return 0; +} + +bool K3bSimpleJobHandler::questionYesNo( const QString& text, + const QString& caption, + const QString& yesText, + const QString& noText ) +{ + Q_UNUSED( text ); + Q_UNUSED( caption ); + Q_UNUSED( yesText ); + Q_UNUSED( noText ); + + return true; +} + +void K3bSimpleJobHandler::blockingInformation( const QString& text, + const QString& caption ) +{ + Q_UNUSED( text ); + Q_UNUSED( caption ); +} + +#include "k3bsimplejobhandler.moc" diff --git a/libk3b/core/k3bsimplejobhandler.h b/libk3b/core/k3bsimplejobhandler.h new file mode 100644 index 0000000..f84064e --- /dev/null +++ b/libk3b/core/k3bsimplejobhandler.h @@ -0,0 +1,61 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_SIMPLE_JOB_HANDLER_H_ +#define _K3B_SIMPLE_JOB_HANDLER_H_ + +#include + +#include +#include + + +/** + * This is a simplified job handler which just consumes the + * job handler calls without doing anything. + * Use it for very simple jobs that don't need the job handler + * methods. + */ +class LIBK3B_EXPORT K3bSimpleJobHandler : public QObject, public K3bJobHandler +{ + Q_OBJECT + + public: + K3bSimpleJobHandler( QObject* parent = 0 ); + ~K3bSimpleJobHandler(); + + /* + * \return 0 + */ + int waitForMedia( K3bDevice::Device*, + int mediaState = K3bDevice::STATE_EMPTY, + int mediaType = K3bDevice::MEDIA_WRITABLE_CD, + const QString& message = QString::null ); + /** + * \return true + */ + bool questionYesNo( const QString& text, + const QString& caption = QString::null, + const QString& yesText = QString::null, + const QString& noText = QString::null ); + + /** + * Does nothing + */ + void blockingInformation( const QString& text, + const QString& caption = QString::null ); +}; + +#endif diff --git a/libk3b/core/k3bthread.cpp b/libk3b/core/k3bthread.cpp new file mode 100644 index 0000000..07414ad --- /dev/null +++ b/libk3b/core/k3bthread.cpp @@ -0,0 +1,221 @@ +/* + * + * $Id: k3bthread.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bthread.h" +#include "k3bprogressinfoevent.h" +#include "k3bdataevent.h" + +#include + +#include + + +static QPtrList s_threads; + + +void K3bThread::waitUntilFinished() +{ + QPtrListIterator it( s_threads ); + while( it.current() ) { + kdDebug() << "Waiting for thread " << it.current() << endl; + it.current()->wait(); + ++it; + } + + kdDebug() << "Thread waiting done." << endl; +} + + +class K3bThread::Private +{ +public: + Private() + : eventHandler( 0 ) { + } + + QObject* eventHandler; +}; + + +K3bThread::K3bThread( QObject* eventHandler ) + : QThread() +{ + d = new Private; + d->eventHandler = eventHandler; + + s_threads.append(this); +} + + +K3bThread::K3bThread( unsigned int stackSize, QObject* eventHandler ) + : QThread( stackSize ) +{ + d = new Private; + d->eventHandler = eventHandler; + + s_threads.append(this); +} + + +K3bThread::~K3bThread() +{ + s_threads.removeRef(this); + delete d; +} + + +void K3bThread::setProgressInfoEventHandler( QObject* eventHandler ) +{ + d->eventHandler = eventHandler; +} + +QString K3bThread::jobDescription() const +{ + return QString::null; +} + + +QString K3bThread::jobDetails() const +{ + return QString::null; +} + + +void K3bThread::init() +{ + // do nothing... +} + + +void K3bThread::cancel() +{ + if( running() ) { + terminate(); + if( d->eventHandler ) { + emitCanceled(); + emitFinished(false); + } + } +} + + +void K3bThread::emitInfoMessage( const QString& msg, int type ) +{ + if( d->eventHandler ) + QApplication::postEvent( d->eventHandler, + new K3bProgressInfoEvent( K3bProgressInfoEvent::InfoMessage, msg, QString::null, type ) ); + else + kdWarning() << "(K3bThread) call to emitInfoMessage() without eventHandler." << endl; +} + +void K3bThread::emitPercent( int p ) +{ + if( d->eventHandler ) + QApplication::postEvent( d->eventHandler, + new K3bProgressInfoEvent( K3bProgressInfoEvent::Progress, p ) ); + else + kdWarning() << "(K3bThread) call to emitPercent() without eventHandler." << endl; +} + +void K3bThread::emitSubPercent( int p ) +{ + if( d->eventHandler ) + QApplication::postEvent( d->eventHandler, + new K3bProgressInfoEvent( K3bProgressInfoEvent::SubProgress, p ) ); + else + kdWarning() << "(K3bThread) call to emitSubPercent() without eventHandler." << endl; +} + +void K3bThread::emitStarted() +{ + if( d->eventHandler ) + QApplication::postEvent( d->eventHandler, new K3bProgressInfoEvent( K3bProgressInfoEvent::Started ) ); + else + kdWarning() << "(K3bThread) call to emitStarted() without eventHandler." << endl; +} + +void K3bThread::emitCanceled() +{ + if( d->eventHandler ) + QApplication::postEvent( d->eventHandler, new K3bProgressInfoEvent( K3bProgressInfoEvent::Canceled ) ); + else + kdWarning() << "(K3bThread) call to emitCanceled() without eventHandler." << endl; +} + +void K3bThread::emitFinished( bool success ) +{ + if( d->eventHandler ) + QApplication::postEvent( d->eventHandler, new K3bProgressInfoEvent( K3bProgressInfoEvent::Finished, success ) ); + else + kdWarning() << "(K3bThread) call to emitFinished() without eventHandler." << endl; +} + +void K3bThread::emitProcessedSize( int p, int size ) +{ + if( d->eventHandler ) + QApplication::postEvent( d->eventHandler, new K3bProgressInfoEvent( K3bProgressInfoEvent::ProcessedSize, p, size ) ); + else + kdWarning() << "(K3bThread) call to emitProcessedSize() without eventHandler." << endl; +} + +void K3bThread::emitProcessedSubSize( int p, int size ) +{ + if( d->eventHandler ) + QApplication::postEvent( d->eventHandler, new K3bProgressInfoEvent( K3bProgressInfoEvent::ProcessedSubSize, p, size ) ); + else + kdWarning() << "(K3bThread) call to emitProcessedSubSize() without eventHandler." << endl; +} + +void K3bThread::emitNewTask( const QString& job ) +{ + if( d->eventHandler ) + QApplication::postEvent( d->eventHandler, new K3bProgressInfoEvent( K3bProgressInfoEvent::NewTask, job ) ); + else + kdWarning() << "(K3bThread) call to emitNewTask() without eventHandler." << endl; +} + +void K3bThread::emitNewSubTask( const QString& job ) +{ + if( d->eventHandler ) + QApplication::postEvent( d->eventHandler, new K3bProgressInfoEvent( K3bProgressInfoEvent::NewSubTask, job ) ); + else + kdWarning() << "(K3bThread) call to emitNewSubTask() without eventHandler." << endl; +} + +void K3bThread::emitDebuggingOutput(const QString& group, const QString& text) +{ + if( d->eventHandler ) + QApplication::postEvent( d->eventHandler, new K3bProgressInfoEvent( K3bProgressInfoEvent::DebuggingOutput, group, text ) ); + else + kdWarning() << "(K3bThread) call to emitDebuggingOutput() without eventHandler." << endl; +} + +void K3bThread::emitData( const char* data, int len ) +{ + if( d->eventHandler ) + QApplication::postEvent( d->eventHandler, new K3bDataEvent( data, len ) ); + else + kdWarning() << "(K3bThread) call to emitData() without eventHandler." << endl; +} + +void K3bThread::emitNextTrack( int t, int n ) +{ + if( d->eventHandler ) + QApplication::postEvent( d->eventHandler, new K3bProgressInfoEvent( K3bProgressInfoEvent::NextTrack, t, n ) ); + else + kdWarning() << "(K3bThread) call to emitNextTrack() without eventHandler." << endl; +} + diff --git a/libk3b/core/k3bthread.h b/libk3b/core/k3bthread.h new file mode 100644 index 0000000..f7e68fc --- /dev/null +++ b/libk3b/core/k3bthread.h @@ -0,0 +1,95 @@ +/* + * + * $Id: k3bthread.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_THREAD_H_ +#define _K3B_THREAD_H_ + +#include +#include "k3b_export.h" + +class QObject; + +/** + * The threaded couterpart to K3bJob + * instead of emitting the information signals + * one has to use the emitXXX methods which will post + * K3bProgressInfoEvents to the eventhandler. + * + * K3bThreadJob can be used to automatically wrap the thread in a K3bJob. + * + * As in K3bJob it is important to call emitStarted and emitFinished. + * + * See K3bThreadJob for more information. + */ +class LIBK3B_EXPORT K3bThread : public QThread +{ + public: + K3bThread( QObject* eventHandler = 0 ); + K3bThread( unsigned int stackSize, QObject* eventHandler = 0 ); + virtual ~K3bThread(); + + void setProgressInfoEventHandler( QObject* eventHandler ); + + /** + * Initialize the thread before starting it in the GUi thread. + * K3bThreadJob automatically calls this. + * + * The default implementation does nothing. + */ + virtual void init(); + + /** + * to provide the same api like K3bJob + * the default implementation calls terminate and + * emitCancled() and emitFinished(false) + */ + virtual void cancel(); + + virtual QString jobDescription() const; + virtual QString jobDetails() const; + + /** + * waits until all running K3bThread have finished. + * This is used by K3bApplication. + */ + static void waitUntilFinished(); + + protected: + virtual void run() = 0; + + /** + * uses the K3bJob::MessageType enum + */ + void emitInfoMessage( const QString& msg, int type ); + void emitPercent( int p ); + void emitSubPercent( int p ); + void emitStarted(); + void emitCanceled(); + void emitFinished( bool success ); + void emitProcessedSize( int processed, int size ); + void emitProcessedSubSize( int processed, int size ); + void emitNewTask( const QString& job ); + void emitNewSubTask( const QString& job ); + void emitDebuggingOutput(const QString&, const QString&); + void emitData( const char* data, int len ); + void emitNextTrack( int track, int trackNum ); + + private: + class Private; + Private* d; +}; + +#endif diff --git a/libk3b/core/k3bthreadjob.cpp b/libk3b/core/k3bthreadjob.cpp new file mode 100644 index 0000000..a13f10a --- /dev/null +++ b/libk3b/core/k3bthreadjob.cpp @@ -0,0 +1,161 @@ +/* + * + * $Id: k3bthreadjob.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bthreadjob.h" +#include "k3bthread.h" +#include "k3bprogressinfoevent.h" +#include "k3bdataevent.h" + +#include +#include + + + +K3bThreadJob::K3bThreadJob( K3bJobHandler* jh, QObject* parent, const char* name ) + : K3bJob( jh, parent, name ), + m_running(false) +{ +} + + +K3bThreadJob::K3bThreadJob( K3bThread* thread, K3bJobHandler* jh, QObject* parent, const char* name ) + : K3bJob( jh, parent, name ), + m_running(false) +{ + setThread(thread); +} + + +K3bThreadJob::~K3bThreadJob() +{ +} + + +QString K3bThreadJob::jobDescription() const +{ + if( m_thread ) + return m_thread->jobDescription(); + else + return QString::null; +} + + +QString K3bThreadJob::jobDetails() const +{ + if( m_thread ) + return m_thread->jobDetails(); + else + return QString::null; +} + + +void K3bThreadJob::setThread( K3bThread* t ) +{ + m_thread = t; + m_thread->setProgressInfoEventHandler(this); +} + + +void K3bThreadJob::start() +{ + if( m_thread ) { + if( !m_running ) { + m_thread->setProgressInfoEventHandler(this); + m_running = true; + m_thread->init(); + m_thread->start(); + } + else + kdDebug() << "(K3bThreadJob) thread not finished yet." << endl; + } + else { + kdError() << "(K3bThreadJob) no job set." << endl; + jobFinished(false); + } +} + + +void K3bThreadJob::cancel() +{ + m_thread->cancel(); + // wait for the thread to finish + // m_thread->wait(); +} + + +void K3bThreadJob::cleanupJob( bool success ) +{ + Q_UNUSED( success ); +} + + +void K3bThreadJob::customEvent( QCustomEvent* e ) +{ + if( K3bDataEvent* de = dynamic_cast(e) ) { + emit data( de->data(), de->length() ); + } + else { + K3bProgressInfoEvent* be = static_cast(e); + switch( be->type() ) { + case K3bProgressInfoEvent::Progress: + emit percent( be->firstValue() ); + break; + case K3bProgressInfoEvent::SubProgress: + emit subPercent( be->firstValue() ); + break; + case K3bProgressInfoEvent::ProcessedSize: + emit processedSize( be->firstValue(), be->secondValue() ); + break; + case K3bProgressInfoEvent::ProcessedSubSize: + emit processedSubSize( be->firstValue(), be->secondValue() ); + break; + case K3bProgressInfoEvent::InfoMessage: + emit infoMessage( be->firstString(), be->firstValue() ); + break; + case K3bProgressInfoEvent::Started: + jobStarted(); + break; + case K3bProgressInfoEvent::Canceled: + emit canceled(); + break; + case K3bProgressInfoEvent::Finished: + // we wait until the thred really finished + // although this may be dangerous if some thread + // emits the finished signal although it has not finished yet + // but makes a lot stuff easier. + kdDebug() << "(K3bThreadJob) waiting for the thread to finish." << endl; + m_thread->wait(); + kdDebug() << "(K3bThreadJob) thread finished." << endl; + cleanupJob( be->firstValue() ); + m_running = false; + jobFinished( be->firstValue() ); + break; + case K3bProgressInfoEvent::NewTask: + emit newTask( be->firstString() ); + break; + case K3bProgressInfoEvent::NewSubTask: + emit newSubTask( be->firstString() ); + break; + case K3bProgressInfoEvent::DebuggingOutput: + emit debuggingOutput( be->firstString(), be->secondString() ); + break; + case K3bProgressInfoEvent::NextTrack: + emit nextTrack( be->firstValue(), be->secondValue() ); + break; + } + } +} + +#include "k3bthreadjob.moc" diff --git a/libk3b/core/k3bthreadjob.h b/libk3b/core/k3bthreadjob.h new file mode 100644 index 0000000..25919f1 --- /dev/null +++ b/libk3b/core/k3bthreadjob.h @@ -0,0 +1,89 @@ +/* + * + * $Id: k3bthreadjob.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_THREAD_JOB_H_ +#define _K3B_THREAD_JOB_H_ + +#include "k3bjob.h" +#include "k3b_export.h" +class QCustomEvent; +class K3bThread; + + +/** + * A Wrapper to use a K3bThread just like a K3bJob. + * Usage: + *
+ *   K3bThread* thread = new MySuperThread(...);
+ *   K3bThreadJob* job = new K3bThreadJob( thread, ... );
+ *   K3bBurnProgressDialog d;
+ *   d.setJob(job);
+ *   job->start();
+ *   d.exec();
+ *   delete job;
+ * 
+ * Be aware that K3bThreadJob'd destructor does NOT delete the thread. + */ +class LIBK3B_EXPORT K3bThreadJob : public K3bJob +{ + Q_OBJECT + + public: + K3bThreadJob( K3bJobHandler*, QObject* parent = 0, const char* name = 0 ); + K3bThreadJob( K3bThread*, K3bJobHandler*, QObject* parent = 0, const char* name = 0 ); + virtual ~K3bThreadJob(); + + void setThread( K3bThread* t ); + K3bThread* thread() const { return m_thread; } + + /** + * \reimplemented from K3bJob + * + * \return true if the job has been started and has not yet + * emitted the finished signal + */ + virtual bool active() const { return m_running; } + + virtual QString jobDescription() const; + virtual QString jobDetails() const; + + public slots: + virtual void start(); + virtual void cancel(); + + protected: + /** + * converts K3bThread events to K3bJob signals + */ + virtual void customEvent( QCustomEvent* ); + + /** + * Reimplement this method to do some housekeeping once + * the thread has finished. + * + * The default implementation does nothing. + * + * \param success True if the thread finished successfully + */ + virtual void cleanupJob( bool success ); + + private: + K3bThread* m_thread; + bool m_running; +}; + +#endif + diff --git a/libk3b/core/k3bversion.cpp b/libk3b/core/k3bversion.cpp new file mode 100644 index 0000000..f7af248 --- /dev/null +++ b/libk3b/core/k3bversion.cpp @@ -0,0 +1,318 @@ +/* + * + * $Id: k3bversion.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bversion.h" + +#include +#include + + +K3bVersion::K3bVersion() + : m_majorVersion( -1 ), + m_minorVersion( -1 ), + m_patchLevel( -1 ) +{ +} + +K3bVersion::K3bVersion( const K3bVersion& v ) + : m_versionString( v.versionString() ), + m_majorVersion( v.majorVersion() ), + m_minorVersion( v.minorVersion() ), + m_patchLevel( v.patchLevel() ), + m_suffix( v.suffix() ) +{ +} + +K3bVersion::K3bVersion( const QString& version ) +{ + setVersion( version ); +} + +K3bVersion::K3bVersion( int majorVersion, + int minorVersion, + int patchlevel, + const QString& suffix ) +{ + setVersion( majorVersion, minorVersion, patchlevel, suffix ); +} + +void K3bVersion::setVersion( const QString& v ) +{ + QString suffix; + splitVersionString( v.stripWhiteSpace(), m_majorVersion, suffix ); + if( m_majorVersion >= 0 ) { + if( suffix.startsWith(".") ) { + suffix = suffix.mid( 1 ); + splitVersionString( suffix, m_minorVersion, suffix ); + if( m_minorVersion < 0 ) { + kdDebug() << "(K3bVersion) suffix must not start with a dot!" << endl; + m_majorVersion = -1; + m_minorVersion = -1; + m_patchLevel = -1; + m_suffix = ""; + } + else { + if( suffix.startsWith(".") ) { + suffix = suffix.mid( 1 ); + splitVersionString( suffix, m_patchLevel, suffix ); + if( m_patchLevel < 0 ) { + kdDebug() << "(K3bVersion) suffix must not start with a dot!" << endl; + m_majorVersion = -1; + m_minorVersion = -1; + m_patchLevel = -1; + m_suffix = ""; + } + else { + m_suffix = suffix; + } + } + else { + m_patchLevel = -1; + m_suffix = suffix; + } + } + } + else { + m_minorVersion = -1; + m_patchLevel = -1; + m_suffix = suffix; + } + } + + m_versionString = createVersionString( m_majorVersion, m_minorVersion, m_patchLevel, m_suffix ); +} + + +// splits the leading number from s and puts it in num +// the dot is removed and the rest put in suffix +// if s does not start with a digit or the first non-digit char is not a dot +// suffix = s and num = -1 is returned +void K3bVersion::splitVersionString( const QString& s, int& num, QString& suffix ) +{ + int pos = s.find( QRegExp("\\D") ); + if( pos < 0 ) { + num = s.toInt(); + suffix = ""; + } + else if( pos == 0 ) { + num = -1; + suffix = s; + } + else { + num = s.left( pos ).toInt(); + suffix = s.mid( pos ); + } +} + + +bool K3bVersion::isValid() const +{ + return (m_majorVersion >= 0); +} + + +void K3bVersion::setVersion( int majorVersion, + int minorVersion, + int patchlevel, + const QString& suffix ) +{ + m_majorVersion = majorVersion; + m_minorVersion = minorVersion; + m_patchLevel = patchlevel; + m_suffix = suffix; + m_versionString = createVersionString( majorVersion, minorVersion, patchlevel, suffix ); +} + +K3bVersion& K3bVersion::operator=( const QString& v ) +{ + setVersion( v ); + return *this; +} + +K3bVersion K3bVersion::simplify() const +{ + K3bVersion v( *this ); + v.m_suffix.truncate(0); + return v; +} + +QString K3bVersion::createVersionString( int majorVersion, + int minorVersion, + int patchlevel, + const QString& suffix ) +{ + if( majorVersion >= 0 ) { + QString s = QString::number(majorVersion); + + if( minorVersion > -1 ) { + s.append( QString(".%1").arg(minorVersion) ); + if( patchlevel > -1 ) + s.append( QString(".%1").arg(patchlevel) ); + } + + if( !suffix.isNull() ) + s.append( suffix ); + + return s; + } + else + return ""; +} + + +int K3bVersion::compareSuffix( const QString& suffix1, const QString& suffix2 ) +{ + static QRegExp rcRx( "rc(\\d+)" ); + static QRegExp preRx( "pre(\\d+)" ); + static QRegExp betaRx( "beta(\\d+)" ); + static QRegExp alphaRx( "a(?:lpha)?(\\d+)" ); + + // first we check if one of the suffixes (or both are empty) becasue that case if simple + if( suffix1.isEmpty() ) { + if( suffix2.isEmpty() ) + return 0; + else + return 1; // empty greater than the non-empty (should we treat something like 1.0a as greater than 1.0?) + } + else if( suffix2.isEmpty() ) + return -1; + + // now search for our special suffixes + if( rcRx.exactMatch( suffix1 ) ) { + int v1 = rcRx.cap(1).toInt(); + + if( rcRx.exactMatch( suffix2 ) ) { + int v2 = rcRx.cap(1).toInt(); + return ( v1 == v2 ? 0 : ( v1 < v2 ? -1 : 1 ) ); + } + else if( preRx.exactMatch( suffix2 ) || + betaRx.exactMatch( suffix2 ) || + alphaRx.exactMatch( suffix2 ) ) + return 1; // rc > than all the others + else + return QString::compare( suffix1, suffix2 ); + } + + else if( preRx.exactMatch( suffix1 ) ) { + int v1 = preRx.cap(1).toInt(); + + if( rcRx.exactMatch( suffix2 ) ) { + return -1; // pre is less than rc + } + else if( preRx.exactMatch( suffix2 ) ) { + int v2 = preRx.cap(1).toInt(); + return ( v1 == v2 ? 0 : ( v1 < v2 ? -1 : 1 ) ); + } + else if( betaRx.exactMatch( suffix2 ) || + alphaRx.exactMatch( suffix2 ) ) + return 1; // pre is greater than beta or alpha + else + return QString::compare( suffix1, suffix2 ); + } + + else if( betaRx.exactMatch( suffix1 ) ) { + int v1 = betaRx.cap(1).toInt(); + + if( rcRx.exactMatch( suffix2 ) || + preRx.exactMatch( suffix2 ) ) + return -1; // beta is less than rc or pre + else if( betaRx.exactMatch( suffix2 ) ) { + int v2 = betaRx.cap(1).toInt(); + return ( v1 == v2 ? 0 : ( v1 < v2 ? -1 : 1 ) ); + } + else if( alphaRx.exactMatch( suffix2 ) ) + return 1; // beta is greater then alpha + else + return QString::compare( suffix1, suffix2 ); + } + + else if( alphaRx.exactMatch( suffix1 ) ) { + int v1 = alphaRx.cap(1).toInt(); + + if( rcRx.exactMatch( suffix2 ) || + preRx.exactMatch( suffix2 ) || + betaRx.exactMatch( suffix2 ) ) + return -1; // alpha is less than all the others + else if( alphaRx.exactMatch( suffix2 ) ) { + int v2 = alphaRx.cap(1).toInt(); + return ( v1 == v2 ? 0 : ( v1 < v2 ? -1 : 1 ) ); + } + else + return QString::compare( suffix1, suffix2 ); + } + + else + return QString::compare( suffix1, suffix2 ); +} + + +bool operator<( const K3bVersion& v1, const K3bVersion& v2 ) +{ + // both version objects need to be valid + + if( v1.majorVersion() == v2.majorVersion() ) { + + // 1 == 1.0 + if( ( v1.minorVersion() == v2.minorVersion() ) + || + ( v1.minorVersion() == -1 && v2.minorVersion() == 0 ) + || + ( v2.minorVersion() == -1 && v1.minorVersion() == 0 ) + ) + { + // 1.0 == 1.0.0 + if( ( v1.patchLevel() == v2.patchLevel() ) + || + ( v1.patchLevel() == -1 && v2.patchLevel() == 0 ) + || + ( v2.patchLevel() == -1 && v1.patchLevel() == 0 ) + ) + { + return K3bVersion::compareSuffix( v1.suffix(), v2.suffix() ) < 0; + } + else + return ( v1.patchLevel() < v2.patchLevel() ); + } + else + return ( v1.minorVersion() < v2.minorVersion() ); + } + else + return ( v1.majorVersion() < v2.majorVersion() ); +} + +bool operator>( const K3bVersion& v1, const K3bVersion& v2 ) +{ + return operator<( v2, v1 ); +} + + +bool operator==( const K3bVersion& v1, const K3bVersion& v2 ) +{ + return ( v1.majorVersion() == v2.majorVersion() && + v1.minorVersion() == v2.minorVersion() && + v1.patchLevel() == v2.patchLevel() && + K3bVersion::compareSuffix( v1.suffix(), v2.suffix() ) == 0 ); +} + + +bool operator<=( const K3bVersion& v1, const K3bVersion& v2 ) +{ + return ( operator<( v1, v2 ) || operator==( v1, v2 ) ); +} + +bool operator>=( const K3bVersion& v1, const K3bVersion& v2 ) +{ + return ( operator>( v1, v2 ) || operator==( v1, v2 ) ); +} diff --git a/libk3b/core/k3bversion.h b/libk3b/core/k3bversion.h new file mode 100644 index 0000000..a6e3aee --- /dev/null +++ b/libk3b/core/k3bversion.h @@ -0,0 +1,141 @@ +/* + * + * $Id: k3bversion.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_VERSION_H_ +#define _K3B_VERSION_H_ + +#include +#include "k3b_export.h" +/** + * \brief Representation of a version. + * + * K3bVersion represents a version consisting of a major version (accessible via majorVersion()), + * a minor version (accessible via minorVersion()), a patchLevel (accessible via patchLevel()), + * and a suffix (accessible via suffix()). + * + * The major version is mandatory while all other fields are optional (in case of the minor version + * and the patchlevel -1 means that the field is undefined). + * + * K3bVersion tries to treat version suffixes in an "intelligent" way to properly compare versions + * (see compareSuffix() for more details). + * + * K3bVersion may also be used everywhere a QString is needed as it automatically converts to a + * string representation using createVersionString(). + */ +class LIBK3B_EXPORT K3bVersion +{ + public: + /** + * construct an empty version object + * which is invalid + * @ see isValid() + */ + K3bVersion(); + + /** + * copy constructor + */ + K3bVersion( const K3bVersion& ); + + /** + * this constructor tries to parse the given version string + */ + K3bVersion( const QString& version ); + + /** + * sets the version and generates a version string from it + */ + K3bVersion( int majorVersion, int minorVersion, int pachlevel = -1, const QString& suffix = QString::null ); + + /** + * tries to parse the version string + * used by the constructor + */ + void setVersion( const QString& ); + + bool isValid() const; + + /** + * sets the version and generates a version string from it + * used by the constructor + * + * If minorVersion or pachlevel are -1 they will not be used when generating the version string. + */ + void setVersion( int majorVersion, int minorVersion = -1, int patchlevel = -1, const QString& suffix = QString::null ); + + const QString& versionString() const { return m_versionString; } + int majorVersion() const { return m_majorVersion; } + int minorVersion() const { return m_minorVersion; } + int patchLevel() const { return m_patchLevel; } + const QString& suffix() const { return m_suffix; } + + /** + * just to make it possible to use as a QString + */ + operator const QString& () const { return m_versionString; } + K3bVersion& operator=( const QString& v ); + + /** + * \return A new K3bVersion object which equals this one except that the suffix is empty. + */ + K3bVersion simplify() const; + + /** + * If minorVersion or pachlevel are -1 they will not be used when generating the version string. + * If minorVersion is -1 patchlevel will be ignored. + */ + static QString createVersionString( int majorVersion, + int minorVersion = -1, + int patchlevel = -1, + const QString& suffix = QString::null ); + + /** + * "Intelligent" comparison of two version suffixes. + * + * This method checks for the following types of suffixes and treats them in the + * following order: + * + * [empty prefix] > rcX > preX > betaX > alphaX = aX (where X is a number) + * + * Every other suffixes are compared alphanumerical. + * An empty prefix is always considered newer than an unknown non-emtpy suffix (e.g. not one of the above.) + * + * @return \li -1 if suffix1 is less than suffix2 + * \li 0 if suffix1 equals suffix2 (be aware that this is not the same as comparing to strings as + * alphaX equals aX in this case.) + * \li 1 if suffix1 is greater than suffix2 + */ + static int compareSuffix( const QString& suffix1, const QString& suffix2 ); + + private: + static void splitVersionString( const QString& s, int& num, QString& suffix ); + + QString m_versionString; + int m_majorVersion; + int m_minorVersion; + int m_patchLevel; + QString m_suffix; +}; + + +LIBK3B_EXPORT bool operator<( const K3bVersion& v1, const K3bVersion& v2 ); +LIBK3B_EXPORT bool operator>( const K3bVersion& v1, const K3bVersion& v2 ); +LIBK3B_EXPORT bool operator==( const K3bVersion& v1, const K3bVersion& v2 ); +LIBK3B_EXPORT bool operator<=( const K3bVersion& v1, const K3bVersion& v2 ); +LIBK3B_EXPORT bool operator>=( const K3bVersion& v1, const K3bVersion& v2 ); + + +#endif diff --git a/libk3b/dummy.cpp b/libk3b/dummy.cpp new file mode 100644 index 0000000..9f6c7b2 --- /dev/null +++ b/libk3b/dummy.cpp @@ -0,0 +1 @@ +/* dummy file to have anything around.*/ diff --git a/libk3b/jobs/Makefile.am b/libk3b/jobs/Makefile.am new file mode 100644 index 0000000..72a9eac --- /dev/null +++ b/libk3b/jobs/Makefile.am @@ -0,0 +1,43 @@ +AM_CPPFLAGS = -I$(srcdir)/../core \ + -I$(srcdir)/../../libk3bdevice \ + -I$(srcdir)/../../src \ + -I$(srcdir)/../tools \ + -I$(srcdir)/../cddb \ + -I$(srcdir)/../plugin \ + -I$(srcdir)/../projects \ + -I$(srcdir)/../videodvd \ + -I$(srcdir)/../projects/audiocd \ + $(all_includes) + +METASOURCES = AUTO + +noinst_LTLIBRARIES = libjobs.la + +if include_videodvdrip +libjobs_la_SOURCES = k3bdatatrackreader.cpp k3breadcdreader.cpp \ + k3bcdcopyjob.cpp k3bclonejob.cpp k3baudiosessionreadingjob.cpp \ + k3bdvdcopyjob.cpp k3bvideodvdtitletranscodingjob.cpp k3bvideodvdtitledetectclippingjob.cpp \ + k3baudiocuefilewritingjob.cpp k3bbinimagewritingjob.cpp \ + k3biso9660imagewritingjob.cpp \ + k3bdvdformattingjob.cpp k3bblankingjob.cpp k3bclonetocreader.cpp \ + k3bverificationjob.cpp + +include_HEADERS = k3bcdcopyjob.h k3bdvdcopyjob.h k3bclonejob.h \ + k3baudiocuefilewritingjob.h k3bbinimagewritingjob.h \ + k3biso9660imagewritingjob.h k3bdvdformattingjob.h \ + k3bblankingjob.h k3bvideodvdtitletranscodingjob.h k3bvideodvdtitledetectclippingjob.h \ + k3bverificationjob.h +else +libjobs_la_SOURCES = k3bdatatrackreader.cpp k3breadcdreader.cpp \ + k3bcdcopyjob.cpp k3bclonejob.cpp k3baudiosessionreadingjob.cpp \ + k3bdvdcopyjob.cpp \ + k3baudiocuefilewritingjob.cpp k3bbinimagewritingjob.cpp \ + k3biso9660imagewritingjob.cpp \ + k3bdvdformattingjob.cpp k3bblankingjob.cpp k3bclonetocreader.cpp \ + k3bverificationjob.cpp + +include_HEADERS = k3bcdcopyjob.h k3bdvdcopyjob.h k3bclonejob.h \ + k3baudiocuefilewritingjob.h k3bbinimagewritingjob.h \ + k3biso9660imagewritingjob.h k3bdvdformattingjob.h \ + k3bblankingjob.h k3bverificationjob.h +endif diff --git a/libk3b/jobs/k3baudiocuefilewritingjob.cpp b/libk3b/jobs/k3baudiocuefilewritingjob.cpp new file mode 100644 index 0000000..0c5cd9a --- /dev/null +++ b/libk3b/jobs/k3baudiocuefilewritingjob.cpp @@ -0,0 +1,272 @@ +/* + * + * $Id: k3baudiocuefilewritingjob.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2005 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3baudiocuefilewritingjob.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +class K3bAudioCueFileWritingJob::AnalyserThread : public K3bThread +{ +public: + AnalyserThread() + : K3bThread() { + } + + void setDecoder( K3bAudioDecoder* dec ) { m_decoder = dec; } + +protected: + void run() { + emitStarted(); + m_decoder->analyseFile(); + emitFinished(true); + } + +private: + K3bAudioDecoder* m_decoder; +}; + + +K3bAudioCueFileWritingJob::K3bAudioCueFileWritingJob( K3bJobHandler* jh, QObject* parent, const char* name ) + : K3bBurnJob( jh, parent, name ), + m_decoder(0) +{ + m_analyserThread = new AnalyserThread(); + m_analyserJob = new K3bThreadJob( m_analyserThread, this, this ); + connect( m_analyserJob, SIGNAL(finished(bool)), this, SLOT(slotAnalyserThreadFinished(bool)) ); + + m_audioDoc = new K3bAudioDoc( this ); + m_audioDoc->newDocument(); + m_audioJob = new K3bAudioJob( m_audioDoc, this, this ); + + // just loop all through + connect( m_audioJob, SIGNAL(newTask(const QString&)), this, SIGNAL(newTask(const QString&)) ); + connect( m_audioJob, SIGNAL(newSubTask(const QString&)), this, SIGNAL(newSubTask(const QString&)) ); + connect( m_audioJob, SIGNAL(debuggingOutput(const QString&, const QString&)), + this, SIGNAL(debuggingOutput(const QString&, const QString&)) ); + connect( m_audioJob, SIGNAL(infoMessage(const QString&, int)), + this, SIGNAL(infoMessage(const QString&, int)) ); + connect( m_audioJob, SIGNAL(finished(bool)), this, SIGNAL(finished(bool)) ); + connect( m_audioJob, SIGNAL(canceled()), this, SIGNAL(canceled()) ); + connect( m_audioJob, SIGNAL(percent(int)), this, SIGNAL(percent(int)) ); + connect( m_audioJob, SIGNAL(subPercent(int)), this, SIGNAL(subPercent(int)) ); + connect( m_audioJob, SIGNAL(processedSize(int, int)), this, SIGNAL(processedSubSize(int, int)) ); + connect( m_audioJob, SIGNAL(processedSubSize(int, int)), this, SIGNAL(processedSubSize(int, int)) ); + connect( m_audioJob, SIGNAL(burning(bool)), this, SIGNAL(burning(bool)) ); + connect( m_audioJob, SIGNAL(bufferStatus(int)), this, SIGNAL(bufferStatus(int)) ); + connect( m_audioJob, SIGNAL(deviceBuffer(int)), this, SIGNAL(deviceBuffer(int)) ); + connect( m_audioJob, SIGNAL(writeSpeed(int, int)), this, SIGNAL(writeSpeed(int, int)) ); + + m_canceled = false; + m_audioJobRunning = false; +} + + +K3bAudioCueFileWritingJob::~K3bAudioCueFileWritingJob() +{ + // the threadjob does not delete the thread + delete m_analyserThread; +} + + +K3bDevice::Device* K3bAudioCueFileWritingJob::writer() const +{ + return m_audioDoc->burner(); +} + + +QString K3bAudioCueFileWritingJob::jobDescription() const +{ + return i18n("Writing Audio Cue File"); +} + + +QString K3bAudioCueFileWritingJob::jobDetails() const +{ + return m_cueFile.section( '/', -1 ); +} + + +void K3bAudioCueFileWritingJob::start() +{ + // FIXME: here we trust that a job won't be started twice :( + jobStarted(); + m_canceled = false; + m_audioJobRunning = false; + importCueInProject(); +} + + +void K3bAudioCueFileWritingJob::cancel() +{ + m_canceled = true; + + // the AudioJob cancel method is very stupid. It emits the canceled signal even if it was never running :( + if( m_audioJobRunning ) + m_audioJob->cancel(); + m_analyserJob->cancel(); +} + + +void K3bAudioCueFileWritingJob::setCueFile( const QString& s ) +{ + m_cueFile = s; +} + + +void K3bAudioCueFileWritingJob::setOnTheFly( bool b ) +{ + m_audioDoc->setOnTheFly( b ); +} + + +void K3bAudioCueFileWritingJob::setSpeed( int s ) +{ + m_audioDoc->setSpeed( s ); +} + + +void K3bAudioCueFileWritingJob::setBurnDevice( K3bDevice::Device* dev ) +{ + m_audioDoc->setBurner( dev ); +} + + +void K3bAudioCueFileWritingJob::setWritingMode( int mode ) +{ + m_audioDoc->setWritingMode( mode ); +} + + +void K3bAudioCueFileWritingJob::setSimulate( bool b ) +{ + m_audioDoc->setDummy( b ); +} + + +void K3bAudioCueFileWritingJob::setCopies( int c ) +{ + m_audioDoc->setCopies( c ); +} + + +void K3bAudioCueFileWritingJob::setTempDir( const QString& s ) +{ + m_audioDoc->setTempDir( s ); +} + + +void K3bAudioCueFileWritingJob::slotAnalyserThreadFinished( bool ) +{ + if( !m_canceled ) { + if( m_audioDoc->lastTrack()->length() == 0 ) { + emit infoMessage( i18n("Analysing the audio file failed. Corrupt file?"), ERROR ); + jobFinished(false); + } + else { + // FIXME: m_audioJobRunning is never reset + m_audioJobRunning = true; + m_audioJob->start(); // from here on the audio job takes over completely + } + } + else { + emit canceled(); + jobFinished(false); + } +} + + +void K3bAudioCueFileWritingJob::importCueInProject() +{ + // cleanup the project (this wil also delete the decoder) + // we do not use newDocument as that would overwrite the settings already made + while( m_audioDoc->firstTrack() ) + delete m_audioDoc->firstTrack()->take(); + + m_decoder = 0; + + K3bCueFileParser parser( m_cueFile ); + if( parser.isValid() && parser.toc().contentType() == K3bDevice::AUDIO ) { + + kdDebug() << "(K3bAudioCueFileWritingJob::importCueFile) parsed with image: " << parser.imageFilename() << endl; + + // global cd-text + m_audioDoc->setTitle( parser.cdText().title() ); + m_audioDoc->setPerformer( parser.cdText().performer() ); + m_audioDoc->writeCdText( !parser.cdText().title().isEmpty() ); + + m_decoder = K3bAudioDecoderFactory::createDecoder( parser.imageFilename() ); + if( m_decoder ) { + m_decoder->setFilename( parser.imageFilename() ); + + K3bAudioTrack* after = 0; + K3bAudioFile* newFile = 0; + unsigned int i = 0; + for( K3bDevice::Toc::const_iterator it = parser.toc().begin(); + it != parser.toc().end(); ++it ) { + const K3bDevice::Track& track = *it; + + newFile = new K3bAudioFile( m_decoder, m_audioDoc ); + newFile->setStartOffset( track.firstSector() ); + newFile->setEndOffset( track.lastSector()+1 ); + + K3bAudioTrack* newTrack = new K3bAudioTrack( m_audioDoc ); + newTrack->addSource( newFile ); + newTrack->moveAfter( after ); + + // cd-text + newTrack->setTitle( parser.cdText()[i].title() ); + newTrack->setPerformer( parser.cdText()[i].performer() ); + + // add the next track after this one + after = newTrack; + ++i; + } + + // let the last source use the data up to the end of the file + if( newFile ) + newFile->setEndOffset(0); + + // now analyze the source + emit newTask( i18n("Analysing the audio file") ); + emit newSubTask( i18n("Analysing %1").arg( parser.imageFilename() ) ); + + // start the analyser thread + m_analyserThread->setDecoder( m_decoder ); + m_analyserJob->start(); + } + else { + emit infoMessage( i18n("Unable to handle '%1' due to an unsupported format.").arg( m_cueFile ), ERROR ); + jobFinished(false); + } + } + else { + emit infoMessage( i18n("No valid audio cue file: '%1'").arg( m_cueFile ), ERROR ); + jobFinished(false); + } +} + +#include "k3baudiocuefilewritingjob.moc" diff --git a/libk3b/jobs/k3baudiocuefilewritingjob.h b/libk3b/jobs/k3baudiocuefilewritingjob.h new file mode 100644 index 0000000..6e0a3c2 --- /dev/null +++ b/libk3b/jobs/k3baudiocuefilewritingjob.h @@ -0,0 +1,79 @@ +/* + * + * $Id: k3baudiocuefilewritingjob.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2005 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_AUDIO_CUE_FILEWRITING_JOB_H_ +#define _K3B_AUDIO_CUE_FILEWRITING_JOB_H_ + +#include +#include "k3b_export.h" +class K3bAudioDoc; +class K3bAudioJob; +class K3bAudioDecoder; +class K3bThreadJob; +namespace K3bDevice { + class Device; +} + + +class LIBK3B_EXPORT K3bAudioCueFileWritingJob : public K3bBurnJob +{ + Q_OBJECT + + public: + K3bAudioCueFileWritingJob( K3bJobHandler*, QObject* parent = 0, const char* name = 0 ); + ~K3bAudioCueFileWritingJob(); + + K3bDevice::Device* writer() const; + + QString jobDescription() const; + QString jobDetails() const; + + const QString& cueFile() const { return m_cueFile; } + + public slots: + void start(); + void cancel(); + + void setCueFile( const QString& ); + void setSpeed( int s ); + void setBurnDevice( K3bDevice::Device* dev ); + void setWritingMode( int mode ); + void setSimulate( bool b ); + void setCopies( int c ); + void setOnTheFly( bool b ); + void setTempDir( const QString& ); + + private slots: + void slotAnalyserThreadFinished(bool); + + private: + void importCueInProject(); + + K3bDevice::Device* m_device; + + QString m_cueFile; + K3bAudioDoc* m_audioDoc; + K3bAudioJob* m_audioJob; + K3bAudioDecoder* m_decoder; + + bool m_canceled; + bool m_audioJobRunning; + + class AnalyserThread; + AnalyserThread* m_analyserThread; + K3bThreadJob* m_analyserJob; +}; + +#endif diff --git a/libk3b/jobs/k3baudiosessionreadingjob.cpp b/libk3b/jobs/k3baudiosessionreadingjob.cpp new file mode 100644 index 0000000..f4ac550 --- /dev/null +++ b/libk3b/jobs/k3baudiosessionreadingjob.cpp @@ -0,0 +1,278 @@ +/* + * + * $Id: k3baudiosessionreadingjob.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3baudiosessionreadingjob.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + + +class K3bAudioSessionReadingJob::WorkThread : public K3bThread +{ +public: + WorkThread(); + ~WorkThread(); + + void init(); + void run(); + void cancel(); + + bool canceled; + + int fd; + K3bCdparanoiaLib* paranoia; + K3bDevice::Device* device; + K3bDevice::Toc toc; + K3bWaveFileWriter* waveFileWriter; + QStringList filenames; + int paranoiaMode; + int retries; + bool neverSkip; +}; + + +K3bAudioSessionReadingJob::WorkThread::WorkThread() + : K3bThread(), + fd(-1), + paranoia(0), + waveFileWriter(0), + paranoiaMode(0), + retries(50), + neverSkip(false) +{ +} + + +K3bAudioSessionReadingJob::WorkThread::~WorkThread() +{ + delete waveFileWriter; + delete paranoia; +} + + +void K3bAudioSessionReadingJob::WorkThread::init() +{ + canceled = false; +} + + +void K3bAudioSessionReadingJob::WorkThread::run() +{ + if( !paranoia ) + paranoia = K3bCdparanoiaLib::create(); + + if( !paranoia ) { + emitInfoMessage( i18n("Could not load libcdparanoia."), K3bJob::ERROR ); + emitFinished(false); + return; + } + + if( toc.isEmpty() ) + toc = device->readToc(); + + if( !paranoia->initParanoia( device, toc ) ) { + emitInfoMessage( i18n("Could not open device %1").arg(device->blockDeviceName()), + K3bJob::ERROR ); + emitFinished(false); + return; + } + + if( !paranoia->initReading() ) { + emitInfoMessage( i18n("Error while initializing audio ripping."), K3bJob::ERROR ); + emitFinished(false); + return; + } + + device->block( true ); + + // init settings + paranoia->setMaxRetries( retries ); + paranoia->setParanoiaMode( paranoiaMode ); + paranoia->setNeverSkip( neverSkip ); + + bool writeError = false; + unsigned int trackNum = 1; + unsigned int currentTrack = 0; + unsigned long trackRead = 0; + unsigned long totalRead = 0; + unsigned int lastTrackPercent = 0; + unsigned int lastTotalPercent = 0; + bool newTrack = true; + int status = 0; + char* buffer = 0; + while( !canceled && (buffer = paranoia->read( &status, &trackNum, fd == -1 /*when writing to a wav be want little endian */ )) ) { + + if( currentTrack != trackNum ) { + emitNextTrack( trackNum, paranoia->toc().count() ); + trackRead = 0; + lastTrackPercent = 0; + + currentTrack = trackNum; + newTrack = true; + } + + if( fd > 0 ) { + if( ::write( fd, buffer, CD_FRAMESIZE_RAW ) != CD_FRAMESIZE_RAW ) { + kdDebug() << "(K3bAudioSessionCopyJob::WorkThread) error while writing to fd " << fd << endl; + writeError = true; + break; + } + } + else { + if( newTrack ) { + newTrack = false; + + if( !waveFileWriter ) + waveFileWriter = new K3bWaveFileWriter(); + + if( filenames.count() < currentTrack ) { + kdDebug() << "(K3bAudioSessionCopyJob) not enough image filenames given: " << currentTrack << endl; + writeError = true; + break; + } + + if( !waveFileWriter->open( filenames[currentTrack-1] ) ) { + emitInfoMessage( i18n("Unable to open '%1' for writing.").arg(filenames[currentTrack-1]), K3bJob::ERROR ); + writeError = true; + break; + } + } + + waveFileWriter->write( buffer, + CD_FRAMESIZE_RAW, + K3bWaveFileWriter::LittleEndian ); + } + + trackRead++; + totalRead++; + + unsigned int trackPercent = 100 * trackRead / toc[currentTrack-1].length().lba(); + if( trackPercent > lastTrackPercent ) { + lastTrackPercent = trackPercent; + emitSubPercent( lastTrackPercent ); + } + unsigned int totalPercent = 100 * totalRead / paranoia->rippedDataLength(); + if( totalPercent > lastTotalPercent ) { + lastTotalPercent = totalPercent; + emitPercent( lastTotalPercent ); + } + } + + if( waveFileWriter ) + waveFileWriter->close(); + + paranoia->close(); + + device->block( false ); + + if( status != K3bCdparanoiaLib::S_OK ) { + emitInfoMessage( i18n("Unrecoverable error while ripping track %1.").arg(trackNum), K3bJob::ERROR ); + emitFinished(false); + return; + } + + emitFinished( !writeError & !canceled ); +} + + +void K3bAudioSessionReadingJob::WorkThread::cancel() +{ + canceled = true; + // FIXME: add backup killing like in the audio ripping and make sure to close paranoia +} + + + + +K3bAudioSessionReadingJob::K3bAudioSessionReadingJob( K3bJobHandler* jh, QObject* parent, const char* name ) + : K3bThreadJob( jh, parent, name ) +{ + m_thread = new WorkThread(); + setThread( m_thread ); +} + + +K3bAudioSessionReadingJob::~K3bAudioSessionReadingJob() +{ + delete m_thread; +} + + +void K3bAudioSessionReadingJob::setDevice( K3bDevice::Device* dev ) +{ + m_thread->device = dev; + m_thread->toc = K3bDevice::Toc(); +} + + +void K3bAudioSessionReadingJob::setToc( const K3bDevice::Toc& toc ) +{ + m_thread->toc = toc; +} + + +void K3bAudioSessionReadingJob::writeToFd( int fd ) +{ + m_thread->fd = fd; +} + +void K3bAudioSessionReadingJob::setImageNames( const QStringList& l ) +{ + m_thread->filenames = l; + m_thread->fd = -1; +} + + +void K3bAudioSessionReadingJob::setParanoiaMode( int m ) +{ + m_thread->paranoiaMode = m; +} + + +void K3bAudioSessionReadingJob::setReadRetries( int r ) +{ + m_thread->retries = r; +} + +void K3bAudioSessionReadingJob::setNeverSkip( bool b ) +{ + m_thread->neverSkip = b; +} + + +void K3bAudioSessionReadingJob::start() +{ + k3bcore->blockDevice( m_thread->device ); + K3bThreadJob::start(); +} + + +void K3bAudioSessionReadingJob::cleanupJob( bool success ) +{ + Q_UNUSED( success ); + k3bcore->unblockDevice( m_thread->device ); +} + +#include "k3baudiosessionreadingjob.moc" diff --git a/libk3b/jobs/k3baudiosessionreadingjob.h b/libk3b/jobs/k3baudiosessionreadingjob.h new file mode 100644 index 0000000..21f3d50 --- /dev/null +++ b/libk3b/jobs/k3baudiosessionreadingjob.h @@ -0,0 +1,75 @@ +/* + * + * $Id: k3baudiosessionreadingjob.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_AUDIOSESSION_READING_JOB_H_ +#define _K3B_AUDIOSESSION_READING_JOB_H_ + +#include + +#include + + +namespace K3bDevice { + class Device; + class Toc; +} + + +class K3bAudioSessionReadingJob : public K3bThreadJob +{ + Q_OBJECT + + public: + K3bAudioSessionReadingJob( K3bJobHandler*, QObject* parent = 0, const char* name = 0 ); + ~K3bAudioSessionReadingJob(); + + /** + * For now this simply reads all the audio tracks at the beginning + * since we only support CD-Extra mixed mode cds. + */ + void setDevice( K3bDevice::Device* ); + + /** + * Use for faster initialization + */ + void setToc( const K3bDevice::Toc& toc ); + + /** + * the data gets written directly into fd instead of imagefiles. + * To disable just set fd to -1 (the default) + */ + void writeToFd( int fd ); + + /** + * Used if fd == -1 + */ + void setImageNames( const QStringList& l ); + + void setParanoiaMode( int m ); + void setReadRetries( int ); + void setNeverSkip( bool b ); + + public slots: + void start(); + + protected: + void cleanupJob( bool success ); + + private: + class WorkThread; + WorkThread* m_thread; +}; + +#endif diff --git a/libk3b/jobs/k3bbinimagewritingjob.cpp b/libk3b/jobs/k3bbinimagewritingjob.cpp new file mode 100644 index 0000000..de76e3f --- /dev/null +++ b/libk3b/jobs/k3bbinimagewritingjob.cpp @@ -0,0 +1,234 @@ +/* + * + * $Id: k3bbinimagewritingjob.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Klaus-Dieter Krannich + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bbinimagewritingjob.h" +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + + + +K3bBinImageWritingJob::K3bBinImageWritingJob( K3bJobHandler* hdl, QObject* parent ) + : K3bBurnJob( hdl, parent ), + m_device(0), + m_simulate(false), + m_force(false), + m_noFix(false), + m_tocFile(0), + m_speed(2), + m_copies(1), + m_writer(0) +{ +} + +K3bBinImageWritingJob::~K3bBinImageWritingJob() +{ +} + +void K3bBinImageWritingJob::start() +{ + m_canceled = false; + + if( m_copies < 1 ) + m_copies = 1; + m_finishedCopies = 0; + + jobStarted(); + emit newTask( i18n("Write Binary Image") ); + + if( prepareWriter() ) + writerStart(); + else + cancel(); + +} + +void K3bBinImageWritingJob::cancel() +{ + m_canceled = true; + m_writer->cancel(); + emit canceled(); + jobFinished( false ); +} + +bool K3bBinImageWritingJob::prepareWriter() +{ + if( m_writer ) + delete m_writer; + + int usedWritingApp = writingApp(); + const K3bExternalBin* cdrecordBin = k3bcore->externalBinManager()->binObject("cdrecord"); + if( usedWritingApp == K3b::CDRECORD || + ( usedWritingApp == K3b::DEFAULT && cdrecordBin && cdrecordBin->hasFeature("cuefile") && m_device->dao() ) ) { + usedWritingApp = K3b::CDRECORD; + + // IMPROVEME: check if it's a cdrdao toc-file + if( m_tocFile.right(4) == ".toc" ) { + kdDebug() << "(K3bBinImageWritingJob) imagefile has ending toc." << endl; + usedWritingApp = K3b::CDRDAO; + } + else { + // TODO: put this into K3bCueFileParser + // TODO: check K3bCueFileParser::imageFilenameInCue() + // let's see if cdrecord can handle the cue file + QFile f( m_tocFile ); + if( f.open( IO_ReadOnly ) ) { + QTextStream fStr( &f ); + if( fStr.read().contains( "MODE1/2352" ) ) { + kdDebug() << "(K3bBinImageWritingJob) cuefile contains MODE1/2352 track. using cdrdao." << endl; + usedWritingApp = K3b::CDRDAO; + } + f.close(); + } + else + kdDebug() << "(K3bBinImageWritingJob) could not open file " << m_tocFile << endl; + } + } + else + usedWritingApp = K3b::CDRDAO; + + if( usedWritingApp == K3b::CDRECORD ) { + // create cdrecord job + K3bCdrecordWriter* writer = new K3bCdrecordWriter( m_device, this ); + + writer->setDao( true ); + writer->setSimulate( m_simulate ); + writer->setBurnSpeed( m_speed ); + writer->setCueFile ( m_tocFile ); + + if( m_noFix ) { + writer->addArgument("-multi"); + } + + if( m_force ) { + writer->addArgument("-force"); + } + + m_writer = writer; + } + else { + // create cdrdao job + K3bCdrdaoWriter* writer = new K3bCdrdaoWriter( m_device, this ); + writer->setCommand( K3bCdrdaoWriter::WRITE ); + writer->setSimulate( m_simulate ); + writer->setBurnSpeed( m_speed ); + writer->setForce( m_force ); + + // multisession + writer->setMulti( m_noFix ); + + writer->setTocFile( m_tocFile ); + + m_writer = writer; + } + + connect( m_writer, SIGNAL(infoMessage(const QString&, int)), this, SIGNAL(infoMessage(const QString&, int)) ); + connect( m_writer, SIGNAL(percent(int)), this, SLOT(copyPercent(int)) ); + connect( m_writer, SIGNAL(subPercent(int)), this, SLOT(copySubPercent(int)) ); + connect( m_writer, SIGNAL(processedSize(int, int)), this, SIGNAL(processedSize(int, int)) ); + connect( m_writer, SIGNAL(buffer(int)), this, SIGNAL(bufferStatus(int)) ); + connect( m_writer, SIGNAL(deviceBuffer(int)), this, SIGNAL(deviceBuffer(int)) ); + connect( m_writer, SIGNAL(writeSpeed(int, int)), this, SIGNAL(writeSpeed(int, int)) ); + connect( m_writer, SIGNAL(finished(bool)), this, SLOT(writerFinished(bool)) ); + connect( m_writer, SIGNAL(newTask(const QString&)), this, SIGNAL(newTask(const QString&)) ); + connect( m_writer, SIGNAL(newSubTask(const QString&)), this, SIGNAL(newSubTask(const QString&)) ); + connect( m_writer, SIGNAL(nextTrack(int, int)), this, SLOT(slotNextTrack(int, int)) ); + connect( m_writer, SIGNAL(debuggingOutput(const QString&, const QString&)), this, SIGNAL(debuggingOutput(const QString&, const QString&)) ); + + return true; +} + + +void K3bBinImageWritingJob::writerStart() +{ + + if( waitForMedia( m_device ) < 0 ) { + cancel(); + } + // just to be sure we did not get canceled during the async discWaiting + else if( !m_canceled ) { + emit burning(true); + m_writer->start(); + } +} + +void K3bBinImageWritingJob::copyPercent(int p) +{ + emit percent( (100*m_finishedCopies + p)/m_copies ); +} + +void K3bBinImageWritingJob::copySubPercent(int p) +{ + emit subPercent(p); +} + +void K3bBinImageWritingJob::writerFinished(bool ok) +{ + if( m_canceled ) + return; + + if (ok) { + m_finishedCopies++; + if ( m_finishedCopies == m_copies ) { + emit infoMessage( i18n("%n copy successfully created", "%n copies successfully created", m_copies),K3bJob::INFO ); + jobFinished( true ); + } + else { + writerStart(); + } + } + else { + jobFinished(false); + } +} + + +void K3bBinImageWritingJob::slotNextTrack( int t, int tt ) +{ + emit newSubTask( i18n("Writing track %1 of %2").arg(t).arg(tt) ); +} + + +QString K3bBinImageWritingJob::jobDescription() const +{ + return ( i18n("Writing cue/bin Image") + + ( m_copies > 1 + ? i18n(" - %n Copy", " - %n Copies", m_copies) + : QString::null ) ); +} + + +QString K3bBinImageWritingJob::jobDetails() const +{ + return m_tocFile.section("/", -1); +} + + +void K3bBinImageWritingJob::setTocFile(const QString& s) +{ + m_tocFile = s; +} + +#include "k3bbinimagewritingjob.moc" diff --git a/libk3b/jobs/k3bbinimagewritingjob.h b/libk3b/jobs/k3bbinimagewritingjob.h new file mode 100644 index 0000000..3666793 --- /dev/null +++ b/libk3b/jobs/k3bbinimagewritingjob.h @@ -0,0 +1,79 @@ +/* + * + * $Id$ + * Copyright (C) 2003 Klaus-Dieter Krannich + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BBINIMAGEWRITINGJOB_H +#define K3BBINIMAGEWRITINGJOB_H + +#include +#include "k3b_export.h" +class K3bAbstractWriter; +namespace K3bDevice { + class Device; +} + +/** + *@author Klaus-Dieter Krannich + */ +class LIBK3B_EXPORT K3bBinImageWritingJob : public K3bBurnJob +{ + Q_OBJECT + + public: + K3bBinImageWritingJob( K3bJobHandler*, QObject* parent = 0 ); + ~K3bBinImageWritingJob(); + + K3bDevice::Device* writer() const { return m_device; }; + + QString jobDescription() const; + QString jobDetails() const; + + public slots: + void start(); + void cancel(); + + void setWriter( K3bDevice::Device* dev ) { m_device = dev; } + void setSimulate( bool b ) { m_simulate = b; } + void setForce(bool b) { m_force = b; } + void setMulti( bool b ) { m_noFix = b; } + void setTocFile( const QString& s); + void setCopies(int c) { m_copies = c; } + void setSpeed( int s ) { m_speed = s; } + + private slots: + void writerFinished(bool); + void copyPercent(int p); + void copySubPercent(int p); + void slotNextTrack( int, int ); + + private: + void writerStart(); + bool prepareWriter(); + + K3bDevice::Device* m_device; + bool m_simulate; + bool m_force; + bool m_noFix; + QString m_tocFile; + int m_speed; + int m_copies; + int m_finishedCopies; + + bool m_canceled; + + K3bAbstractWriter* m_writer; +}; + +#endif diff --git a/libk3b/jobs/k3bblankingjob.cpp b/libk3b/jobs/k3bblankingjob.cpp new file mode 100644 index 0000000..c11f4b4 --- /dev/null +++ b/libk3b/jobs/k3bblankingjob.cpp @@ -0,0 +1,176 @@ +/* + * + * $Id: k3bblankingjob.cpp 630823 2007-02-06 14:07:10Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bblankingjob.h" +#include "k3bcdrecordwriter.h" +#include "k3bcdrdaowriter.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + + + +K3bBlankingJob::K3bBlankingJob( K3bJobHandler* hdl, QObject* parent ) + : K3bBurnJob( hdl, parent ), + m_writerJob(0), + m_force(true), + m_device(0), + m_speed(0), + m_mode(Fast), + m_writingApp(K3b::DEFAULT), + m_canceled(false), + m_forceNoEject(false) +{ +} + + +K3bBlankingJob::~K3bBlankingJob() +{ + delete m_writerJob; +} + + +K3bDevice::Device* K3bBlankingJob::writer() const +{ + return m_device; +} + + +void K3bBlankingJob::setDevice( K3bDevice::Device* dev ) +{ + m_device = dev; +} + + +void K3bBlankingJob::start() +{ + if( m_device == 0 ) + return; + + jobStarted(); + + slotStartErasing(); +} + +void K3bBlankingJob::slotStartErasing() +{ + m_canceled = false; + + if( m_writerJob ) + delete m_writerJob; + + if( m_writingApp == K3b::CDRDAO ) { + K3bCdrdaoWriter* writer = new K3bCdrdaoWriter( m_device, this ); + m_writerJob = writer; + + writer->setCommand(K3bCdrdaoWriter::BLANK); + writer->setBlankMode( m_mode == Fast ? K3bCdrdaoWriter::MINIMAL : K3bCdrdaoWriter::FULL ); + writer->setForce(m_force); + writer->setBurnSpeed(m_speed); + writer->setForceNoEject( m_forceNoEject ); + } + else { + K3bCdrecordWriter* writer = new K3bCdrecordWriter( m_device, this ); + m_writerJob = writer; + + QString mode; + switch( m_mode ) { + case Fast: + mode = "fast"; + break; + case Complete: + mode = "all"; + break; + case Track: + mode = "track"; + break; + case Unclose: + mode = "unclose"; + break; + case Session: + mode = "session"; + break; + } + + writer->addArgument("blank="+ mode); + + if (m_force) + writer->addArgument("-force"); + writer->setBurnSpeed(m_speed); + writer->setForceNoEject( m_forceNoEject ); + } + + connect(m_writerJob, SIGNAL(finished(bool)), this, SLOT(slotFinished(bool))); + connect(m_writerJob, SIGNAL(infoMessage( const QString&, int)), + this,SIGNAL(infoMessage( const QString&, int))); + connect( m_writerJob, SIGNAL(debuggingOutput(const QString&, const QString&)), + this, SIGNAL(debuggingOutput(const QString&, const QString&)) ); + + if( waitForMedia( m_device, + K3bDevice::STATE_COMPLETE|K3bDevice::STATE_INCOMPLETE, + K3bDevice::MEDIA_CD_RW, + i18n("Please insert a rewritable CD medium into drive

%1 %2 (%3).") + .arg(m_device->vendor()) + .arg(m_device->description()) + .arg(m_device->devicename()) ) < 0 ) { + emit canceled(); + jobFinished(false); + return; + } + + m_writerJob->start(); +} + + +void K3bBlankingJob::cancel() +{ + m_canceled = true; + + if( m_writerJob ) + m_writerJob->cancel(); +} + + +void K3bBlankingJob::slotFinished(bool success) +{ + if( success ) { + emit infoMessage( i18n("Process completed successfully"), K3bJob::SUCCESS ); + jobFinished( true ); + } + else { + if( m_canceled ) { + emit infoMessage( i18n("Canceled."), ERROR ); + emit canceled(); + } + else { + emit infoMessage( i18n("Blanking error "), K3bJob::ERROR ); + emit infoMessage( i18n("Sorry, no error handling yet."), K3bJob::ERROR ); + } + jobFinished( false ); + } +} + + + +#include "k3bblankingjob.moc" diff --git a/libk3b/jobs/k3bblankingjob.h b/libk3b/jobs/k3bblankingjob.h new file mode 100644 index 0000000..8cfe0a1 --- /dev/null +++ b/libk3b/jobs/k3bblankingjob.h @@ -0,0 +1,71 @@ +/* + * + * $Id: k3bblankingjob.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef K3B_BLANKING_JOB_H +#define K3B_BLANKING_JOB_H + +#include +#include "k3b_export.h" +class KProcess; +class QString; +class K3bDevice::Device; +class K3bAbstractWriter; + + +class LIBK3B_EXPORT K3bBlankingJob : public K3bBurnJob +{ + Q_OBJECT + + public: + K3bBlankingJob( K3bJobHandler*, QObject* parent = 0 ); + ~K3bBlankingJob(); + + K3bDevice::Device* writer() const; + + bool hasBeenCanceled() const { return m_canceled; } + + enum blank_mode { Fast, Complete, Track, Unclose, Session }; + + public slots: + void start(); + void cancel(); + void setForce( bool f ) { m_force = f; } + void setDevice( K3bDevice::Device* d ); + void setSpeed( int s ) { m_speed = s; } + void setMode( int m ) { m_mode = m; } + void setWritingApp (int app) { m_writingApp = app; } + + /** + * If set true the job ignores the global K3b setting + * and does not eject the CD-RW after finishing + */ + void setForceNoEject( bool b ) { m_forceNoEject = b; } + + private slots: + void slotFinished(bool); + void slotStartErasing(); + + private: + K3bAbstractWriter* m_writerJob; + bool m_force; + K3bDevice::Device* m_device; + int m_speed; + int m_mode; + int m_writingApp; + bool m_canceled; + bool m_forceNoEject; +}; + +#endif diff --git a/libk3b/jobs/k3bcdcopyjob.cpp b/libk3b/jobs/k3bcdcopyjob.cpp new file mode 100644 index 0000000..ff8f35d --- /dev/null +++ b/libk3b/jobs/k3bcdcopyjob.cpp @@ -0,0 +1,1213 @@ +/* + * + * $Id.cpp,v 1.82 2005/02/04 09:27:19 trueg Exp $ + * Copyright (C) 2003-2007 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bcdcopyjob.h" +#include "k3baudiosessionreadingjob.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +class K3bCdCopyJob::Private +{ +public: + Private() + : canceled(false), + running(false), + readcdReader(0), + dataTrackReader(0), + audioSessionReader(0), + cdrecordWriter(0), + infFileWriter(0), + cddb(0) { + } + + bool canceled; + bool error; + bool readingSuccessful; + bool running; + + unsigned int numSessions; + bool doNotCloseLastSession; + + unsigned int doneCopies; + unsigned int currentReadSession; + unsigned int currentWrittenSession; + + K3bDevice::Toc toc; + QByteArray cdTextRaw; + + K3bReadcdReader* readcdReader; + K3bDataTrackReader* dataTrackReader; + K3bAudioSessionReadingJob* audioSessionReader; + K3bCdrecordWriter* cdrecordWriter; + K3bInfFileWriter* infFileWriter; + + bool audioReaderRunning; + bool dataReaderRunning; + bool writerRunning; + + // image filenames, one for every track + QStringList imageNames; + + // inf-filenames for writing audio tracks + QStringList infNames; + + // indicates if we created a dir or not + bool deleteTempDir; + + K3bCddb* cddb; + K3bCddbResultEntry cddbInfo; + + bool haveCddb; + bool haveCdText; + + QValueVector dataSessionProbablyTAORecorded; + + // used to determine progress + QValueVector sessionSizes; + long overallSize; +}; + + +K3bCdCopyJob::K3bCdCopyJob( K3bJobHandler* hdl, QObject* parent ) + : K3bBurnJob( hdl, parent ), + m_simulate(false), + m_copies(1), + m_onlyCreateImages(false), + m_onTheFly(true), + m_ignoreDataReadErrors(false), + m_ignoreAudioReadErrors(true), + m_noCorrection(false), + m_dataReadRetries(128), + m_audioReadRetries(5), + m_preferCdText(false), + m_copyCdText(true), + m_writingMode( K3b::WRITING_MODE_AUTO ) +{ + d = new Private(); +} + + +K3bCdCopyJob::~K3bCdCopyJob() +{ + delete d->infFileWriter; + delete d; +} + + +void K3bCdCopyJob::start() +{ + d->running = true; + d->canceled = false; + d->error = false; + d->readingSuccessful = false; + d->audioReaderRunning = d->dataReaderRunning = d->writerRunning = false; + d->sessionSizes.clear(); + d->dataSessionProbablyTAORecorded.clear(); + d->deleteTempDir = false; + d->haveCdText = false; + d->haveCddb = false; + + jobStarted(); + + emit newTask( i18n("Checking Source Medium") ); + + emit burning(false); + emit newSubTask( i18n("Waiting for source medium") ); + + // wait for a source disk + if( waitForMedia( m_readerDevice, + K3bDevice::STATE_COMPLETE|K3bDevice::STATE_INCOMPLETE, + K3bDevice::MEDIA_WRITABLE_CD|K3bDevice::MEDIA_CD_ROM ) < 0 ) { + finishJob( true, false ); + return; + } + + emit newSubTask( i18n("Checking source medium") ); + + // FIXME: read ISRCs and MCN + + connect( K3bDevice::diskInfo( m_readerDevice ), SIGNAL(finished(K3bDevice::DeviceHandler*)), + this, SLOT(slotDiskInfoReady(K3bDevice::DeviceHandler*)) ); +} + + +void K3bCdCopyJob::slotDiskInfoReady( K3bDevice::DeviceHandler* dh ) +{ + if( dh->success() ) { + d->toc = dh->toc(); + + // + // for now we copy audio, pure data (aka 1 data track), cd-extra (2 session, audio and data), + // and data multisession which one track per session. + // Everything else will be rejected + // + bool canCopy = true; + bool audio = false; + d->numSessions = dh->diskInfo().numSessions(); + d->doNotCloseLastSession = (dh->diskInfo().diskState() == K3bDevice::STATE_INCOMPLETE); + switch( dh->toc().contentType() ) { + case K3bDevice::DATA: + // check if every track is in it's own session + // only then we copy the cd + if( (int)dh->toc().count() != dh->diskInfo().numSessions() ) { + emit infoMessage( i18n("K3b does not copy CDs containing multiple data tracks."), ERROR ); + canCopy = false; + } + else if( dh->diskInfo().numSessions() > 1 ) + emit infoMessage( i18n("Copying Multisession Data CD."), INFO ); + else + emit infoMessage( i18n("Copying Data CD."), INFO ); + break; + + case K3bDevice::MIXED: + audio = true; + if( dh->diskInfo().numSessions() != 2 || d->toc[0].type() != K3bDevice::Track::AUDIO ) { + emit infoMessage( i18n("K3b can only copy CD-Extra mixed mode CDs."), ERROR ); + canCopy = false; + } + else + emit infoMessage( i18n("Copying Enhanced Audio CD (CD-Extra)."), INFO ); + break; + + case K3bDevice::AUDIO: + audio = true; + emit infoMessage( i18n("Copying Audio CD."), INFO ); + break; + + case K3bDevice::NONE: + default: + emit infoMessage( i18n("The source disk is empty."), ERROR ); + canCopy = false; + break; + } + + // + // A data track recorded in TAO mode has two run-out blocks which cannot be read and contain + // zero data anyway. The problem is that I do not know of a valid method to determine if a track + // was written in TAO (the control nibble does definitely not work, I never saw one which did not + // equal 4). + // So the solution for now is to simply try to read the last sector of a data track. If this is not + // possible we assume it was written in TAO mode and reduce the length by 2 sectors + // + unsigned char buffer[2048]; + int i = 1; + for( K3bDevice::Toc::iterator it = d->toc.begin(); it != d->toc.end(); ++it ) { + if( (*it).type() == K3bDevice::Track::DATA ) { + // we try twice just to be sure + if( m_readerDevice->read10( buffer, 2048, (*it).lastSector().lba(), 1 ) || + m_readerDevice->read10( buffer, 2048, (*it).lastSector().lba(), 1 ) ) { + d->dataSessionProbablyTAORecorded.append(false); + kdDebug() << "(K3bCdCopyJob) track " << i << " probably DAO recorded." << endl; + } + else { + d->dataSessionProbablyTAORecorded.append(true); + kdDebug() << "(K3bCdCopyJob) track " << i << " probably TAO recorded." << endl; + } + } + + ++i; + } + + + // + // To copy mode2 data tracks we need cdrecord >= 2.01a12 which introduced the -xa1 and -xamix options + // + if( k3bcore->externalBinManager()->binObject("cdrecord") && + !k3bcore->externalBinManager()->binObject("cdrecord")->hasFeature( "xamix" ) ) { + for( K3bDevice::Toc::const_iterator it = d->toc.begin(); it != d->toc.end(); ++it ) { + if( (*it).type() == K3bDevice::Track::DATA && + ( (*it).mode() == K3bDevice::Track::XA_FORM1 || + (*it).mode() == K3bDevice::Track::XA_FORM2 ) ) { + emit infoMessage( i18n("K3b needs cdrecord 2.01a12 or newer to copy Mode2 data tracks."), ERROR ); + finishJob( true, false ); + return; + } + } + } + + + // + // It is not possible to create multisession cds in raw writing mode + // + if( d->numSessions > 1 && m_writingMode == K3b::RAW ) { + if( !questionYesNo( i18n("You will only be able to copy the first session in raw writing mode. " + "Continue anyway?"), + i18n("Multisession CD") ) ) { + finishJob( true, false ); + return; + } + else { + emit infoMessage( i18n("Only copying first session."), WARNING ); + // TODO: remove the second session from the progress stuff + } + } + + + // + // We already create the temp filenames here since we need them to check the free space + // + if( !m_onTheFly || m_onlyCreateImages ) { + if( !prepareImageFiles() ) { + finishJob( false, true ); + return; + } + + // + // check free temp space + // + KIO::filesize_t imageSpaceNeeded = 0; + for( K3bDevice::Toc::const_iterator it = d->toc.begin(); it != d->toc.end(); ++it ) { + if( (*it).type() == K3bDevice::Track::AUDIO ) + imageSpaceNeeded += (*it).length().audioBytes() + 44; + else + imageSpaceNeeded += (*it).length().mode1Bytes(); + } + + unsigned long avail, size; + QString pathToTest = m_tempPath.left( m_tempPath.findRev( '/' ) ); + if( !K3b::kbFreeOnFs( pathToTest, size, avail ) ) { + emit infoMessage( i18n("Unable to determine free space in temporary directory '%1'.").arg(pathToTest), ERROR ); + d->error = true; + canCopy = false; + } + else { + if( avail < imageSpaceNeeded/1024 ) { + emit infoMessage( i18n("Not enough space left in temporary directory."), ERROR ); + d->error = true; + canCopy = false; + } + } + } + + if( canCopy ) { + if( K3b::isMounted( m_readerDevice ) ) { + emit infoMessage( i18n("Unmounting source medium"), INFO ); + K3b::unmount( m_readerDevice ); + } + + d->overallSize = 0; + + // now create some progress helper values + for( K3bDevice::Toc::const_iterator it = d->toc.begin(); it != d->toc.end(); ++it ) { + d->overallSize += (*it).length().lba(); + if( d->sessionSizes.isEmpty() || (*it).type() == K3bDevice::Track::DATA ) + d->sessionSizes.append( (*it).length().lba() ); + else + d->sessionSizes[0] += (*it).length().lba(); + } + + if( audio && !m_onlyCreateImages ) { + if( m_copyCdText ) + searchCdText(); + else + queryCddb(); + } + else + startCopy(); + } + else { + finishJob( false, true ); + } + } + else { + emit infoMessage( i18n("Unable to read TOC"), ERROR ); + finishJob( false, true ); + } +} + + +void K3bCdCopyJob::searchCdText() +{ + emit newSubTask( i18n("Searching CD-TEXT") ); + + connect( K3bDevice::sendCommand( K3bDevice::DeviceHandler::CD_TEXT_RAW, m_readerDevice ), + SIGNAL(finished(K3bDevice::DeviceHandler*)), + this, + SLOT(slotCdTextReady(K3bDevice::DeviceHandler*)) ); +} + + +void K3bCdCopyJob::slotCdTextReady( K3bDevice::DeviceHandler* dh ) +{ + if( dh->success() ) { + if( K3bDevice::CdText::checkCrc( dh->cdTextRaw() ) ) { + K3bDevice::CdText cdt( dh->cdTextRaw() ); + emit infoMessage( i18n("Found CD-TEXT (%1 - %2).").arg(cdt.performer()).arg(cdt.title()), SUCCESS ); + d->haveCdText = true; + d->cdTextRaw = dh->cdTextRaw(); + } + else { + emit infoMessage( i18n("Found corrupted CD-TEXT. Ignoring it."), WARNING ); + d->haveCdText = false; + } + + if( d->haveCdText && m_preferCdText ) + startCopy(); + else + queryCddb(); + } + else { + emit infoMessage( i18n("No CD-TEXT found."), INFO ); + + d->haveCdText = false; + + queryCddb(); + } +} + + +void K3bCdCopyJob::queryCddb() +{ + emit newSubTask( i18n("Querying Cddb") ); + + d->haveCddb = false; + + if( !d->cddb ) { + d->cddb = new K3bCddb( this ); + connect( d->cddb, SIGNAL(queryFinished(int)), + this, SLOT(slotCddbQueryFinished(int)) ); + } + + KConfig* c = k3bcore->config(); + c->setGroup("Cddb"); + + d->cddb->readConfig( c ); + d->cddb->query( d->toc ); +} + + +void K3bCdCopyJob::slotCddbQueryFinished( int error ) +{ + if( error == K3bCddbQuery::SUCCESS ) { + d->cddbInfo = d->cddb->result(); + d->haveCddb = true; + + emit infoMessage( i18n("Found Cddb entry (%1 - %2).").arg(d->cddbInfo.cdArtist).arg(d->cddbInfo.cdTitle), SUCCESS ); + + // save the entry locally + KConfig* c = k3bcore->config(); + c->setGroup( "Cddb" ); + if( c->readBoolEntry( "save cddb entries locally", true ) ) + d->cddb->saveEntry( d->cddbInfo ); + } + else if( error == K3bCddbQuery::NO_ENTRY_FOUND ) { + emit infoMessage( i18n("No Cddb entry found."), WARNING ); + } + else { + emit infoMessage( i18n("Cddb error (%1).").arg(d->cddb->errorString()), ERROR ); + } + + startCopy(); +} + + +void K3bCdCopyJob::startCopy() +{ + d->currentWrittenSession = d->currentReadSession = 1; + d->doneCopies = 0; + + if( m_onTheFly ) { + emit newSubTask( i18n("Preparing write process...") ); + + if( writeNextSession() ) + readNextSession(); + else { + finishJob( d->canceled, d->error ); + } + } + else + readNextSession(); +} + + +void K3bCdCopyJob::cancel() +{ + d->canceled = true; + + if( d->writerRunning ) { + // + // we will handle cleanup in slotWriterFinished() + // if we are writing onthefly the reader won't be able to write + // anymore and will finish unsuccessfully, too + // + d->cdrecordWriter->cancel(); + } + else if( d->audioReaderRunning ) + d->audioSessionReader->cancel(); + else if( d->dataReaderRunning ) + // d->readcdReader->cancel(); + d->dataTrackReader->cancel(); +} + + +bool K3bCdCopyJob::prepareImageFiles() +{ + kdDebug() << "(K3bCdCopyJob) prepareImageFiles()" << endl; + + d->imageNames.clear(); + d->infNames.clear(); + d->deleteTempDir = false; + + QFileInfo fi( m_tempPath ); + + if( d->toc.count() > 1 || d->toc.contentType() == K3bDevice::AUDIO ) { + // create a directory which contains all the images and inf and stuff + // and save it in some cool structure + + bool tempDirReady = false; + if( !fi.isDir() ) { + if( QFileInfo( m_tempPath.section( '/', 0, -2 ) ).isDir() ) { + if( !QFile::exists( m_tempPath ) ) { + QDir dir( m_tempPath.section( '/', 0, -2 ) ); + dir.mkdir( m_tempPath.section( '/', -1 ) ); + tempDirReady = true; + } + else + m_tempPath = m_tempPath.section( '/', 0, -2 ); + } + else { + emit infoMessage( i18n("Specified an unusable temporary path. Using default."), WARNING ); + m_tempPath = K3b::defaultTempPath(); + } + } + + // create temp dir + if( !tempDirReady ) { + QDir dir( m_tempPath ); + m_tempPath = K3b::findUniqueFilePrefix( "k3bCdCopy", m_tempPath ); + kdDebug() << "(K3bCdCopyJob) creating temp dir: " << m_tempPath << endl; + if( !dir.mkdir( m_tempPath, true ) ) { + emit infoMessage( i18n("Unable to create temporary directory '%1'.").arg(m_tempPath), ERROR ); + return false; + } + d->deleteTempDir = true; + } + + m_tempPath = K3b::prepareDir( m_tempPath ); + emit infoMessage( i18n("Using temporary directory %1.").arg(m_tempPath), INFO ); + + // create temp filenames + int i = 1; + for( K3bDevice::Toc::const_iterator it = d->toc.begin(); it != d->toc.end(); ++it ) { + if( (*it).type() == K3bDevice::Track::AUDIO ) { + d->imageNames.append( m_tempPath + QString("Track%1.wav").arg(QString::number(i).rightJustify(2, '0')) ); + d->infNames.append( m_tempPath + QString("Track%1.inf").arg(QString::number(i).rightJustify(2, '0')) ); + } + else + d->imageNames.append( m_tempPath + QString("Track%1.iso").arg(QString::number(i).rightJustify(2, '0')) ); + ++i; + } + + kdDebug() << "(K3bCdCopyJob) created image filenames:" << endl; + for( unsigned int i = 0; i < d->imageNames.count(); ++i ) + kdDebug() << "(K3bCdCopyJob) " << d->imageNames[i] << endl; + + return true; + } + else { + // we only need a single image file + if( !fi.isFile() || + questionYesNo( i18n("Do you want to overwrite %1?").arg(m_tempPath), + i18n("File Exists") ) ) { + if( fi.isDir() ) + m_tempPath = K3b::findTempFile( "iso", m_tempPath ); + else if( !QFileInfo( m_tempPath.section( '/', 0, -2 ) ).isDir() ) { + emit infoMessage( i18n("Specified an unusable temporary path. Using default."), WARNING ); + m_tempPath = K3b::findTempFile( "iso" ); + } + // else the user specified a file in an existing dir + + emit infoMessage( i18n("Writing image file to %1.").arg(m_tempPath), INFO ); + } + else + return false; + + d->imageNames.append( m_tempPath ); + + return true; + } +} + + +void K3bCdCopyJob::readNextSession() +{ + if( !m_onTheFly || m_onlyCreateImages ) { + if( d->numSessions > 1 ) + emit newTask( i18n("Reading Session %1").arg(d->currentReadSession) ); + else + emit newTask( i18n("Reading Source Medium") ); + + if( d->currentReadSession == 1 ) + emit newSubTask( i18n("Reading track %1 of %2").arg(1).arg(d->toc.count()) ); + } + + // there is only one situation where we need the audiosessionreader: + // if the first session is an audio session. That means the first track + // is an audio track + if( d->currentReadSession == 1 && d->toc[0].type() == K3bDevice::Track::AUDIO ) { + if( !d->audioSessionReader ) { + d->audioSessionReader = new K3bAudioSessionReadingJob( this, this ); + connect( d->audioSessionReader, SIGNAL(nextTrack(int, int)), + this, SLOT(slotReadingNextTrack(int, int)) ); + connectSubJob( d->audioSessionReader, + SLOT(slotSessionReaderFinished(bool)), + true, + SLOT(slotReaderProgress(int)), + SLOT(slotReaderSubProgress(int)) ); + } + + d->audioSessionReader->setDevice( m_readerDevice ); + d->audioSessionReader->setToc( d->toc ); + d->audioSessionReader->setParanoiaMode( m_paranoiaMode ); + d->audioSessionReader->setReadRetries( m_audioReadRetries ); + d->audioSessionReader->setNeverSkip( !m_ignoreAudioReadErrors ); + if( m_onTheFly ) + d->audioSessionReader->writeToFd( d->cdrecordWriter->fd() ); + else + d->audioSessionReader->setImageNames( d->imageNames ); // the audio tracks are always the first tracks + + d->audioReaderRunning = true; + d->audioSessionReader->start(); + } + else { + if( !d->dataTrackReader ) { + d->dataTrackReader = new K3bDataTrackReader( this, this ); + connect( d->dataTrackReader, SIGNAL(percent(int)), this, SLOT(slotReaderProgress(int)) ); + connect( d->dataTrackReader, SIGNAL(processedSize(int, int)), this, SLOT(slotReaderProcessedSize(int, int)) ); + connect( d->dataTrackReader, SIGNAL(finished(bool)), this, SLOT(slotSessionReaderFinished(bool)) ); + connect( d->dataTrackReader, SIGNAL(infoMessage(const QString&, int)), this, SIGNAL(infoMessage(const QString&, int)) ); + connect( d->dataTrackReader, SIGNAL(debuggingOutput(const QString&, const QString&)), + this, SIGNAL(debuggingOutput(const QString&, const QString&)) ); + } + + d->dataTrackReader->setDevice( m_readerDevice ); + d->dataTrackReader->setIgnoreErrors( m_ignoreDataReadErrors ); + d->dataTrackReader->setNoCorrection( m_noCorrection ); + d->dataTrackReader->setRetries( m_dataReadRetries ); + if( m_onlyCreateImages ) + d->dataTrackReader->setSectorSize( K3bDataTrackReader::MODE1 ); + else + d->dataTrackReader->setSectorSize( K3bDataTrackReader::AUTO ); + + K3bTrack* track = 0; + unsigned int dataTrackIndex = 0; + if( d->toc.contentType() == K3bDevice::MIXED ) { + track = &d->toc[d->toc.count()-1]; + dataTrackIndex = 0; + } + else { + track = &d->toc[d->currentReadSession-1]; // only one track per session + dataTrackIndex = d->currentReadSession-1; + } + + // HACK: if the track is TAO recorded cut the two run-out sectors + if( d->dataSessionProbablyTAORecorded.count() > dataTrackIndex && + d->dataSessionProbablyTAORecorded[dataTrackIndex] ) + d->dataTrackReader->setSectorRange( track->firstSector(), track->lastSector() - 2 ); + else + d->dataTrackReader->setSectorRange( track->firstSector(), track->lastSector() ); + + int trackNum = d->currentReadSession; + if( d->toc.contentType() == K3bDevice::MIXED ) + trackNum = d->toc.count(); + + if( m_onTheFly ) + d->dataTrackReader->writeToFd( d->cdrecordWriter->fd() ); + else + d->dataTrackReader->setImagePath( d->imageNames[trackNum-1] ); + + d->dataReaderRunning = true; + if( !m_onTheFly || m_onlyCreateImages ) + slotReadingNextTrack( 1, 1 ); + + d->dataTrackReader->start(); + } +} + + +bool K3bCdCopyJob::writeNextSession() +{ + // we emit our own task since the cdrecord task is way too simple + if( d->numSessions > 1 ) { + if( m_simulate ) + emit newTask( i18n("Simulating Session %1").arg(d->currentWrittenSession) ); + else if( m_copies > 1 ) + emit newTask( i18n("Writing Copy %1 (Session %2)").arg(d->doneCopies+1).arg(d->currentWrittenSession) ); + else + emit newTask( i18n("Writing Copy (Session %2)").arg(d->currentWrittenSession) ); + } + else { + if( m_simulate ) + emit newTask( i18n("Simulating") ); + else if( m_copies > 1 ) + emit newTask( i18n("Writing Copy %1").arg(d->doneCopies+1) ); + else + emit newTask( i18n("Writing Copy") ); + } + + emit newSubTask( i18n("Waiting for media") ); + + // if session > 1 we wait for an appendable CD + if( waitForMedia( m_writerDevice, + d->currentWrittenSession > 1 && !m_simulate + ? K3bDevice::STATE_INCOMPLETE + : K3bDevice::STATE_EMPTY, + K3bDevice::MEDIA_WRITABLE_CD ) < 0 ) { + + finishJob( true, false ); + return false; + } + + if( !d->cdrecordWriter ) { + d->cdrecordWriter = new K3bCdrecordWriter( m_writerDevice, this, this ); + connect( d->cdrecordWriter, SIGNAL(infoMessage(const QString&, int)), this, SIGNAL(infoMessage(const QString&, int)) ); + connect( d->cdrecordWriter, SIGNAL(percent(int)), this, SLOT(slotWriterProgress(int)) ); + connect( d->cdrecordWriter, SIGNAL(processedSize(int, int)), this, SIGNAL(processedSize(int, int)) ); + connect( d->cdrecordWriter, SIGNAL(subPercent(int)), this, SIGNAL(subPercent(int)) ); + connect( d->cdrecordWriter, SIGNAL(processedSubSize(int, int)), this, SIGNAL(processedSubSize(int, int)) ); + connect( d->cdrecordWriter, SIGNAL(nextTrack(int, int)), this, SLOT(slotWritingNextTrack(int, int)) ); + connect( d->cdrecordWriter, SIGNAL(buffer(int)), this, SIGNAL(bufferStatus(int)) ); + connect( d->cdrecordWriter, SIGNAL(deviceBuffer(int)), this, SIGNAL(deviceBuffer(int)) ); + connect( d->cdrecordWriter, SIGNAL(writeSpeed(int, int)), this, SIGNAL(writeSpeed(int, int)) ); + connect( d->cdrecordWriter, SIGNAL(finished(bool)), this, SLOT(slotWriterFinished(bool)) ); + // connect( d->cdrecordWriter, SIGNAL(newTask(const QString&)), this, SIGNAL(newTask(const QString&)) ); + connect( d->cdrecordWriter, SIGNAL(newSubTask(const QString&)), this, SIGNAL(newSubTask(const QString&)) ); + connect( d->cdrecordWriter, SIGNAL(debuggingOutput(const QString&, const QString&)), + this, SIGNAL(debuggingOutput(const QString&, const QString&)) ); + } + + d->cdrecordWriter->setBurnDevice( m_writerDevice ); + d->cdrecordWriter->clearArguments(); + d->cdrecordWriter->setSimulate( m_simulate ); + d->cdrecordWriter->setBurnSpeed( m_speed ); + + + // create the cdrecord arguments + if( d->currentWrittenSession == 1 && d->toc[0].type() == K3bDevice::Track::AUDIO ) { + // + // Audio session + // + + + if( !d->infFileWriter ) + d->infFileWriter = new K3bInfFileWriter(); + + // + // create the inf files if not already done + // + if( d->infNames.isEmpty() || !QFile::exists( d->infNames[0] ) ) { + + unsigned int trackNumber = 1; + + for( K3bDevice::Toc::const_iterator it = d->toc.begin(); it != d->toc.end(); ++it ) { + const K3bDevice::Track& track = *it; + + if( track.type() == K3bDevice::Track::DATA ) + break; + + d->infFileWriter->setTrack( track ); + d->infFileWriter->setTrackNumber( trackNumber ); + + if( d->haveCddb ) { + d->infFileWriter->setTrackTitle( d->cddbInfo.titles[trackNumber-1] ); + d->infFileWriter->setTrackPerformer( d->cddbInfo.artists[trackNumber-1] ); + d->infFileWriter->setTrackMessage( d->cddbInfo.extInfos[trackNumber-1] ); + + d->infFileWriter->setAlbumTitle( d->cddbInfo.cdTitle ); + d->infFileWriter->setAlbumPerformer( d->cddbInfo.cdArtist ); + } + + if( m_onTheFly ) { + + d->infFileWriter->setBigEndian( true ); + + // we let KTempFile choose a temp file but delete it on our own + // the same way we delete them when writing with images + // It is important that the files have the ending inf because + // cdrecord only checks this + + KTempFile tmp( QString::null, ".inf" ); + d->infNames.append( tmp.name() ); + bool success = d->infFileWriter->save( *tmp.textStream() ); + tmp.close(); + if( !success ) + return false; + } + else { + d->infFileWriter->setBigEndian( false ); + + if( !d->infFileWriter->save( d->infNames[trackNumber-1] ) ) + return false; + } + + ++trackNumber; + } + } + + // + // the inf files are ready and named correctly when writing with images + // + int usedWritingMode = m_writingMode; + if( usedWritingMode == K3b::WRITING_MODE_AUTO ) { + // + // there are a lot of writers out there which produce coasters + // in dao mode if the CD contains pregaps of length 0 (or maybe already != 2 secs?) + // + bool zeroPregap = false; + if( d->numSessions == 1 ) { + for( K3bDevice::Toc::const_iterator it = d->toc.begin(); it != d->toc.end(); ++it ) { + const K3bDevice::Track& track = *it; + if( track.index0() == 0 ) { + ++it; + if( it != d->toc.end() ) + zeroPregap = true; + --it; + } + } + } + + if( zeroPregap && m_writerDevice->supportsRawWriting() ) { + if( d->numSessions == 1 ) + usedWritingMode = K3b::RAW; + else + usedWritingMode = K3b::TAO; + } + else if( m_writerDevice->dao() ) + usedWritingMode = K3b::DAO; + else if( m_writerDevice->supportsRawWriting() ) + usedWritingMode = K3b::RAW; + else + usedWritingMode = K3b::TAO; + } + d->cdrecordWriter->setWritingMode( usedWritingMode ); + + if( d->numSessions > 1 ) + d->cdrecordWriter->addArgument( "-multi" ); + + if( d->haveCddb || d->haveCdText ) { + if( usedWritingMode == K3b::TAO ) { + emit infoMessage( i18n("It is not possible to write CD-Text in TAO mode."), WARNING ); + } + else if( d->haveCdText && ( !d->haveCddb || m_preferCdText ) ) { + // use the raw CDTEXT data + d->cdrecordWriter->setRawCdText( d->cdTextRaw ); + } + else { + // make sure the writer job does not create raw cdtext + d->cdrecordWriter->setRawCdText( QByteArray() ); + // cdrecord will use the cdtext data in the inf files + d->cdrecordWriter->addArgument( "-text" ); + } + } + + d->cdrecordWriter->addArgument( "-useinfo" ); + + // + // add all the audio tracks + // + d->cdrecordWriter->addArgument( "-audio" )->addArgument( "-shorttrack" ); + + for( unsigned int i = 0; i < d->infNames.count(); ++i ) { + if( m_onTheFly ) + d->cdrecordWriter->addArgument( d->infNames[i] ); + else + d->cdrecordWriter->addArgument( d->imageNames[i] ); + } + } + else { + // + // Data Session + // + K3bTrack* track = 0; + unsigned int dataTrackIndex = 0; + if( d->toc.contentType() == K3bDevice::MIXED ) { + track = &d->toc[d->toc.count()-1]; + dataTrackIndex = 0; + } + else { + track = &d->toc[d->currentWrittenSession-1]; + dataTrackIndex = d->currentWrittenSession-1; + } + + bool multi = d->doNotCloseLastSession || (d->numSessions > 1 && d->currentWrittenSession < d->toc.count()); + int usedWritingMode = m_writingMode; + if( usedWritingMode == K3b::WRITING_MODE_AUTO ) { + // at least the NEC3540a does write 2056 byte sectors only in tao mode. Same for LG4040b + // since writing data tracks in TAO mode is no loss let's default to TAO in the case of 2056 byte + // sectors (which is when writing xa form1 sectors here) + if( m_writerDevice->dao() && + d->toc.count() == 1 && + !multi && + track->mode() == K3bDevice::Track::MODE1 ) + usedWritingMode = K3b::DAO; + else + usedWritingMode = K3b::TAO; + } + d->cdrecordWriter->setWritingMode( usedWritingMode ); + + // + // all but the last session of a multisession disk are written in multi mode + // and every data track has it's own session which we forced above + // + if( multi ) + d->cdrecordWriter->addArgument( "-multi" ); + + // just to let the reader init + if( m_onTheFly ) + d->cdrecordWriter->addArgument( "-waiti" ); + + if( track->mode() == K3bDevice::Track::MODE1 ) + d->cdrecordWriter->addArgument( "-data" ); + else if( track->mode() == K3bDevice::Track::XA_FORM1 ) + d->cdrecordWriter->addArgument( "-xa1" ); + else + d->cdrecordWriter->addArgument( "-xamix" ); + + if( m_onTheFly ) { + // HACK: if the track is TAO recorded cut the two run-out sectors + unsigned long trackLen = track->length().lba(); + if( d->dataSessionProbablyTAORecorded.count() > dataTrackIndex && + d->dataSessionProbablyTAORecorded[dataTrackIndex] ) + trackLen -= 2; + + if( track->mode() == K3bDevice::Track::MODE1 ) + trackLen = trackLen * 2048; + else if( track->mode() == K3bDevice::Track::XA_FORM1 ) + trackLen = trackLen * 2056; // see k3bdatatrackreader.h + else + trackLen = trackLen * 2332; // see k3bdatatrackreader.h + d->cdrecordWriter->addArgument( QString("-tsize=%1").arg(trackLen) )->addArgument("-"); + } + else if( d->toc.contentType() == K3bDevice::MIXED ) + d->cdrecordWriter->addArgument( d->imageNames[d->toc.count()-1] ); + else + d->cdrecordWriter->addArgument( d->imageNames[d->currentWrittenSession-1] ); + + // clear cd text from previous sessions + d->cdrecordWriter->setRawCdText( QByteArray() ); + } + + + // + // Finally start the writer + // + emit burning(true); + d->writerRunning = true; + d->cdrecordWriter->start(); + + return true; +} + + +// both the readcdreader and the audiosessionreader are connected to this slot +void K3bCdCopyJob::slotSessionReaderFinished( bool success ) +{ + d->audioReaderRunning = d->dataReaderRunning = false; + + if( success ) { + if( d->numSessions > 1 ) + emit infoMessage( i18n("Successfully read session %1.").arg(d->currentReadSession), SUCCESS ); + else + emit infoMessage( i18n("Successfully read source disk."), SUCCESS ); + + if( !m_onTheFly ) { + if( d->numSessions > d->currentReadSession ) { + d->currentReadSession++; + readNextSession(); + } + else { + d->readingSuccessful = true; + if( !m_onlyCreateImages ) { + if( m_readerDevice == m_writerDevice ) { + // eject the media (we do this blocking to know if it worked + // becasue if it did not it might happen that k3b overwrites a CD-RW + // source) + if( !m_readerDevice->eject() ) { + blockingInformation( i18n("K3b was unable to eject the source disk. Please do so manually.") ); + } + } + + if( !writeNextSession() ) { + // nothing is running here... + finishJob( d->canceled, d->error ); + } + } + else { + finishJob( false, false ); + } + } + } + } + else { + if( !d->canceled ) { + emit infoMessage( i18n("Error while reading session %1.").arg(d->currentReadSession), ERROR ); + if( m_onTheFly ) + d->cdrecordWriter->setSourceUnreadable(true); + } + + finishJob( d->canceled, !d->canceled ); + } +} + + +void K3bCdCopyJob::slotWriterFinished( bool success ) +{ + emit burning(false); + + d->writerRunning = false; + + if( success ) { + // + // if this was the last written session we need to reset d->currentWrittenSession + // and start a new writing if more copies are wanted + // + + if( d->currentWrittenSession < d->numSessions ) { + d->currentWrittenSession++; + d->currentReadSession++; + + // reload the media + emit newSubTask( i18n("Reloading the medium") ); + connect( K3bDevice::reload( m_writerDevice ), SIGNAL(finished(K3bDevice::DeviceHandler*)), + this, SLOT(slotMediaReloadedForNextSession(K3bDevice::DeviceHandler*)) ); + } + else { + d->doneCopies++; + + if( !m_simulate && d->doneCopies < m_copies ) { + // start next copy + K3bDevice::eject( m_writerDevice ); + + d->currentWrittenSession = 1; + d->currentReadSession = 1; + if( writeNextSession() ) { + if( m_onTheFly ) + readNextSession(); + } + else { + // nothing running here... + finishJob( d->canceled, d->error ); + } + } + else { + finishJob( false, false ); + } + } + } + else { + // + // If we are writing on the fly the reader will also stop when it is not able to write anymore + // The error handling will be done only here in that case + // + + // the K3bCdrecordWriter emitted an error message + + finishJob( d->canceled, !d->canceled ); + } +} + + +void K3bCdCopyJob::slotMediaReloadedForNextSession( K3bDevice::DeviceHandler* dh ) +{ + if( !dh->success() ) + blockingInformation( i18n("Please reload the medium and press 'ok'"), + i18n("Unable to close the tray") ); + + if( !writeNextSession() ) { + // nothing is running here... + finishJob( d->canceled, d->error ); + } + else if( m_onTheFly ) + readNextSession(); +} + + +void K3bCdCopyJob::cleanup() +{ + if( m_onTheFly || !m_keepImage || ((d->canceled || d->error) && !d->readingSuccessful) ) { + emit infoMessage( i18n("Removing temporary files."), INFO ); + for( QStringList::iterator it = d->infNames.begin(); it != d->infNames.end(); ++it ) + QFile::remove( *it ); + } + + if( !m_onTheFly && (!m_keepImage || ((d->canceled || d->error) && !d->readingSuccessful)) ) { + emit infoMessage( i18n("Removing image files."), INFO ); + for( QStringList::iterator it = d->imageNames.begin(); it != d->imageNames.end(); ++it ) + QFile::remove( *it ); + + // remove the tempdir created in prepareImageFiles() + if( d->deleteTempDir ) { + KIO::NetAccess::del( KURL::fromPathOrURL(m_tempPath), 0 ); + d->deleteTempDir = false; + } + } +} + + +void K3bCdCopyJob::slotReaderProgress( int p ) +{ + if( !m_onTheFly || m_onlyCreateImages ) { + int bigParts = ( m_onlyCreateImages ? 1 : (m_simulate ? 2 : m_copies + 1 ) ); + double done = (double)p * (double)d->sessionSizes[d->currentReadSession-1] / 100.0; + for( unsigned int i = 0; i < d->currentReadSession-1; ++i ) + done += (double)d->sessionSizes[i]; + emit percent( (int)(100.0*done/(double)d->overallSize/(double)bigParts) ); + + if( d->dataReaderRunning ) + emit subPercent(p); + } +} + + +void K3bCdCopyJob::slotReaderSubProgress( int p ) +{ + // only if reading an audiosession + if( !m_onTheFly || m_onlyCreateImages ) { + emit subPercent( p ); + } +} + + +void K3bCdCopyJob::slotReaderProcessedSize( int p, int pp ) +{ + if( !m_onTheFly ) + emit processedSubSize( p, pp ); +} + + +void K3bCdCopyJob::slotWriterProgress( int p ) +{ + int bigParts = ( m_simulate ? 1 : m_copies ) + ( m_onTheFly ? 0 : 1 ); + long done = ( m_onTheFly ? d->doneCopies : d->doneCopies+1 ) * d->overallSize + + (p * d->sessionSizes[d->currentWrittenSession-1] / 100); + for( unsigned int i = 0; i < d->currentWrittenSession-1; ++i ) + done += d->sessionSizes[i]; + emit percent( 100*done/d->overallSize/bigParts ); +} + + +void K3bCdCopyJob::slotWritingNextTrack( int t, int tt ) +{ + if( d->toc.contentType() == K3bDevice::MIXED ) { + if( d->currentWrittenSession == 1 ) + emit newSubTask( i18n("Writing track %1 of %2").arg(t).arg(d->toc.count()) ); + else + emit newSubTask( i18n("Writing track %1 of %2").arg(d->toc.count()).arg(d->toc.count()) ); + } + else if( d->numSessions > 1 ) + emit newSubTask( i18n("Writing track %1 of %2").arg(d->currentWrittenSession).arg(d->toc.count()) ); + else + emit newSubTask( i18n("Writing track %1 of %2").arg(t).arg(tt) ); +} + + +void K3bCdCopyJob::slotReadingNextTrack( int t, int ) +{ + if( !m_onTheFly || m_onlyCreateImages ) { + int track = t; + if( d->audioReaderRunning ) + track = t; + else if( d->toc.contentType() == K3bDevice::MIXED ) + track = d->toc.count(); + else + track = d->currentReadSession; + + emit newSubTask( i18n("Reading track %1 of %2").arg(track).arg(d->toc.count()) ); + } +} + + +QString K3bCdCopyJob::jobDescription() const +{ + if( m_onlyCreateImages ) { + return i18n("Creating CD Image"); + } + else if( m_simulate ) { + if( m_onTheFly ) + return i18n("Simulating CD Copy On-The-Fly"); + else + return i18n("Simulating CD Copy"); + } + else { + if( m_onTheFly ) + return i18n("Copying CD On-The-Fly"); + else + return i18n("Copying CD"); + } +} + + +QString K3bCdCopyJob::jobDetails() const +{ + return i18n("Creating 1 copy", + "Creating %n copies", + (m_simulate||m_onlyCreateImages) ? 1 : m_copies ); +} + + +void K3bCdCopyJob::finishJob( bool c, bool e ) +{ + if( d->running ) { + if( c ) { + d->canceled = true; + emit canceled(); + } + if( e ) + d->error = true; + + cleanup(); + + d->running = false; + + jobFinished( !(c||e) ); + } +} + +#include "k3bcdcopyjob.moc" diff --git a/libk3b/jobs/k3bcdcopyjob.h b/libk3b/jobs/k3bcdcopyjob.h new file mode 100644 index 0000000..3ab77e8 --- /dev/null +++ b/libk3b/jobs/k3bcdcopyjob.h @@ -0,0 +1,117 @@ +/* + * + * $Id: k3bcdcopyjob.h 690187 2007-07-20 09:18:03Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3BCDCOPYJOB_H_ +#define _K3BCDCOPYJOB_H_ + +#include +#include "k3b_export.h" + +namespace K3bDevice { + class Device; + class DeviceHandler; +} + + +/** + *@author Sebastian Trueg + */ +class LIBK3B_EXPORT K3bCdCopyJob : public K3bBurnJob +{ + Q_OBJECT + + public: + K3bCdCopyJob( K3bJobHandler* hdl, QObject* parent = 0 ); + ~K3bCdCopyJob(); + + K3bDevice::Device* writer() const { return m_onlyCreateImages ? 0 : m_writerDevice; } + K3bDevice::Device* reader() const { return m_readerDevice; } + + QString jobDescription() const; + QString jobDetails() const; + + public slots: + void start(); + void cancel(); + + public: + void setWriterDevice( K3bDevice::Device* dev ) { m_writerDevice = dev; } + void setReaderDevice( K3bDevice::Device* dev ) { m_readerDevice = dev; } + void setWritingMode( int m ) { m_writingMode = m; } + void setSpeed( int s ) { m_speed = s; } + void setOnTheFly( bool b ) { m_onTheFly = b; } + void setKeepImage( bool b ) { m_keepImage = b; } + void setOnlyCreateImage( bool b ) { m_onlyCreateImages = b; } + void setSimulate( bool b ) { m_simulate = b; } + void setTempPath( const QString& path ) { m_tempPath= path; } + void setCopies( unsigned int c ) { m_copies = c; } + void setParanoiaMode( int i ) { m_paranoiaMode = i; } + void setIgnoreDataReadErrors( bool b ) { m_ignoreDataReadErrors = b; } + void setDataReadRetries( int i ) { m_dataReadRetries = i; } + void setIgnoreAudioReadErrors( bool b ) { m_ignoreAudioReadErrors = b; } + void setAudioReadRetries( int i ) { m_audioReadRetries = i; } + void setPreferCdText( bool b ) { m_preferCdText = b; } + void setCopyCdText( bool b ) { m_copyCdText = b; } + void setNoCorrection( bool b ) { m_noCorrection = b; } + + private slots: + void slotDiskInfoReady( K3bDevice::DeviceHandler* ); + void slotCdTextReady( K3bDevice::DeviceHandler* ); + void slotMediaReloadedForNextSession( K3bDevice::DeviceHandler* dh ); + void slotCddbQueryFinished(int); + void slotWritingNextTrack( int t, int tt ); + void slotReadingNextTrack( int t, int tt ); + void slotSessionReaderFinished( bool success ); + void slotWriterFinished( bool success ); + void slotReaderProgress( int p ); + void slotReaderSubProgress( int p ); + void slotWriterProgress( int p ); + void slotReaderProcessedSize( int p, int pp ); + + private: + void startCopy(); + void searchCdText(); + void queryCddb(); + bool writeNextSession(); + void readNextSession(); + bool prepareImageFiles(); + void cleanup(); + void finishJob( bool canceled, bool error ); + + K3bDevice::Device* m_writerDevice; + K3bDevice::Device* m_readerDevice; + bool m_simulate; + int m_speed; + int m_paranoiaMode; + unsigned int m_copies; + bool m_keepImage; + bool m_onlyCreateImages; + bool m_onTheFly; + bool m_ignoreDataReadErrors; + bool m_ignoreAudioReadErrors; + bool m_noCorrection; + int m_dataReadRetries; + int m_audioReadRetries; + bool m_preferCdText; + bool m_copyCdText; + QString m_tempPath; + int m_writingMode; + + class Private; + Private* d; +}; + +#endif diff --git a/libk3b/jobs/k3bcdda2wavreader.cpp b/libk3b/jobs/k3bcdda2wavreader.cpp new file mode 100644 index 0000000..3df87d3 --- /dev/null +++ b/libk3b/jobs/k3bcdda2wavreader.cpp @@ -0,0 +1,254 @@ +/* + * + * $Id: k3bcdda2wavreader.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bcdda2wavreader.h" + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + + +class K3bCdda2wavReader::Private +{ +public: + Private() + : cdda2wavBin(0), + process(0), + cancaled(false), + running(false), + fdToWriteTo(-1) { + } + + const K3bExternalBin* cdda2wavBin; + K3bProcess* process; + + bool cancaled; + bool running; + + int fdToWriteTo; + + int currentTrack; + QValueVector trackOffsets; +}; + + +K3bCdda2wavReader::K3bCdda2wavReader( QObject* parent, const char* name ) + : K3bJob( parent, name ) +{ + d = new Private(); +} + + +K3bCdda2wavReader::~K3bCdda2wavReader() +{ + delete d->process; + delete d; +} + + +bool K3bCdda2wavReader::active() const +{ + return d->running; +} + + +void K3bCdda2wavReader::writeToFd( int fd ) +{ + d->fdToWriteTo = fd; +} + + +void K3bCdda2wavReader::start() +{ + start( false ); +} + + +void K3bCdda2wavReader::start( bool onlyInfo ) +{ + d->running = true; + d->cancaled = false; + d->currentTrack = 1; + d->trackOffsets.clear(); + + jobStarted(); + + d->cdda2wavBin = k3bcore->externalBinManager()->binObject( "cdda2wav" ); + if( !d->cdda2wavBin ) { + emit infoMessage( i18n("Could not find %1 executable.").arg("cdda2wav"), ERROR ); + jobFinished(false); + d->running = false; + return; + } + + // prepare the process + delete d->process; + d->process = new K3bProcess(); + d->process->setSplitStdout(true); + d->process->setSuppressEmptyLines(true); + d->process->setWorkingDirectory( m_imagePath ); + connect( d->process, SIGNAL(stdoutLine(const QString&)), this, SLOT(slotProcessLine(const QString&)) ); + connect( d->process, SIGNAL(stderrLine(const QString&)), this, SLOT(slotProcessLine(const QString&)) ); + connect( d->process, SIGNAL(processExited(KProcess*)), this, SLOT(slotProcessExited(KProcess*)) ); + + // create the command line + *d->process << d->cdda2wavBin->path; + *d->process << "-vall" << ( d->cdda2wavBin->hasFeature( "gui" ) ? "-gui" : "-g" ); + if( d->cdda2wavBin->hasFeature( "dev" ) ) + *d->process << QString("dev=%1").arg(K3bDevice::externalBinDeviceParameter(m_device, d->cdda2wavBin)); + else + *d->process << "-D" << K3bDevice::externalBinDeviceParameter(m_device, d->cdda2wavBin); + *d->process << ( d->cdda2wavBin->hasFeature( "bulk" ) ? "-bulk" : "-B" ); + if( onlyInfo ) + *d->process << ( d->cdda2wavBin->hasFeature( "info-only" ) ? "-info-only" : "-J" ); + else if( d->fdToWriteTo != -1 ) + *d->process << ( d->cdda2wavBin->hasFeature( "no-infofile" ) ? "-no-infofile" : "-H" ); + + // additional user parameters from config + const QStringList& params = d->cdda2wavBin->userParameters(); + for( QStringList::const_iterator it = params.begin(); it != params.end(); ++it ) + *d->process << *it; + + // start the thing + if( !d->process->start( KProcess::NotifyOnExit, KProcess::All ) ) { + // something went wrong when starting the program + // it "should" be the executable + kdDebug() << "(K3bCdda2wavReader) could not start cdda2wav" << endl; + emit infoMessage( i18n("Could not start %1.").arg("cdda2wav"), K3bJob::ERROR ); + d->running = false; + jobFinished(false); + } +} + + +void K3bCdda2wavReader::cancel() +{ + if( d->running ) { + d->cancaled = true; + if( d->process ) + if( d->process->isRunning() ) + d->process->kill(); + } +} + + +void K3bCdda2wavReader::slotProcessLine( const QString& line ) +{ + // Tracks:11 44:37.30 + // CDINDEX discid: ZvzBXv614ACgzn1bWWy107cs0nA- + // CDDB discid: 0x8a0a730b + // CD-Text: not detected + // CD-Extra: not detected + // Album title: '' from '' + // T01: 0 3:39.70 audio linear copydenied stereo title '' from '' + // T02: 16495 3:10.47 audio linear copydenied stereo title '' from '' + // T03: 30792 3:30.00 audio linear copydenied stereo title '' from '' + // T04: 46542 4:05.05 audio linear copydenied stereo title '' from '' + // T05: 64922 3:44.35 audio linear copydenied stereo title '' from '' + // T06: 81757 4:36.45 audio linear copydenied stereo title '' from '' + // T07: 102502 3:59.30 audio linear copydenied stereo title '' from '' + // T08: 120457 5:24.30 audio linear copydenied stereo title '' from '' + // T09: 144787 3:26.28 audio linear copydenied stereo title '' from '' + // T10: 160265 4:07.20 audio linear copydenied stereo title '' from '' + // T11: 178810 4:51.20 audio linear copydenied stereo title '' from '' + + // percent_done: + // 100% track 1 successfully recorded + // 100% track 2 successfully recorded + // 100% track 3 successfully recorded + + + + static QRegExp rx( "T\\d\\d:" ); + if( rx.exactMatch( line.left(4) ) || line.startsWith( "Leadout" ) ) { + int pos = line.find( " " ); + int endpos = line.find( QRegExp( "\\d" ), pos ); + endpos = line.find( " ", endpos ); + bool ok; + int offset = line.mid( pos, endpos-pos ).toInt(&ok); + if( ok ) + d->trackOffsets.append( offset ); + else + kdDebug() << "(K3bCdda2wavReader) track offset parsing error: '" << line.mid( pos, endpos-pos ) << "'" << endl; + } + + else if( line.startsWith( "percent_done" ) ) { + // the reading starts + d->currentTrack = 1; + emit nextTrack( d->currentTrack, d->trackOffsets.count() ); + } + + else if( line.contains("successfully recorded") ) { + d->currentTrack++; + emit nextTrack( d->currentTrack, d->trackOffsets.count() ); + } + + else if( line.contains("%") ) { + // parse progress + bool ok; + int p = line.left(3).toInt(&ok); + if( ok ) { + emit subPercent( p ); + + int overall = d->trackOffsets[d->currentTrack-1]; + int tSize = d->trackOffsets[d->currentTrack] - d->trackOffsets[d->currentTrack-1]; + overall += (tSize*p/100); + + emit percent( overall*100/d->trackOffsets[d->trackOffsets.count()-1] ); + } + else + kdDebug() << "(K3bCdda2wavReader) track progress parsing error: '" << line.left(3) << "'" << endl; + } +} + + +void K3bCdda2wavReader::slotProcessExited( KProcess* p ) +{ + d->running = false; + + if( d->cancaled ) { + emit canceled(); + jobFinished(false); + return; + } + + if( p->normalExit() ) { + // TODO: improve this + + if( p->exitStatus() == 0 ) { + jobFinished( true ); + } + else { + emit infoMessage( i18n("%1 returned an unknown error (code %2).") + .arg("Cdda2wav").arg(p->exitStatus()), ERROR ); + jobFinished( false ); + } + } + else { + emit infoMessage( i18n("%1 did not exit cleanly.").arg("Cdda2wav"), + ERROR ); + jobFinished( false ); + } +} + +#include "k3bcdda2wavreader.moc" diff --git a/libk3b/jobs/k3bcdda2wavreader.h b/libk3b/jobs/k3bcdda2wavreader.h new file mode 100644 index 0000000..edde65c --- /dev/null +++ b/libk3b/jobs/k3bcdda2wavreader.h @@ -0,0 +1,70 @@ +/* + * + * $Id: k3bcdda2wavreader.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_CDDA2WAV_READER_H_ +#define _K3B_CDDA2WAV_READER_H_ + +#include + +class KProcess; +namespace K3bDevice { + class Device; +}; + + +/** + * An Audio CD reader completely based on cdda2wav. + * It does not use K3bDevice::Device but parses the track offsets + * from the cdda2wav output. + */ +class K3bCdda2wavReader : public K3bJob +{ + Q_OBJECT + + public: + K3bCdda2wavReader( QObject* parent = 0, const char* name = 0 ); + ~K3bCdda2wavReader(); + + bool active() const; + + public slots: + void start(); + void start( bool onlyReadInfo ); + void cancel(); + + void setReadDevice( K3bDevice::Device* dev ) { m_device = dev; } + void setImagePath( const QString& p ) { m_imagePath = p; } + + /** + * the data gets written directly into fd instead of the imagefile. + * Be aware that this only makes sense before starting the job. + * To disable just set fd to -1 + */ + void writeToFd( int fd ); + + private slots: + void slotProcessLine( const QString& ); + void slotProcessExited( KProcess* ); + + private: + K3bDevice::Device* m_device; + + QString m_imagePath; + + class Private; + Private* d; +}; + +#endif diff --git a/libk3b/jobs/k3bclonejob.cpp b/libk3b/jobs/k3bclonejob.cpp new file mode 100644 index 0000000..9fb61ab --- /dev/null +++ b/libk3b/jobs/k3bclonejob.cpp @@ -0,0 +1,375 @@ +/* + * + * $Id: k3bclonejob.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bclonejob.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + + + +class K3bCloneJob::Private +{ +public: + Private() + : doneCopies(0) { + } + + int doneCopies; +}; + + +K3bCloneJob::K3bCloneJob( K3bJobHandler* hdl, QObject* parent, const char* name ) + : K3bBurnJob( hdl, parent, name ), + m_writerDevice(0), + m_readerDevice(0), + m_writerJob(0), + m_readcdReader(0), + m_removeImageFiles(false), + m_canceled(false), + m_running(false), + m_simulate(false), + m_speed(1), + m_copies(1), + m_onlyCreateImage(false), + m_onlyBurnExistingImage(false), + m_readRetries(128) +{ + d = new Private; +} + + +K3bCloneJob::~K3bCloneJob() +{ + delete d; +} + + +void K3bCloneJob::start() +{ + jobStarted(); + + m_canceled = false; + m_running = true; + + + // TODO: check the cd size and warn the user if not enough space + + // + // We first check if cdrecord has clone support + // The readcdReader will check the same for readcd + // + const K3bExternalBin* cdrecordBin = k3bcore->externalBinManager()->binObject( "cdrecord" ); + if( !cdrecordBin ) { + emit infoMessage( i18n("Could not find %1 executable.").arg("cdrecord"), ERROR ); + jobFinished(false); + m_running = false; + return; + } + else if( !cdrecordBin->hasFeature( "clone" ) ) { + emit infoMessage( i18n("Cdrecord version %1 does not have cloning support.").arg(cdrecordBin->version), ERROR ); + jobFinished(false); + m_running = false; + return; + } + + if( (!m_onlyCreateImage && !writer()) || + (!m_onlyBurnExistingImage && !readingDevice()) ) { + emit infoMessage( i18n("No device set."), ERROR ); + jobFinished(false); + m_running = false; + return; + } + + if( !m_onlyCreateImage ) { + if( !writer()->supportsWritingMode( K3bDevice::RAW_R96R ) && + !writer()->supportsWritingMode( K3bDevice::RAW_R16 ) ) { + emit infoMessage( i18n("CD writer %1 does not support cloning.") + .arg(writer()->vendor()) + .arg(writer()->description()), ERROR ); + m_running = false; + jobFinished(false); + return; + } + } + + if( m_imagePath.isEmpty() ) { + m_imagePath = K3b::findTempFile( "img" ); + } + else if( QFileInfo(m_imagePath).isDir() ) { + m_imagePath = K3b::findTempFile( "img", m_imagePath ); + } + + if( m_onlyBurnExistingImage ) { + startWriting(); + } + else { + emit burning( false ); + + prepareReader(); + + if( waitForMedia( readingDevice(), + K3bDevice::STATE_COMPLETE, + K3bDevice::MEDIA_WRITABLE_CD|K3bDevice::MEDIA_CD_ROM ) < 0 ) { + m_running = false; + emit canceled(); + jobFinished(false); + return; + } + + emit newTask( i18n("Reading clone image") ); + + m_readcdReader->start(); + } +} + + +void K3bCloneJob::prepareReader() +{ + if( !m_readcdReader ) { + m_readcdReader = new K3bReadcdReader( this, this ); + connect( m_readcdReader, SIGNAL(percent(int)), this, SLOT(slotReadingPercent(int)) ); + connect( m_readcdReader, SIGNAL(percent(int)), this, SIGNAL(subPercent(int)) ); + connect( m_readcdReader, SIGNAL(processedSize(int, int)), this, SIGNAL(processedSubSize(int, int)) ); + connect( m_readcdReader, SIGNAL(finished(bool)), this, SLOT(slotReadingFinished(bool)) ); + connect( m_readcdReader, SIGNAL(infoMessage(const QString&, int)), this, SIGNAL(infoMessage(const QString&, int)) ); + connect( m_readcdReader, SIGNAL(newTask(const QString&)), this, SIGNAL(newSubTask(const QString&)) ); + connect( m_readcdReader, SIGNAL(debuggingOutput(const QString&, const QString&)), + this, SIGNAL(debuggingOutput(const QString&, const QString&)) ); + } + + m_readcdReader->setReadDevice( readingDevice() ); + m_readcdReader->setReadSpeed( 0 ); // MAX + m_readcdReader->setDisableCorrection( m_noCorrection ); + m_readcdReader->setImagePath( m_imagePath ); + m_readcdReader->setClone( true ); + m_readcdReader->setRetries( m_readRetries ); +} + + +void K3bCloneJob::prepareWriter() +{ + if( !m_writerJob ) { + m_writerJob = new K3bCdrecordWriter( writer(), this, this ); + connect( m_writerJob, SIGNAL(infoMessage(const QString&, int)), this, SIGNAL(infoMessage(const QString&, int)) ); + connect( m_writerJob, SIGNAL(percent(int)), this, SLOT(slotWriterPercent(int)) ); + connect( m_writerJob, SIGNAL(percent(int)), this, SIGNAL(subPercent(int)) ); + connect( m_writerJob, SIGNAL(nextTrack(int, int)), this, SLOT(slotWriterNextTrack(int, int)) ); + connect( m_writerJob, SIGNAL(processedSize(int, int)), this, SIGNAL(processedSubSize(int, int)) ); + connect( m_writerJob, SIGNAL(buffer(int)), this, SIGNAL(bufferStatus(int)) ); + connect( m_writerJob, SIGNAL(deviceBuffer(int)), this, SIGNAL(deviceBuffer(int)) ); + connect( m_writerJob, SIGNAL(writeSpeed(int, int)), this, SIGNAL(writeSpeed(int, int)) ); + connect( m_writerJob, SIGNAL(finished(bool)), this, SLOT(slotWriterFinished(bool)) ); + // connect( m_writerJob, SIGNAL(newTask(const QString&)), this, SIGNAL(newTask(const QString&)) ); + connect( m_writerJob, SIGNAL(newSubTask(const QString&)), this, SIGNAL(newSubTask(const QString&)) ); + connect( m_writerJob, SIGNAL(debuggingOutput(const QString&, const QString&)), + this, SIGNAL(debuggingOutput(const QString&, const QString&)) ); + } + + m_writerJob->clearArguments(); + m_writerJob->setWritingMode( K3b::RAW ); + m_writerJob->setClone( true ); + m_writerJob->setSimulate( m_simulate ); + m_writerJob->setBurnSpeed( m_speed ); + m_writerJob->addArgument( m_imagePath ); +} + + +void K3bCloneJob::cancel() +{ + if( m_running ) { + m_canceled = true; + if( m_readcdReader ) + m_readcdReader->cancel(); + if( m_writerJob ) + m_writerJob->cancel(); + } +} + + +void K3bCloneJob::slotWriterPercent( int p ) +{ + if( m_onlyBurnExistingImage ) + emit percent( (int)((double)(d->doneCopies)*100.0/(double)(m_copies) + (double)p/(double)(m_copies)) ); + else + emit percent( (int)((double)(1+d->doneCopies)*100.0/(double)(1+m_copies) + (double)p/(double)(1+m_copies)) ); +} + + +void K3bCloneJob::slotWriterNextTrack( int t, int tt ) +{ + emit newSubTask( i18n("Writing Track %1 of %2").arg(t).arg(tt) ); +} + + +void K3bCloneJob::slotWriterFinished( bool success ) +{ + if( m_canceled ) { + removeImageFiles(); + m_running = false; + emit canceled(); + jobFinished(false); + return; + } + + if( success ) { + d->doneCopies++; + + emit infoMessage( i18n("Successfully written clone copy %1.").arg(d->doneCopies), INFO ); + + if( d->doneCopies < m_copies ) { + K3bDevice::eject( writer() ); + startWriting(); + } + else { + if( m_removeImageFiles ) + removeImageFiles(); + m_running = false; + jobFinished(true); + } + } + else { + removeImageFiles(); + m_running = false; + jobFinished(false); + } +} + + +void K3bCloneJob::slotReadingPercent( int p ) +{ + emit percent( m_onlyCreateImage ? p : (int)((double)p/(double)(1+m_copies)) ); +} + + +void K3bCloneJob::slotReadingFinished( bool success ) +{ + if( m_canceled ) { + removeImageFiles(); + m_running = false; + emit canceled(); + jobFinished(false); + return; + } + + if( success ) { + // + // Make a quick test if the image is really valid. + // Readcd does not seem to have proper exit codes + // + K3bCloneTocReader ctr( m_imagePath ); + if( ctr.isValid() ) { + emit infoMessage( i18n("Successfully read disk."), INFO ); + if( m_onlyCreateImage ) { + m_running = false; + jobFinished(true); + } + else { + if( writer() == readingDevice() ) + K3bDevice::eject( writer() ); + startWriting(); + } + } + else { + emit infoMessage( i18n("Failed to read disk completely in clone mode."), ERROR ); + removeImageFiles(); + m_running = false; + jobFinished(false); + } + } + else { + emit infoMessage( i18n("Error while reading disk."), ERROR ); + removeImageFiles(); + m_running = false; + jobFinished(false); + } +} + + +void K3bCloneJob::startWriting() +{ + emit burning( true ); + + // start writing + prepareWriter(); + + if( waitForMedia( writer(), + K3bDevice::STATE_EMPTY, + K3bDevice::MEDIA_WRITABLE_CD ) < 0 ) { + removeImageFiles(); + m_running = false; + emit canceled(); + jobFinished(false); + return; + } + + if( m_simulate ) + emit newTask( i18n("Simulating clone copy") ); + else + emit newTask( i18n("Writing clone copy %1").arg(d->doneCopies+1) ); + + m_writerJob->start(); +} + + +void K3bCloneJob::removeImageFiles() +{ + if( !m_onlyBurnExistingImage ) { + emit infoMessage( i18n("Removing image files."), INFO ); + if( QFile::exists( m_imagePath ) ) + QFile::remove( m_imagePath ); + if( QFile::exists( m_imagePath + ".toc" ) ) + QFile::remove( m_imagePath + ".toc" ); + } +} + + +QString K3bCloneJob::jobDescription() const +{ + if( m_onlyCreateImage ) + return i18n("Creating Clone Image"); + else if( m_onlyBurnExistingImage ) { + if( m_simulate ) + return i18n("Simulating Clone Image"); + else + return i18n("Burning Clone Image"); + } + else if( m_simulate ) + return i18n("Simulating CD Cloning"); + else + return i18n("Cloning CD"); +} + + +QString K3bCloneJob::jobDetails() const +{ + return i18n("Creating 1 clone copy", + "Creating %n clone copies", + (m_simulate||m_onlyCreateImage) ? 1 : m_copies ); +} + +#include "k3bclonejob.moc" diff --git a/libk3b/jobs/k3bclonejob.h b/libk3b/jobs/k3bclonejob.h new file mode 100644 index 0000000..80c8ea9 --- /dev/null +++ b/libk3b/jobs/k3bclonejob.h @@ -0,0 +1,99 @@ +/* + * + * $Id: k3bclonejob.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_CLONE_JOB_H_ +#define _K3B_CLONE_JOB_H_ + +#include +#include "k3b_export.h" +#include + + +namespace K3bDevice { + class Device; +} +class K3bCdrecordWriter; +class K3bReadcdReader; + + +class LIBK3B_EXPORT K3bCloneJob : public K3bBurnJob +{ + Q_OBJECT + + public: + K3bCloneJob( K3bJobHandler*, QObject* parent = 0, const char* name = 0 ); + ~K3bCloneJob(); + + K3bDevice::Device* writer() const { return m_writerDevice; } + K3bDevice::Device* readingDevice() const { return m_readerDevice; } + + QString jobDescription() const; + QString jobDetails() const; + + public slots: + void start(); + void cancel(); + + void setWriterDevice( K3bDevice::Device* w ) { m_writerDevice = w; } + void setReaderDevice( K3bDevice::Device* w ) { m_readerDevice = w; } + void setImagePath( const QString& p ) { m_imagePath = p; } + void setNoCorrection( bool b ) { m_noCorrection = b; } + void setRemoveImageFiles( bool b ) { m_removeImageFiles = b; } + void setOnlyCreateImage( bool b ) { m_onlyCreateImage = b; } + void setOnlyBurnExistingImage( bool b ) { m_onlyBurnExistingImage = b; } + void setSimulate( bool b ) { m_simulate = b; } + void setWriteSpeed( int s ) { m_speed = s; } + void setCopies( int c ) { m_copies = c; } + void setReadRetries( int i ) { m_readRetries = i; } + + private slots: + void slotWriterPercent( int ); + void slotWriterFinished( bool ); + void slotWriterNextTrack( int, int ); + void slotReadingPercent( int ); + void slotReadingFinished( bool ); + + private: + void removeImageFiles(); + void prepareReader(); + void prepareWriter(); + void startWriting(); + + K3bDevice::Device* m_writerDevice; + K3bDevice::Device* m_readerDevice; + QString m_imagePath; + + K3bCdrecordWriter* m_writerJob; + K3bReadcdReader* m_readcdReader; + + bool m_noCorrection; + bool m_removeImageFiles; + + bool m_canceled; + bool m_running; + + bool m_simulate; + int m_speed; + int m_copies; + bool m_onlyCreateImage; + bool m_onlyBurnExistingImage; + int m_readRetries; + + class Private; + Private* d; +}; + + +#endif diff --git a/libk3b/jobs/k3bclonetocreader.cpp b/libk3b/jobs/k3bclonetocreader.cpp new file mode 100644 index 0000000..5dd8b8b --- /dev/null +++ b/libk3b/jobs/k3bclonetocreader.cpp @@ -0,0 +1,235 @@ +/* + * + * $Id: k3bclonetocreader.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include + + +#include "k3bclonetocreader.h" + +#include +#include + +#include +#include + +#include + + +class K3bCloneTocReader::Private +{ +public: + Private() + : size(0) { + } + + K3b::Msf size; + QString tocFile; +}; + + + +K3bCloneTocReader::K3bCloneTocReader( const QString& filename ) + : K3bImageFileReader() +{ + d = new Private; + openFile( filename ); +} + + +K3bCloneTocReader::~K3bCloneTocReader() +{ + delete d; +} + + +const K3b::Msf& K3bCloneTocReader::imageSize() const +{ + return d->size; +} + + +void K3bCloneTocReader::readFile() +{ + // first of all we check if we find the image file which contains the data for this toc + // cdrecord always uses this strange file naming: + // somedata + // somedata.toc + + // filename should always be the toc file + if( filename().right( 4 ) == ".toc" ) + d->tocFile = filename(); + else + d->tocFile = filename() + ".toc"; + + // now get rid of the ".toc" extension + QString imageFileName = d->tocFile.left( d->tocFile.length()-4 ); + if( !QFile::exists( imageFileName ) ) { + kdDebug() << "(K3bCloneTocReader) could not find image file " << imageFileName << endl; + return; + } + + setImageFilename( imageFileName ); + + d->size = 0; + + QFile f( d->tocFile ); + if( f.open( IO_ReadOnly ) ) { + // + // Inspired by clone.c from the cdrecord sources + // + char buffer[2048]; + int read = f.readBlock( buffer, 2048 ); + f.close(); + + if( read == 2048 ) { + kdDebug() << "(K3bCloneTocReader) TOC too large." << endl; + return; + } + + // the toc starts with a tocheader + struct tocheader { + unsigned char len[2]; + unsigned char first; // first session + unsigned char last; // last session + }; + + struct tocheader* th = (struct tocheader*)buffer; + int dataLen = K3bDevice::from2Byte( th->len ) + 2; // the len field does not include it's own length + + if( th->first != 1 ) { + kdDebug() << "(K3bCloneTocReader) first session != 1" << endl; + return; + } + + // the following bytes are multiple instances of + struct ftrackdesc { + unsigned char sess_number; +#ifdef WORDS_BIGENDIAN // __BYTE_ORDER == __BIG_ENDIAN + unsigned char adr : 4; + unsigned char control : 4; +#else + unsigned char control : 4; + unsigned char adr : 4; +#endif + unsigned char track; + unsigned char point; + unsigned char amin; + unsigned char asec; + unsigned char aframe; + unsigned char res7; + unsigned char pmin; + unsigned char psec; + unsigned char pframe; + }; + + for( int i = 4; i < dataLen; i += 11) { + struct ftrackdesc* ft = (struct ftrackdesc*)&buffer[i]; + + if( ft->sess_number != 1 ) { + kdDebug() << "(K3bCloneTocReader} session number != 1" << endl; + return; + } + + // now we check some of the values + if( ft->point >= 0x1 && ft->point <= 0x63 ) { + if( ft->adr == 1 ) { + // check track starttime + if( ft->psec > 60 || ft->pframe > 75 ) { + kdDebug() << "(K3bCloneTocReader) invalid track start: " + << (int)ft->pmin << "." + << (int)ft->psec << "." + << (int)ft->pframe << endl; + return; + } + } + } + else { + switch( ft->point ) { + case 0xa0: + if( ft->adr != 1 ) { + kdDebug() << "(K3bCloneTocReader) adr != 1" << endl; + return; + } + + // disk type in psec + if( ft->psec != 0x00 && ft->psec != 0x10 && ft->psec != 0x20 ) { + kdDebug() << "(K3bCloneTocReader) invalid disktype: " << ft->psec << endl; + return; + } + + if( ft->pmin != 1 ) { + kdDebug() << "(K3bCloneTocReader) first track number != 1 " << endl; + return; + } + + if( ft->pframe != 0x0 ) { + kdDebug() << "(K3bCloneTocReader) found data when there should be 0x0" << endl; + return; + } + break; + + case 0xa1: + if( ft->adr != 1 ) { + kdDebug() << "(K3bCloneTocReader) adr != 1" << endl; + return; + } + + if( !(ft->pmin >= 1) ) { + kdDebug() << "(K3bCloneTocReader) last track number needs to be >= 1." << endl; + return; + } + if( ft->psec != 0x0 || ft->pframe != 0x0 ) { + kdDebug() << "(K3bCloneTocReader) found data when there should be 0x0" << endl; + return; + } + break; + + case 0xa2: + if( ft->adr != 1 ) { + kdDebug() << "(K3bCloneTocReader) adr != 1" << endl; + return; + } + + // start of the leadout = size of the image + // substract 2 seconds since in cdrecord other than in K3b lba 0 = msf 2:00 + // (the cdrecord way is actually more accurate but we use k3b::Msf for many + // things and it is simpler this way.) + d->size = K3b::Msf( ft->pmin, ft->psec, ft->pframe ) - K3b::Msf( 0, 2, 0 ); + + // leadout... no check so far... + break; + + default: + if( ft->adr != 5 ) { + kdDebug() << "(K3bCloneTocReader) adr != 5" << endl; + return; + } + break; + } + } + } + + if( d->size.rawBytes() != K3b::filesize( imageFileName ) ) { + kdDebug() << "(K3bCloneTocReader) image file size invalid." << endl; + return; + } + + // ok, could be a cdrecord toc file + setValid(true); + } + else { + kdDebug() << "(K3bCloneTocReader) could not open file " << d->tocFile << endl; + } +} diff --git a/libk3b/jobs/k3bclonetocreader.h b/libk3b/jobs/k3bclonetocreader.h new file mode 100644 index 0000000..17e80d7 --- /dev/null +++ b/libk3b/jobs/k3bclonetocreader.h @@ -0,0 +1,45 @@ +/* + * + * $Id: k3bclonetocreader.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_CLONETOC_FILE_PARSER_H_ +#define _K3B_CLONETOC_FILE_PARSER_H_ + +#include "k3bimagefilereader.h" + +#include + +#include "k3b_export.h" + + +/** + * Reads a cdrecord clone toc file and searches for the + * corresponding image file. + */ +class LIBK3B_EXPORT K3bCloneTocReader : public K3bImageFileReader +{ + public: + K3bCloneTocReader( const QString& filename = QString::null ); + ~K3bCloneTocReader(); + + const K3b::Msf& imageSize() const; + + protected: + void readFile(); + + class Private; + Private* d; +}; + +#endif diff --git a/libk3b/jobs/k3bdatatrackreader.cpp b/libk3b/jobs/k3bdatatrackreader.cpp new file mode 100644 index 0000000..8300ada --- /dev/null +++ b/libk3b/jobs/k3bdatatrackreader.cpp @@ -0,0 +1,515 @@ +/* + * + * $Id: k3bdatatrackreader.cpp 690529 2007-07-21 10:51:47Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bdatatrackreader.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include + + + +// FIXME: determine max DMA buffer size +static int s_bufferSizeSectors = 10; + + +class K3bDataTrackReader::WorkThread : public K3bThread +{ +public: + WorkThread(); + ~WorkThread(); + + void init(); + void run(); + int read( unsigned char* buffer, unsigned long sector, unsigned int len ); + bool retryRead( unsigned char* buffer, unsigned long startSector, unsigned int len ); + bool setErrorRecovery( K3bDevice::Device* dev, int code ); + void cancel(); + + bool m_canceled; + bool m_ignoreReadErrors; + bool m_noCorrection; + int m_retries; + K3bDevice::Device* m_device; + K3b::Msf m_firstSector; + K3b::Msf m_lastSector; + K3b::Msf m_nextReadSector; + int m_fd; + QString m_imagePath; + int m_sectorSize; + bool m_useLibdvdcss; + K3bLibDvdCss* m_libcss; + + int m_oldErrorRecoveryMode; + + int m_errorSectorCount; + +private: + int m_usedSectorSize; +}; + + +K3bDataTrackReader::K3bDataTrackReader( K3bJobHandler* jh, QObject* parent, const char* name ) + : K3bThreadJob( jh, parent, name ) +{ + m_thread = new WorkThread(); + setThread( m_thread ); +} + + +K3bDataTrackReader::WorkThread::WorkThread() + : K3bThread(), + m_canceled(false), + m_ignoreReadErrors(false), + m_noCorrection(false), + m_retries(10), + m_device(0), + m_fd(-1), + m_libcss(0) +{ +} + + +K3bDataTrackReader::WorkThread::~WorkThread() +{ + delete m_libcss; +} + + +void K3bDataTrackReader::WorkThread::init() +{ + m_canceled = false; +} + + +void K3bDataTrackReader::WorkThread::run() +{ + emitStarted(); + + if( !m_device->open() ) { + emitInfoMessage( i18n("Could not open device %1").arg(m_device->blockDeviceName()), K3bJob::ERROR ); + emitFinished(false); + return; + } + + // 1. determine sector size by checking the first sectors mode + // if impossible or MODE2 (mode2 formless) finish(false) + + m_useLibdvdcss = false; + m_usedSectorSize = m_sectorSize; + if( m_device->isDVD() ) { + m_usedSectorSize = MODE1; + + // + // In case of an encrypted VideoDVD we read with libdvdcss which takes care of decrypting the vobs + // + if( m_device->copyrightProtectionSystemType() == 1 ) { + + // close the device for libdvdcss + m_device->close(); + + kdDebug() << "(K3bDataTrackReader::WorkThread) found encrypted dvd. using libdvdcss." << endl; + + // open the libdvdcss stuff + if( !m_libcss ) + m_libcss = K3bLibDvdCss::create(); + if( !m_libcss ) { + emitInfoMessage( i18n("Unable to open libdvdcss."), K3bJob::ERROR ); + emitFinished(false); + return; + } + + if( !m_libcss->open(m_device) ) { + emitInfoMessage( i18n("Could not open device %1").arg(m_device->blockDeviceName()), K3bJob::ERROR ); + emitFinished(false); + return; + } + + emitInfoMessage( i18n("Retrieving all CSS keys. This might take a while."), K3bJob::INFO ); + if( !m_libcss->crackAllKeys() ) { + m_libcss->close(); + emitInfoMessage( i18n("Failed to retrieve all CSS keys."), K3bJob::ERROR ); + emitInfoMessage( i18n("Video DVD decryption failed."), K3bJob::ERROR ); + emitFinished(false); + return; + } + + m_useLibdvdcss = true; + } + } + else { + if( m_usedSectorSize == AUTO ) { + switch( m_device->getDataMode( m_firstSector ) ) { + case K3bDevice::Track::MODE1: + case K3bDevice::Track::DVD: + m_usedSectorSize = MODE1; + break; + case K3bDevice::Track::XA_FORM1: + m_usedSectorSize = MODE2FORM1; + break; + case K3bDevice::Track::XA_FORM2: + m_usedSectorSize = MODE2FORM2; + break; + case K3bDevice::Track::MODE2: + emitInfoMessage( i18n("No support for reading formless Mode2 sectors."), K3bJob::ERROR ); + default: + emitInfoMessage( i18n("Unsupported sector type."), K3bJob::ERROR ); + m_device->close(); + emitFinished(false); + return; + } + } + } + + emitInfoMessage( i18n("Reading with sector size %1.").arg(m_usedSectorSize), K3bJob::INFO ); + emitDebuggingOutput( "K3bDataTrackReader", + QString("reading sectors %1 to %2 with sector size %3. Length: %4 sectors, %5 bytes.") + .arg( m_firstSector.lba() ) + .arg( m_lastSector.lba() ) + .arg( m_usedSectorSize ) + .arg( m_lastSector.lba() - m_firstSector.lba() + 1 ) + .arg( Q_UINT64(m_usedSectorSize) * (Q_UINT64)(m_lastSector.lba() - m_firstSector.lba() + 1) ) ); + + QFile file; + if( m_fd == -1 ) { + file.setName( m_imagePath ); + if( !file.open( IO_WriteOnly ) ) { + m_device->close(); + if( m_useLibdvdcss ) + m_libcss->close(); + emitInfoMessage( i18n("Unable to open '%1' for writing.").arg(m_imagePath), K3bJob::ERROR ); + emitFinished( false ); + return; + } + } + + k3bcore->blockDevice( m_device ); + m_device->block( true ); + + // + // set the error recovery mode to 0x21 or 0x20 depending on m_ignoreReadErrors + // TODO: should we also set RC=1 in m_ignoreReadErrors mode (0x11 because TB is ignored) + // + setErrorRecovery( m_device, m_noCorrection ? 0x21 : 0x20 ); + + // + // Let the drive determine the optimal reading speed + // + m_device->setSpeed( 0xffff, 0xffff ); + + s_bufferSizeSectors = 128; + unsigned char* buffer = new unsigned char[m_usedSectorSize*s_bufferSizeSectors]; + while( s_bufferSizeSectors > 0 && read( buffer, m_firstSector.lba(), s_bufferSizeSectors ) < 0 ) { + kdDebug() << "(K3bDataTrackReader) determine max read sectors: " + << s_bufferSizeSectors << " too high." << endl; + s_bufferSizeSectors--; + } + kdDebug() << "(K3bDataTrackReader) determine max read sectors: " + << s_bufferSizeSectors << " is max." << endl; + + // s_bufferSizeSectors = K3bDevice::determineMaxReadingBufferSize( m_device, m_firstSector ); + if( s_bufferSizeSectors <= 0 ) { + emitInfoMessage( i18n("Error while reading sector %1.").arg(m_firstSector.lba()), K3bJob::ERROR ); + emitFinished(false); + m_device->block( false ); + k3bcore->unblockDevice( m_device ); + return; + } + + kdDebug() << "(K3bDataTrackReader) using buffer size of " << s_bufferSizeSectors << " blocks." << endl; + emitDebuggingOutput( "K3bDataTrackReader", QString("using buffer size of %1 blocks.").arg( s_bufferSizeSectors ) ); + + // 2. get it on + K3b::Msf currentSector = m_firstSector; + K3b::Msf totalReadSectors; + m_nextReadSector = 0; + m_errorSectorCount = 0; + bool writeError = false; + bool readError = false; + int lastPercent = 0; + unsigned long lastReadMb = 0; + int bufferLen = s_bufferSizeSectors*m_usedSectorSize; + while( !m_canceled && currentSector <= m_lastSector ) { + + int maxReadSectors = QMIN( bufferLen/m_usedSectorSize, m_lastSector.lba()-currentSector.lba()+1 ); + + int readSectors = read( buffer, + currentSector.lba(), + maxReadSectors ); + if( readSectors < 0 ) { + if( !retryRead( buffer, + currentSector.lba(), + maxReadSectors ) ) { + readError = true; + break; + } + else + readSectors = maxReadSectors; + } + + totalReadSectors += readSectors; + + int readBytes = readSectors * m_usedSectorSize; + + if( m_fd != -1 ) { + if( ::write( m_fd, reinterpret_cast(buffer), readBytes ) != readBytes ) { + kdDebug() << "(K3bDataTrackReader::WorkThread) error while writing to fd " << m_fd + << " current sector: " << (currentSector.lba()-m_firstSector.lba()) << endl; + emitDebuggingOutput( "K3bDataTrackReader", + QString("Error while writing to fd %1. Current sector is %2.") + .arg(m_fd).arg(currentSector.lba()-m_firstSector.lba()) ); + writeError = true; + break; + } + } + else { + if( file.writeBlock( reinterpret_cast(buffer), readBytes ) != readBytes ) { + kdDebug() << "(K3bDataTrackReader::WorkThread) error while writing to file " << m_imagePath + << " current sector: " << (currentSector.lba()-m_firstSector.lba()) << endl; + emitDebuggingOutput( "K3bDataTrackReader", + QString("Error while writing to file %1. Current sector is %2.") + .arg(m_imagePath).arg(currentSector.lba()-m_firstSector.lba()) ); + writeError = true; + break; + } + } + + currentSector += readSectors; + + int percent = 100 * (currentSector.lba() - m_firstSector.lba() + 1 ) / + (m_lastSector.lba() - m_firstSector.lba() + 1 ); + + if( percent > lastPercent ) { + lastPercent = percent; + emitPercent( percent ); + } + + unsigned long readMb = (currentSector.lba() - m_firstSector.lba() + 1) / 512; + if( readMb > lastReadMb ) { + lastReadMb = readMb; + emitProcessedSize( readMb, ( m_lastSector.lba() - m_firstSector.lba() + 1 ) / 512 ); + } + } + + if( m_errorSectorCount > 0 ) + emitInfoMessage( i18n("Ignored %n erroneous sector.", "Ignored a total of %n erroneous sectors.", m_errorSectorCount ), + K3bJob::ERROR ); + + // reset the error recovery mode + setErrorRecovery( m_device, m_oldErrorRecoveryMode ); + + m_device->block( false ); + k3bcore->unblockDevice( m_device ); + + // cleanup + if( m_useLibdvdcss ) + m_libcss->close(); + m_device->close(); + delete [] buffer; + + emitDebuggingOutput( "K3bDataTrackReader", + QString("Read a total of %1 sectors (%2 bytes)") + .arg(totalReadSectors.lba()) + .arg((Q_UINT64)totalReadSectors.lba()*(Q_UINT64)m_usedSectorSize) ); + + if( m_canceled ) + emitCanceled(); + + emitFinished( !m_canceled && !writeError && !readError ); +} + + +int K3bDataTrackReader::WorkThread::read( unsigned char* buffer, unsigned long sector, unsigned int len ) +{ + + // + // Encrypted DVD reading with libdvdcss + // + if( m_useLibdvdcss ) { + return m_libcss->readWrapped( reinterpret_cast(buffer), sector, len ); + } + + // + // Standard reading + // + else { + bool success = false; + // setErrorRecovery( m_device, m_ignoreReadErrors ? 0x21 : 0x20 ); + if( m_usedSectorSize == 2048 ) + success = m_device->read10( buffer, len*2048, sector, len ); + else + success = m_device->readCd( buffer, + len*m_usedSectorSize, + 0, // all sector types + false, // no dap + sector, + len, + false, // no sync + false, // no header + m_usedSectorSize != MODE1, // subheader + true, // user data + false, // no edc/ecc + 0, // no c2 error info... FIXME: should we check this?? + 0 // no subchannel data + ); + + if( success ) + return len; + else + return -1; + } +} + + +// here we read every single sector for itself to find the troubleing ones +bool K3bDataTrackReader::WorkThread::retryRead( unsigned char* buffer, unsigned long startSector, unsigned int len ) +{ + emitDebuggingOutput( "K3bDataTrackReader", QString( "Problem while reading. Retrying from sector %1.").arg(startSector) ); + emitInfoMessage( i18n("Problem while reading. Retrying from sector %1.").arg(startSector), K3bJob::WARNING ); + + int sectorsRead = -1; + bool success = true; + for( unsigned long sector = startSector; sector < startSector+len; ++sector ) { + int retry = m_retries; + while( !m_canceled && retry && (sectorsRead = read( &buffer[( sector - startSector ) * m_usedSectorSize], sector, 1 )) < 0 ) + --retry; + + success = ( sectorsRead > 0 ); + + if( m_canceled ) + return false; + + if( !success ) { + if( m_ignoreReadErrors ) { + emitInfoMessage( i18n("Ignoring read error in sector %1.").arg(sector), K3bJob::ERROR ); + emitDebuggingOutput( "K3bDataTrackReader", QString( "Ignoring read error in sector %1.").arg(sector) ); + + ++m_errorSectorCount; + // ::memset( &buffer[i], 0, 1 ); + success = true; + } + else { + emitInfoMessage( i18n("Error while reading sector %1.").arg(sector), K3bJob::ERROR ); + emitDebuggingOutput( "K3bDataTrackReader", QString( "Read error in sector %1.").arg(sector) ); + break; + } + } + } + + return success; +} + + +bool K3bDataTrackReader::WorkThread::setErrorRecovery( K3bDevice::Device* dev, int code ) +{ + unsigned char* data = 0; + unsigned int dataLen = 0; + if( !dev->modeSense( &data, dataLen, 0x01 ) ) + return false; + + // in MMC1 the page has 8 bytes (12 in MMC4 but we only need the first 3 anyway) + if( dataLen < 8+8 ) { + kdDebug() << "(K3bDataTrackReader) modepage 0x01 data too small: " << dataLen << endl; + delete [] data; + return false; + } + + m_oldErrorRecoveryMode = data[8+2]; + data[8+2] = code; + + if( m_oldErrorRecoveryMode != code ) + kdDebug() << "(K3bDataTrackReader) changing data recovery mode from " << m_oldErrorRecoveryMode << " to " << code << endl; + + bool success = dev->modeSelect( data, dataLen, true, false ); + + delete [] data; + + return success; +} + + +void K3bDataTrackReader::WorkThread::cancel() +{ + m_canceled = true; +} + + + + + +K3bDataTrackReader::~K3bDataTrackReader() +{ + delete m_thread; +} + + +void K3bDataTrackReader::setDevice( K3bDevice::Device* dev ) +{ + m_thread->m_device = dev; +} + + +void K3bDataTrackReader::setSectorRange( const K3b::Msf& start, const K3b::Msf& end ) +{ + m_thread->m_firstSector = start; + m_thread->m_lastSector = end; +} + + +void K3bDataTrackReader::setRetries( int r ) +{ + m_thread->m_retries = r; +} + + +void K3bDataTrackReader::setIgnoreErrors( bool b ) +{ + m_thread->m_ignoreReadErrors = b; +} + + +void K3bDataTrackReader::setNoCorrection( bool b ) +{ + m_thread->m_noCorrection = b; +} + + +void K3bDataTrackReader::writeToFd( int fd ) +{ + m_thread->m_fd = fd; +} + + +void K3bDataTrackReader::setImagePath( const QString& p ) +{ + m_thread->m_imagePath = p; + m_thread->m_fd = -1; +} + + +void K3bDataTrackReader::setSectorSize( SectorSize size ) +{ + m_thread->m_sectorSize = size; +} diff --git a/libk3b/jobs/k3bdatatrackreader.h b/libk3b/jobs/k3bdatatrackreader.h new file mode 100644 index 0000000..814c01c --- /dev/null +++ b/libk3b/jobs/k3bdatatrackreader.h @@ -0,0 +1,87 @@ +/* + * + * $Id: k3bdatatrackreader.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_DATATRACK_READER_H_ +#define _K3B_DATATRACK_READER_H_ + + +#include +#include +#include + +namespace K3bDevice { + class Device; +} + + +/** + * This is a replacement for readcd. We need this since + * it is not possible to influence the sector size used + * by readcd and readcd is not very good to handle anyway. + * + * The sector size read is the following: + * @li Mode1: 2048 bytes (only user data) + * @li Mode2 Form1: 2056 bytes containing the subheader and the user data + * @li Mode2 Form2: 2332 bytes containing the subheader and the user data + * + * Formless Mode2 sectors will not be read. + */ +class K3bDataTrackReader : public K3bThreadJob +{ + public: + K3bDataTrackReader( K3bJobHandler*, QObject* parent = 0, const char* name = 0 ); + ~K3bDataTrackReader(); + + enum SectorSize { + AUTO = 0, + MODE1 = K3b::SECTORSIZE_DATA_2048, + MODE2FORM1 = K3b::SECTORSIZE_DATA_2048_SUBHEADER, + MODE2FORM2 = K3b::SECTORSIZE_DATA_2324_SUBHEADER + }; + + void setSectorSize( SectorSize size ); + + void setDevice( K3bDevice::Device* ); + + /** + * @param start the first sector to be read + * @end the last sector to be read + */ + void setSectorRange( const K3b::Msf& start, const K3b::Msf& end ); + void setRetries( int ); + + /** + * If true unreadable sectors will be replaced by zero data to always + * maintain the track length. + */ + void setIgnoreErrors( bool b ); + + void setNoCorrection( bool b ); + + /** + * the data gets written directly into fd instead of the imagefile. + * Be aware that this only makes sense before starting the job. + * To disable just set fd to -1 + */ + void writeToFd( int fd ); + + void setImagePath( const QString& p ); + + private: + class WorkThread; + WorkThread* m_thread; +}; + +#endif diff --git a/libk3b/jobs/k3bdvdcopyjob.cpp b/libk3b/jobs/k3bdvdcopyjob.cpp new file mode 100644 index 0000000..96d727c --- /dev/null +++ b/libk3b/jobs/k3bdvdcopyjob.cpp @@ -0,0 +1,894 @@ +/* + * + * $Id: k3bdvdcopyjob.cpp 690529 2007-07-21 10:51:47Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bdvdcopyjob.h" +#include "k3blibdvdcss.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + + +class K3bDvdCopyJob::Private +{ +public: + Private() + : doneCopies(0), + running(false), + canceled(false), + writerJob(0), + readcdReader(0), + dataTrackReader(0), + verificationJob(0), + usedWritingMode(0), + verifyData(false) { + outPipe.readFromIODevice( &imageFile ); + } + + int doneCopies; + + bool running; + bool readerRunning; + bool writerRunning; + bool canceled; + + K3bGrowisofsWriter* writerJob; + K3bReadcdReader* readcdReader; + K3bDataTrackReader* dataTrackReader; + K3bVerificationJob* verificationJob; + + K3bDevice::DiskInfo sourceDiskInfo; + + K3b::Msf lastSector; + + int usedWritingMode; + + K3bFileSplitter imageFile; + K3bChecksumPipe inPipe; + K3bActivePipe outPipe; + + bool verifyData; +}; + + +K3bDvdCopyJob::K3bDvdCopyJob( K3bJobHandler* hdl, QObject* parent, const char* name ) + : K3bBurnJob( hdl, parent, name ), + m_writerDevice(0), + m_readerDevice(0), + m_onTheFly(false), + m_removeImageFiles(false), + m_simulate(false), + m_speed(1), + m_copies(1), + m_onlyCreateImage(false), + m_ignoreReadErrors(false), + m_readRetries(128), + m_writingMode( K3b::WRITING_MODE_AUTO ) +{ + d = new Private(); +} + + +K3bDvdCopyJob::~K3bDvdCopyJob() +{ + delete d; +} + + +void K3bDvdCopyJob::start() +{ + jobStarted(); + emit burning(false); + + d->canceled = false; + d->running = true; + d->readerRunning = d->writerRunning = false; + + emit newTask( i18n("Checking Source Medium") ); + + if( m_onTheFly && + k3bcore->externalBinManager()->binObject( "growisofs" )->version < K3bVersion( 5, 12 ) ) { + m_onTheFly = false; + emit infoMessage( i18n("K3b does not support writing on-the-fly with growisofs %1.") + .arg(k3bcore->externalBinManager()->binObject( "growisofs" )->version), ERROR ); + emit infoMessage( i18n("Disabling on-the-fly writing."), INFO ); + } + + emit newSubTask( i18n("Waiting for source medium") ); + + // wait for a source disk + if( waitForMedia( m_readerDevice, + K3bDevice::STATE_COMPLETE|K3bDevice::STATE_INCOMPLETE, + K3bDevice::MEDIA_WRITABLE_DVD|K3bDevice::MEDIA_DVD_ROM ) < 0 ) { + emit canceled(); + d->running = false; + jobFinished( false ); + return; + } + + emit newSubTask( i18n("Checking source medium") ); + + connect( K3bDevice::sendCommand( K3bDevice::DeviceHandler::DISKINFO, m_readerDevice ), + SIGNAL(finished(K3bDevice::DeviceHandler*)), + this, + SLOT(slotDiskInfoReady(K3bDevice::DeviceHandler*)) ); +} + + +void K3bDvdCopyJob::slotDiskInfoReady( K3bDevice::DeviceHandler* dh ) +{ + if( d->canceled ) { + emit canceled(); + jobFinished(false); + d->running = false; + } + + d->sourceDiskInfo = dh->diskInfo(); + + if( dh->diskInfo().empty() || dh->diskInfo().diskState() == K3bDevice::STATE_NO_MEDIA ) { + emit infoMessage( i18n("No source medium found."), ERROR ); + jobFinished(false); + d->running = false; + } + else { + if( m_readerDevice->copyrightProtectionSystemType() == 1 ) { + emit infoMessage( i18n("Found encrypted DVD."), WARNING ); + // check for libdvdcss + bool haveLibdvdcss = false; + kdDebug() << "(K3bDvdCopyJob) trying to open libdvdcss." << endl; + if( K3bLibDvdCss* libcss = K3bLibDvdCss::create() ) { + kdDebug() << "(K3bDvdCopyJob) succeeded." << endl; + kdDebug() << "(K3bDvdCopyJob) dvdcss_open(" << m_readerDevice->blockDeviceName() << ") = " + << libcss->open(m_readerDevice) << endl; + haveLibdvdcss = true; + + delete libcss; + } + else + kdDebug() << "(K3bDvdCopyJob) failed." << endl; + + if( !haveLibdvdcss ) { + emit infoMessage( i18n("Cannot copy encrypted DVDs."), ERROR ); + d->running = false; + jobFinished( false ); + return; + } + } + + + // + // We cannot rely on the kernel to determine the size of the DVD for some reason + // On the other hand it is not always a good idea to rely on the size from the ISO9660 + // header since that may be wrong due to some buggy encoder or some boot code appended + // after creating the image. + // That is why we try our best to determine the size of the DVD. For DVD-ROM this is very + // easy since it has only one track. The same goes for single session DVD-R(W) and DVD+R. + // Multisession DVDs we will simply not copy. ;) + // For DVD+RW and DVD-RW in restricted overwrite mode we are left with no other choice but + // to use the ISO9660 header. + // + // On the other hand: in on-the-fly mode growisofs determines the size of the data to be written + // by looking at the ISO9660 header when writing in DAO mode. So in this case + // it would be best for us to do the same.... + // + // With growisofs 5.15 we have the option to specify the size of the image to be written in DAO mode. + // + + switch( dh->diskInfo().mediaType() ) { + case K3bDevice::MEDIA_DVD_ROM: + case K3bDevice::MEDIA_DVD_PLUS_R_DL: + case K3bDevice::MEDIA_DVD_R_DL: + case K3bDevice::MEDIA_DVD_R_DL_SEQ: + case K3bDevice::MEDIA_DVD_R_DL_JUMP: + if( !m_onlyCreateImage ) { + if( dh->diskInfo().numLayers() > 1 && + dh->diskInfo().size().mode1Bytes() > 4700372992LL ) { + if( !(m_writerDevice->type() & (K3bDevice::DEVICE_DVD_R_DL|K3bDevice::DEVICE_DVD_PLUS_R_DL)) ) { + emit infoMessage( i18n("The writer does not support writing Double Layer DVD."), ERROR ); + d->running = false; + jobFinished(false); + return; + } + // FIXME: check for growisofs 5.22 (or whatever version is needed) for DVD-R DL + else if( k3bcore->externalBinManager()->binObject( "growisofs" ) && + k3bcore->externalBinManager()->binObject( "growisofs" )->version < K3bVersion( 5, 20 ) ) { + emit infoMessage( i18n("Growisofs >= 5.20 is needed to write Double Layer DVD+R."), ERROR ); + d->running = false; + jobFinished(false); + return; + } + } + } + case K3bDevice::MEDIA_DVD_R: + case K3bDevice::MEDIA_DVD_R_SEQ: + case K3bDevice::MEDIA_DVD_RW: + case K3bDevice::MEDIA_DVD_RW_SEQ: + case K3bDevice::MEDIA_DVD_PLUS_R: + + if( dh->diskInfo().numSessions() > 1 ) { + emit infoMessage( i18n("K3b does not support copying multi-session DVDs."), ERROR ); + d->running = false; + jobFinished(false); + return; + } + + // growisofs only uses the size from the PVD for reserving + // writable space in DAO mode + // with version >= 5.15 growisofs supports specifying the size of the track + if( m_writingMode != K3b::DAO || !m_onTheFly || m_onlyCreateImage || + ( k3bcore->externalBinManager()->binObject( "growisofs" ) && + k3bcore->externalBinManager()->binObject( "growisofs" )->version >= K3bVersion( 5, 15, -1 ) ) ) { + d->lastSector = dh->toc().lastSector(); + break; + } + + // fallthrough + + case K3bDevice::MEDIA_DVD_PLUS_RW: + case K3bDevice::MEDIA_DVD_RW_OVWR: + { + emit infoMessage( i18n("K3b relies on the size saved in the ISO9660 header."), WARNING ); + emit infoMessage( i18n("This might result in a corrupt copy if the source was mastered with buggy software."), WARNING ); + + K3bIso9660 isoF( m_readerDevice, 0 ); + if( isoF.open() ) { + d->lastSector = ((long long)isoF.primaryDescriptor().logicalBlockSize*isoF.primaryDescriptor().volumeSpaceSize)/2048LL - 1; + } + else { + emit infoMessage( i18n("Unable to determine the ISO9660 filesystem size."), ERROR ); + jobFinished(false); + d->running = false; + return; + } + } + break; + + case K3bDevice::MEDIA_DVD_RAM: + emit infoMessage( i18n("K3b does not support copying DVD-RAM."), ERROR ); + jobFinished(false); + d->running = false; + return; + + default: + emit infoMessage( i18n("Unable to determine DVD media type."), ERROR ); + jobFinished(false); + d->running = false; + return; + } + + + if( !m_onTheFly ) { + // + // Check the image path + // + QFileInfo fi( m_imagePath ); + if( !fi.isFile() || + questionYesNo( i18n("Do you want to overwrite %1?").arg(m_imagePath), + i18n("File Exists") ) ) { + if( fi.isDir() ) + m_imagePath = K3b::findTempFile( "iso", m_imagePath ); + else if( !QFileInfo( m_imagePath.section( '/', 0, -2 ) ).isDir() ) { + emit infoMessage( i18n("Specified an unusable temporary path. Using default."), WARNING ); + m_imagePath = K3b::findTempFile( "iso" ); + } + // else the user specified a file in an existing dir + + emit infoMessage( i18n("Writing image file to %1.").arg(m_imagePath), INFO ); + emit newSubTask( i18n("Reading source medium.") ); + } + + // + // check free temp space + // + KIO::filesize_t imageSpaceNeeded = (KIO::filesize_t)(d->lastSector.lba()+1)*2048; + unsigned long avail, size; + QString pathToTest = m_imagePath.left( m_imagePath.findRev( '/' ) ); + if( !K3b::kbFreeOnFs( pathToTest, size, avail ) ) { + emit infoMessage( i18n("Unable to determine free space in temporary directory '%1'.").arg(pathToTest), ERROR ); + jobFinished(false); + d->running = false; + return; + } + else { + if( avail < imageSpaceNeeded/1024 ) { + emit infoMessage( i18n("Not enough space left in temporary directory."), ERROR ); + jobFinished(false); + d->running = false; + return; + } + } + + d->imageFile.setName( m_imagePath ); + if( !d->imageFile.open( IO_WriteOnly ) ) { + emit infoMessage( i18n("Unable to open '%1' for writing.").arg(m_imagePath), ERROR ); + jobFinished( false ); + d->running = false; + return; + } + } + + if( K3b::isMounted( m_readerDevice ) ) { + emit infoMessage( i18n("Unmounting source medium"), INFO ); + K3b::unmount( m_readerDevice ); + } + + if( m_onlyCreateImage || !m_onTheFly ) { + emit newTask( i18n("Creating DVD image") ); + } + else if( m_onTheFly && !m_onlyCreateImage ) { + if( waitForDvd() ) { + prepareWriter(); + if( m_simulate ) + emit newTask( i18n("Simulating DVD copy") ); + else if( m_copies > 1 ) + emit newTask( i18n("Writing DVD copy %1").arg(d->doneCopies+1) ); + else + emit newTask( i18n("Writing DVD copy") ); + + emit burning(true); + d->writerRunning = true; + d->writerJob->start(); + } + else { + if( d->canceled ) + emit canceled(); + jobFinished(false); + d->running = false; + return; + } + } + + prepareReader(); + d->readerRunning = true; + d->dataTrackReader->start(); + } +} + + +void K3bDvdCopyJob::cancel() +{ + if( d->running ) { + d->canceled = true; + if( d->readerRunning ) + d->dataTrackReader->cancel(); + if( d->writerRunning ) + d->writerJob->cancel(); + d->inPipe.close(); + d->outPipe.close(); + d->imageFile.close(); + } + else { + kdDebug() << "(K3bDvdCopyJob) not running." << endl; + } +} + + +void K3bDvdCopyJob::prepareReader() +{ + if( !d->dataTrackReader ) { + d->dataTrackReader = new K3bDataTrackReader( this ); + connect( d->dataTrackReader, SIGNAL(percent(int)), this, SLOT(slotReaderProgress(int)) ); + connect( d->dataTrackReader, SIGNAL(processedSize(int, int)), this, SLOT(slotReaderProcessedSize(int, int)) ); + connect( d->dataTrackReader, SIGNAL(finished(bool)), this, SLOT(slotReaderFinished(bool)) ); + connect( d->dataTrackReader, SIGNAL(infoMessage(const QString&, int)), this, SIGNAL(infoMessage(const QString&, int)) ); + connect( d->dataTrackReader, SIGNAL(newTask(const QString&)), this, SIGNAL(newSubTask(const QString&)) ); + connect( d->dataTrackReader, SIGNAL(debuggingOutput(const QString&, const QString&)), + this, SIGNAL(debuggingOutput(const QString&, const QString&)) ); + } + + d->dataTrackReader->setDevice( m_readerDevice ); + d->dataTrackReader->setIgnoreErrors( m_ignoreReadErrors ); + d->dataTrackReader->setRetries( m_readRetries ); + d->dataTrackReader->setSectorRange( 0, d->lastSector ); + + if( m_onTheFly && !m_onlyCreateImage ) + d->inPipe.writeToFd( d->writerJob->fd(), true ); + else + d->inPipe.writeToIODevice( &d->imageFile ); + + d->inPipe.open( true ); + d->dataTrackReader->writeToFd( d->inPipe.in() ); +} + + +// ALWAYS CALL WAITFORDVD BEFORE PREPAREWRITER! +void K3bDvdCopyJob::prepareWriter() +{ + delete d->writerJob; + + d->writerJob = new K3bGrowisofsWriter( m_writerDevice, this ); + + connect( d->writerJob, SIGNAL(infoMessage(const QString&, int)), this, SIGNAL(infoMessage(const QString&, int)) ); + connect( d->writerJob, SIGNAL(percent(int)), this, SLOT(slotWriterProgress(int)) ); + connect( d->writerJob, SIGNAL(processedSize(int, int)), this, SIGNAL(processedSize(int, int)) ); + connect( d->writerJob, SIGNAL(processedSubSize(int, int)), this, SIGNAL(processedSubSize(int, int)) ); + connect( d->writerJob, SIGNAL(buffer(int)), this, SIGNAL(bufferStatus(int)) ); + connect( d->writerJob, SIGNAL(deviceBuffer(int)), this, SIGNAL(deviceBuffer(int)) ); + connect( d->writerJob, SIGNAL(writeSpeed(int, int)), this, SIGNAL(writeSpeed(int, int)) ); + connect( d->writerJob, SIGNAL(finished(bool)), this, SLOT(slotWriterFinished(bool)) ); + // connect( d->writerJob, SIGNAL(newTask(const QString&)), this, SIGNAL(newTask(const QString&)) ); + connect( d->writerJob, SIGNAL(newSubTask(const QString&)), this, SIGNAL(newSubTask(const QString&)) ); + connect( d->writerJob, SIGNAL(debuggingOutput(const QString&, const QString&)), + this, SIGNAL(debuggingOutput(const QString&, const QString&)) ); + + // these do only make sense with DVD-R(W) + d->writerJob->setSimulate( m_simulate ); + d->writerJob->setBurnSpeed( m_speed ); + d->writerJob->setWritingMode( d->usedWritingMode ); + d->writerJob->setCloseDvd( true ); + + // + // In case the first layer size is not known let the + // split be determined by growisofs + // + if( d->sourceDiskInfo.numLayers() > 1 && + d->sourceDiskInfo.firstLayerSize() > 0 ) { + d->writerJob->setLayerBreak( d->sourceDiskInfo.firstLayerSize().lba() ); + } + else { + // this is only used in DAO mode with growisofs >= 5.15 + d->writerJob->setTrackSize( d->lastSector.lba()+1 ); + } + + d->writerJob->setImageToWrite( QString::null ); // write to stdin +} + + +void K3bDvdCopyJob::slotReaderProgress( int p ) +{ + if( !m_onTheFly || m_onlyCreateImage ) { + emit subPercent( p ); + + int bigParts = ( m_onlyCreateImage ? 1 : (m_simulate ? 2 : ( d->verifyData ? m_copies*2 : m_copies ) + 1 ) ); + emit percent( p/bigParts ); + } +} + + +void K3bDvdCopyJob::slotReaderProcessedSize( int p, int c ) +{ + if( !m_onTheFly || m_onlyCreateImage ) + emit processedSubSize( p, c ); + + if( m_onlyCreateImage ) + emit processedSize( p, c ); +} + + +void K3bDvdCopyJob::slotWriterProgress( int p ) +{ + int bigParts = ( m_simulate ? 1 : ( d->verifyData ? m_copies*2 : m_copies ) ) + ( m_onTheFly ? 0 : 1 ); + int doneParts = ( m_simulate ? 0 : ( d->verifyData ? d->doneCopies*2 : d->doneCopies ) ) + ( m_onTheFly ? 0 : 1 ); + emit percent( 100*doneParts/bigParts + p/bigParts ); + + emit subPercent( p ); +} + + +void K3bDvdCopyJob::slotVerificationProgress( int p ) +{ + int bigParts = ( m_simulate ? 1 : ( d->verifyData ? m_copies*2 : m_copies ) ) + ( m_onTheFly ? 0 : 1 ); + int doneParts = ( m_simulate ? 0 : ( d->verifyData ? d->doneCopies*2 : d->doneCopies ) ) + ( m_onTheFly ? 0 : 1 ) + 1; + emit percent( 100*doneParts/bigParts + p/bigParts ); +} + + +void K3bDvdCopyJob::slotReaderFinished( bool success ) +{ + d->readerRunning = false; + + d->inPipe.close(); + + // close the socket + // otherwise growisofs will never quit. + // FIXME: is it posiible to do this in a generic manner? + if( d->writerJob ) + d->writerJob->closeFd(); + + // already finished? + if( !d->running ) + return; + + if( d->canceled ) { + removeImageFiles(); + emit canceled(); + jobFinished(false); + d->running = false; + } + + if( success ) { + emit infoMessage( i18n("Successfully read source DVD."), SUCCESS ); + if( m_onlyCreateImage ) { + jobFinished(true); + d->running = false; + } + else { + if( m_writerDevice == m_readerDevice ) { + // eject the media (we do this blocking to know if it worked + // because if it did not it might happen that k3b overwrites a CD-RW + // source) + if( !m_readerDevice->eject() ) { + blockingInformation( i18n("K3b was unable to eject the source disk. Please do so manually.") ); + } + } + + if( !m_onTheFly ) { + if( waitForDvd() ) { + prepareWriter(); + if( m_copies > 1 ) + emit newTask( i18n("Writing DVD copy %1").arg(d->doneCopies+1) ); + else + emit newTask( i18n("Writing DVD copy") ); + + emit burning(true); + + d->writerRunning = true; + d->writerJob->start(); + d->outPipe.writeToFd( d->writerJob->fd(), true ); + d->outPipe.open( true ); + } + else { + if( m_removeImageFiles ) + removeImageFiles(); + if( d->canceled ) + emit canceled(); + jobFinished(false); + d->running = false; + } + } + } + } + else { + removeImageFiles(); + jobFinished(false); + d->running = false; + } +} + + +void K3bDvdCopyJob::slotWriterFinished( bool success ) +{ + d->writerRunning = false; + + d->outPipe.close(); + + // already finished? + if( !d->running ) + return; + + if( d->canceled ) { + if( m_removeImageFiles ) + removeImageFiles(); + emit canceled(); + jobFinished(false); + d->running = false; + } + + if( success ) { + emit infoMessage( i18n("Successfully written DVD copy %1.").arg(d->doneCopies+1), INFO ); + + if( d->verifyData && !m_simulate ) { + if( !d->verificationJob ) { + d->verificationJob = new K3bVerificationJob( this, this ); + connect( d->verificationJob, SIGNAL(infoMessage(const QString&, int)), + this, SIGNAL(infoMessage(const QString&, int)) ); + connect( d->verificationJob, SIGNAL(newTask(const QString&)), + this, SIGNAL(newSubTask(const QString&)) ); + connect( d->verificationJob, SIGNAL(percent(int)), + this, SLOT(slotVerificationProgress(int)) ); + connect( d->verificationJob, SIGNAL(percent(int)), + this, SIGNAL(subPercent(int)) ); + connect( d->verificationJob, SIGNAL(finished(bool)), + this, SLOT(slotVerificationFinished(bool)) ); + connect( d->verificationJob, SIGNAL(debuggingOutput(const QString&, const QString&)), + this, SIGNAL(debuggingOutput(const QString&, const QString&)) ); + + } + d->verificationJob->setDevice( m_writerDevice ); + d->verificationJob->addTrack( 1, d->inPipe.checksum(), d->lastSector+1 ); + + if( m_copies > 1 ) + emit newTask( i18n("Verifying DVD copy %1").arg(d->doneCopies+1) ); + else + emit newTask( i18n("Verifying DVD copy") ); + + emit burning( false ); + + d->verificationJob->start(); + } + + else if( ++d->doneCopies < m_copies ) { + + if ( !m_writerDevice->eject() ) { + blockingInformation( i18n("K3b was unable to eject the written disk. Please do so manually.") ); + } + + if( waitForDvd() ) { + prepareWriter(); + emit newTask( i18n("Writing DVD copy %1").arg(d->doneCopies+1) ); + + emit burning(true); + + d->writerRunning = true; + d->writerJob->start(); + } + else { + if( d->canceled ) + emit canceled(); + jobFinished(false); + d->running = false; + return; + } + + if( m_onTheFly ) { + prepareReader(); + d->readerRunning = true; + d->dataTrackReader->start(); + } + else { + d->outPipe.writeToFd( d->writerJob->fd(), true ); + d->outPipe.open( true ); + } + } + else { + if( m_removeImageFiles ) + removeImageFiles(); + d->running = false; + jobFinished(true); + } + } + else { + if( m_removeImageFiles ) + removeImageFiles(); + d->running = false; + jobFinished(false); + } +} + + +void K3bDvdCopyJob::slotVerificationFinished( bool success ) +{ + // we simply ignore the results from the verification, the verification + // job already emits a message + if( ++d->doneCopies < m_copies ) { + + if( waitForDvd() ) { + prepareWriter(); + emit newTask( i18n("Writing DVD copy %1").arg(d->doneCopies+1) ); + + emit burning(true); + + d->writerRunning = true; + d->writerJob->start(); + } + else { + if( d->canceled ) + emit canceled(); + jobFinished(false); + d->running = false; + return; + } + + if( m_onTheFly ) { + prepareReader(); + d->readerRunning = true; + d->dataTrackReader->start(); + } + else { + d->outPipe.writeToFd( d->writerJob->fd(), true ); + d->outPipe.open( true ); + } + } + else { + if( m_removeImageFiles ) + removeImageFiles(); + d->running = false; + jobFinished( success ); + } +} + + +// this is basically the same code as in K3bDvdJob... :( +// perhaps this should be moved to some K3bGrowisofsHandler which also parses the growisofs output? +bool K3bDvdCopyJob::waitForDvd() +{ + int mt = 0; + if( m_writingMode == K3b::WRITING_MODE_RES_OVWR ) // we treat DVD+R(W) as restricted overwrite media + mt = K3bDevice::MEDIA_DVD_RW_OVWR|K3bDevice::MEDIA_DVD_PLUS_RW|K3bDevice::MEDIA_DVD_PLUS_R; + else + mt = K3bDevice::MEDIA_WRITABLE_DVD_SL; + + // + // in case the source is a double layer DVD we made sure above that the writer + // is capable of writing DVD+R-DL or DVD-R DL and here we wait for a DL DVD + // + if( d->sourceDiskInfo.numLayers() > 1 && + d->sourceDiskInfo.size().mode1Bytes() > 4700372992LL ) { + mt = K3bDevice::MEDIA_WRITABLE_DVD_DL; + } + + int m = waitForMedia( m_writerDevice, K3bDevice::STATE_EMPTY, mt ); + + if( m < 0 ) { + cancel(); + return false; + } + + if( m == 0 ) { + emit infoMessage( i18n("Forced by user. Growisofs will be called without further tests."), INFO ); + } + + else { + // ------------------------------- + // DVD Plus + // ------------------------------- + if( m & K3bDevice::MEDIA_DVD_PLUS_ALL ) { + + d->usedWritingMode = K3b::WRITING_MODE_RES_OVWR; + + if( m_simulate ) { + if( !questionYesNo( i18n("K3b does not support simulation with DVD+R(W) media. " + "Do you really want to continue? The media will actually be " + "written to."), + i18n("No Simulation with DVD+R(W)") ) ) { + cancel(); + return false; + } + +// m_simulate = false; + emit newTask( i18n("Writing DVD copy") ); + } + + if( m_writingMode != K3b::WRITING_MODE_AUTO && m_writingMode != K3b::WRITING_MODE_RES_OVWR ) + emit infoMessage( i18n("Writing mode ignored when writing DVD+R(W) media."), INFO ); + + if( m & K3bDevice::MEDIA_DVD_PLUS_RW ) + emit infoMessage( i18n("Writing DVD+RW."), INFO ); + else if( m & K3bDevice::MEDIA_DVD_PLUS_R_DL ) + emit infoMessage( i18n("Writing Double Layer DVD+R."), INFO ); + else + emit infoMessage( i18n("Writing DVD+R."), INFO ); + } + + // ------------------------------- + // DVD Minus + // ------------------------------- + else { + if( m_simulate && !m_writerDevice->dvdMinusTestwrite() ) { + if( !questionYesNo( i18n("Your writer (%1 %2) does not support simulation with DVD-R(W) media. " + "Do you really want to continue? The media will be written " + "for real.") + .arg(m_writerDevice->vendor()) + .arg(m_writerDevice->description()), + i18n("No Simulation with DVD-R(W)") ) ) { + cancel(); + return false; + } + +// m_simulate = false; + } + + // + // We do not default to DAO in onthefly mode since otherwise growisofs would + // use the size from the PVD to reserve space on the DVD and that can be bad + // if this size is wrong + // With growisofs 5.15 we have the option to specify the size of the image to be written in DAO mode. + // +// bool sizeWithDao = ( k3bcore->externalBinManager()->binObject( "growisofs" ) && +// k3bcore->externalBinManager()->binObject( "growisofs" )->version >= K3bVersion( 5, 15, -1 ) ); + + + // TODO: check for feature 0x21 + + if( m & K3bDevice::MEDIA_DVD_RW_OVWR ) { + emit infoMessage( i18n("Writing DVD-RW in restricted overwrite mode."), INFO ); + d->usedWritingMode = K3b::WRITING_MODE_RES_OVWR; + } + else if( m & (K3bDevice::MEDIA_DVD_RW_SEQ| + K3bDevice::MEDIA_DVD_RW) ) { + if( m_writingMode == K3b::DAO ) { +// ( m_writingMode == K3b::WRITING_MODE_AUTO && +// ( sizeWithDao || !m_onTheFly ) ) ) { + emit infoMessage( i18n("Writing DVD-RW in DAO mode."), INFO ); + d->usedWritingMode = K3b::DAO; + } + else { + emit infoMessage( i18n("Writing DVD-RW in incremental mode."), INFO ); + d->usedWritingMode = K3b::WRITING_MODE_INCR_SEQ; + } + } + else { + + // FIXME: DVD-R DL jump and stuff + + if( m_writingMode == K3b::WRITING_MODE_RES_OVWR ) + emit infoMessage( i18n("Restricted Overwrite is not possible with DVD-R media."), INFO ); + + if( m_writingMode == K3b::DAO ) { +// ( m_writingMode == K3b::WRITING_MODE_AUTO && +// ( sizeWithDao || !m_onTheFly ) ) ) { + emit infoMessage( i18n("Writing %1 in DAO mode.").arg( K3bDevice::mediaTypeString(m, true) ), INFO ); + d->usedWritingMode = K3b::DAO; + } + else { + emit infoMessage( i18n("Writing %1 in incremental mode.").arg( K3bDevice::mediaTypeString(m, true) ), INFO ); + d->usedWritingMode = K3b::WRITING_MODE_INCR_SEQ; + } + } + } + } + + return true; +} + + + +void K3bDvdCopyJob::removeImageFiles() +{ + if( QFile::exists( m_imagePath ) ) { + d->imageFile.remove(); + emit infoMessage( i18n("Removed image file %1").arg(m_imagePath), K3bJob::SUCCESS ); + } +} + + +QString K3bDvdCopyJob::jobDescription() const +{ + if( m_onlyCreateImage ) { + return i18n("Creating DVD Image"); + } + else { + if( m_onTheFly ) + return i18n("Copying DVD On-The-Fly"); + else + return i18n("Copying DVD"); + } +} + + +QString K3bDvdCopyJob::jobDetails() const +{ + return i18n("Creating 1 copy", + "Creating %n copies", + (m_simulate||m_onlyCreateImage) ? 1 : m_copies ); +} + + +void K3bDvdCopyJob::setVerifyData( bool b ) +{ + d->verifyData = b; +} + +#include "k3bdvdcopyjob.moc" diff --git a/libk3b/jobs/k3bdvdcopyjob.h b/libk3b/jobs/k3bdvdcopyjob.h new file mode 100644 index 0000000..91da4e9 --- /dev/null +++ b/libk3b/jobs/k3bdvdcopyjob.h @@ -0,0 +1,99 @@ +/* + * + * $Id: k3bdvdcopyjob.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_DVD_COPY_JOB_H_ +#define _K3B_DVD_COPY_JOB_H_ + +#include +#include "k3b_export.h" +#include + + +namespace K3bDevice { + class Device; + class DeviceHandler; +} + + +class LIBK3B_EXPORT K3bDvdCopyJob : public K3bBurnJob +{ + Q_OBJECT + + public: + K3bDvdCopyJob( K3bJobHandler* hdl, QObject* parent = 0, const char* name = 0 ); + ~K3bDvdCopyJob(); + + K3bDevice::Device* writer() const { return m_onlyCreateImage ? 0 : m_writerDevice; } + K3bDevice::Device* readingDevice() const { return m_readerDevice; } + + QString jobDescription() const; + QString jobDetails() const; + + public slots: + void start(); + void cancel(); + + void setWriterDevice( K3bDevice::Device* w ) { m_writerDevice = w; } + void setReaderDevice( K3bDevice::Device* w ) { m_readerDevice = w; } + void setImagePath( const QString& p ) { m_imagePath = p; } + void setRemoveImageFiles( bool b ) { m_removeImageFiles = b; } + void setOnlyCreateImage( bool b ) { m_onlyCreateImage = b; } + void setSimulate( bool b ) { m_simulate = b; } + void setOnTheFly( bool b ) { m_onTheFly = b; } + void setWriteSpeed( int s ) { m_speed = s; } + void setCopies( int c ) { m_copies = c; } + void setWritingMode( int w ) { m_writingMode = w; } + void setIgnoreReadErrors( bool b ) { m_ignoreReadErrors = b; } + void setReadRetries( int i ) { m_readRetries = i; } + void setVerifyData( bool b ); + + private slots: + void slotDiskInfoReady( K3bDevice::DeviceHandler* ); + void slotReaderProgress( int ); + void slotReaderProcessedSize( int, int ); + void slotWriterProgress( int ); + void slotReaderFinished( bool ); + void slotWriterFinished( bool ); + void slotVerificationFinished( bool ); + void slotVerificationProgress( int p ); + + private: + bool waitForDvd(); + void prepareReader(); + void prepareWriter(); + void removeImageFiles(); + + K3bDevice::Device* m_writerDevice; + K3bDevice::Device* m_readerDevice; + QString m_imagePath; + + bool m_onTheFly; + bool m_removeImageFiles; + + bool m_simulate; + int m_speed; + int m_copies; + bool m_onlyCreateImage; + bool m_ignoreReadErrors; + int m_readRetries; + + int m_writingMode; + + class Private; + Private* d; +}; + + +#endif diff --git a/libk3b/jobs/k3bdvdformattingjob.cpp b/libk3b/jobs/k3bdvdformattingjob.cpp new file mode 100644 index 0000000..732e404 --- /dev/null +++ b/libk3b/jobs/k3bdvdformattingjob.cpp @@ -0,0 +1,536 @@ +/* + * + * $Id: k3bdvdformattingjob.cpp 696897 2007-08-06 07:14:14Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bdvdformattingjob.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + + +class K3bDvdFormattingJob::Private +{ +public: + Private() + : quick(false), + force(false), + mode(K3b::WRITING_MODE_AUTO), + device(0), + process(0), + dvdFormatBin(0), + lastProgressValue(0), + running(false), + forceNoEject(false) { + } + + bool quick; + bool force; + int mode; + + K3bDevice::Device* device; + K3bProcess* process; + const K3bExternalBin* dvdFormatBin; + + int lastProgressValue; + + bool success; + bool canceled; + bool running; + + bool forceNoEject; + + bool error; +}; + + +K3bDvdFormattingJob::K3bDvdFormattingJob( K3bJobHandler* jh, QObject* parent, const char* name ) + : K3bBurnJob( jh, parent, name ) +{ + d = new Private; +} + + +K3bDvdFormattingJob::~K3bDvdFormattingJob() +{ + delete d->process; + delete d; +} + + +K3bDevice::Device* K3bDvdFormattingJob::writer() const +{ + return d->device; +} + + +void K3bDvdFormattingJob::setForceNoEject( bool b ) +{ + d->forceNoEject = b; +} + + +QString K3bDvdFormattingJob::jobDescription() const +{ + return i18n("Formatting DVD"); // Formatting DVD±RW +} + + +QString K3bDvdFormattingJob::jobDetails() const +{ + if( d->quick ) + return i18n("Quick Format"); + else + return QString::null; +} + + +void K3bDvdFormattingJob::start() +{ + d->canceled = false; + d->running = true; + d->error = false; + + jobStarted(); + + if( !d->device ) { + emit infoMessage( i18n("No device set"), ERROR ); + d->running = false; + jobFinished(false); + return; + } + + // FIXME: check the return value + if( K3b::isMounted( d->device ) ) { + emit infoMessage( i18n("Unmounting medium"), INFO ); + K3b::unmount( d->device ); + } + + // + // first wait for a dvd+rw or dvd-rw + // Be aware that an empty DVD-RW might be reformatted to another writing mode + // so we also wait for empty dvds + // + if( waitForMedia( d->device, + K3bDevice::STATE_COMPLETE|K3bDevice::STATE_INCOMPLETE|K3bDevice::STATE_EMPTY, + K3bDevice::MEDIA_WRITABLE_DVD, + i18n("Please insert a rewritable DVD medium into drive

%1 %2 (%3).") + .arg(d->device->vendor()).arg(d->device->description()).arg(d->device->devicename()) ) == -1 ) { + emit canceled(); + d->running = false; + jobFinished(false); + return; + } + + emit infoMessage( i18n("Checking media..."), INFO ); + emit newTask( i18n("Checking media") ); + + connect( K3bDevice::sendCommand( K3bDevice::DeviceHandler::NG_DISKINFO, d->device ), + SIGNAL(finished(K3bDevice::DeviceHandler*)), + this, + SLOT(slotDeviceHandlerFinished(K3bDevice::DeviceHandler*)) ); +} + + +void K3bDvdFormattingJob::start( const K3bDevice::DiskInfo& di ) +{ + d->canceled = false; + d->running = true; + + jobStarted(); + + startFormatting( di ); +} + + +void K3bDvdFormattingJob::cancel() +{ + if( d->running ) { + d->canceled = true; + if( d->process ) + d->process->kill(); + } + else { + kdDebug() << "(K3bDvdFormattingJob) not running." << endl; + } +} + + +void K3bDvdFormattingJob::setDevice( K3bDevice::Device* dev ) +{ + d->device = dev; +} + + +void K3bDvdFormattingJob::setMode( int m ) +{ + d->mode = m; +} + + +void K3bDvdFormattingJob::setQuickFormat( bool b ) +{ + d->quick = b; +} + + +void K3bDvdFormattingJob::setForce( bool b ) +{ + d->force = b; +} + + +void K3bDvdFormattingJob::slotStderrLine( const QString& line ) +{ +// * DVDRW format utility by , version 4.4. +// * 4.7GB DVD-RW media in Sequential mode detected. +// * blanking 100.0| + +// * formatting 100.0| + + emit debuggingOutput( "dvd+rw-format", line ); + + // parsing for the -gui mode (since dvd+rw-format 4.6) + int pos = line.find( "blanking" ); + if( pos < 0 ) + pos = line.find( "formatting" ); + if( pos >= 0 ) { + pos = line.find( QRegExp( "\\d" ), pos ); + } + // parsing for \b\b... stuff + else if( !line.startsWith("*") ) { + pos = line.find( QRegExp( "\\d" ) ); + } + else if( line.startsWith( ":-(" ) ) { + if( line.startsWith( ":-( unable to proceed with format" ) ) { + d->error = true; + } + } + + if( pos >= 0 ) { + int endPos = line.find( QRegExp("[^\\d\\.]"), pos ) - 1; + bool ok; + int progress = (int)(line.mid( pos, endPos - pos ).toDouble(&ok)); + if( ok ) { + d->lastProgressValue = progress; + emit percent( progress ); + } + else { + kdDebug() << "(K3bDvdFormattingJob) parsing error: '" << line.mid( pos, endPos - pos ) << "'" << endl; + } + } +} + + +void K3bDvdFormattingJob::slotProcessFinished( KProcess* p ) +{ + if( d->canceled ) { + emit canceled(); + d->success = false; + } + else if( p->normalExit() ) { + if( !d->error && p->exitStatus() == 0 ) { + emit infoMessage( i18n("Formatting successfully completed"), K3bJob::SUCCESS ); + + if( d->lastProgressValue < 100 ) { + emit infoMessage( i18n("Do not be concerned with the progress stopping before 100%."), INFO ); + emit infoMessage( i18n("The formatting will continue in the background while writing."), INFO ); + } + + d->success = true; + } + else { + emit infoMessage( i18n("%1 returned an unknown error (code %2).").arg(d->dvdFormatBin->name()).arg(p->exitStatus()), + K3bJob::ERROR ); + emit infoMessage( i18n("Please send me an email with the last output."), K3bJob::ERROR ); + + d->success = false; + } + } + else { + emit infoMessage( i18n("%1 did not exit cleanly.").arg(d->dvdFormatBin->name()), + ERROR ); + d->success = false; + } + + if( d->forceNoEject || + !k3bcore->globalSettings()->ejectMedia() ) { + d->running = false; + jobFinished(d->success); + } + else { + emit infoMessage( i18n("Ejecting DVD..."), INFO ); + connect( K3bDevice::eject( d->device ), + SIGNAL(finished(K3bDevice::DeviceHandler*)), + this, + SLOT(slotEjectingFinished(K3bDevice::DeviceHandler*)) ); + } +} + + +void K3bDvdFormattingJob::slotEjectingFinished( K3bDevice::DeviceHandler* dh ) +{ + if( !dh->success() ) + emit infoMessage( i18n("Unable to eject media."), ERROR ); + + d->running = false; + jobFinished(d->success); +} + + +void K3bDvdFormattingJob::slotDeviceHandlerFinished( K3bDevice::DeviceHandler* dh ) +{ + if( d->canceled ) { + emit canceled(); + jobFinished(false); + d->running = false; + } + + if( dh->success() ) { + startFormatting( dh->diskInfo() ); + } + else { + emit infoMessage( i18n("Unable to determine media state."), ERROR ); + d->running = false; + jobFinished(false); + } +} + + +void K3bDvdFormattingJob::startFormatting( const K3bDevice::DiskInfo& diskInfo ) +{ + // + // Now check the media type: + // if DVD-RW: use d->mode + // emit warning if formatting is full and stuff + // + // in overwrite mode: emit info that progress might stop before 100% since formatting will continue + // in the background once the media gets rewritten (only DVD+RW?) + // + + // emit info about what kind of media has been found + + if( !(diskInfo.mediaType() & (K3bDevice::MEDIA_DVD_RW| + K3bDevice::MEDIA_DVD_RW_SEQ| + K3bDevice::MEDIA_DVD_RW_OVWR| + K3bDevice::MEDIA_DVD_PLUS_RW)) ) { + emit infoMessage( i18n("No rewritable DVD media found. Unable to format."), ERROR ); + d->running = false; + jobFinished(false); + return; + } + + + bool format = true; // do we need to format + bool blank = false; // blank is for DVD-RW sequential incremental + // DVD-RW restricted overwrite and DVD+RW uses the force option (or no option at all) + + + + // + // DVD+RW is quite easy to handle. There is only one possible mode and it is always recommended to not + // format it more than once but to overwrite it once it is formatted + // Once the initial formatting has been done it's always "appendable" (or "complete"???) + // + + + if( diskInfo.mediaType() == K3bDevice::MEDIA_DVD_PLUS_RW ) { + emit infoMessage( i18n("Found %1 media.").arg(K3bDevice::mediaTypeString(K3bDevice::MEDIA_DVD_PLUS_RW)), + INFO ); + + // mode is ignored + + if( diskInfo.empty() ) { + // + // The DVD+RW is blank and needs to be initially formatted + // + blank = false; + } + else { + emit infoMessage( i18n("No need to format %1 media more than once.") + .arg(K3bDevice::mediaTypeString(K3bDevice::MEDIA_DVD_PLUS_RW)), INFO ); + emit infoMessage( i18n("It may simply be overwritten."), INFO ); + + if( d->force ) { + emit infoMessage( i18n("Forcing formatting anyway."), INFO ); + emit infoMessage( i18n("It is not recommended to force formatting of DVD+RW media."), INFO ); + emit infoMessage( i18n("Already after 10-20 reformats the media might be unusable."), INFO ); + blank = false; + } + else { + format = false; + } + } + + if( format ) + emit newSubTask( i18n("Formatting DVD+RW") ); + } + + + + // + // DVD-RW has two modes: incremental sequential (the default which is also needed for DAO writing) + // and restricted overwrite which compares to the DVD+RW mode. + // + + else { // MEDIA_DVD_RW + emit infoMessage( i18n("Found %1 media.").arg(K3bDevice::mediaTypeString(K3bDevice::MEDIA_DVD_RW)), + INFO ); + + if( diskInfo.currentProfile() != K3bDevice::MEDIA_UNKNOWN ) { + emit infoMessage( i18n("Formatted in %1 mode.").arg(K3bDevice::mediaTypeString(diskInfo.currentProfile())), INFO ); + + + // + // Is it possible to have an empty DVD-RW in restricted overwrite mode???? I don't think so. + // + + if( diskInfo.empty() && + (d->mode == K3b::WRITING_MODE_AUTO || + (d->mode == K3b::WRITING_MODE_INCR_SEQ && + diskInfo.currentProfile() == K3bDevice::MEDIA_DVD_RW_SEQ) || + (d->mode == K3b::WRITING_MODE_RES_OVWR && + diskInfo.currentProfile() == K3bDevice::MEDIA_DVD_RW_OVWR) ) + ) { + emit infoMessage( i18n("Media is already empty."), INFO ); + if( d->force ) + emit infoMessage( i18n("Forcing formatting anyway."), INFO ); + else + format = false; + } + else if( diskInfo.currentProfile() == K3bDevice::MEDIA_DVD_RW_OVWR && + d->mode != K3b::WRITING_MODE_INCR_SEQ ) { + emit infoMessage( i18n("No need to format %1 media more than once.") + .arg(K3bDevice::mediaTypeString(diskInfo.currentProfile())), INFO ); + emit infoMessage( i18n("It may simply be overwritten."), INFO ); + + if( d->force ) + emit infoMessage( i18n("Forcing formatting anyway."), INFO ); + else + format = false; + } + + + if( format ) { + if( d->mode == K3b::WRITING_MODE_AUTO ) { + // just format in the same mode as the media is currently formatted + blank = (diskInfo.currentProfile() == K3bDevice::MEDIA_DVD_RW_SEQ); + } + else { + blank = (d->mode == K3b::WRITING_MODE_INCR_SEQ); + } + + emit newSubTask( i18n("Formatting" + " DVD-RW in %1 mode.").arg(K3bDevice::mediaTypeString( blank ? + K3bDevice::MEDIA_DVD_RW_SEQ : + K3bDevice::MEDIA_DVD_RW_OVWR )) ); + } + } + else { + emit infoMessage( i18n("Unable to determine the current formatting state of the DVD-RW media."), ERROR ); + d->running = false; + jobFinished(false); + return; + } + } + + + if( format ) { + delete d->process; + d->process = new K3bProcess(); + d->process->setRunPrivileged(true); + // d->process->setSuppressEmptyLines(false); + connect( d->process, SIGNAL(stderrLine(const QString&)), this, SLOT(slotStderrLine(const QString&)) ); + connect( d->process, SIGNAL(processExited(KProcess*)), this, SLOT(slotProcessFinished(KProcess*)) ); + + d->dvdFormatBin = k3bcore->externalBinManager()->binObject( "dvd+rw-format" ); + if( !d->dvdFormatBin ) { + emit infoMessage( i18n("Could not find %1 executable.").arg("dvd+rw-format"), ERROR ); + d->running = false; + jobFinished(false); + return; + } + + if( !d->dvdFormatBin->copyright.isEmpty() ) + emit infoMessage( i18n("Using %1 %2 - Copyright (C) %3").arg(d->dvdFormatBin->name()).arg(d->dvdFormatBin->version).arg(d->dvdFormatBin->copyright), INFO ); + + + *d->process << d->dvdFormatBin; + + if( d->dvdFormatBin->version >= K3bVersion( 4, 6 ) ) + *d->process << "-gui"; + + QString p; + if( blank ) + p = "-blank"; + else + p = "-force"; + if( !d->quick ) + p += "=full"; + + *d->process << p; + + *d->process << d->device->blockDeviceName(); + + // additional user parameters from config + const QStringList& params = d->dvdFormatBin->userParameters(); + for( QStringList::const_iterator it = params.begin(); it != params.end(); ++it ) + *d->process << *it; + + kdDebug() << "***** dvd+rw-format parameters:\n"; + const QValueList& args = d->process->args(); + QString s; + for( QValueList::const_iterator it = args.begin(); it != args.end(); ++it ) { + s += *it + " "; + } + kdDebug() << s << endl << flush; + emit debuggingOutput( "dvd+rw-format command:", s ); + + if( !d->process->start( KProcess::NotifyOnExit, KProcess::All ) ) { + // something went wrong when starting the program + // it "should" be the executable + kdDebug() << "(K3bDvdFormattingJob) could not start " << d->dvdFormatBin->path << endl; + emit infoMessage( i18n("Could not start %1.").arg(d->dvdFormatBin->name()), K3bJob::ERROR ); + d->running = false; + jobFinished(false); + } + else { + emit newTask( i18n("Formatting") ); + } + } + else { + // already formatted :) + d->running = false; + jobFinished(true); + } +} + + +#include "k3bdvdformattingjob.moc" diff --git a/libk3b/jobs/k3bdvdformattingjob.h b/libk3b/jobs/k3bdvdformattingjob.h new file mode 100644 index 0000000..10672cb --- /dev/null +++ b/libk3b/jobs/k3bdvdformattingjob.h @@ -0,0 +1,91 @@ +/* + * + * $Id: k3bdvdformattingjob.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_DVD_FORMATTING_JOB_H_ +#define _K3B_DVD_FORMATTING_JOB_H_ + + +#include +#include "k3b_export.h" + +class KProcess; +namespace K3bDevice { + class Device; + class DeviceHandler; +} + + +class LIBK3B_EXPORT K3bDvdFormattingJob : public K3bBurnJob +{ + Q_OBJECT + + public: + K3bDvdFormattingJob( K3bJobHandler*, QObject* parent = 0, const char* name = 0 ); + ~K3bDvdFormattingJob(); + + QString jobDescription() const; + QString jobDetails() const; + + K3bDevice::Device* writer() const; + + public slots: + void start(); + + /** + * Use this to force the start of the formatting without checking for a usable medium. + */ + void start( const K3bDevice::DiskInfo& ); + + void cancel(); + + void setDevice( K3bDevice::Device* ); + + /** + * One of: WRITING_MODE_INCR_SEQ, WRITING_MODE_RES_OVWR + * Ignored for DVD+RW + */ + void setMode( int ); + + /** + * Not all writers support this + */ + void setQuickFormat( bool ); + + /** + * @param b If true empty DVDs will also be formatted + */ + void setForce( bool b ); + + /** + * If set true the job ignores the global K3b setting + * and does not eject the CD-RW after finishing + */ + void setForceNoEject( bool ); + + private slots: + void slotStderrLine( const QString& ); + void slotProcessFinished( KProcess* ); + void slotDeviceHandlerFinished( K3bDevice::DeviceHandler* ); + void slotEjectingFinished( K3bDevice::DeviceHandler* ); + + private: + void startFormatting( const K3bDevice::DiskInfo& ); + + class Private; + Private* d; +}; + + +#endif diff --git a/libk3b/jobs/k3biso9660imagewritingjob.cpp b/libk3b/jobs/k3biso9660imagewritingjob.cpp new file mode 100644 index 0000000..1fb3871 --- /dev/null +++ b/libk3b/jobs/k3biso9660imagewritingjob.cpp @@ -0,0 +1,458 @@ +/* + * + * $Id: k3biso9660imagewritingjob.cpp 690187 2007-07-20 09:18:03Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3biso9660imagewritingjob.h" +#include "k3bverificationjob.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +class K3bIso9660ImageWritingJob::Private +{ +public: + K3bChecksumPipe checksumPipe; + K3bFileSplitter imageFile; +}; + + +K3bIso9660ImageWritingJob::K3bIso9660ImageWritingJob( K3bJobHandler* hdl ) + : K3bBurnJob( hdl ), + m_writingMode(K3b::WRITING_MODE_AUTO), + m_simulate(false), + m_device(0), + m_noFix(false), + m_speed(2), + m_dataMode(K3b::DATA_MODE_AUTO), + m_writer(0), + m_tocFile(0), + m_copies(1), + m_verifyJob(0) +{ + d = new Private; +} + +K3bIso9660ImageWritingJob::~K3bIso9660ImageWritingJob() +{ + delete m_tocFile; + delete d; +} + + +void K3bIso9660ImageWritingJob::start() +{ + m_canceled = m_finished = false; + m_currentCopy = 1; + + jobStarted(); + + if( m_simulate ) + m_verifyData = false; + + emit newTask( i18n("Preparing data") ); + + if( !QFile::exists( m_imagePath ) ) { + emit infoMessage( i18n("Could not find image %1").arg(m_imagePath), K3bJob::ERROR ); + jobFinished( false ); + return; + } + + unsigned long gb = K3b::imageFilesize( m_imagePath )/1024/1024; + + // very rough test but since most dvd images are 4,x or 8,x GB it should be enough + m_dvd = ( gb > 900 ); + + startWriting(); +} + + +void K3bIso9660ImageWritingJob::slotWriterJobFinished( bool success ) +{ + if( m_canceled ) { + m_finished = true; + emit canceled(); + jobFinished(false); + return; + } + + d->checksumPipe.close(); + + if( success ) { + if( !m_simulate && m_verifyData ) { + emit burning(false); + + // allright + // the writerJob should have emited the "simulation/writing successful" signal + + if( !m_verifyJob ) { + m_verifyJob = new K3bVerificationJob( this ); + connectSubJob( m_verifyJob, + SLOT(slotVerificationFinished(bool)), + true, + SLOT(slotVerificationProgress(int)), + SIGNAL(subPercent(int)) ); + } + m_verifyJob->setDevice( m_device ); + m_verifyJob->clear(); + m_verifyJob->addTrack( 1, d->checksumPipe.checksum(), K3b::imageFilesize( m_imagePath )/2048 ); + + if( m_copies == 1 ) + emit newTask( i18n("Verifying written data") ); + else + emit newTask( i18n("Verifying written copy %1 of %2").arg(m_currentCopy).arg(m_copies) ); + + m_verifyJob->start(); + } + else if( m_currentCopy >= m_copies ) { + m_finished = true; + jobFinished(true); + } + else { + m_currentCopy++; + startWriting(); + } + } + else { + m_finished = true; + jobFinished(false); + } +} + + +void K3bIso9660ImageWritingJob::slotVerificationFinished( bool success ) +{ + if( m_canceled ) { + m_finished = true; + emit canceled(); + jobFinished(false); + return; + } + + if( success && m_currentCopy < m_copies ) { + m_currentCopy++; + connect( K3bDevice::eject( m_device ), SIGNAL(finished(bool)), + this, SLOT(startWriting()) ); + return; + } + + k3bcore->config()->setGroup("General Options"); + if( !k3bcore->config()->readBoolEntry( "No cd eject", false ) ) + K3bDevice::eject( m_device ); + + m_finished = true; + jobFinished( success ); +} + + +void K3bIso9660ImageWritingJob::slotVerificationProgress( int p ) +{ + emit percent( (int)(100.0 / (double)m_copies * ( (double)(m_currentCopy-1) + 0.5 + (double)p/200.0 )) ); +} + + +void K3bIso9660ImageWritingJob::slotWriterPercent( int p ) +{ + emit subPercent( p ); + + if( m_verifyData ) + emit percent( (int)(100.0 / (double)m_copies * ( (double)(m_currentCopy-1) + ((double)p/200.0) )) ); + else + emit percent( (int)(100.0 / (double)m_copies * ( (double)(m_currentCopy-1) + ((double)p/100.0) )) ); +} + + +void K3bIso9660ImageWritingJob::slotNextTrack( int, int ) +{ + if( m_copies == 1 ) + emit newSubTask( i18n("Writing image") ); + else + emit newSubTask( i18n("Writing copy %1 of %2").arg(m_currentCopy).arg(m_copies) ); +} + + +void K3bIso9660ImageWritingJob::cancel() +{ + if( !m_finished ) { + m_canceled = true; + + if( m_writer ) + m_writer->cancel(); + if( m_verifyData && m_verifyJob ) + m_verifyJob->cancel(); + } +} + + +void K3bIso9660ImageWritingJob::startWriting() +{ + emit newSubTask( i18n("Waiting for medium") ); + + // we wait for the following: + // 1. if writing mode auto and writing app auto: all writable media types + // 2. if writing mode auto and writing app not growisofs: all writable cd types + // 3. if writing mode auto and writing app growisofs: all writable dvd types + // 4. if writing mode TAO or RAW: all writable cd types + // 5. if writing mode DAO and writing app auto: all writable cd types and DVD-R(W) + // 6. if writing mode DAO and writing app GROWISOFS: DVD-R(W) + // 7. if writing mode DAO and writing app CDRDAO or CDRECORD: all writable cd types + // 8. if writing mode WRITING_MODE_INCR_SEQ: DVD-R(W) + // 9. if writing mode WRITING_MODE_RES_OVWR: DVD-RW or DVD+RW + + int mt = 0; + if( m_writingMode == K3b::WRITING_MODE_AUTO ) { + if( writingApp() == K3b::DEFAULT ) { + if( m_dvd ) + mt = K3bDevice::MEDIA_WRITABLE_DVD; + else + mt = K3bDevice::MEDIA_WRITABLE_CD; + } + else if( writingApp() != K3b::GROWISOFS ) + mt = K3bDevice::MEDIA_WRITABLE_CD; + else + mt = K3bDevice::MEDIA_WRITABLE_DVD; + } + else if( m_writingMode == K3b::TAO || m_writingMode == K3b::RAW ) + mt = K3bDevice::MEDIA_WRITABLE_CD; + else if( m_writingMode == K3b::DAO ) { + if( writingApp() == K3b::DEFAULT ) { + if( m_dvd ) + mt = K3bDevice::MEDIA_WRITABLE_DVD; + else + mt = K3bDevice::MEDIA_WRITABLE_CD; + } + else if( writingApp() == K3b::GROWISOFS ) + mt = K3bDevice::MEDIA_WRITABLE_DVD; + else + mt = K3bDevice::MEDIA_WRITABLE_CD; + } + else if( m_writingMode == K3b::WRITING_MODE_RES_OVWR ) + mt = K3bDevice::MEDIA_DVD_PLUS_R|K3bDevice::MEDIA_DVD_PLUS_R_DL|K3bDevice::MEDIA_DVD_PLUS_RW|K3bDevice::MEDIA_DVD_RW_OVWR; + else + mt = K3bDevice::MEDIA_WRITABLE_DVD; + + + // wait for the media + int media = waitForMedia( m_device, K3bDevice::STATE_EMPTY, mt ); + if( media < 0 ) { + m_finished = true; + emit canceled(); + jobFinished(false); + return; + } + + // we simply always calculate the checksum, thus making the code simpler + d->imageFile.close(); + d->imageFile.setName( m_imagePath ); + d->imageFile.open( IO_ReadOnly ); + d->checksumPipe.close(); + d->checksumPipe.readFromIODevice( &d->imageFile ); + + if( prepareWriter( media ) ) { + emit burning(true); + m_writer->start(); + d->checksumPipe.writeToFd( m_writer->fd(), true ); + d->checksumPipe.open( K3bChecksumPipe::MD5, true ); + } + else { + m_finished = true; + jobFinished(false); + } +} + + +bool K3bIso9660ImageWritingJob::prepareWriter( int mediaType ) +{ + if( mediaType == 0 ) { // media forced + // just to get it going... + if( writingApp() != K3b::GROWISOFS && !m_dvd ) + mediaType = K3bDevice::MEDIA_CD_R; + else + mediaType = K3bDevice::MEDIA_DVD_R; + } + + delete m_writer; + + if( mediaType == K3bDevice::MEDIA_CD_R || mediaType == K3bDevice::MEDIA_CD_RW ) { + int usedWritingMode = m_writingMode; + if( usedWritingMode == K3b::WRITING_MODE_AUTO ) { + // cdrecord seems to have problems when writing in mode2 in dao mode + // so with cdrecord we use TAO + if( m_noFix || m_dataMode == K3b::MODE2 || !m_device->dao() ) + usedWritingMode = K3b::TAO; + else + usedWritingMode = K3b::DAO; + } + + int usedApp = writingApp(); + if( usedApp == K3b::DEFAULT ) { + if( usedWritingMode == K3b::DAO && + ( m_dataMode == K3b::MODE2 || m_noFix ) ) + usedApp = K3b::CDRDAO; + else + usedApp = K3b::CDRECORD; + } + + + if( usedApp == K3b::CDRECORD ) { + K3bCdrecordWriter* writer = new K3bCdrecordWriter( m_device, this ); + + writer->setWritingMode( usedWritingMode ); + writer->setSimulate( m_simulate ); + writer->setBurnSpeed( m_speed ); + + if( m_noFix ) { + writer->addArgument("-multi"); + } + + if( (m_dataMode == K3b::DATA_MODE_AUTO && m_noFix) || + m_dataMode == K3b::MODE2 ) { + if( k3bcore->externalBinManager()->binObject("cdrecord") && + k3bcore->externalBinManager()->binObject("cdrecord")->hasFeature( "xamix" ) ) + writer->addArgument( "-xa" ); + else + writer->addArgument( "-xa1" ); + } + else + writer->addArgument("-data"); + + // read from stdin + writer->addArgument( QString("-tsize=%1s").arg( K3b::imageFilesize( m_imagePath )/2048 ) )->addArgument( "-" ); + + m_writer = writer; + } + else { + // create cdrdao job + K3bCdrdaoWriter* writer = new K3bCdrdaoWriter( m_device, this ); + writer->setCommand( K3bCdrdaoWriter::WRITE ); + writer->setSimulate( m_simulate ); + writer->setBurnSpeed( m_speed ); + // multisession + writer->setMulti( m_noFix ); + + // now write the tocfile + delete m_tocFile; + m_tocFile = new KTempFile( QString::null, "toc" ); + m_tocFile->setAutoDelete(true); + + if( QTextStream* s = m_tocFile->textStream() ) { + if( (m_dataMode == K3b::DATA_MODE_AUTO && m_noFix) || + m_dataMode == K3b::MODE2 ) { + *s << "CD_ROM_XA" << "\n"; + *s << "\n"; + *s << "TRACK MODE2_FORM1" << "\n"; + } + else { + *s << "CD_ROM" << "\n"; + *s << "\n"; + *s << "TRACK MODE1" << "\n"; + } + *s << "DATAFILE \"-\" " << QString::number( K3b::imageFilesize( m_imagePath ) ) << "\n"; + + m_tocFile->close(); + } + else { + kdDebug() << "(K3bDataJob) could not write tocfile." << endl; + emit infoMessage( i18n("IO Error"), ERROR ); + return false; + } + + writer->setTocFile( m_tocFile->name() ); + + m_writer = writer; + } + } + else { // DVD + if( mediaType & K3bDevice::MEDIA_DVD_PLUS_ALL ) { + if( m_simulate ) { + if( questionYesNo( i18n("K3b does not support simulation with DVD+R(W) media. " + "Do you really want to continue? The media will be written " + "for real."), + i18n("No Simulation with DVD+R(W)") ) ) { + return false; + } + } + + m_simulate = false; + } + + K3bGrowisofsWriter* writer = new K3bGrowisofsWriter( m_device, this ); + writer->setSimulate( m_simulate ); + writer->setBurnSpeed( m_speed ); + writer->setWritingMode( m_writingMode == K3b::DAO ? K3b::DAO : 0 ); + writer->setImageToWrite( QString::null ); // read from stdin + writer->setCloseDvd( !m_noFix ); + writer->setTrackSize( K3b::imageFilesize( m_imagePath )/2048 ); + + m_writer = writer; + } + + connect( m_writer, SIGNAL(infoMessage(const QString&, int)), this, SIGNAL(infoMessage(const QString&, int)) ); + connect( m_writer, SIGNAL(nextTrack(int, int)), this, SLOT(slotNextTrack(int, int)) ); + connect( m_writer, SIGNAL(percent(int)), this, SLOT(slotWriterPercent(int)) ); + connect( m_writer, SIGNAL(processedSize(int, int)), this, SIGNAL(processedSize(int, int)) ); + connect( m_writer, SIGNAL(buffer(int)), this, SIGNAL(bufferStatus(int)) ); + connect( m_writer, SIGNAL(deviceBuffer(int)), this, SIGNAL(deviceBuffer(int)) ); + connect( m_writer, SIGNAL(writeSpeed(int, int)), this, SIGNAL(writeSpeed(int, int)) ); + connect( m_writer, SIGNAL(finished(bool)), this, SLOT(slotWriterJobFinished(bool)) ); + connect( m_writer, SIGNAL(newTask(const QString&)), this, SIGNAL(newTask(const QString&)) ); + connect( m_writer, SIGNAL(newSubTask(const QString&)), this, SIGNAL(newSubTask(const QString&)) ); + connect( m_writer, SIGNAL(debuggingOutput(const QString&, const QString&)), + this, SIGNAL(debuggingOutput(const QString&, const QString&)) ); + + return true; +} + + +QString K3bIso9660ImageWritingJob::jobDescription() const +{ + if( m_simulate ) + return i18n("Simulating ISO9660 Image"); + else + return ( i18n("Burning ISO9660 Image") + + ( m_copies > 1 + ? i18n(" - %n Copy", " - %n Copies", m_copies) + : QString::null ) ); +} + + +QString K3bIso9660ImageWritingJob::jobDetails() const +{ + return m_imagePath.section("/", -1) + QString( " (%1)" ).arg(KIO::convertSize(K3b::filesize(KURL::fromPathOrURL(m_imagePath)))); +} + + +#include "k3biso9660imagewritingjob.moc" diff --git a/libk3b/jobs/k3biso9660imagewritingjob.h b/libk3b/jobs/k3biso9660imagewritingjob.h new file mode 100644 index 0000000..eceb6dc --- /dev/null +++ b/libk3b/jobs/k3biso9660imagewritingjob.h @@ -0,0 +1,98 @@ +/* + * + * $Id$ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BISO9660_IMAGE_WRITING_JOB_H +#define K3BISO9660_IMAGE_WRITING_JOB_H + +#include +#include "k3b_export.h" +class QString; +class K3bAbstractWriter; +class KTempFile; +namespace K3bDevice { + class Device; +} +class K3bVerificationJob; + + +/** + *@author Sebastian Trueg + */ +class LIBK3B_EXPORT K3bIso9660ImageWritingJob : public K3bBurnJob +{ + Q_OBJECT + + public: + K3bIso9660ImageWritingJob( K3bJobHandler* ); + ~K3bIso9660ImageWritingJob(); + + K3bDevice::Device* writer() const { return m_device; }; + + QString jobDescription() const; + QString jobDetails() const; + + public slots: + void cancel(); + void start(); + + void setImagePath( const QString& path ) { m_imagePath = path; } + void setSpeed( int s ) { m_speed = s; } + void setBurnDevice( K3bDevice::Device* dev ) { m_device = dev; } + void setWritingMode( int mode ) { m_writingMode = mode; } + void setSimulate( bool b ) { m_simulate = b; } + void setNoFix( bool b ) { m_noFix = b; } + void setDataMode( int m ) { m_dataMode = m; } + void setVerifyData( bool b ) { m_verifyData = b; } + void setCopies( int c ) { m_copies = c; } + + protected slots: + void slotWriterJobFinished( bool ); + void slotVerificationFinished( bool ); + void slotVerificationProgress( int ); + void slotWriterPercent( int ); + void slotNextTrack( int, int ); + void startWriting(); + + private: + bool prepareWriter( int mediaType ); + + int m_writingMode; + bool m_simulate; + K3bDevice::Device* m_device; + bool m_noFix; + int m_speed; + int m_dataMode; + bool m_verifyData; + bool m_dvd; + + QString m_imagePath; + + K3bAbstractWriter* m_writer; + KTempFile* m_tocFile; + + bool m_canceled; + bool m_finished; + + int m_copies; + int m_currentCopy; + + K3bVerificationJob* m_verifyJob; + + class Private; + Private* d; +}; + +#endif diff --git a/libk3b/jobs/k3breadcdreader.cpp b/libk3b/jobs/k3breadcdreader.cpp new file mode 100644 index 0000000..d75eb63 --- /dev/null +++ b/libk3b/jobs/k3breadcdreader.cpp @@ -0,0 +1,335 @@ +/* + * + * $Id: k3breadcdreader.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3breadcdreader.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + + + +class K3bReadcdReader::Private +{ +public: + Private() + : process(0), + fdToWriteTo(-1), + canceled(false) { + } + + K3b::Msf firstSector, lastSector; + + K3bProcess* process; + const K3bExternalBin* readcdBinObject; + + int fdToWriteTo; + bool canceled; + + long blocksToRead; + int unreadableBlocks; + + int lastProgress; + int lastProcessedSize; +}; + + + +K3bReadcdReader::K3bReadcdReader( K3bJobHandler* jh, QObject* parent, const char* name ) + : K3bJob( jh, parent, name ), + m_noCorr(false), + m_clone(false), + m_noError(false), + m_c2Scan(false), + m_speed(0), + m_retries(128) +{ + d = new Private(); +} + + +K3bReadcdReader::~K3bReadcdReader() +{ + delete d->process; + delete d; +} + + +bool K3bReadcdReader::active() const +{ + return (d->process ? d->process->isRunning() : false); +} + + +void K3bReadcdReader::writeToFd( int fd ) +{ + d->fdToWriteTo = fd; +} + + +void K3bReadcdReader::start() +{ + jobStarted(); + + d->blocksToRead = 1; + d->unreadableBlocks = 0; + d->lastProgress = 0; + d->lastProcessedSize = 0; + + // the first thing to do is to check for readcd + d->readcdBinObject = k3bcore->externalBinManager()->binObject( "readcd" ); + if( !d->readcdBinObject ) { + emit infoMessage( i18n("Could not find %1 executable.").arg("readcd"), ERROR ); + jobFinished(false); + return; + } + + // check if we have clone support if we need it + if( m_clone ) { + bool foundCloneSupport = false; + + if( !d->readcdBinObject->hasFeature( "clone" ) ) { + // search all readcd installations + K3bExternalProgram* readcdProgram = k3bcore->externalBinManager()->program( "readcd" ); + const QPtrList& readcdBins = readcdProgram->bins(); + for( QPtrListIterator it( readcdBins ); it.current(); ++it ) { + if( it.current()->hasFeature( "clone" ) ) { + d->readcdBinObject = it.current(); + emit infoMessage( i18n("Using readcd %1 instead of default version for clone support.").arg(d->readcdBinObject->version), INFO ); + foundCloneSupport = true; + break; + } + } + + if( !foundCloneSupport ) { + emit infoMessage( i18n("Could not find readcd executable with cloning support."), ERROR ); + jobFinished(false); + return; + } + } + } + + + // create the commandline + delete d->process; + d->process = new K3bProcess(); + connect( d->process, SIGNAL(stderrLine(const QString&)), this, SLOT(slotStdLine(const QString&)) ); + connect( d->process, SIGNAL(processExited(KProcess*)), this, SLOT(slotProcessExited(KProcess*)) ); + + + *d->process << d->readcdBinObject; + + // display progress + *d->process << "-v"; + + // Again we assume the device to be set! + *d->process << QString("dev=%1").arg(K3b::externalBinDeviceParameter(m_readDevice, + d->readcdBinObject)); + if( m_speed > 0 ) + *d->process << QString("speed=%1").arg(m_speed); + + + // output + if( d->fdToWriteTo != -1 ) { + *d->process << "f=-"; + d->process->dupStdout( d->fdToWriteTo ); + } + else { + emit newTask( i18n("Writing image to %1.").arg(m_imagePath) ); + emit infoMessage( i18n("Writing image to %1.").arg(m_imagePath), INFO ); + *d->process << "f=" + m_imagePath; + } + + + if( m_noError ) + *d->process << "-noerror"; + if( m_clone ) { + *d->process << "-clone"; + // noCorr can only be used with cloning + if( m_noCorr ) + *d->process << "-nocorr"; + } + if( m_c2Scan ) + *d->process << "-c2scan"; + + *d->process << QString("retries=%1").arg(m_retries); + + // readcd does not read the last sector specified + if( d->firstSector < d->lastSector ) + *d->process << QString("sectors=%1-%2").arg(d->firstSector.lba()).arg(d->lastSector.lba()+1); + + // Joerg sais it is a Linux kernel bug, anyway, with the default value it does not work + *d->process << "ts=128k"; + + // additional user parameters from config + const QStringList& params = d->readcdBinObject->userParameters(); + for( QStringList::const_iterator it = params.begin(); it != params.end(); ++it ) + *d->process << *it; + + + kdDebug() << "***** readcd parameters:\n"; + const QValueList& args = d->process->args(); + QString s; + for( QValueList::const_iterator it = args.begin(); it != args.end(); ++it ) { + s += *it + " "; + } + kdDebug() << s << endl << flush; + + emit debuggingOutput("readcd command:", s); + + d->canceled = false; + + if( !d->process->start( KProcess::NotifyOnExit, KProcess::AllOutput) ) { + // something went wrong when starting the program + // it "should" be the executable + kdError() << "(K3bReadcdReader) could not start readcd" << endl; + emit infoMessage( i18n("Could not start readcd."), K3bJob::ERROR ); + jobFinished( false ); + } +} + + +void K3bReadcdReader::cancel() +{ + if( d->process ) { + if( d->process->isRunning() ) { + d->canceled = true; + d->process->kill(); + } + } +} + + +void K3bReadcdReader::slotStdLine( const QString& line ) +{ + emit debuggingOutput( "readcd", line ); + + int pos = -1; + + if( line.startsWith( "end:" ) ) { + bool ok; + d->blocksToRead = line.mid(4).toInt(&ok); + if( d->firstSector < d->lastSector ) + d->blocksToRead -= d->firstSector.lba(); + if( !ok ) + kdError() << "(K3bReadcdReader) blocksToRead parsing error in line: " + << line.mid(4) << endl; + } + + else if( line.startsWith( "addr:" ) ) { + bool ok; + long currentReadBlock = line.mid( 6, line.find("cnt")-7 ).toInt(&ok); + if( d->firstSector < d->lastSector ) + currentReadBlock -= d->firstSector.lba(); + if( ok ) { + int p = (int)(100.0 * (double)currentReadBlock / (double)d->blocksToRead); + if( p > d->lastProgress ) { + emit percent( p ); + d->lastProgress = p; + } + int ps = currentReadBlock*2/1024; + if( ps > d->lastProcessedSize ) { + emit processedSize( ps, d->blocksToRead*2/1024 ); + d->lastProcessedSize = ps; + } + } + else + kdError() << "(K3bReadcdReader) currentReadBlock parsing error in line: " + << line.mid( 6, line.find("cnt")-7 ) << endl; + } + + else if( line.contains("Cannot read source disk") ) { + emit infoMessage( i18n("Cannot read source disk."), ERROR ); + } + + else if( (pos = line.find("Retrying from sector")) >= 0 ) { + // parse the sector + pos += 21; + bool ok; + int problemSector = line.mid( pos, line.find( QRegExp("\\D"), pos )-pos ).toInt(&ok); + if( !ok ) { + kdError() << "(K3bReadcdReader) problemSector parsing error in line: " + << line.mid( pos, line.find( QRegExp("\\D"), pos )-pos ) << endl; + } + emit infoMessage( i18n("Retrying from sector %1.").arg(problemSector), INFO ); + } + + else if( (pos = line.find("Error on sector")) >= 0 ) { + d->unreadableBlocks++; + + pos += 16; + bool ok; + int problemSector = line.mid( pos, line.find( QRegExp("\\D"), pos )-pos ).toInt(&ok); + if( !ok ) { + kdError() << "(K3bReadcdReader) problemSector parsing error in line: " + << line.mid( pos, line.find( QRegExp("\\D"), pos )-pos ) << endl; + } + + if( line.contains( "not corrected") ) { + emit infoMessage( i18n("Uncorrected error in sector %1").arg(problemSector), ERROR ); + } + else { + emit infoMessage( i18n("Corrected error in sector %1").arg(problemSector), ERROR ); + } + } + + else { + kdDebug() << "(readcd) " << line << endl; + } +} + +void K3bReadcdReader::slotProcessExited( KProcess* p ) +{ + if( d->canceled ) { + emit canceled(); + jobFinished(false); + } + else if( p->normalExit() ) { + if( p->exitStatus() == 0 ) { + jobFinished( true ); + } + else { + emit infoMessage( i18n("%1 returned error: %2").arg("Readcd").arg(p->exitStatus()), ERROR ); + jobFinished( false ); + } + } + else { + emit infoMessage( i18n("Readcd exited abnormally."), ERROR ); + jobFinished( false ); + } +} + + +void K3bReadcdReader::setSectorRange( const K3b::Msf& first, const K3b::Msf& last ) +{ + d->firstSector = first; + d->lastSector = last; +} + +#include "k3breadcdreader.moc" + diff --git a/libk3b/jobs/k3breadcdreader.h b/libk3b/jobs/k3breadcdreader.h new file mode 100644 index 0000000..93ebce0 --- /dev/null +++ b/libk3b/jobs/k3breadcdreader.h @@ -0,0 +1,91 @@ +/* + * + * $Id: k3breadcdreader.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_READCD_READER_H_ +#define _K3B_READCD_READER_H_ + +#include + + +class K3bProcess; +class KProcess; +class K3bExternalBin; +namespace K3bDevice { + class Device; +} +namespace K3b { + class Msf; +} + + +class K3bReadcdReader : public K3bJob +{ + Q_OBJECT + + public: + K3bReadcdReader( K3bJobHandler*, QObject* parent = 0, const char* name = 0 ); + ~K3bReadcdReader(); + + bool active() const; + + public slots: + void start(); + void cancel(); + + void setReadDevice( K3bDevice::Device* dev ) { m_readDevice = dev; } + + /** 0 means MAX */ + void setReadSpeed( int s ) { m_speed = s; } + void setDisableCorrection( bool b ) { m_noCorr = b; } + + /** default: true */ + void setAbortOnError( bool b ) { m_noError = !b; } + void setC2Scan( bool b ) { m_c2Scan = b; } + void setClone( bool b ) { m_clone = b; } + void setRetries( int i ) { m_retries = i; } + + void setSectorRange( const K3b::Msf&, const K3b::Msf& ); + + void setImagePath( const QString& p ) { m_imagePath = p; } + + /** + * the data gets written directly into fd instead of the imagefile. + * Be aware that this only makes sense before starting the job. + * To disable just set fd to -1 + */ + void writeToFd( int fd ); + + private slots: + void slotStdLine( const QString& line ); + void slotProcessExited(KProcess*); + + private: + bool m_noCorr; + bool m_clone; + bool m_noError; + bool m_c2Scan; + int m_speed; + int m_retries; + + K3bDevice::Device* m_readDevice; + + QString m_imagePath; + + class Private; + Private* d; +}; + +#endif diff --git a/libk3b/jobs/k3bverificationjob.cpp b/libk3b/jobs/k3bverificationjob.cpp new file mode 100644 index 0000000..e73530e --- /dev/null +++ b/libk3b/jobs/k3bverificationjob.cpp @@ -0,0 +1,384 @@ +/* + * + * $Id: k3bisoimageverificationjob.cpp 597651 2006-10-21 08:04:01Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bverificationjob.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +class K3bVerificationJobTrackEntry +{ +public: + K3bVerificationJobTrackEntry() + : trackNumber(0) { + } + + K3bVerificationJobTrackEntry( int tn, const QCString& cs, const K3b::Msf& msf ) + : trackNumber(tn), + checksum(cs), + length(msf) { + } + + int trackNumber; + QCString checksum; + K3b::Msf length; +}; + + +class K3bVerificationJob::Private +{ +public: + Private() + : md5Job(0), + device(0), + dataTrackReader(0) { + } + + bool canceled; + K3bMd5Job* md5Job; + K3bDevice::Device* device; + + K3b::Msf grownSessionSize; + + QValueList tracks; + int currentTrackIndex; + + K3bDevice::DiskInfo diskInfo; + K3bDevice::Toc toc; + + K3bDataTrackReader* dataTrackReader; + + K3b::Msf currentTrackSize; + K3b::Msf totalSectors; + K3b::Msf alreadyReadSectors; + + K3bPipe pipe; + + bool readSuccessful; + + bool mediumHasBeenReloaded; +}; + + +K3bVerificationJob::K3bVerificationJob( K3bJobHandler* hdl, QObject* parent, const char* name ) + : K3bJob( hdl, parent, name ) +{ + d = new Private(); + + d->md5Job = new K3bMd5Job( this ); + connect( d->md5Job, SIGNAL(infoMessage(const QString&, int)), this, SIGNAL(infoMessage(const QString&, int)) ); + connect( d->md5Job, SIGNAL(finished(bool)), this, SLOT(slotMd5JobFinished(bool)) ); + connect( d->md5Job, SIGNAL(debuggingOutput(const QString&, const QString&)), + this, SIGNAL(debuggingOutput(const QString&, const QString&)) ); +} + + +K3bVerificationJob::~K3bVerificationJob() +{ + delete d; +} + + +void K3bVerificationJob::cancel() +{ + d->canceled = true; + if( d->md5Job && d->md5Job->active() ) + d->md5Job->cancel(); + if( d->dataTrackReader && d->dataTrackReader->active() ) + d->dataTrackReader->cancel(); +} + + +void K3bVerificationJob::addTrack( int trackNum, const QCString& checksum, const K3b::Msf& length ) +{ + d->tracks.append( K3bVerificationJobTrackEntry( trackNum, checksum, length ) ); +} + + +void K3bVerificationJob::clear() +{ + d->tracks.clear(); + d->grownSessionSize = 0; +} + + +void K3bVerificationJob::setDevice( K3bDevice::Device* dev ) +{ + d->device = dev; +} + + +void K3bVerificationJob::setGrownSessionSize( const K3b::Msf& s ) +{ + d->grownSessionSize = s; +} + + +void K3bVerificationJob::start() +{ + jobStarted(); + + d->canceled = false; + d->currentTrackIndex = 0; + d->alreadyReadSectors = 0; + + emit newTask( i18n("Checking medium") ); + + d->mediumHasBeenReloaded = false; + connect( K3bDevice::sendCommand( K3bDevice::DeviceHandler::DISKINFO, d->device ), + SIGNAL(finished(K3bDevice::DeviceHandler*)), + this, + SLOT(slotDiskInfoReady(K3bDevice::DeviceHandler*)) ); +} + + +void K3bVerificationJob::slotMediaReloaded( bool /*success*/ ) +{ + // we always need to wait for the medium. Otherwise the diskinfo below + // may run before the drive is ready! + waitForMedia( d->device, + K3bDevice::STATE_COMPLETE|K3bDevice::STATE_INCOMPLETE, + K3bDevice::MEDIA_WRITABLE ); + + d->mediumHasBeenReloaded = true; + + emit newTask( i18n("Checking medium") ); + + connect( K3bDevice::sendCommand( K3bDevice::DeviceHandler::DISKINFO, d->device ), + SIGNAL(finished(K3bDevice::DeviceHandler*)), + this, + SLOT(slotDiskInfoReady(K3bDevice::DeviceHandler*)) ); +} + + +void K3bVerificationJob::slotDiskInfoReady( K3bDevice::DeviceHandler* dh ) +{ + if( d->canceled ) { + emit canceled(); + jobFinished(false); + } + + d->diskInfo = dh->diskInfo(); + d->toc = dh->toc(); + d->totalSectors = 0; + + // just to be sure check if we actually have all the tracks + int i = 0; + for( QValueList::iterator it = d->tracks.begin(); + it != d->tracks.end(); ++i, ++it ) { + + // 0 means "last track" + if( (*it).trackNumber == 0 ) + (*it).trackNumber = d->toc.count(); + + if( (int)d->toc.count() < (*it).trackNumber ) { + if ( d->mediumHasBeenReloaded ) { + emit infoMessage( i18n("Internal Error: Verification job improperly initialized (%1)") + .arg( "Specified track number not found on medium" ), ERROR ); + jobFinished( false ); + return; + } + else { + // many drives need to reload the medium to return to a proper state + emit newTask( i18n("Reloading the medium") ); + connect( K3bDevice::reload( d->device ), + SIGNAL(finished(bool)), + this, + SLOT(slotMediaReloaded(bool)) ); + return; + } + } + + d->totalSectors += trackLength( i ); + } + + readTrack( 0 ); +} + + +void K3bVerificationJob::readTrack( int trackIndex ) +{ + d->currentTrackIndex = trackIndex; + d->readSuccessful = true; + + d->currentTrackSize = trackLength( trackIndex ); + if( d->currentTrackSize == 0 ) { + jobFinished(false); + return; + } + + emit newTask( i18n("Verifying track %1").arg( d->tracks[trackIndex].trackNumber ) ); + + d->pipe.open(); + + if( d->toc[d->tracks[trackIndex].trackNumber-1].type() == K3bDevice::Track::DATA ) { + if( !d->dataTrackReader ) { + d->dataTrackReader = new K3bDataTrackReader( this ); + connect( d->dataTrackReader, SIGNAL(percent(int)), this, SLOT(slotReaderProgress(int)) ); + // connect( d->dataTrackReader, SIGNAL(processedSize(int, int)), this, SLOT(slotReaderProcessedSize(int, int)) ); + connect( d->dataTrackReader, SIGNAL(finished(bool)), this, SLOT(slotReaderFinished(bool)) ); + connect( d->dataTrackReader, SIGNAL(infoMessage(const QString&, int)), this, SIGNAL(infoMessage(const QString&, int)) ); + connect( d->dataTrackReader, SIGNAL(newTask(const QString&)), this, SIGNAL(newSubTask(const QString&)) ); + connect( d->dataTrackReader, SIGNAL(debuggingOutput(const QString&, const QString&)), + this, SIGNAL(debuggingOutput(const QString&, const QString&)) ); + } + + d->dataTrackReader->setDevice( d->device ); + d->dataTrackReader->setIgnoreErrors( false ); + d->dataTrackReader->setSectorSize( K3bDataTrackReader::MODE1 ); + + // in case a session was grown the track size does not say anything about the verification data size + if( d->diskInfo.mediaType() & (K3bDevice::MEDIA_DVD_PLUS_RW|K3bDevice::MEDIA_DVD_RW_OVWR) && + d->grownSessionSize > 0 ) { + K3bIso9660 isoF( d->device ); + if( isoF.open() ) { + int firstSector = isoF.primaryDescriptor().volumeSpaceSize - d->grownSessionSize.lba(); + d->dataTrackReader->setSectorRange( firstSector, + isoF.primaryDescriptor().volumeSpaceSize -1 ); + } + else { + emit infoMessage( i18n("Unable to determine the ISO9660 filesystem size."), ERROR ); + jobFinished( false ); + return; + } + } + else + d->dataTrackReader->setSectorRange( d->toc[d->tracks[trackIndex].trackNumber-1].firstSector(), + d->toc[d->tracks[trackIndex].trackNumber-1].firstSector() + d->currentTrackSize -1 ); + + d->md5Job->setMaxReadSize( d->currentTrackSize.mode1Bytes() ); + + d->dataTrackReader->writeToFd( d->pipe.in() ); + d->dataTrackReader->start(); + } + else { + // FIXME: handle audio tracks + } + + d->md5Job->setFd( d->pipe.out() ); + d->md5Job->start(); +} + + +void K3bVerificationJob::slotReaderProgress( int p ) +{ + emit subPercent( p ); + + emit percent( 100 * ( d->alreadyReadSectors.lba() + ( p*d->currentTrackSize.lba()/100 ) ) / d->totalSectors.lba() ); +} + + +void K3bVerificationJob::slotMd5JobFinished( bool success ) +{ + d->pipe.close(); + + if( success && !d->canceled && d->readSuccessful ) { + // compare the two sums + if( d->tracks[d->currentTrackIndex].checksum != d->md5Job->hexDigest() ) { + emit infoMessage( i18n("Written data in track %1 differs from original.").arg(d->tracks[d->currentTrackIndex].trackNumber), ERROR ); + jobFinished(false); + } + else { + emit infoMessage( i18n("Written data verified."), SUCCESS ); + ++d->currentTrackIndex; + if( d->currentTrackIndex < (int)d->tracks.count() ) + readTrack( d->currentTrackIndex ); + else + jobFinished(true); + } + } + else { + // The md5job emitted an error message. So there is no need to do this again + jobFinished(false); + } +} + + +void K3bVerificationJob::slotReaderFinished( bool success ) +{ + d->readSuccessful = success; + if( !d->readSuccessful ) + d->md5Job->cancel(); + else { + d->alreadyReadSectors += trackLength( d->currentTrackIndex ); + + // close the pipe and let the md5 job finish gracefully + d->pipe.closeIn(); + // d->md5Job->stop(); + } +} + + +K3b::Msf K3bVerificationJob::trackLength( int trackIndex ) +{ + K3b::Msf& trackSize = d->tracks[trackIndex].length; + const int& trackNum = d->tracks[trackIndex].trackNumber; + + if( trackSize == 0 ) { + trackSize = d->toc[trackNum-1].length(); + + if( d->diskInfo.mediaType() & (K3bDevice::MEDIA_DVD_PLUS_RW|K3bDevice::MEDIA_DVD_RW_OVWR) ) { + K3bIso9660 isoF( d->device, d->toc[trackNum-1].firstSector().lba() ); + if( isoF.open() ) { + trackSize = isoF.primaryDescriptor().volumeSpaceSize; + } + else { + emit infoMessage( i18n("Unable to determine the ISO9660 filesystem size."), ERROR ); + return 0; + } + } + + // + // A data track recorded in TAO mode has two run-out blocks which cannot be read and contain + // zero data anyway. The problem is that I do not know of a valid method to determine if a track + // was written in TAO (the control nibble does definitely not work, I never saw one which did not + // equal 4). + // So the solution for now is to simply try to read the last sector of a data track. If this is not + // possible we assume it was written in TAO mode and reduce the length by 2 sectors + // + if( d->toc[trackNum-1].type() == K3bDevice::Track::DATA && + d->diskInfo.mediaType() & K3bDevice::MEDIA_CD_ALL ) { + // we try twice just to be sure + unsigned char buffer[2048]; + if( !d->device->read10( buffer, 2048, d->toc[trackNum-1].lastSector().lba(), 1 ) && + !d->device->read10( buffer, 2048, d->toc[trackNum-1].lastSector().lba(), 1 ) ) { + trackSize -= 2; + kdDebug() << "(K3bCdCopyJob) track " << trackNum << " probably TAO recorded." << endl; + } + } + } + + return trackSize; +} + + +#include "k3bverificationjob.moc" diff --git a/libk3b/jobs/k3bverificationjob.h b/libk3b/jobs/k3bverificationjob.h new file mode 100644 index 0000000..ad750ee --- /dev/null +++ b/libk3b/jobs/k3bverificationjob.h @@ -0,0 +1,92 @@ +/* + * + * $Id: k3bisoimageverificationjob.h 597651 2006-10-21 08:04:01Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_VERIFICATION_JOB_H_ +#define _K3B_VERIFICATION_JOB_H_ + +#include + +namespace K3bDevice { + class Device; + class DeviceHandler; +} + + +/** + * Generic verification job. Add tracks to be verified via addTrack. + * The job will then verifiy the tracks set against the set checksums. + * + * The different track types are handled as follows: + * \li Data/DVD tracks: Read the track with a 2048 bytes sector size. + * Tracks length on DVD+RW media will be read from the iso9660 + * descriptor. + * \li Audio tracks: Rip the track with a 2352 bytes sector size. + * In the case of audio tracks the job will not fail if the checksums + * differ becasue audio CD tracks do not contain error correction data. + * In this case only a warning will be emitted. + * + * Other sector sizes than 2048 bytes for data tracks are not supported yet, + * i.e. Video CDs cannot be verified. + * + * TAO written tracks have two run-out sectors that are not read. + * + * The VerificationJob will also reload the medium before starting. + */ +class K3bVerificationJob : public K3bJob +{ + Q_OBJECT + + public: + K3bVerificationJob( K3bJobHandler*, QObject* parent = 0, const char* name = 0 ); + ~K3bVerificationJob(); + + public slots: + void start(); + void cancel(); + void setDevice( K3bDevice::Device* dev ); + + void clear(); + + /** + * Add a track to be verified. + * \param tracknum The number of the track. If \a tracknum is 0 + * the last track will be verified. + * \param length Set to override the track length from the TOC. This may be + * useful when writing to DVD+RW media and the iso descriptor does not + * contain the exact image size (as true for many commercial Video DVDs) + */ + void addTrack( int tracknum, const QCString& checksum, const K3b::Msf& length = K3b::Msf() ); + + /** + * Handle the special case of iso session growing + */ + void setGrownSessionSize( const K3b::Msf& ); + + private slots: + void slotMediaReloaded( bool success ); + void slotDiskInfoReady( K3bDevice::DeviceHandler* dh ); + void readTrack( int trackIndex ); + void slotMd5JobFinished( bool success ); + void slotReaderProgress( int p ); + void slotReaderFinished( bool success ); + + private: + K3b::Msf trackLength( int trackNum ); + + class Private; + Private* d; +}; + +#endif diff --git a/libk3b/jobs/k3bvideodvdtitledetectclippingjob.cpp b/libk3b/jobs/k3bvideodvdtitledetectclippingjob.cpp new file mode 100644 index 0000000..fdcc3a4 --- /dev/null +++ b/libk3b/jobs/k3bvideodvdtitledetectclippingjob.cpp @@ -0,0 +1,291 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bvideodvdtitledetectclippingjob.h" + +#include +#include +#include +#include + +#include +#include + + +static const int s_unrealisticHighClippingValue = 100000; + + +class K3bVideoDVDTitleDetectClippingJob::Private +{ +public: + const K3bExternalBin* usedTranscodeBin; + + K3bProcess* process; + + bool canceled; + + unsigned int currentChapter; + unsigned int currentFrames; + unsigned int totalChapters; + + int lastProgress; + int lastSubProgress; +}; + + + +K3bVideoDVDTitleDetectClippingJob::K3bVideoDVDTitleDetectClippingJob( K3bJobHandler* hdl, QObject* parent ) + : K3bJob( hdl, parent ), + m_clippingTop( 0 ), + m_clippingBottom( 0 ), + m_clippingLeft( 0 ), + m_clippingRight( 0 ), + m_lowPriority( true ) +{ + d = new Private; + d->process = 0; +} + + +K3bVideoDVDTitleDetectClippingJob::~K3bVideoDVDTitleDetectClippingJob() +{ + delete d->process; + delete d; +} + + +void K3bVideoDVDTitleDetectClippingJob::start() +{ + jobStarted(); + + d->canceled = false; + d->lastProgress = 0; + + // + // It seems as if the last chapter is often way too short + // + d->totalChapters = m_dvd[m_titleNumber-1].numPTTs(); + if( d->totalChapters > 1 && m_dvd[m_titleNumber-1][d->totalChapters-1].playbackTime().totalFrames() < 200 ) + d->totalChapters--; + + // initial values (some way to big value) + m_clippingTop = s_unrealisticHighClippingValue; + m_clippingBottom = s_unrealisticHighClippingValue; + m_clippingLeft = s_unrealisticHighClippingValue; + m_clippingRight = s_unrealisticHighClippingValue; + + d->usedTranscodeBin = k3bcore->externalBinManager()->binObject("transcode"); + if( !d->usedTranscodeBin ) { + emit infoMessage( i18n("%1 executable could not be found.").arg("transcode"), ERROR ); + jobFinished( false ); + return; + } + + if( d->usedTranscodeBin->version < K3bVersion( 1, 0, 0 ) ){ + emit infoMessage( i18n("%1 version %2 is too old.") + .arg("transcode") + .arg(d->usedTranscodeBin->version), ERROR ); + jobFinished( false ); + return; + } + + emit debuggingOutput( "Used versions", "transcode: " + d->usedTranscodeBin->version ); + + if( !d->usedTranscodeBin->copyright.isEmpty() ) + emit infoMessage( i18n("Using %1 %2 - Copyright (C) %3") + .arg(d->usedTranscodeBin->name()) + .arg(d->usedTranscodeBin->version) + .arg(d->usedTranscodeBin->copyright), INFO ); + + emit newTask( i18n("Analysing Title %1 of Video DVD %2").arg(m_titleNumber).arg(m_dvd.volumeIdentifier()) ); + + startTranscode( 1 ); +} + + +void K3bVideoDVDTitleDetectClippingJob::startTranscode( int chapter ) +{ + d->currentChapter = chapter; + d->lastSubProgress = 0; + + // + // If we have only one chapter and it is not longer than 2 minutes (value guessed based on some test DVD) + // use the whole chapter + // + if( d->totalChapters == 1 ) + d->currentFrames = QMIN( 3000, QMAX( 1, m_dvd[m_titleNumber-1][d->currentChapter-1].playbackTime().totalFrames() ) ); + else + d->currentFrames = QMIN( 200, QMAX( 1, m_dvd[m_titleNumber-1][d->currentChapter-1].playbackTime().totalFrames() ) ); + + // + // prepare the process + // + delete d->process; + d->process = new K3bProcess(); + d->process->setSuppressEmptyLines(true); + d->process->setSplitStdout(true); + // connect( d->process, SIGNAL(stderrLine(const QString&)), this, SLOT(slotTranscodeStderr(const QString&)) ); + connect( d->process, SIGNAL(stdoutLine(const QString&)), this, SLOT(slotTranscodeStderr(const QString&)) ); + connect( d->process, SIGNAL(processExited(KProcess*)), this, SLOT(slotTranscodeExited(KProcess*)) ); + + // the executable + *d->process << d->usedTranscodeBin; + + // low priority + if( m_lowPriority ) + *d->process << "--nice" << "19"; + + // the input + *d->process << "-i" << m_dvd.device()->blockDeviceName(); + + // select the title number and chapter + *d->process << "-T" << QString("%1,%2").arg(m_titleNumber).arg(chapter); + + // null output + *d->process << "-y" << "null,null" << "-o" << "/dev/null"; + + // analyze the first 200 frames + *d->process << "-J" << QString("detectclipping=range=0-%1/5").arg(d->currentFrames); + + // also only decode the first 200 frames + *d->process << "-c" << QString("0-%1").arg(d->currentFrames+1); + + // additional user parameters from config + const QStringList& params = d->usedTranscodeBin->userParameters(); + for( QStringList::const_iterator it = params.begin(); it != params.end(); ++it ) + *d->process << *it; + + // produce some debugging output + kdDebug() << "***** transcode parameters:\n"; + const QValueList& args = d->process->args(); + QString s; + for( QValueList::const_iterator it = args.begin(); it != args.end(); ++it ) { + s += *it + " "; + } + kdDebug() << s << flush << endl; + emit debuggingOutput( d->usedTranscodeBin->name() + " command:", s); + + // start the process + if( !d->process->start( KProcess::NotifyOnExit, KProcess::All ) ) { + // something went wrong when starting the program + // it "should" be the executable + emit infoMessage( i18n("Could not start %1.").arg(d->usedTranscodeBin->name()), K3bJob::ERROR ); + jobFinished(false); + } + else { + emit newSubTask( i18n("Analysing Chapter %1 of %2").arg(chapter).arg(m_dvd[m_titleNumber-1].numPTTs()) ); + emit subPercent( 0 ); + } +} + + +void K3bVideoDVDTitleDetectClippingJob::cancel() +{ + d->canceled = true; + if( d->process && d->process->isRunning() ) + d->process->kill(); +} + + +void K3bVideoDVDTitleDetectClippingJob::slotTranscodeStderr( const QString& line ) +{ + emit debuggingOutput( "transcode", line ); + + // parse progress + // encoding frame [185], 24.02 fps, 93.0%, ETA: 0:00:00, ( 0| 0| 0) + if( line.startsWith( "encoding frame" ) ) { + int pos1 = line.find( '[', 15 ); + int pos2 = line.find( ']', pos1+1 ); + if( pos1 > 0 && pos2 > 0 ) { + bool ok; + int encodedFrames = line.mid( pos1+1, pos2-pos1-1 ).toInt( &ok ); + if( ok ) { + int progress = 100 * encodedFrames / d->currentFrames; + + if( progress > d->lastSubProgress ) { + d->lastSubProgress = progress; + emit subPercent( progress ); + } + + double part = 100.0 / (double)d->totalChapters; + + progress = (int)( ( (double)(d->currentChapter-1) * part ) + + ( (double)progress / (double)d->totalChapters ) + + 0.5 ); + + if( progress > d->lastProgress ) { + d->lastProgress = progress; + emit percent( progress ); + } + } + } + } + + // [detectclipping#0] valid area: X: 5..719 Y: 72..507 -> -j 72,6,68,0 + else if( line.startsWith( "[detectclipping" ) ) { + int pos = line.find( "-j" ); + if( pos > 0 ) { + QStringList values = QStringList::split( ',', line.mid( pos+3 ) ); + m_clippingTop = QMIN( m_clippingTop, values[0].toInt() ); + m_clippingLeft = QMIN( m_clippingLeft, values[1].toInt() ); + m_clippingBottom = QMIN( m_clippingBottom, values[2].toInt() ); + m_clippingRight = QMIN( m_clippingRight, values[3].toInt() ); + } + else + kdDebug() << "(K3bVideoDVDTitleDetectClippingJob) failed to parse line: " << line << endl; + } +} + + +void K3bVideoDVDTitleDetectClippingJob::slotTranscodeExited( KProcess* p ) +{ + switch( p->exitStatus() ) { + case 0: + d->currentChapter++; + if( d->currentChapter > d->totalChapters ) { + // + // check if we did set any values at all + // + if( m_clippingTop == s_unrealisticHighClippingValue ) + m_clippingTop = m_clippingLeft = m_clippingBottom = m_clippingRight = 0; + + if( d->totalChapters < m_dvd[m_titleNumber-1].numPTTs() ) + emit infoMessage( i18n("Ignoring last chapter due to its short playback time."), INFO ); + + jobFinished( true ); + } + else { + startTranscode( d->currentChapter ); + } + break; + + default: + // FIXME: error handling + + if( d->canceled ) { + emit canceled(); + } + else { + emit infoMessage( i18n("%1 returned an unknown error (code %2).") + .arg(d->usedTranscodeBin->name()).arg(p->exitStatus()), + K3bJob::ERROR ); + emit infoMessage( i18n("Please send me an email with the last output."), K3bJob::ERROR ); + } + + jobFinished( false ); + } +} + +#include "k3bvideodvdtitledetectclippingjob.moc" diff --git a/libk3b/jobs/k3bvideodvdtitledetectclippingjob.h b/libk3b/jobs/k3bvideodvdtitledetectclippingjob.h new file mode 100644 index 0000000..b13bbf8 --- /dev/null +++ b/libk3b/jobs/k3bvideodvdtitledetectclippingjob.h @@ -0,0 +1,106 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_VIDEODVD_TITLE_DETECTCLIPPING_JOB_H_ +#define _K3B_VIDEODVD_TITLE_DETECTCLIPPING_JOB_H_ + +#include +#include +#include + +class KProcess; + +/** + * Job to detect the clipping values for a Video DVD title. + */ +class LIBK3B_EXPORT K3bVideoDVDTitleDetectClippingJob : public K3bJob +{ + Q_OBJECT + + public: + K3bVideoDVDTitleDetectClippingJob( K3bJobHandler* hdl, QObject* parent ); + ~K3bVideoDVDTitleDetectClippingJob(); + + const K3bVideoDVD::VideoDVD& videoDVD() const { return m_dvd; } + int title() const { return m_titleNumber; } + bool lowPriority() const { return m_lowPriority; } + + /** + * Only valid after a successful completion of the job. + */ + int clippingTop() const { return m_clippingTop; } + + /** + * Only valid after a successful completion of the job. + */ + int clippingLeft() const { return m_clippingLeft; } + + /** + * Only valid after a successful completion of the job. + */ + int clippingBottom() const { return m_clippingBottom; } + + /** + * Only valid after a successful completion of the job. + */ + int clippingRight() const { return m_clippingRight; } + + public slots: + void start(); + void cancel(); + + /** + * The device containing the Video DVD + */ + void setVideoDVD( const K3bVideoDVD::VideoDVD& dvd ) { m_dvd = dvd; } + + /** + * Set the title number to be analysed + * + * The default value is 1, denoting the first title. + */ + void setTitle( int t ) { m_titleNumber = t; } + + /** + * If true the transcode processes will be run with a very low scheduling + * priority. + * + * The default is true. + */ + void setLowPriority( bool b ) { m_lowPriority = b; } + + private slots: + void slotTranscodeStderr( const QString& ); + void slotTranscodeExited( KProcess* ); + + private: + void startTranscode( int chapter ); + + K3bVideoDVD::VideoDVD m_dvd; + + int m_clippingTop; + int m_clippingBottom; + int m_clippingLeft; + int m_clippingRight; + + int m_titleNumber; + + bool m_lowPriority; + + class Private; + Private* d; +}; + +#endif diff --git a/libk3b/jobs/k3bvideodvdtitletranscodingjob.cpp b/libk3b/jobs/k3bvideodvdtitletranscodingjob.cpp new file mode 100644 index 0000000..9fec637 --- /dev/null +++ b/libk3b/jobs/k3bvideodvdtitletranscodingjob.cpp @@ -0,0 +1,583 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bvideodvdtitletranscodingjob.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + + +class K3bVideoDVDTitleTranscodingJob::Private +{ +public: + const K3bExternalBin* usedTranscodeBin; + + K3bProcess* process; + + QString twoPassEncodingLogFile; + + int currentEncodingPass; + + bool canceled; + + int lastProgress; + int lastSubProgress; +}; + + + +K3bVideoDVDTitleTranscodingJob::K3bVideoDVDTitleTranscodingJob( K3bJobHandler* hdl, QObject* parent ) + : K3bJob( hdl, parent ), + m_clippingTop( 0 ), + m_clippingBottom( 0 ), + m_clippingLeft( 0 ), + m_clippingRight( 0 ), + m_width( 0 ), + m_height( 0 ), + m_titleNumber( 1 ), + m_audioStreamIndex( 0 ), + m_videoCodec( VIDEO_CODEC_FFMPEG_MPEG4 ), + m_audioCodec( AUDIO_CODEC_MP3 ), + m_videoBitrate( 1800 ), + m_audioBitrate( 128 ), + m_audioVBR( false ), + m_resampleAudio( false ), + m_twoPassEncoding( false ), + m_lowPriority( true ) +{ + d = new Private; + d->process = 0; +} + + +K3bVideoDVDTitleTranscodingJob::~K3bVideoDVDTitleTranscodingJob() +{ + delete d->process; + delete d; +} + + +void K3bVideoDVDTitleTranscodingJob::start() +{ + jobStarted(); + + d->canceled = false; + d->lastProgress = 0; + + d->usedTranscodeBin = k3bcore->externalBinManager()->binObject("transcode"); + if( !d->usedTranscodeBin ) { + emit infoMessage( i18n("%1 executable could not be found.").arg("transcode"), ERROR ); + jobFinished( false ); + return; + } + + if( d->usedTranscodeBin->version < K3bVersion( 1, 0, 0 ) ){ + emit infoMessage( i18n("%1 version %2 is too old.") + .arg("transcode") + .arg(d->usedTranscodeBin->version), ERROR ); + jobFinished( false ); + return; + } + + emit debuggingOutput( "Used versions", "transcode: " + d->usedTranscodeBin->version ); + + if( !d->usedTranscodeBin->copyright.isEmpty() ) + emit infoMessage( i18n("Using %1 %2 - Copyright (C) %3") + .arg(d->usedTranscodeBin->name()) + .arg(d->usedTranscodeBin->version) + .arg(d->usedTranscodeBin->copyright), INFO ); + + // + // Let's take a look at the filename + // + if( m_filename.isEmpty() ) { + m_filename = K3b::findTempFile( "avi" ); + } + else { + // let's see if the directory exists and we can write to it + QFileInfo fileInfo( m_filename ); + QFileInfo dirInfo( fileInfo.dirPath() ); + if( !dirInfo.exists() && !KStandardDirs::makeDir( dirInfo.absFilePath() ) ) { + emit infoMessage( i18n("Unable to create folder '%1'").arg(dirInfo.filePath()), ERROR ); + return; + } + else if( !dirInfo.isDir() || !dirInfo.isWritable() ) { + emit infoMessage( i18n("Invalid filename: '%1'").arg(m_filename), ERROR ); + jobFinished( false ); + return; + } + } + + // + // Determine a log file for two-pass encoding + // + d->twoPassEncodingLogFile = K3b::findTempFile( "log" ); + + emit newTask( i18n("Transcoding title %1 from Video DVD %2").arg(m_titleNumber).arg(m_dvd.volumeIdentifier()) ); + + // + // Ok then, let's begin + // + startTranscode( m_twoPassEncoding ? 1 : 0 ); +} + + +void K3bVideoDVDTitleTranscodingJob::startTranscode( int pass ) +{ + d->currentEncodingPass = pass; + d->lastSubProgress = 0; + + QString videoCodecString; + switch( m_videoCodec ) { + case VIDEO_CODEC_XVID: + videoCodecString = "xvid"; + break; + + case VIDEO_CODEC_FFMPEG_MPEG4: + videoCodecString = "ffmpeg"; + break; + + default: + emit infoMessage( i18n("Invalid Video codec set: %1").arg(m_videoCodec), ERROR ); + jobFinished( false ); + return; + } + + QString audioCodecString; + switch( m_audioCodec ) { + case AUDIO_CODEC_MP3: + audioCodecString = "0x55"; + break; + + // ogg only works (as in: transcode does something) with .y ,ogg + // but then the video is garbage (at least to xine and mplayer on my system) + // case AUDIO_CODEC_OGG_VORBIS: + // audioCodecString = "0xfffe"; + // break; + + case AUDIO_CODEC_AC3_STEREO: + case AUDIO_CODEC_AC3_PASSTHROUGH: + audioCodecString = "0x2000"; + break; + + default: + emit infoMessage( i18n("Invalid Audio codec set: %1").arg(m_audioCodec), ERROR ); + jobFinished( false ); + return; + } + + // + // prepare the process + // + delete d->process; + d->process = new K3bProcess(); + d->process->setSuppressEmptyLines(true); + d->process->setSplitStdout(true); + connect( d->process, SIGNAL(stderrLine(const QString&)), this, SLOT(slotTranscodeStderr(const QString&)) ); + connect( d->process, SIGNAL(stdoutLine(const QString&)), this, SLOT(slotTranscodeStderr(const QString&)) ); + connect( d->process, SIGNAL(processExited(KProcess*)), this, SLOT(slotTranscodeExited(KProcess*)) ); + + // the executable + *d->process << d->usedTranscodeBin; + + // low priority + if( m_lowPriority ) + *d->process << "--nice" << "19"; + + // we only need 100 steps, but to make sure we use 150 + if ( d->usedTranscodeBin->version.simplify() >= K3bVersion( 1, 1, 0 ) ) + *d->process << "--progress_meter" << "2" << "--progress_rate" << QString::number(m_dvd[m_titleNumber-1].playbackTime().totalFrames()/150); + else + *d->process << "--print_status" << QString::number(m_dvd[m_titleNumber-1].playbackTime().totalFrames()/150); + + // the input + *d->process << "-i" << m_dvd.device()->blockDeviceName(); + + // just to make sure + *d->process << "-x" << "dvd"; + + // select the title number + *d->process << "-T" << QString("%1,-1,1").arg( m_titleNumber ); + + // select the audio stream to extract + if ( m_dvd[m_titleNumber-1].numAudioStreams() > 0 ) + *d->process << "-a" << QString::number( m_audioStreamIndex ); + + // clipping + *d->process << "-j" << QString("%1,%2,%3,%4") + .arg(m_clippingTop) + .arg(m_clippingLeft) + .arg(m_clippingBottom) + .arg(m_clippingRight); + + // select the encoding type (single pass or two-pass) and the log file for two-pass encoding + // the latter is unused for pass = 0 + *d->process << "-R" << QString("%1,%2").arg( pass ).arg( d->twoPassEncodingLogFile ); + + // depending on the pass we use different options + if( pass != 1 ) { + // select video codec + *d->process << "-y" << videoCodecString; + + // select the audio codec to use + *d->process << "-N" << audioCodecString; + + if( m_audioCodec == AUDIO_CODEC_AC3_PASSTHROUGH ) { + // keep 5.1 sound + *d->process << "-A"; + } + else { + // audio quality settings + *d->process << "-b" << QString("%1,%2").arg(m_audioBitrate).arg(m_audioVBR ? 1 : 0); + + // resample audio stream to 44.1 khz + if( m_resampleAudio ) + *d->process << "-E" << "44100"; + } + + // the output filename + *d->process << "-o" << m_filename; + } + else { + // gather information about the video stream, ignore audio + *d->process << "-y" << QString("%1,null").arg( videoCodecString ); + + // we ignore the output from the first pass + *d->process << "-o" << "/dev/null"; + } + + // choose the ffmpeg codec + if( m_videoCodec == VIDEO_CODEC_FFMPEG_MPEG4 ) { + *d->process << "-F" << "mpeg4"; + } + + // video bitrate + *d->process << "-w" << QString::number( m_videoBitrate ); + + // video resizing + int usedWidth = m_width; + int usedHeight = m_height; + if( m_width == 0 || m_height == 0 ) { + // + // The "real" size of the video, considering anamorph encoding + // + int realHeight = m_dvd[m_titleNumber-1].videoStream().realPictureHeight(); + int readWidth = m_dvd[m_titleNumber-1].videoStream().realPictureWidth(); + + // + // The clipped size with the correct aspect ratio + // + int clippedHeight = realHeight - m_clippingTop - m_clippingBottom; + int clippedWidth = readWidth - m_clippingLeft - m_clippingRight; + + // + // Now simply resize the clipped video to the wanted size + // + if( usedWidth > 0 ) { + usedHeight = clippedHeight * usedWidth / clippedWidth; + } + else { + if( usedHeight == 0 ) { + // + // This is the default case in which both m_width and m_height are 0. + // The result will be a size of clippedWidth x clippedHeight + // + usedHeight = clippedHeight; + } + usedWidth = clippedWidth * usedHeight / clippedHeight; + } + } + + // + // Now make sure both width and height are multiple of 16 the simple way + // + usedWidth -= usedWidth%16; + usedHeight -= usedHeight%16; + + // we only give information about the resizing of the video once + if( pass < 2 ) + emit infoMessage( i18n("Resizing picture of title %1 to %2x%3").arg(m_titleNumber).arg(usedWidth).arg(usedHeight), INFO ); + *d->process << "-Z" << QString("%1x%2").arg(usedWidth).arg(usedHeight); + + // additional user parameters from config + const QStringList& params = d->usedTranscodeBin->userParameters(); + for( QStringList::const_iterator it = params.begin(); it != params.end(); ++it ) + *d->process << *it; + + // produce some debugging output + kdDebug() << "***** transcode parameters:\n"; + const QValueList& args = d->process->args(); + QString s; + for( QValueList::const_iterator it = args.begin(); it != args.end(); ++it ) { + s += *it + " "; + } + kdDebug() << s << flush << endl; + emit debuggingOutput( d->usedTranscodeBin->name() + " command:", s); + + // start the process + if( !d->process->start( KProcess::NotifyOnExit, KProcess::All ) ) { + // something went wrong when starting the program + // it "should" be the executable + emit infoMessage( i18n("Could not start %1.").arg(d->usedTranscodeBin->name()), K3bJob::ERROR ); + jobFinished(false); + } + else { + if( pass == 0 ) + emit newSubTask( i18n("Single-pass Encoding") ); + else if( pass == 1 ) + emit newSubTask( i18n("Two-pass Encoding: First Pass") ); + else + emit newSubTask( i18n("Two-pass Encoding: Second Pass") ); + + emit subPercent( 0 ); + } +} + + +void K3bVideoDVDTitleTranscodingJob::cancel() +{ + // FIXME: do not cancel before one frame has been encoded. transcode seems to hang then + // find a way to determine all subprocess ids to kill all of them + d->canceled = true; + if( d->process && d->process->isRunning() ) + d->process->kill(); +} + + +void K3bVideoDVDTitleTranscodingJob::cleanup( bool success ) +{ + if( QFile::exists( d->twoPassEncodingLogFile ) ) { + QFile::remove( d->twoPassEncodingLogFile ); + } + + if( !success && QFile::exists( m_filename ) ) { + emit infoMessage( i18n("Removing incomplete video file '%1'").arg(m_filename), INFO ); + QFile::remove( m_filename ); + } +} + + +void K3bVideoDVDTitleTranscodingJob::slotTranscodeStderr( const QString& line ) +{ + emit debuggingOutput( "transcode", line ); + + // parse progress + // encoding frames [000000-000144], 27.58 fps, EMT: 0:00:05, ( 0| 0| 0) + if( line.startsWith( "encoding frame" ) ) { + int pos1 = line.find( '-', 15 ); + int pos2 = line.find( ']', pos1+1 ); + if( pos1 > 0 && pos2 > 0 ) { + bool ok; + int encodedFrames = line.mid( pos1+1, pos2-pos1-1 ).toInt( &ok ); + if( ok ) { + int progress = 100 * encodedFrames / m_dvd[m_titleNumber-1].playbackTime().totalFrames(); + + if( progress > d->lastSubProgress ) { + d->lastSubProgress = progress; + emit subPercent( progress ); + } + + if( m_twoPassEncoding ) { + progress /= 2; + if( d->currentEncodingPass == 2 ) + progress += 50; + } + + if( progress > d->lastProgress ) { + d->lastProgress = progress; + emit percent( progress ); + } + } + } + } +} + + +void K3bVideoDVDTitleTranscodingJob::slotTranscodeExited( KProcess* p ) +{ + if( d->canceled ) { + emit canceled(); + cleanup( false ); + jobFinished( false ); + } + else if( p->normalExit() ) { + switch( p->exitStatus() ) { + case 0: + if( d->currentEncodingPass == 1 ) { + emit percent( 50 ); + // start second encoding pass + startTranscode( 2 ); + } + else { + emit percent( 100 ); + cleanup( true ); + jobFinished( true ); + } + break; + + default: + // FIXME: error handling + + emit infoMessage( i18n("%1 returned an unknown error (code %2).") + .arg(d->usedTranscodeBin->name()).arg(p->exitStatus()), + K3bJob::ERROR ); + emit infoMessage( i18n("Please send me an email with the last output."), K3bJob::ERROR ); + + cleanup( false ); + jobFinished( false ); + } + } + else { + cleanup( false ); + emit infoMessage( i18n("Execution of %1 failed.").arg("transcode"), ERROR ); + emit infoMessage( i18n("Please consult the debugging output for details."), ERROR ); + jobFinished( false ); + } +} + + +void K3bVideoDVDTitleTranscodingJob::setClipping( int top, int left, int bottom, int right ) +{ + m_clippingTop = top; + m_clippingLeft = left; + m_clippingBottom = bottom; + m_clippingRight = right; + + // + // transcode seems unable to handle different clipping values for left and right + // + m_clippingLeft = m_clippingRight = QMIN( m_clippingRight, m_clippingLeft ); +} + + +void K3bVideoDVDTitleTranscodingJob::setSize( int width, int height ) +{ + m_width = width; + m_height = height; +} + + +QString K3bVideoDVDTitleTranscodingJob::audioCodecString( K3bVideoDVDTitleTranscodingJob::AudioCodec codec ) +{ + switch( codec ) { + case AUDIO_CODEC_AC3_STEREO: + return i18n("AC3 (Stereo)"); + case AUDIO_CODEC_AC3_PASSTHROUGH: + return i18n("AC3 (Pass-through)"); + case AUDIO_CODEC_MP3: + return i18n("MPEG1 Layer III"); + default: + return "unknown audio codec"; + } +} + + +QString K3bVideoDVDTitleTranscodingJob::videoCodecString( K3bVideoDVDTitleTranscodingJob::VideoCodec codec ) +{ + switch( codec ) { + case VIDEO_CODEC_FFMPEG_MPEG4: + return i18n("MPEG4 (FFMPEG)"); + case VIDEO_CODEC_XVID: + return i18n("XviD"); + default: + return "unknown video codec"; + } +} + + +QString K3bVideoDVDTitleTranscodingJob::videoCodecDescription( K3bVideoDVDTitleTranscodingJob::VideoCodec codec ) +{ + switch( codec ) { + case VIDEO_CODEC_FFMPEG_MPEG4: + return i18n("FFmpeg is an open-source project trying to support most video and audio codecs used " + "these days. Its subproject libavcodec forms the basis for multimedia players such as " + "xine or mplayer.") + + "
" + + i18n("FFmpeg contains an implementation of the MPEG-4 video encoding standard which produces " + "high quality results."); + case VIDEO_CODEC_XVID: + return i18n("XviD is a free and open source MPEG-4 video codec. XviD was created by a group of " + "volunteer programmers after the OpenDivX source was closed in July 2001.") + + "
" + + i18n("XviD features MPEG-4 Advanced Profile settings such as b-frames, global " + "and quarter pixel motion compensation, lumi masking, trellis quantization, and " + "H.263, MPEG and custom quantization matrices.") + + "
" + + i18n("XviD is a primary competitor of DivX (XviD being DivX spelled backwards). " + "While DivX is closed source and may only run on Windows, Mac OS and Linux, " + "XviD is open source and can potentially run on any platform.") + + "
" + + i18n("(Description taken from the Wikipedia article)") + + ""; + default: + return "unknown video codec"; + } +} + + +QString K3bVideoDVDTitleTranscodingJob::audioCodecDescription( K3bVideoDVDTitleTranscodingJob::AudioCodec codec ) +{ + static QString s_ac3General = i18n("AC3, better known as Dolby Digital is standardized as ATSC A/52. " + "It contains up to 6 total channels of sound."); + switch( codec ) { + case AUDIO_CODEC_AC3_STEREO: + return s_ac3General + + "
" + i18n("With this setting K3b will create a two-channel stereo " + "Dolby Digital audio stream."); + case AUDIO_CODEC_AC3_PASSTHROUGH: + return s_ac3General + + "
" + i18n("With this setting K3b will use the Dolby Digital audio stream " + "from the source DVD without changing it.") + + "
" + i18n("Use this setting to preserve 5.1 channel sound from the DVD."); + case AUDIO_CODEC_MP3: + return i18n("MPEG1 Layer III is better known as MP3 and is the most used lossy audio format.") + + "
" + i18n("With this setting K3b will create a two-channel stereo MPEG1 Layer III audio stream."); + default: + return "unknown audio codec"; + } +} + + +bool K3bVideoDVDTitleTranscodingJob::transcodeBinaryHasSupportFor( K3bVideoDVDTitleTranscodingJob::VideoCodec codec, const K3bExternalBin* bin ) +{ + static char* s_codecFeatures[] = { "xvid", "ffmpeg" }; + if( !bin ) + bin = k3bcore->externalBinManager()->binObject("transcode"); + if( !bin ) + return false; + return bin->hasFeature( QString::fromLatin1( s_codecFeatures[(int)codec] ) ); +} + + +bool K3bVideoDVDTitleTranscodingJob::transcodeBinaryHasSupportFor( K3bVideoDVDTitleTranscodingJob::AudioCodec codec, const K3bExternalBin* bin ) +{ + static char* s_codecFeatures[] = { "lame", "ac3", "ac3" }; + if( !bin ) + bin = k3bcore->externalBinManager()->binObject("transcode"); + if( !bin ) + return false; + return bin->hasFeature( QString::fromLatin1( s_codecFeatures[(int)codec] ) ); +} + +#include "k3bvideodvdtitletranscodingjob.moc" diff --git a/libk3b/jobs/k3bvideodvdtitletranscodingjob.h b/libk3b/jobs/k3bvideodvdtitletranscodingjob.h new file mode 100644 index 0000000..77a48b5 --- /dev/null +++ b/libk3b/jobs/k3bvideodvdtitletranscodingjob.h @@ -0,0 +1,275 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_VIDEODVD_TITLE_TRANSCODING_JOB_H_ +#define _K3B_VIDEODVD_TITLE_TRANSCODING_JOB_H_ + +#include +#include +#include + +class KProcess; +class K3bExternalBin; + + +/** + * The K3bVideoDVDTitleTranscodingJob rips a Video DVD title directly + * from the medium and transcodes it on-the-fly to, for example, an XviD video + * + * For now only one audio stream is supported. + */ +class LIBK3B_EXPORT K3bVideoDVDTitleTranscodingJob : public K3bJob +{ + Q_OBJECT + + public: + K3bVideoDVDTitleTranscodingJob( K3bJobHandler* hdl, QObject* parent ); + ~K3bVideoDVDTitleTranscodingJob(); + + /** + * The video codecs supported by this job. + */ + enum VideoCodec { + VIDEO_CODEC_XVID, + VIDEO_CODEC_FFMPEG_MPEG4, + VIDEO_CODEC_NUM_ENTRIES /**< Do not use this as a codec. */ + }; + + /** + * The audio codecs supported by this job. + */ + enum AudioCodec { + AUDIO_CODEC_MP3, + /* AUDIO_CODEC_OGG_VORBIS,*/ + AUDIO_CODEC_AC3_STEREO, + AUDIO_CODEC_AC3_PASSTHROUGH, + AUDIO_CODEC_NUM_ENTRIES /**< Do not use this as a codec. */ + }; + + const K3bVideoDVD::VideoDVD& videoDVD() const { return m_dvd; } + int title() const { return m_titleNumber; } + int audioStream() const { return m_audioStreamIndex; } + int clippingTop() const { return m_clippingTop; } + int clippingLeft() const { return m_clippingLeft; } + int clippingBottom() const { return m_clippingBottom; } + int clippingRight() const { return m_clippingRight; } + int height() const { return m_height; } + int width() const { return m_width; } + const QString& filename() { return m_filename; } + VideoCodec videoCodec() const { return m_videoCodec; } + int videoBitrate() const { return m_videoBitrate; } + bool twoPassEncoding() const { return m_twoPassEncoding; } + AudioCodec audioCodec() const { return m_audioCodec; } + int audioBitrate() const { return m_audioBitrate; } + bool audioVBR() const { return m_audioVBR; } + bool resampleAudioTo44100() const { return m_resampleAudio; } + bool lowPriority() const { return m_lowPriority; } + + /** + * \param bin If 0 the default binary from K3bCore will be used + */ + static bool transcodeBinaryHasSupportFor( VideoCodec codec, const K3bExternalBin* bin = 0 ); + + /** + * \param bin If 0 the default binary from K3bCore will be used + */ + static bool transcodeBinaryHasSupportFor( AudioCodec codec, const K3bExternalBin* bin = 0 ); + + static QString videoCodecString( VideoCodec ); + static QString audioCodecString( AudioCodec ); + + static QString videoCodecDescription( VideoCodec ); + static QString audioCodecDescription( AudioCodec ); + + public slots: + void start(); + void cancel(); + + /** + * The device containing the Video DVD + */ + void setVideoDVD( const K3bVideoDVD::VideoDVD& dvd ) { m_dvd = dvd; } + + /** + * Set the title number to be transcoded + * + * The default value is 1, denoting the first title. + */ + void setTitle( int t ) { m_titleNumber = t; } + + /** + * Set the audio stream to use. + * + * For now K3b does not support encoding multiple audio streams + * in one video file. + * + * The default value is 0, meaning that the first audio stream will + * be encoded. + */ + void setAudioStream( int i ) { m_audioStreamIndex = i; } + + /** + * Set the clipping values for the Video title. + * The clipping will be applied before the transcoding. + * + * For now it is not possible to use different clipping values for left + * and right as transcode cannot handle this. Thus, the job uses the + * smaller value for both the left and right clipping. + * + * The default is to not clip the video. + */ + void setClipping( int top, int left, int bottom, int right ); + + /** + * The size of the resulting transcoded video. + * + * The default is to automatically adjust the size (width=height=0), which + * essentially means that anamorph encoded source material will be resized + * according to its aspect ratio. + * + * It is also possible to set just the width or just the height and leave + * the other value to 0 which will then be determined automatically. + * + * The clipping values will be taken into account if at least one value + * is determined automatically. + * + * The width and height values have to be a multiple of 16. If it is not, + * they will be changed accordingly. + * + * FIXME: GET INFORMATION: why a multiple of 16 and not 8 or 32? + */ + void setSize( int width, int height ); + + /** + * The filename to write the resulting video to. + * + * The default is some automatically generated filename + * in the default K3b temp directory. + */ + void setFilename( const QString& name ) { m_filename = name; } + + /** + * Set the video codec used to encode the video title. + * + * The default is VIDEO_CODEC_FFMPEG_MPEG4 + */ + void setVideoCodec( VideoCodec codec ) { m_videoCodec = codec; } + + /** + * Set the bitrate used to encode the video. + * + * The default is 1800 + */ + void setVideoBitrate( int bitrate ) { m_videoBitrate = bitrate; } + + /** + * Set if the job should use two-pass encoding to improve + * the quality of the resulting video. + * + * The default is false. + */ + void setTwoPassEncoding( bool b ) { m_twoPassEncoding = b; } + + /** + * Set the audio codec used to encode the audio stream + * in the video title. + * + * The default is AUDIO_CODEC_MP3 + */ + void setAudioCodec( AudioCodec codec ) { m_audioCodec = codec; } + + /** + * Set the bitrate used to encode the audio stream. + * + * The default is 128 + * + * In case of the AC3 codec the bitrate can be some value between 32 and 640. + * + * For the AC3 passthrough mode the bitrate is ignored. + */ + void setAudioBitrate( int bitrate ) { m_audioBitrate = bitrate; } + + /** + * Set if the audio stream should be encoded with a variable bitrate. + * + * The default is false. + * + * For the AC3 passthrough mode the bitrate is ignored. + */ + void setAudioVBR( bool vbr ) { m_audioVBR = vbr; } + + /** + * Set if the audio data should be resampled to 44100 Hz/s + * + * The default is false. + * + * For the AC3 passthrough mode this is ignored. + */ + void setResampleAudioTo44100( bool b ) { m_resampleAudio = b; } + + /** + * If true the transcode processes will be run with a very low scheduling + * priority. + * + * The default is true. + */ + void setLowPriority( bool b ) { m_lowPriority = b; } + + private slots: + void slotTranscodeStderr( const QString& ); + void slotTranscodeExited( KProcess* ); + + private: + /** + * \param 0 - single pass encoding + * 1 - two pass encoding/first pass + * 2 - two pass encoding/second pass + */ + void startTranscode( int pass ); + + void cleanup( bool success ); + + K3bVideoDVD::VideoDVD m_dvd; + + QString m_filename; + + int m_clippingTop; + int m_clippingBottom; + int m_clippingLeft; + int m_clippingRight; + + int m_width; + int m_height; + + int m_titleNumber; + int m_audioStreamIndex; + + VideoCodec m_videoCodec; + AudioCodec m_audioCodec; + + int m_videoBitrate; + int m_audioBitrate; + bool m_audioVBR; + + bool m_resampleAudio; + bool m_twoPassEncoding; + + bool m_lowPriority; + + class Private; + Private* d; +}; + +#endif diff --git a/libk3b/k3bimage.xsd b/libk3b/k3bimage.xsd new file mode 100644 index 0000000..ab7f36c --- /dev/null +++ b/libk3b/k3bimage.xsd @@ -0,0 +1,175 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libk3b/plugin/Makefile.am b/libk3b/plugin/Makefile.am new file mode 100644 index 0000000..49ac69b --- /dev/null +++ b/libk3b/plugin/Makefile.am @@ -0,0 +1,28 @@ +if compile_libsamplerate +USED_LIBSAMPLERATE=./libsamplerate/libsamplerate.la +SUBDIRS = libsamplerate +else +USED_LIBSAMPLERATE=$(LIBSAMPLERATE) +endif + + +AM_CPPFLAGS = -I$(srcdir)/.. -I$(srcdir)/../core/ -I$(srcdir)/../../src -I$(srcdir)/../../libk3bdevice $(all_includes) + +METASOURCES = AUTO + +noinst_LTLIBRARIES = libk3bplugin.la + +libk3bplugin_la_LIBADD = $(USED_LIBSAMPLERATE) + +libk3bplugin_la_LDFLAGS = $(all_libraries) + +libk3bplugin_la_SOURCES = k3bplugin.cpp \ + k3bpluginconfigwidget.cpp \ + k3bpluginmanager.cpp \ + k3baudiodecoder.cpp \ + k3baudioencoder.cpp \ + k3baudioclient.cpp \ + k3baudioserver.cpp + + +include_HEADERS = k3bplugin.h k3bpluginfactory.h k3bpluginmanager.h k3baudiodecoder.h k3baudioencoder.h k3bpluginconfigwidget.h k3baudiooutputplugin.h k3bprojectplugin.h diff --git a/libk3b/plugin/k3baudioclient.cpp b/libk3b/plugin/k3baudioclient.cpp new file mode 100644 index 0000000..5133d28 --- /dev/null +++ b/libk3b/plugin/k3baudioclient.cpp @@ -0,0 +1,46 @@ +/* + * + * $Id: k3baudioclient.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3baudioclient.h" +#include "k3baudioserver.h" + + +K3bAudioClient::K3bAudioClient() + : m_attached(false) +{ +} + + +K3bAudioClient::~K3bAudioClient() +{ +} + + +void K3bAudioClient::startStreaming() +{ + if( !m_attached ) { + K3bAudioServer::instance()->attachClient( this ); + m_attached = true; + } +} + + +void K3bAudioClient::stopStreaming() +{ + if( m_attached ) { + K3bAudioServer::instance()->detachClient( this ); + m_attached = false; + } +} diff --git a/libk3b/plugin/k3baudioclient.h b/libk3b/plugin/k3baudioclient.h new file mode 100644 index 0000000..9d6c015 --- /dev/null +++ b/libk3b/plugin/k3baudioclient.h @@ -0,0 +1,51 @@ +/* + * + * $Id: k3baudioclient.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_AUDIO_CLIENT_H_ +#define _K3B_AUDIO_CLIENT_H_ + +#include "k3b_export.h" +/** + * Interface for all K3b audio client classes which may attach to + * a K3b Audio Server to play 44100 16bit stereo audio data. + */ +class LIBK3B_EXPORT K3bAudioClient +{ + public: + virtual ~K3bAudioClient(); + + /** + * if this method returns a value below 0 streaming is stopped. + */ + virtual int read( char* data, int maxlen ) = 0; + + protected: + K3bAudioClient(); + + /** + * This will start the streaming. + */ + void startStreaming(); + + /** + * This stops the streaming, + */ + void stopStreaming(); + + private: + bool m_attached; +}; + +#endif diff --git a/libk3b/plugin/k3baudiodecoder.cpp b/libk3b/plugin/k3baudiodecoder.cpp new file mode 100644 index 0000000..82f4adb --- /dev/null +++ b/libk3b/plugin/k3baudiodecoder.cpp @@ -0,0 +1,599 @@ +/* + * + * $Id: k3baudiodecoder.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include + +#include + +#include "k3baudiodecoder.h" +#include "k3bpluginmanager.h" + +#include +#include + +#include + +#include + +#ifdef HAVE_LIBSAMPLERATE +#include +#else +#include "libsamplerate/samplerate.h" +#endif + +#if !(HAVE_LRINT && HAVE_LRINTF) +#define lrint(dbl) ((int) (dbl)) +#define lrintf(flt) ((int) (flt)) +#endif + +// use a one second buffer +static const int DECODING_BUFFER_SIZE = 75*2352; + +class K3bAudioDecoder::Private +{ +public: + Private() + : metaInfo(0), + resampleState(0), + resampleData(0), + inBuffer(0), + inBufferPos(0), + inBufferFill(0), + outBuffer(0), + monoBuffer(0), + decodingBufferPos(0), + decodingBufferFill(0), + valid(true) { + } + + // the current position of the decoder + // This does NOT include the decodingBuffer + K3b::Msf currentPos; + + // since the current position above is measured in frames + // there might be a little offset since the decoded data is not + // always a multiple of 2353 bytes + int currentPosOffset; + + // already decoded bytes from last init or last seek + // TODO: replace alreadyDecoded with currentPos + unsigned long alreadyDecoded; + + K3b::Msf decodingStartPos; + + KFileMetaInfo* metaInfo; + + // set to true once decodeInternal() returned 0 + bool decoderFinished; + + // resampling + SRC_STATE* resampleState; + SRC_DATA* resampleData; + + float* inBuffer; + float* inBufferPos; + int inBufferFill; + + float* outBuffer; + + int samplerate; + int channels; + + // mono -> stereo conversion + char* monoBuffer; + + char decodingBuffer[DECODING_BUFFER_SIZE]; + char* decodingBufferPos; + int decodingBufferFill; + + QMap technicalInfoMap; + QMap metaInfoMap; + + bool valid; +}; + + + +K3bAudioDecoder::K3bAudioDecoder( QObject* parent, const char* name ) + : QObject( parent, name ) +{ + d = new Private(); +} + + +K3bAudioDecoder::~K3bAudioDecoder() +{ + cleanup(); + + if( d->inBuffer ) delete [] d->inBuffer; + if( d->outBuffer ) delete [] d->outBuffer; + if( d->monoBuffer ) delete [] d->monoBuffer; + + delete d->metaInfo; + delete d->resampleData; + if( d->resampleState ) + src_delete( d->resampleState ); + delete d; +} + + +void K3bAudioDecoder::setFilename( const QString& filename ) +{ + m_fileName = filename; + delete d->metaInfo; + d->metaInfo = 0; +} + + +bool K3bAudioDecoder::isValid() const +{ + return d->valid; +} + + +bool K3bAudioDecoder::analyseFile() +{ + d->technicalInfoMap.clear(); + d->metaInfoMap.clear(); + delete d->metaInfo; + d->metaInfo = 0; + + cleanup(); + + bool ret = analyseFileInternal( m_length, d->samplerate, d->channels ); + if( ret && ( d->channels == 1 || d->channels == 2 ) && m_length > 0 ) { + d->valid = initDecoder(); + return d->valid; + } + else { + d->valid = false; + return false; + } +} + + +bool K3bAudioDecoder::initDecoder( const K3b::Msf& startOffset ) +{ + if( initDecoder() ) { + if( startOffset > 0 ) + return seek( startOffset ); + else + return true; + } + else + return false; +} + + +bool K3bAudioDecoder::initDecoder() +{ + cleanup(); + + if( d->resampleState ) + src_reset( d->resampleState ); + + d->alreadyDecoded = 0; + d->currentPos = 0; + d->currentPosOffset = 0; + d->decodingBufferFill = 0; + d->decodingBufferPos = 0; + d->decodingStartPos = 0; + d->inBufferFill = 0; + + d->decoderFinished = false; + + return initDecoderInternal(); +} + + +int K3bAudioDecoder::decode( char* _data, int maxLen ) +{ + unsigned long lengthToDecode = (m_length - d->decodingStartPos).audioBytes(); + + if( d->alreadyDecoded >= lengthToDecode ) + return 0; + + if( maxLen <= 0 ) + return 0; + + int read = 0; + + if( d->decodingBufferFill == 0 ) { + // + // now we decode into the decoding buffer + // to ensure a minimum buffer size + // + d->decodingBufferFill = 0; + d->decodingBufferPos = d->decodingBuffer; + + if( !d->decoderFinished ) { + if( d->samplerate != 44100 ) { + + // check if we have data left from some previous conversion + if( d->inBufferFill > 0 ) { + read = resample( d->decodingBuffer, DECODING_BUFFER_SIZE ); + } + else { + if( !d->inBuffer ) { + d->inBuffer = new float[DECODING_BUFFER_SIZE/2]; + } + + if( (read = decodeInternal( d->decodingBuffer, DECODING_BUFFER_SIZE )) == 0 ) + d->decoderFinished = true; + + d->inBufferFill = read/2; + d->inBufferPos = d->inBuffer; + from16bitBeSignedToFloat( d->decodingBuffer, d->inBuffer, d->inBufferFill ); + + read = resample( d->decodingBuffer, DECODING_BUFFER_SIZE ); + } + } + else if( d->channels == 1 ) { + if( !d->monoBuffer ) { + d->monoBuffer = new char[DECODING_BUFFER_SIZE/2]; + } + + // we simply duplicate every frame + if( (read = decodeInternal( d->monoBuffer, DECODING_BUFFER_SIZE/2 )) == 0 ) + d->decoderFinished = true; + + for( int i = 0; i < read; i+=2 ) { + d->decodingBuffer[2*i] = d->decodingBuffer[2*i+2] = d->monoBuffer[i]; + d->decodingBuffer[2*i+1] = d->decodingBuffer[2*i+3] = d->monoBuffer[i+1]; + } + + read *= 2; + } + else { + if( (read = decodeInternal( d->decodingBuffer, DECODING_BUFFER_SIZE )) == 0 ) + d->decoderFinished = true; + } + } + + if( read < 0 ) { + return -1; + } + else if( read == 0 ) { + // check if we need to pad + int bytesToPad = lengthToDecode - d->alreadyDecoded; + if( bytesToPad > 0 ) { + kdDebug() << "(K3bAudioDecoder) track length: " << lengthToDecode + << "; decoded module data: " << d->alreadyDecoded + << "; we need to pad " << bytesToPad << " bytes." << endl; + + if( DECODING_BUFFER_SIZE < bytesToPad ) + bytesToPad = DECODING_BUFFER_SIZE; + + ::memset( d->decodingBuffer, 0, bytesToPad ); + + kdDebug() << "(K3bAudioDecoder) padded " << bytesToPad << " bytes." << endl; + + read = bytesToPad; + } + else { + kdDebug() << "(K3bAudioDecoder) decoded " << d->alreadyDecoded << " bytes." << endl; + return 0; + } + } + else { + + // check if we decoded too much + if( d->alreadyDecoded + read > lengthToDecode ) { + kdDebug() << "(K3bAudioDecoder) we decoded too much. Cutting output by " + << (read + d->alreadyDecoded - lengthToDecode) << endl; + read = lengthToDecode - d->alreadyDecoded; + } + } + + d->decodingBufferFill = read; + } + + + // clear out the decoding buffer + read = QMIN( maxLen, d->decodingBufferFill ); + ::memcpy( _data, d->decodingBufferPos, read ); + d->decodingBufferPos += read; + d->decodingBufferFill -= read; + + d->alreadyDecoded += read; + d->currentPos += (read+d->currentPosOffset)/2352; + d->currentPosOffset = (read+d->currentPosOffset)%2352; + + return read; +} + + +// resample data in d->inBufferPos and save the result to data +// +// +int K3bAudioDecoder::resample( char* data, int maxLen ) +{ + if( !d->resampleState ) { + d->resampleState = src_new( SRC_SINC_MEDIUM_QUALITY, d->channels, 0 ); + if( !d->resampleState ) { + kdDebug() << "(K3bAudioDecoder) unable to initialize resampler." << endl; + return -1; + } + d->resampleData = new SRC_DATA; + } + + if( !d->outBuffer ) { + d->outBuffer = new float[DECODING_BUFFER_SIZE/2]; + } + + d->resampleData->data_in = d->inBufferPos; + d->resampleData->data_out = d->outBuffer; + d->resampleData->input_frames = d->inBufferFill/d->channels; + d->resampleData->output_frames = maxLen/2/2; // in case of mono files we need the space anyway + d->resampleData->src_ratio = 44100.0/(double)d->samplerate; + if( d->inBufferFill == 0 ) + d->resampleData->end_of_input = 1; // this should force libsamplerate to output the last frames + else + d->resampleData->end_of_input = 0; + + int len = 0; + if( (len = src_process( d->resampleState, d->resampleData ) ) ) { + kdDebug() << "(K3bAudioDecoder) error while resampling: " << src_strerror(len) << endl; + return -1; + } + + if( d->channels == 2 ) + fromFloatTo16BitBeSigned( d->outBuffer, data, d->resampleData->output_frames_gen*d->channels ); + else { + for( int i = 0; i < d->resampleData->output_frames_gen; ++i ) { + fromFloatTo16BitBeSigned( &d->outBuffer[i], &data[4*i], 1 ); + fromFloatTo16BitBeSigned( &d->outBuffer[i], &data[4*i+2], 1 ); + } + } + + d->inBufferPos += d->resampleData->input_frames_used*d->channels; + d->inBufferFill -= d->resampleData->input_frames_used*d->channels; + if( d->inBufferFill <= 0 ) { + d->inBufferPos = d->inBuffer; + d->inBufferFill = 0; + } + + // 16 bit frames, so we need to multiply by 2 + // and we always have two channels + return d->resampleData->output_frames_gen*2*2; +} + + +void K3bAudioDecoder::from16bitBeSignedToFloat( char* src, float* dest, int samples ) +{ + while( samples ) { + samples--; + dest[samples] = static_cast( Q_INT16(((src[2*samples]<<8)&0xff00)|(src[2*samples+1]&0x00ff)) / 32768.0 ); + } +} + + +void K3bAudioDecoder::fromFloatTo16BitBeSigned( float* src, char* dest, int samples ) +{ + while( samples ) { + samples--; + + float scaled = src[samples] * 32768.0; + Q_INT16 val = 0; + + // clipping + if( scaled >= ( 1.0 * 0x7FFF ) ) + val = 32767; + else if( scaled <= ( -8.0 * 0x1000 ) ) + val = -32768; + else + val = lrintf(scaled); + + dest[2*samples] = val>>8; + dest[2*samples+1] = val; + } +} + + +void K3bAudioDecoder::from8BitTo16BitBeSigned( char* src, char* dest, int samples ) +{ + while( samples ) { + samples--; + + float scaled = static_cast(Q_UINT8(src[samples])-128) / 128.0 * 32768.0; + Q_INT16 val = 0; + + // clipping + if( scaled >= ( 1.0 * 0x7FFF ) ) + val = 32767; + else if( scaled <= ( -8.0 * 0x1000 ) ) + val = -32768; + else + val = lrintf(scaled); + + dest[2*samples] = val>>8; + dest[2*samples+1] = val; + } +} + + +bool K3bAudioDecoder::seek( const K3b::Msf& pos ) +{ + kdDebug() << "(K3bAudioDecoder) seek from " << d->currentPos.toString() << " (+" << d->currentPosOffset + << ") to " << pos.toString() << endl; + + if( pos > length() ) + return false; + + d->decoderFinished = false; + + if( pos == d->currentPos && d->currentPosOffset == 0 ) + return true; + + if( pos == 0 ) + return initDecoder(); + + bool success = false; + + // + // First check if we may do a "perfect seek". + // We cannot rely on the decoding plugins to seek perfectly. Especially + // the mp3 decoder does not. But in case we want to split a live recording + // it is absolutely nesseccary to perform a perfect seek. + // So if we did not already decode past the seek position and the difference + // between the current position and the seek position is less than some fixed + // value we simply decode up to the seek position. + // + if( ( pos > d->currentPos || + ( pos == d->currentPos && d->currentPosOffset == 0 ) ) + && + ( pos - d->currentPos < K3b::Msf(0,10,0) ) ) { // < 10 seconds is ok + kdDebug() << "(K3bAudioDecoder) performing perfect seek from " << d->currentPos.toString() + << " to " << pos.toString() << ". :)" << endl; + + unsigned long bytesToDecode = pos.audioBytes() - d->currentPos.audioBytes() - d->currentPosOffset; + kdDebug() << "(K3bAudioDecoder) seeking " << bytesToDecode << " bytes." << endl; + char buffi[10*2352]; + while( bytesToDecode > 0 ) { + int read = decode( buffi, QMIN(10*2352, bytesToDecode) ); + if( read <= 0 ) + return false; + + bytesToDecode -= read; + } + + kdDebug() << "(K3bAudioDecoder) perfect seek done." << endl; + + success = true; + } + else { + // + // Here we have to reset the resampling stuff since we restart decoding at another position. + // + if( d->resampleState ) + src_reset( d->resampleState ); + d->inBufferFill = 0; + + // + // And also reset the decoding buffer to not return any garbage from previous decoding. + // + d->decodingBufferFill = 0; + + success = seekInternal( pos ); + } + + d->alreadyDecoded = 0; + d->currentPos = d->decodingStartPos = pos; + d->currentPosOffset = 0; + + return success; +} + + +void K3bAudioDecoder::cleanup() +{ +} + + +QString K3bAudioDecoder::metaInfo( MetaDataField f ) +{ + if( d->metaInfoMap.contains( f ) ) + return d->metaInfoMap[f]; + + // fall back to KFileMetaInfo + if( !d->metaInfo ) + d->metaInfo = new KFileMetaInfo( filename() ); + + if( d->metaInfo->isValid() ) { + QString tag; + switch( f ) { + case META_TITLE: + tag = "Title"; + break; + case META_ARTIST: + tag = "Artist"; + break; + case META_SONGWRITER: + tag = "Songwriter"; + break; + case META_COMPOSER: + tag = "Composer"; + break; + case META_COMMENT: + tag = "Comment"; + break; + } + + KFileMetaInfoItem item = d->metaInfo->item( tag ); + if( item.isValid() ) + return item.string(); + } + + return QString::null; +} + + +void K3bAudioDecoder::addMetaInfo( MetaDataField f, const QString& value ) +{ + if( !value.isEmpty() ) + d->metaInfoMap[f] = value; + else + kdDebug() << "(K3bAudioDecoder) empty meta data field." << endl; +} + + +QStringList K3bAudioDecoder::supportedTechnicalInfos() const +{ + QStringList l; + for( QMap::const_iterator it = d->technicalInfoMap.begin(); + it != d->technicalInfoMap.end(); ++it ) + l.append( it.key() ); + return l; +} + + +QString K3bAudioDecoder::technicalInfo( const QString& key ) const +{ + return d->technicalInfoMap[key]; +} + + +void K3bAudioDecoder::addTechnicalInfo( const QString& key, const QString& value ) +{ + d->technicalInfoMap[key] = value; +} + + +K3bAudioDecoder* K3bAudioDecoderFactory::createDecoder( const KURL& url ) +{ + kdDebug() << "(K3bAudioDecoderFactory::createDecoder( " << url.path() << " )" << endl; + QPtrList fl = k3bcore->pluginManager()->plugins( "AudioDecoder" ); + + // first search for a single format decoder + for( QPtrListIterator it( fl ); it.current(); ++it ) { + K3bAudioDecoderFactory* f = dynamic_cast( it.current() ); + if( f && !f->multiFormatDecoder() && f->canDecode( url ) ) { + kdDebug() << "1" << endl; return f->createDecoder();} + } + + // no single format decoder. Search for a multi format decoder + for( QPtrListIterator it( fl ); it.current(); ++it ) { + K3bAudioDecoderFactory* f = dynamic_cast( it.current() ); + if( f && f->multiFormatDecoder() && f->canDecode( url ) ) { + kdDebug() << "2" << endl; return f->createDecoder();} + } + + kdDebug() << "(K3bAudioDecoderFactory::createDecoder( " << url.path() << " ) no success" << endl; + + // nothing found + return 0; +} + +#include "k3baudiodecoder.moc" diff --git a/libk3b/plugin/k3baudiodecoder.h b/libk3b/plugin/k3baudiodecoder.h new file mode 100644 index 0000000..69f594c --- /dev/null +++ b/libk3b/plugin/k3baudiodecoder.h @@ -0,0 +1,254 @@ +/* + * + * $Id: k3baudiodecoder.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_AUDIO_DECODER_H_ +#define _K3B_AUDIO_DECODER_H_ + + +#include +#include +#include "k3b_export.h" +#include + + + +/** + * Abstract streaming class for all the audio input. + * Has to output data in the following format: + * MSBLeft LSBLeft MSBRight LSBRight (big endian byte order) + * + * Instances are created by K3bAudioDecoderFactory + **/ +class LIBK3B_EXPORT K3bAudioDecoder : public QObject +{ + Q_OBJECT + + public: + K3bAudioDecoder( QObject* parent = 0, const char* name = 0 ); + virtual ~K3bAudioDecoder(); + + + /** + * Set the file to decode. Be aware that one cannot rely + * on the file length until analyseFile() has been called. + */ + void setFilename( const QString& ); + + /** + * Since this may take a while depending on the filetype it is best + * to run it in a separate thread. + * + * This method will also call initDecoder(). + */ + bool analyseFile(); + + /** + * @return true if the file was successfully analysed by analyseFile. + */ + bool isValid() const; + + /** + * Initialize the decoding. + * Normally there is no need to call this as analyseFile already does so. + */ + bool initDecoder(); + + /** + * initialize the decoding. + * @param startOffset the number of frames to skip at the beginning of the file. + * + * This is the same as calling: initDecoder() and seek(startOffset) + */ + bool initDecoder( const K3b::Msf& startOffset ); + + enum MetaDataField { + META_TITLE, + META_ARTIST, + META_SONGWRITER, + META_COMPOSER, + META_COMMENT + }; + + /** + * This should at least support "Title" and "Artist" + * + * the default implementation returns the infos set via @p addMetaInfo + * and uses KFileMetaInfo if none was set + */ + virtual QString metaInfo( MetaDataField ); + + /** + * The filetype is only used for informational purposes. + * It is not necessary but highly recommended to implement this method + * as it enhances usability. + * @returne The filetype of the decoded file. + */ + virtual QString fileType() const { return QString::null; } + + /** + * This method may be reimplemented to provide technical information about + * the file. It should return localized strings. + * + * the default implementation returns the infos set via @p addTechnicalInfo + */ + virtual QStringList supportedTechnicalInfos() const; + + /** + * The framework will call this method with all strings returned by the + * supportedTechnicalInfos() method. It should return localized strings. + * + * the default implementation returns the infos set via @p addTechnicalInfo + */ + virtual QString technicalInfo( const QString& ) const; + + /** + * returnes -1 on error, 0 when finished, length of data otherwise + * takes care of padding + * calls decodeInternal() to actually decode data + * + * Fill the data buffer with maximal maxLen bytes. + */ + int decode( char* data, int maxLen ); + + /** + * Cleanup after decoding like closing files. + * Be aware that this is the counterpart to @p initDecoder(). + * + * There might happen multiple calls to initDecoder() and cleanup(). + */ + virtual void cleanup(); + + /** + * Seek to the position pos. + * Decoding is started new. That means that the data will be padded to + * length() - pos. + * returnes true on success; + */ + bool seek( const K3b::Msf& pos ); + + /** + * Be aware that one cannot rely + * on the file length until analyseFile() has been called. + */ + virtual K3b::Msf length() const { return m_length; } + + const QString& filename() const { return m_fileName; } + + // some helper methods + static void fromFloatTo16BitBeSigned( float* src, char* dest, int samples ); + static void from16bitBeSignedToFloat( char* src, float* dest, int samples ); + static void from8BitTo16BitBeSigned( char* src, char* dest, int samples ); + + protected: + /** + * Use this method if using the default implementation of @p metaInfo + */ + void addMetaInfo( MetaDataField, const QString& ); + + /** + * Use this method if using the default implementation of @p technicalInfo + * and @p supportedTechnicalInfos. + */ + void addTechnicalInfo( const QString&, const QString& ); + + /** + * This will be called once before the first call to decodeInternal. + * Use it to initialize decoding structures if necessary. + * + * There might happen multiple calls to initDecoder() and cleanup(). + */ + virtual bool initDecoderInternal() = 0; + + /** + * This method should analyze the file to determine the exact length, + * the samplerate in Hz, and the number of channels. The framework takes care of + * resampling and converting mono to stereo data. + * This method may be time consuming. + */ + virtual bool analyseFileInternal( K3b::Msf& length, int& samplerate, int& channels ) = 0; + + /** + * fill the already allocated data with maximal maxLen bytes of decoded samples. + * The framework will take care of padding or cutting the decoded data as well + * as resampling to 44100 Hz and converting mono samples to stereo. + */ + virtual int decodeInternal( char* data, int maxLen ) = 0; + + virtual bool seekInternal( const K3b::Msf& ) { return false; } + + private: + int resample( char* data, int maxLen ); + + QString m_fileName; + K3b::Msf m_length; + + class Private; + Private* d; +}; + + + +/** + * PluginFactory that needs to be subclassed in order to create an + * audio decoder. + * We need this because K3b uses multiple AudioDecoders of the same type at the + * same time. + */ +class LIBK3B_EXPORT K3bAudioDecoderFactory : public K3bPlugin +{ + Q_OBJECT + + public: + K3bAudioDecoderFactory( QObject* parent = 0, const char* name = 0 ) + : K3bPlugin( parent, name ) { + } + + virtual ~K3bAudioDecoderFactory() { + } + + QString group() const { return "AudioDecoder"; } + + /** + * K3b uses this flag to decide which plugins to test first + * when searching for an audio decoder. + * + * Decoders that are specialized on one format are favored over + * multi-format-decoders. + */ + virtual bool multiFormatDecoder() const { return false; } + + /** + * This is the most important method of the AudioDecoderFactory. + * It is used to determine if a certain file can be decoded by the + * decoder this factory creates. + * It is important that this method does not work lazy since it will + * be called with urls to every kind of files and if it returns true + * a decoder of this type is used for the file. + */ + virtual bool canDecode( const KURL& filename ) = 0; + + virtual K3bAudioDecoder* createDecoder( QObject* parent = 0, const char* name = 0 ) const = 0; + + /** + * Searching for an audiodecoder for @p filename. + * + * It first searches the single format decoder and the the multiformat decoder. + * + * @returns a newly created decoder on success and 0 when no decoder could be found. + */ + static K3bAudioDecoder* createDecoder( const KURL& url ); +}; + +#endif diff --git a/libk3b/plugin/k3baudioencoder.cpp b/libk3b/plugin/k3baudioencoder.cpp new file mode 100644 index 0000000..3b1309a --- /dev/null +++ b/libk3b/plugin/k3baudioencoder.cpp @@ -0,0 +1,175 @@ +/* + * + * $Id: k3baudioencoder.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3baudioencoder.h" + +#include + +#include + + +class K3bAudioEncoder::Private +{ +public: + Private() + : outputFile(0) { + } + + QFile* outputFile; + QString outputFilename; + + QString lastErrorString; +}; + + +K3bAudioEncoder::K3bAudioEncoder( QObject* parent, const char* name ) + : K3bPlugin( parent, name ) +{ + d = new Private(); +} + + +K3bAudioEncoder::~K3bAudioEncoder() +{ + closeFile(); + delete d; +} + + +bool K3bAudioEncoder::openFile( const QString& ext, const QString& filename, const K3b::Msf& length ) +{ + closeFile(); + + d->outputFile = new QFile( filename ); + if( d->outputFile->open( IO_WriteOnly ) ) { + return initEncoder( ext, length ); + } + else { + kdDebug() << "(K3bAudioEncoder) unable to open file " << filename << endl; + closeFile(); + return false; + } +} + + +bool K3bAudioEncoder::isOpen() const +{ + if( d->outputFile ) + return d->outputFile->isOpen(); + else + return false; +} + + +void K3bAudioEncoder::closeFile() +{ + if( d->outputFile ) { + finishEncoder(); + if( d->outputFile->isOpen() ) + d->outputFile->close(); + delete d->outputFile; + d->outputFile = 0; + d->outputFilename = QString::null; + } +} + + +const QString& K3bAudioEncoder::filename() const +{ + if( d->outputFile ) + return d->outputFilename; + else + return QString::null; +} + + + +void K3bAudioEncoder::setMetaData( K3bAudioEncoder::MetaDataField f, const QString& data ) +{ + if( !data.isEmpty() ) + return setMetaDataInternal( f, data ); +} + + +long K3bAudioEncoder::encode( const char* data, Q_ULONG len ) +{ + return encodeInternal( data, len ); +} + + +bool K3bAudioEncoder::initEncoder( const QString& ext, const K3b::Msf& length ) +{ + if( !isOpen() ) { + kdDebug() << "(K3bAudioEncoder) call to initEncoder without openFile!" << endl; + return false; + } + + return initEncoderInternal( ext, length ); +} + + +Q_LONG K3bAudioEncoder::writeData( const char* data, Q_ULONG len ) +{ + if( d->outputFile ) { + return d->outputFile->writeBlock( data, len ); + } + else { + kdDebug() << "(K3bAudioEncoder) call to writeData without opening a file first." << endl; + return -1; + } +} + + +bool K3bAudioEncoder::initEncoderInternal( const QString&, const K3b::Msf& ) +{ + // do nothing + return true; +} + + +void K3bAudioEncoder::setMetaDataInternal( K3bAudioEncoder::MetaDataField, const QString& ) +{ + // do nothing +} + + +void K3bAudioEncoder::finishEncoder() +{ + if( isOpen() ) + finishEncoderInternal(); +} + + +void K3bAudioEncoder::finishEncoderInternal() +{ + // do nothing +} + + +void K3bAudioEncoder::setLastError( const QString& e ) +{ + d->lastErrorString = e; +} + + +QString K3bAudioEncoder::lastErrorString() const +{ + if( d->lastErrorString.isEmpty() ) + return i18n("An unknown error occurred."); + else + return d->lastErrorString; +} + +#include "k3baudioencoder.moc" diff --git a/libk3b/plugin/k3baudioencoder.h b/libk3b/plugin/k3baudioencoder.h new file mode 100644 index 0000000..137b49d --- /dev/null +++ b/libk3b/plugin/k3baudioencoder.h @@ -0,0 +1,203 @@ +/* + * + * $Id: k3baudioencoder.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_AUDIO_ENCODER_H_ +#define _K3B_AUDIO_ENCODER_H_ + +#include + +#include +#include "k3b_export.h" + + +/** + * The base class for all audio encoders. + * Do not be alarmed by the number of methods since most of them + * do not need to be touched. They are just there to keep the API + * clean and extendable. + * + * see the skeleton files for further help. + */ +class LIBK3B_EXPORT K3bAudioEncoder : public K3bPlugin +{ + Q_OBJECT + + public: + K3bAudioEncoder( QObject* parent = 0, const char* name = 0 ); + virtual ~K3bAudioEncoder(); + + // TODO: if the following methods are to be activated the config methods in + // K3bPluginConfigWidget also need to be changed since they do not allow + // to use an extern config object yet. + // Perhaps these two methods should even go into K3bPlugin. + /** + * This calls readConfig using the k3bcore config object + */ + // void readConfig(); + + /** + * Force the plugin to read it's configuration + */ + // virtual void readConfig( KConfig* ); + + QString group() const { return "AudioEncoder"; } + + /** + * This should return the fileextensions supported by the filetype written in the + * encoder. + * May return an empty list in which case the encoder will not be usable (this may come + * in handy if the encoder is based on some external program or lib which is not + * available on runtime.) + */ + virtual QStringList extensions() const = 0; + + /** + * The filetype as presented to the user. + */ + virtual QString fileTypeComment( const QString& extension ) const = 0; + + /** + * Determine the filesize of the encoded file (~) + * default implementation returnes -1 (unknown) + * First parameter is the extension to be used + */ + virtual long long fileSize( const QString&, const K3b::Msf& ) const { return -1; } + + /** + * The default implementation openes the file for writing with + * writeData. Normally this does not need to be reimplemented. + * @param extension the filetype to be used. + * + */ + virtual bool openFile( const QString& extension, const QString& filename, const K3b::Msf& length ); + + + /** + * The default implementation returnes true if openFile (default implementation) has been + * successfully called. Normally this does not need to be reimplemented but it has to be + * if openFile is reimplemented. + */ + virtual bool isOpen() const; + + /** + * The default implementation closes the file opened by openFile + * (default implementation) + * Normally this does not need to be reimplemented but it has to be + * if openFile is reimplemented. + */ + virtual void closeFile(); + + /** + * The default implementation returnes the filename set in openFile + * or QString::null if no file has been opened. + * Normally this does not need to be reimplemented but it has to be + * if openFile is reimplemented. + */ + virtual const QString& filename() const; + + enum MetaDataField { + META_TRACK_TITLE, + META_TRACK_ARTIST, + META_TRACK_COMMENT, + META_TRACK_NUMBER, + META_ALBUM_TITLE, + META_ALBUM_ARTIST, + META_ALBUM_COMMENT, + META_YEAR, + META_GENRE }; + + /** + * Calling this method does only make sense after successfully + * calling openFile and before calling encode. + * This calls setMetaDataInternal. + */ + void setMetaData( MetaDataField, const QString& ); + + /** + * Returnes the amount of actually written bytes or -1 if an error + * occurred. + * + * Be aware that the returned amount of written data may very well differ + * from len since the data is encoded. + */ + long encode( const char*, Q_ULONG len ); + + /** + * Use this signal in case of an error to provide the user with information + * about the problem. + */ + virtual QString lastErrorString() const; + + protected: + /** + * Called by the default implementation of openFile + * This calls initEncoderInternal. + */ + bool initEncoder( const QString& extension, const K3b::Msf& length ); + + /** + * Called by the deafult implementation of openFile + * This calls finishEncoderInternal. + */ + void finishEncoder(); + + /** + * Use this to write the data to the file when + * using the default implementation of openFile + * Returnes the number of bytes actually written. + */ + Q_LONG writeData( const char*, Q_ULONG len ); + + /** + * initzialize the decoder structures. + * default implementation does nothing + * this may already write data. + */ + virtual bool initEncoderInternal( const QString& extension, const K3b::Msf& length ); + + /** + * reimplement this if the encoder needs to do some + * finishing touch. + */ + virtual void finishEncoderInternal(); + + /** + * encode the data and write it with writeData (when using + * the default) + * The data will always be 16bit 44100 Hz stereo little endian samples. + * Should return the amount of actually written bytes (may be 0) and -1 + * on error. + */ + // TODO: use Q_INT16* instead of char* + // FIXME: why little endian while CDs use big endian??? + virtual long encodeInternal( const char*, Q_ULONG len ) = 0; + + /** + * default implementation does nothing + * this may already write data. + */ + virtual void setMetaDataInternal( MetaDataField, const QString& ); + + /** + * Use this in combination with the default implementation of lastError() + */ + void setLastError( const QString& ); + + private: + class Private; + Private* d; +}; + +#endif diff --git a/libk3b/plugin/k3baudiooutputplugin.h b/libk3b/plugin/k3baudiooutputplugin.h new file mode 100644 index 0000000..97e897a --- /dev/null +++ b/libk3b/plugin/k3baudiooutputplugin.h @@ -0,0 +1,69 @@ +/* + * + * $Id: k3baudiooutputplugin.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_AUDIO_OUTPUTPLUGIN_H_ +#define _K3B_AUDIO_OUTPUTPLUGIN_H_ + +#include +#include "k3b_export.h" + +/** + * + */ +class LIBK3B_EXPORT K3bAudioOutputPlugin : public K3bPlugin +{ + Q_OBJECT + + public: + virtual ~K3bAudioOutputPlugin() { + } + + QString group() const { return "AudioOutput"; } + + /** + * This is the short name of the sound system which can be used + * to specify the sound system on the command line (like "arts", "alsa", or "oss") + */ + virtual QCString soundSystem() const = 0; + + /** + * Initialize the plugin. + * + * Return true on success. + * In case of a failure report the error through lastErrorMessage + */ + virtual bool init() { return true; } + + /** + * Cleanup the plugin. This is the counterpart to init() + */ + virtual void cleanup() {} + + virtual QString lastErrorMessage() const { return QString::null; } + + /** + * Let there be sound... + * + * @returns number of written bytes or -1 on error. + */ + virtual int write( char* data, int len ) = 0; + + protected: + K3bAudioOutputPlugin( QObject* parent = 0, const char* name = 0 ) + : K3bPlugin( parent, name ) { + } +}; + +#endif diff --git a/libk3b/plugin/k3baudioserver.cpp b/libk3b/plugin/k3baudioserver.cpp new file mode 100644 index 0000000..ecfb25f --- /dev/null +++ b/libk3b/plugin/k3baudioserver.cpp @@ -0,0 +1,214 @@ +/* + * + * $Id: k3baudioserver.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include +#include +#include +#include "k3baudioserver.h" +#include "k3baudioclient.h" +#include "k3bpluginmanager.h" +#include "k3baudiooutputplugin.h" + +#include +#include +#include +#include + +#include + + + +K3bAudioServer* K3bAudioServer::s_instance = 0; + + + +class K3bAudioServer::Private : public K3bThread +{ +public: + Private( K3bAudioServer* s ) + : m_streaming(false), + m_server(s) { + setProgressInfoEventHandler( m_server ); + } + + + void stop() { + m_streaming = false; + } + +protected: + void run() { + m_streaming = true; + + char buffer[2048*10]; + + while( m_streaming ) { + int len = m_server->m_client->read( buffer, 2048*10 ); + if( len > 0 ) { + if( m_server->m_pluginInitialized ) { + if( write( buffer, len ) < 0 ) { + kdDebug() << "Audio Streaming failed: " << m_server->m_usedOutputPlugin->lastErrorMessage() << endl; + emitInfoMessage( m_server->m_usedOutputPlugin->lastErrorMessage(), 0 ); + return; + } + } + // else just drop the data into space... + } + else { + // FIXME: no data or error... what to do? + } + } + } + + int write( char* buffer, int len ) { + int written = m_server->m_usedOutputPlugin->write( buffer, len ); + return written; +// if( written < 0 ) +// return -1; +// else if( written < len ) +// return write( buffer+written, len-written ) + written; +// else +// return len; + } + +private: + bool m_streaming; + K3bAudioServer* m_server; +}; + + +K3bAudioServer::K3bAudioServer( QObject* parent, const char* name ) + : QObject( parent, name ), + m_usedOutputPlugin(0), + m_pluginInitialized(false), + m_client(0) +{ + s_instance = this; + d = new Private( this ); +} + + +K3bAudioServer::~K3bAudioServer() +{ + delete d; + s_instance = 0; +} + + +bool K3bAudioServer::setOutputMethod( const QCString& name ) +{ + if( K3bAudioOutputPlugin* p = findOutputPlugin( name ) ) { + setOutputPlugin( p ); + return true; + } + else + return false; +} + + +void K3bAudioServer::setOutputPlugin( K3bAudioOutputPlugin* p ) +{ + if( p != m_usedOutputPlugin ) { + bool restart = d->running(); + if( restart ) { + d->stop(); + d->wait(); + } + + if( m_usedOutputPlugin ) { + m_usedOutputPlugin->cleanup(); + m_pluginInitialized = false; + } + + m_usedOutputPlugin = p; + + if( restart ) + d->start(); + } +} + + +void K3bAudioServer::attachClient( K3bAudioClient* c ) +{ + // for now we simply allow only one client and stop the old one + if( m_client ) { + kdDebug() << "(K3bAudioServer) leaving old client hanging. :(" << endl; + detachClient( m_client ); + } + + m_client = c; + + if( m_usedOutputPlugin && !m_pluginInitialized ) { + if( !m_usedOutputPlugin->init() ) { + emit error( i18n("Could not initialize Audio Output plugin %1 (%2)") + .arg(m_usedOutputPlugin->pluginInfo().name()) + .arg(m_usedOutputPlugin->lastErrorMessage()) ); + } + else + m_pluginInitialized = true; + } + else + kdDebug() << "(K3bAudioServer::attachClient) no output plugin selected. Using null output." << endl; + + // start the streaming + d->start(); +} + + +void K3bAudioServer::detachClient( K3bAudioClient* c ) +{ + if( m_client == c ) { + m_client = 0; + + // stop the streaming + d->stop(); + d->wait(); + + if( m_usedOutputPlugin && m_pluginInitialized ) { + m_usedOutputPlugin->cleanup(); + m_pluginInitialized = false; + } + } +} + + +K3bAudioOutputPlugin* K3bAudioServer::findOutputPlugin( const QCString& name ) +{ + QPtrList fl = k3bcore->pluginManager()->plugins( "AudioOutput" ); + + for( QPtrListIterator it( fl ); it.current(); ++it ) { + K3bAudioOutputPlugin* f = dynamic_cast( it.current() ); + + if( f && f->soundSystem() == name ) { + return f; + } + } + + kdDebug() << "(K3bAudioServer::findOutputPlugin) could not find output plugin " << name << endl; + + return 0; +} + + +void K3bAudioServer::customEvent( QCustomEvent* e ) +{ + if( K3bProgressInfoEvent* be = dynamic_cast(e) ) { + if( be->type() == K3bProgressInfoEvent::InfoMessage ) { + emit error( be->firstString() ); + } + } +} + +#include "k3baudioserver.moc" diff --git a/libk3b/plugin/k3baudioserver.h b/libk3b/plugin/k3baudioserver.h new file mode 100644 index 0000000..1e8d4a8 --- /dev/null +++ b/libk3b/plugin/k3baudioserver.h @@ -0,0 +1,85 @@ +/* + * + * $Id$ + * Copyright (C) 2004 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_AUDIO_SERVER_H_ +#define _K3B_AUDIO_SERVER_H_ + +#include +#include "k3b_export.h" +class K3bAudioOutputPlugin; +class K3bAudioClient; + + +/** + * The AudioServer manages AudioClients to play audio data through + * some output plugin. + */ +class LIBK3B_EXPORT K3bAudioServer : public QObject +{ + Q_OBJECT + + public: + K3bAudioServer( QObject* parent = 0, const char* name = 0 ); + ~K3bAudioServer(); + + /** + * Returns false in case the named output method could not be found. + */ + bool setOutputMethod( const QCString& name ); + void setOutputPlugin( K3bAudioOutputPlugin* p ); + + /** + * Start playing the clients data. It's up to the server if older + * clients are suspended, stopped or mixed into a single stream. + * + * This is called by K3bAudioClient + */ + void attachClient( K3bAudioClient* ); + + /** + * Stop streaming data from the client. + * This is called by K3bAudioClient + */ + void detachClient( K3bAudioClient* ); + + /** + * We need to be able to play data from everywhere in K3b. + */ + static K3bAudioServer* instance() { return s_instance; } + + /** + * Find a plugin by classname. + */ + static K3bAudioOutputPlugin* findOutputPlugin( const QCString& name ); + + signals: + void error( const QString& ); + + private: + void customEvent( QCustomEvent* e ); + + class Private; + friend class Private; + + static K3bAudioServer* s_instance; + + K3bAudioOutputPlugin* m_usedOutputPlugin; + bool m_pluginInitialized; + K3bAudioClient* m_client; + + Private* d; +}; + +#endif diff --git a/libk3b/plugin/k3bplugin.cpp b/libk3b/plugin/k3bplugin.cpp new file mode 100644 index 0000000..db75bb4 --- /dev/null +++ b/libk3b/plugin/k3bplugin.cpp @@ -0,0 +1,36 @@ +/* + * + * $Id: k3bplugin.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bplugin.h" + + +K3bPlugin::K3bPlugin( QObject* parent, const char* name ) + : QObject( parent, name ) +{ +} + + +K3bPlugin::~K3bPlugin() +{ +} + + +K3bPluginConfigWidget* K3bPlugin::createConfigWidget( QWidget*, const char* ) const +{ + return 0; +} + +#include "k3bplugin.moc" diff --git a/libk3b/plugin/k3bplugin.h b/libk3b/plugin/k3bplugin.h new file mode 100644 index 0000000..f4501a7 --- /dev/null +++ b/libk3b/plugin/k3bplugin.h @@ -0,0 +1,113 @@ +/* + * + * $Id: k3bplugin.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_PLUGIN_H_ +#define _K3B_PLUGIN_H_ + +#include +#include +#include "k3b_export.h" + +#define K3B_PLUGIN_SYSTEM_VERSION 3 + + +class K3bPluginConfigWidget; +class QWidget; + + + +class K3bPluginInfo +{ + friend class K3bPluginManager; + + public: + K3bPluginInfo() { + } + + K3bPluginInfo( QString libraryName, + QString name, + QString author, + QString email, + QString comment, + QString version, + QString licence ) + : m_libraryName(libraryName), + m_name(name), + m_author(author), + m_email(email), + m_comment(comment), + m_version(version), + m_licence(licence) { + } + + const QString& name() const { return m_name; } + const QString& author() const { return m_author; } + const QString& email() const { return m_email; } + const QString& comment() const { return m_comment; } + const QString& version() const { return m_version; } + const QString& licence() const { return m_licence; } + + const QString& libraryName() const { return m_libraryName; } + + private: + QString m_libraryName; + + QString m_name; + QString m_author; + QString m_email; + QString m_comment; + QString m_version; + QString m_licence; +}; + + +/** + * Base class for all plugins. You may use the K3bPluginFactory to make your plugin available. + */ +class LIBK3B_EXPORT K3bPlugin : public QObject +{ + Q_OBJECT + + friend class K3bPluginManager; + + public: + K3bPlugin( QObject* parent = 0, const char* name = 0 ); + virtual ~K3bPlugin(); + + const K3bPluginInfo& pluginInfo() const { return m_pluginInfo; } + + /** + * Version of the plugin system this plugin was written for. + */ + virtual int pluginSystemVersion() const = 0; + + /** + * The plugin group. + */ + virtual QString group() const = 0; + + /** + * Returns a widget which configures the plugin. + * + * The caller has to destroy the widget + */ + virtual K3bPluginConfigWidget* createConfigWidget( QWidget* parent = 0, const char* name = 0 ) const; + + private: + K3bPluginInfo m_pluginInfo; +}; + +#endif diff --git a/libk3b/plugin/k3bpluginconfigwidget.cpp b/libk3b/plugin/k3bpluginconfigwidget.cpp new file mode 100644 index 0000000..09b7f0b --- /dev/null +++ b/libk3b/plugin/k3bpluginconfigwidget.cpp @@ -0,0 +1,48 @@ +/* + * + * $Id: k3bpluginconfigwidget.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bpluginconfigwidget.h" +#include "k3bpluginfactory.h" + +#include + +#include +#include + + +K3bPluginConfigWidget::K3bPluginConfigWidget( QWidget* parent, const char* name ) + : QWidget( parent, name ) +{ +} + + +K3bPluginConfigWidget::~K3bPluginConfigWidget() +{ +} + + +void K3bPluginConfigWidget::loadConfig() +{ + // do nothing +} + + +void K3bPluginConfigWidget::saveConfig() +{ + // do nothing +} + + +#include "k3bpluginconfigwidget.moc" diff --git a/libk3b/plugin/k3bpluginconfigwidget.h b/libk3b/plugin/k3bpluginconfigwidget.h new file mode 100644 index 0000000..baa07ab --- /dev/null +++ b/libk3b/plugin/k3bpluginconfigwidget.h @@ -0,0 +1,40 @@ +/* + * + * $Id: k3bpluginconfigwidget.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_PLUGIN_CONFIG_WIDGET_H_ +#define _K3B_PLUGIN_CONFIG_WIDGET_H_ + +#include +#include "k3b_export.h" + +class LIBK3B_EXPORT K3bPluginConfigWidget : public QWidget +{ + Q_OBJECT + + public: + K3bPluginConfigWidget( QWidget* parent = 0, const char* name = 0 ); + virtual ~K3bPluginConfigWidget(); + + public slots: + /** + * Use k3bcore->config() to store the settings + * FIXME: add a KConfig parameter here + */ + virtual void loadConfig(); + virtual void saveConfig(); +}; + +#endif diff --git a/libk3b/plugin/k3bpluginfactory.cpp b/libk3b/plugin/k3bpluginfactory.cpp new file mode 100644 index 0000000..7d8f8fe --- /dev/null +++ b/libk3b/plugin/k3bpluginfactory.cpp @@ -0,0 +1,33 @@ +/* + * + * $Id: k3bpluginfactory.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bpluginfactory.h" + + +template +KInstance* K3bPluginFactory::s_instance = 0; + + +template +K3bPluginFactory* K3bPluginFactory::s_self = 0; + + +template +KInstance* K3bPluginFactory::instance() +{ + if( !s_instance && s_self ) + s_instance = new KInstance( s_self->m_instanceName ); + return s_instance; +} diff --git a/libk3b/plugin/k3bpluginfactory.h b/libk3b/plugin/k3bpluginfactory.h new file mode 100644 index 0000000..6dbc6cb --- /dev/null +++ b/libk3b/plugin/k3bpluginfactory.h @@ -0,0 +1,98 @@ +/* + * + * $Id: k3bpluginfactory.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_PLUGIN_FACTORY_H_ +#define _K3B_PLUGIN_FACTORY_H_ + +#include +#include +#include +#include + +/** + * Template based on KGenericFactory. This is just here to avoid using the QStringList args parameter + * in every plugin's constructor. + * + * Use this as follows: + * K_EXPORT_COMPONENT_FACTORY( libk3bartsaudioserver, K3bPluginFactory( "k3bartsaudioserver" ) ) + * + * See KGenericFactory for more information. + */ +template +class K3bPluginFactory : public KLibFactory +{ + public: + K3bPluginFactory( const char* instanceName ) + : m_instanceName(instanceName) { + s_self = this; + m_catalogueInitialized = false; + } + + ~K3bPluginFactory() { + if ( s_instance ) + KGlobal::locale()->removeCatalogue( s_instance->instanceName() ); + delete s_instance; + s_instance = 0; + s_self = 0; + } + + static KInstance* instance(); + + protected: + virtual void setupTranslations( void ) { + if( instance() ) + KGlobal::locale()->insertCatalogue( instance()->instanceName() ); + } + + void initializeMessageCatalogue() { + if( !m_catalogueInitialized ) { + m_catalogueInitialized = true; + setupTranslations(); + } + } + + virtual QObject* createObject( QObject *parent, const char *name, + const char*, const QStringList& ) { + initializeMessageCatalogue(); + return new T( parent, name ); + } + + private: + QCString m_instanceName; + bool m_catalogueInitialized; + + static KInstance* s_instance; + static K3bPluginFactory *s_self; +}; + + +template +KInstance* K3bPluginFactory::s_instance = 0; + + +template +K3bPluginFactory* K3bPluginFactory::s_self = 0; + + +template +KInstance* K3bPluginFactory::instance() +{ + if( !s_instance && s_self ) + s_instance = new KInstance( s_self->m_instanceName ); + return s_instance; +} + +#endif diff --git a/libk3b/plugin/k3bpluginmanager.cpp b/libk3b/plugin/k3bpluginmanager.cpp new file mode 100644 index 0000000..3e963a2 --- /dev/null +++ b/libk3b/plugin/k3bpluginmanager.cpp @@ -0,0 +1,189 @@ +/* + * + * $Id: k3bpluginmanager.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bpluginmanager.h" +#include "k3bplugin.h" +#include "k3bpluginconfigwidget.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + + +class K3bPluginManager::Private +{ +public: + QPtrList plugins; +}; + + + + +K3bPluginManager::K3bPluginManager( QObject* parent, const char* name ) + : QObject( parent, name ) +{ + d = new Private(); +} + + +K3bPluginManager::~K3bPluginManager() +{ + delete d; +} + + + +QStringList K3bPluginManager::groups() const +{ + QStringList grps; + + QPtrList fl; + for( QPtrListIterator it( d->plugins ); + it.current(); ++it ) { + if( !grps.contains( it.current()->group() ) ) + grps.append( it.current()->group() ); + } + + return grps; +} + + +QPtrList K3bPluginManager::plugins( const QString& group ) const +{ + QPtrList fl; + for( QPtrListIterator it( d->plugins ); + it.current(); ++it ) { + if( it.current()->group() == group || group.isEmpty() ) + fl.append( it.current() ); + } + return fl; +} + + +void K3bPluginManager::loadPlugin( const QString& fileName ) +{ + KSimpleConfig c( fileName, true ); + c.setGroup( "K3b Plugin" ); + + QString libName = c.readEntry( "Lib" ); + if( libName.isEmpty() ) { + kdDebug() << "(K3bPluginManager) no Lib specified in " << fileName << endl; + return; + } + + // read the lib + KLibFactory* factory = KLibLoader::self()->factory( libName.latin1() ); + if( factory ) { + K3bPlugin* plugin = dynamic_cast( factory->create( this ) ); + if( plugin ) { + // FIXME: improve this versioning stuff + if( plugin->pluginSystemVersion() != K3B_PLUGIN_SYSTEM_VERSION ) { + delete plugin; + kdDebug() << "(K3bPluginManager) plugin system does not fit lib " << libName << endl; + } + else { + plugin->m_pluginInfo = K3bPluginInfo( libName, + c.readEntry( "Name" ), + c.readEntry( "Author" ), + c.readEntry( "Email" ), + c.readEntry( "Comment" ), + c.readEntry( "Version" ), + c.readEntry( "License" ) ); + + // make sure to only use the latest version of one plugin + bool addPlugin = true; + for( QPtrListIterator it( d->plugins ); *it; ++it ) { + if( it.current()->pluginInfo().name() == plugin->pluginInfo().name() ) { + if( K3bVersion(it.current()->pluginInfo().version()) < K3bVersion(plugin->pluginInfo().version()) ) { + K3bPlugin* p = it.current(); + d->plugins.removeRef( p ); + delete p; + } + else { + addPlugin = false; + } + break; + } + } + if( addPlugin ) + d->plugins.append( plugin ); + else + delete plugin; + } + } + else + kdDebug() << "(K3bPluginManager) lib " << libName << " not a K3b plugin" << endl; + } + else + kdDebug() << "(K3bPluginManager) lib " << libName << " not found" << endl; +} + + +void K3bPluginManager::loadAll() +{ + // we simply search the K3b plugin dir for now + QStringList dirs = KGlobal::dirs()->findDirs( "data", "k3b/plugins/" ); + + for( QStringList::const_iterator it = dirs.begin(); + it != dirs.end(); ++it ) { + QStringList entries = QDir(*it).entryList( "*.plugin", QDir::Files ); + for( QStringList::const_iterator it2 = entries.begin(); + it2 != entries.end(); ++it2 ) { + loadPlugin( *it + *it2 ); + } + } +} + +int K3bPluginManager::pluginSystemVersion() const +{ + return K3B_PLUGIN_SYSTEM_VERSION; +} + + +int K3bPluginManager::execPluginDialog( K3bPlugin* plugin, QWidget* parent, const char* name ) +{ + KDialogBase dlg( parent, + name, + true, + i18n("Configure plugin %1").arg( plugin->pluginInfo().name() ) ); + + K3bPluginConfigWidget* configWidget = plugin->createConfigWidget( &dlg ); + if( configWidget ) { + dlg.setMainWidget( configWidget ); + connect( &dlg, SIGNAL(applyClicked()), configWidget, SLOT(saveConfig()) ); + connect( &dlg, SIGNAL(okClicked()), configWidget, SLOT(saveConfig()) ); + configWidget->loadConfig(); + int r = dlg.exec(); + delete configWidget; + return r; + } + else { + KMessageBox::sorry( parent, i18n("No settings available for plugin %1.").arg( plugin->pluginInfo().name() ) ); + return 0; + } +} + +#include "k3bpluginmanager.moc" diff --git a/libk3b/plugin/k3bpluginmanager.h b/libk3b/plugin/k3bpluginmanager.h new file mode 100644 index 0000000..9295dee --- /dev/null +++ b/libk3b/plugin/k3bpluginmanager.h @@ -0,0 +1,70 @@ +/* + * + * $Id: k3bpluginmanager.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_PLUGIN_MANAGER_H_ +#define _K3B_PLUGIN_MANAGER_H_ + +#include +#include +#include +#include "k3b_export.h" + + +class K3bPlugin; +class QWidget; + + +/** + * Use this class to access all K3b plugins (this does not include the + * KParts Plugins!). + * Like the K3bCore the single instance (which has to be created manually) + * can be obtained with the k3bpluginmanager macro. + */ +class LIBK3B_EXPORT K3bPluginManager : public QObject +{ + Q_OBJECT + + public: + K3bPluginManager( QObject* parent = 0, const char* name = 0 ); + ~K3bPluginManager(); + + /** + * if group is empty all plugins are returned + */ + QPtrList plugins( const QString& group = QString::null ) const; + + /** + * Returnes a list of the available groups. + */ + QStringList groups() const; + + int pluginSystemVersion() const; + + public slots: + /** + * Loads all plugins from the ressource directories. + */ + void loadAll(); + + void loadPlugin( const QString& fileName ); + + int execPluginDialog( K3bPlugin*, QWidget* parent = 0, const char* name = 0 ); + + private: + class Private; + Private* d; +}; + +#endif diff --git a/libk3b/plugin/k3bprojectplugin.h b/libk3b/plugin/k3bprojectplugin.h new file mode 100644 index 0000000..c15b9a3 --- /dev/null +++ b/libk3b/plugin/k3bprojectplugin.h @@ -0,0 +1,161 @@ +/* + * + * $Id: k3bprojectplugin.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_PROJECT_PLUGIN_H_ +#define _K3B_PROJECT_PLUGIN_H_ + +#include +#include +#include "k3b_export.h" +class K3bDoc; + +/** + * In case your plugin provides a GUI it is recommended to use the + * K3bProjectPluginGUIBase interface. That way K3b can embed the GUI into + * a fancy dialog which fits the overall look. + * + * This is not derived from QWidget to make it possible to inherit + * from other QWidget derivates. + */ +class K3bProjectPluginGUIBase +{ + public: + K3bProjectPluginGUIBase() {} + virtual ~K3bProjectPluginGUIBase() {} + + virtual QWidget* qWidget() = 0; + + /** + * Title used for the GUI + */ + virtual QString title() const = 0; + virtual QString subTitle() const { return QString::null; } + + virtual void readSettings( KConfigBase* ) {} + virtual void saveSettings( KConfigBase* ) {} + + /** + * Load system defaults for the GUI + */ + virtual void loadDefaults() {} + + /** + * Start the plugin. This method should do the actual work. + */ + virtual void activate() = 0; +}; + + +/** + * A K3bProjectPlugin is supposed to modify a k3b project in some way or + * create additional data based on the project. + * + * Reimplement createGUI or activate and use setText, setToolTip, setWhatsThis, and setIcon + * to specify the gui elements used when presenting the plugin to the user. + */ +class LIBK3B_EXPORT K3bProjectPlugin : public K3bPlugin +{ + Q_OBJECT + + public: + /** + * @param type The type of the plugin + * @param gui If true the plugin is supposed to provide a widget via @p createGUI(). In that case + * @p activate() will not be used. A plugin has a GUI if it's functionality is started + * by some user input. + */ + K3bProjectPlugin( int type, bool gui = false, QObject* parent = 0, const char* name = 0 ) + : K3bPlugin( parent, name ), + m_type(type), + m_hasGUI(gui) { + } + + virtual ~K3bProjectPlugin() { + } + + // TODO: move this to K3bDoc? + enum Type { + AUDIO_CD = 0x1, + DATA_CD = 0x2, + MIXED_CD = 0x4, + VIDEO_CD = 0x8, + MOVIX_CD = 0x10, + DATA_DVD = 0x20, + VIDEO_DVD = 0x40, + MOVIX_DVD = 0x80, + DATA_PROJECTS = DATA_CD|DATA_DVD, + MOVIX_PROJECTS = MOVIX_CD|MOVIX_DVD + }; + + // TODO: maybe we should use something like "ProjectPlugin/AudioCD" based on the type? + QString group() const { return "ProjectPlugin"; } + + /** + * audio, data, videocd, or videodvd + * Needs to return a proper type. The default implementation returns the type specified + * in the constructor. + */ + virtual int type() const { return m_type; } + + /** + * Text used for menu entries and the like. + */ + const QString& text() const { return m_text; } + const QString& toolTip() const { return m_toolTip; } + const QString& whatsThis() const { return m_whatsThis; } + const QString& icon() const { return m_icon; } + + bool hasGUI() const { return m_hasGUI; } + + /** + * Create the GUI which provides the features for the plugin. + * This only needs to be implemented in case hasGUI returns true. + * The returned object has to be a QWidget based class. + * + * @param doc based on the type returned by the factory + * this will be the doc to work on. It should + * be dynamically casted to the needed project type. + */ + virtual K3bProjectPluginGUIBase* createGUI( K3bDoc* doc, QWidget* = 0, const char* = 0 ) { Q_UNUSED(doc); return 0; } + + /** + * This is where the action happens. + * There is no need to implement this in case hasGUI returns true. + * + * @param doc based on the type returned by the factory + * this will be the doc to work on. It should + * be dynamically casted to the needed project type. + * + * @param parent the parent widget to be used for things like progress dialogs. + */ + virtual void activate( K3bDoc* doc, QWidget* parent ) { Q_UNUSED(doc); Q_UNUSED(parent); } + + protected: + void setText( const QString& s ) { m_text = s; } + void setToolTip( const QString& s ) { m_toolTip = s; } + void setWhatsThis( const QString& s ) { m_whatsThis = s; } + void setIcon( const QString& s ) { m_icon = s; } + + private: + int m_type; + bool m_hasGUI; + QString m_text; + QString m_toolTip; + QString m_whatsThis; + QString m_icon; +}; + + +#endif diff --git a/libk3b/plugin/libsamplerate/Makefile.am b/libk3b/plugin/libsamplerate/Makefile.am new file mode 100644 index 0000000..3154ce2 --- /dev/null +++ b/libk3b/plugin/libsamplerate/Makefile.am @@ -0,0 +1,20 @@ +# This file was automatically generated from the Makefile.am +# DO NOT EDIT! + +noinst_LTLIBRARIES = libsamplerate.la +#include_HEADERS = samplerate.h + +EXTRA_DIST = config.h.in Version_script.in + +COEFF_HDRS = high_qual_coeffs.h mid_qual_coeffs.h fastest_coeffs.h + +noinst_HEADERS = common.h float_cast.h $(COEFF_HDRS) + +SRC_SOURCES = samplerate.c src_sinc.c src_zoh.c src_linear.c + +libsamplerate_la_SOURCES = $(SRC_SOURCES) +#libsamplerate_la_LDFLAGS = -version-info @SHARED_VERSION_INFO@ @SHLIB_VERSION_ARG@ +libsamplerate_la_LIBADD = -lm + +# Disable autoheader. +#AUTOHEADER=echo diff --git a/libk3b/plugin/libsamplerate/common.h b/libk3b/plugin/libsamplerate/common.h new file mode 100644 index 0000000..86021ae --- /dev/null +++ b/libk3b/plugin/libsamplerate/common.h @@ -0,0 +1,105 @@ +/* +** Copyright (C) 2002,2003 Erik de Castro Lopo +** +** 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 2 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, write to the Free Software +** Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef COMMON_H_INCLUDED +#define COMMON_H_INCLUDED + +#ifdef HAVE_STDINT_H +#include +#elif (SIZEOF_INT == 4) +typedef int int32_t ; +#elif (SIZEOF_LONG == 4) +typedef long int32_t ; +#endif + +#define SRC_MAX_RATIO 12 +#define SRC_MIN_RATIO_DIFF (1e-20) + +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) + +#define MAKE_MAGIC(a,b,c,d,e,f) ((a)+((b)<<4)+((c)<<8)+((d)<<12)+((e)<<16)+((f)<<20)) + +#include "samplerate.h" + +enum +{ SRC_FALSE = 0, + SRC_TRUE = 1 +} ; + +enum +{ SRC_ERR_NO_ERROR = 0, + + SRC_ERR_MALLOC_FAILED, + SRC_ERR_BAD_STATE, + SRC_ERR_BAD_DATA, + SRC_ERR_BAD_DATA_PTR, + SRC_ERR_NO_PRIVATE, + SRC_ERR_BAD_SRC_RATIO, + SRC_ERR_BAD_PROC_PTR, + SRC_ERR_SHIFT_BITS, + SRC_ERR_FILTER_LEN, + SRC_ERR_BAD_CONVERTER, + SRC_ERR_BAD_CHANNEL_COUNT, + SRC_ERR_SINC_BAD_BUFFER_LEN, + SRC_ERR_SIZE_INCOMPATIBILITY, + SRC_ERR_BAD_PRIV_PTR, + SRC_ERR_BAD_SINC_STATE, + SRC_ERR_DATA_OVERLAP, + + /* This must be the last error number. */ + SRC_ERR_MAX_ERROR +} ; + +typedef struct SRC_PRIVATE_tag +{ double last_ratio, last_position ; + + void *private_data ; + + int (*process) (struct SRC_PRIVATE_tag *psrc, SRC_DATA *data) ; + void (*reset) (struct SRC_PRIVATE_tag *psrc) ; + + int error ; + int channels ; +} SRC_PRIVATE ; + +/* In src_sinc.c */ +int sinc_process (SRC_PRIVATE *psrc, SRC_DATA *data) ; + +const char* sinc_get_name (int src_enum) ; +const char* sinc_get_description (int src_enum) ; + +int sinc_set_converter (SRC_PRIVATE *psrc, int src_enum) ; + +/* In src_linear.c */ +int linear_process (SRC_PRIVATE *psrc, SRC_DATA *data) ; + +const char* linear_get_name (int src_enum) ; +const char* linear_get_description (int src_enum) ; + +int linear_set_converter (SRC_PRIVATE *psrc, int src_enum) ; + +/* In src_zoh.c */ +int zoh_process (SRC_PRIVATE *psrc, SRC_DATA *data) ; + +const char* zoh_get_name (int src_enum) ; +const char* zoh_get_description (int src_enum) ; + +int zoh_set_converter (SRC_PRIVATE *psrc, int src_enum) ; + +#endif /* COMMON_H_INCLUDED */ diff --git a/libk3b/plugin/libsamplerate/configure.in.in b/libk3b/plugin/libsamplerate/configure.in.in new file mode 100644 index 0000000..06a8f55 --- /dev/null +++ b/libk3b/plugin/libsamplerate/configure.in.in @@ -0,0 +1,13 @@ +LIBS="-lm $all_libraries" + +AC_CHECK_DECL(lrint, + AC_DEFINE(HAVE_LRINT,1,[Define if lrint is supported]), + AC_DEFINE(HAVE_LRINT,0,[Define if lrint is not supported]), + [#include ] +) + +AC_CHECK_DECL(lrintf, + AC_DEFINE(HAVE_LRINTF,1,[Define if lrintf is supported]), + AC_DEFINE(HAVE_LRINTF,0,[Define if lrintf is not supported]), + [#include ] +) diff --git a/libk3b/plugin/libsamplerate/fastest_coeffs.h b/libk3b/plugin/libsamplerate/fastest_coeffs.h new file mode 100644 index 0000000..5343fc6 --- /dev/null +++ b/libk3b/plugin/libsamplerate/fastest_coeffs.h @@ -0,0 +1,2493 @@ +/* +** Copyright (C) 2002,2003 Erik de Castro Lopo +** +** 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 2 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, write to the Free Software +** Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +/* +** f = make_filter (8, 128, 100.3) ; +** Pass band width : 0.0039062 (should be 0.0039062) +** Stop band atten. : 100.71 dB +** -3dB band width : 0.484 +** half length : 2463 +** increment : 128 +*/ + + 8.31472372954840555082e-01, + 8.31414005540308198583e-01, + 8.31238918266223869580e-01, + 8.30947156036480505392e-01, + 8.30538793675450581766e-01, + 8.30013935904800659316e-01, + 8.29372717311066987023e-01, + 8.28615302303967515840e-01, + 8.27741885065490623496e-01, + 8.26752689489751890761e-01, + 8.25647969113678215081e-01, + 8.24428007038499943704e-01, + 8.23093115842108757896e-01, + 8.21643637482293187624e-01, + 8.20079943190897053817e-01, + 8.18402433358933589780e-01, + 8.16611537412689103554e-01, + 8.14707713680854150873e-01, + 8.12691449252757824873e-01, + 8.10563259827706050764e-01, + 8.08323689555523805517e-01, + 8.05973310868314363198e-01, + 8.03512724303517833491e-01, + 8.00942558318331943035e-01, + 7.98263469095534694553e-01, + 7.95476140340800830231e-01, + 7.92581283071560838138e-01, + 7.89579635397499868255e-01, + 7.86471962292734527722e-01, + 7.83259055359786127148e-01, + 7.79941732585400893107e-01, + 7.76520838088307852054e-01, + 7.72997241859018080490e-01, + 7.69371839491718167992e-01, + 7.65645551908390675777e-01, + 7.61819325075220210586e-01, + 7.57894129711408459649e-01, + 7.53870960990470018181e-01, + 7.49750838234153449413e-01, + 7.45534804599028211314e-01, + 7.41223926755909090502e-01, + 7.36819294562192195208e-01, + 7.32322020727209643809e-01, + 7.27733240470738174110e-01, + 7.23054111174766811487e-01, + 7.18285812028632841830e-01, + 7.13429543667664534112e-01, + 7.08486527805442301009e-01, + 7.03458006859804640953e-01, + 6.98345243572719653891e-01, + 6.93149520624175785599e-01, + 6.87872140240182283755e-01, + 6.82514423795047564525e-01, + 6.77077711408058502407e-01, + 6.71563361534684655219e-01, + 6.65972750552474845875e-01, + 6.60307272341742135247e-01, + 6.54568337861228477514e-01, + 6.48757374718860524432e-01, + 6.42875826737744904271e-01, + 6.36925153517562181449e-01, + 6.30906829991492501541e-01, + 6.24822345978837789815e-01, + 6.18673205733470954470e-01, + 6.12460927488293727095e-01, + 6.06187042995817604307e-01, + 5.99853097065060292259e-01, + 5.93460647094893878339e-01, + 5.87011262603992944875e-01, + 5.80506524757569142281e-01, + 5.73948025891025337408e-01, + 5.67337369030688098981e-01, + 5.60676167411809700525e-01, + 5.53966043993961543279e-01, + 5.47208630974010734604e-01, + 5.40405569296826038261e-01, + 5.33558508163880174102e-01, + 5.26669104539922661168e-01, + 5.19739022657876970079e-01, + 5.12769933522119303326e-01, + 5.05763514410336290084e-01, + 4.98721448374081555155e-01, + 4.91645423738241937883e-01, + 4.84537133599546865348e-01, + 4.77398275324308896117e-01, + 4.70230550045545592219e-01, + 4.63035662159660077464e-01, + 4.55815318822846149427e-01, + 4.48571229447379538069e-01, + 4.41305105197960123586e-01, + 4.34018658488283970431e-01, + 4.26713602477997000495e-01, + 4.19391650570203500248e-01, + 4.12054515909689722530e-01, + 4.04703910882034223473e-01, + 3.97341546613763640927e-01, + 3.89969132473721613596e-01, + 3.82588375575806771689e-01, + 3.75200980283257823356e-01, + 3.67808647714624070701e-01, + 3.60413075251609871241e-01, + 3.53015956048925771960e-01, + 3.45618978546330835044e-01, + 3.38223825983006376461e-01, + 3.30832175914426429575e-01, + 3.23445699731881031180e-01, + 3.16066062184803764357e-01, + 3.08694920906066150312e-01, + 3.01333925940378832831e-01, + 2.93984719275965256102e-01, + 2.86648934379644393378e-01, + 2.79328195735489559492e-01, + 2.72024118387182545220e-01, + 2.64738307484245039003e-01, + 2.57472357832259801658e-01, + 2.50227853447243409057e-01, + 2.43006367114305704691e-01, + 2.35809459950733935063e-01, + 2.28638680973647728800e-01, + 2.21495566672345989279e-01, + 2.14381640585498134399e-01, + 2.07298412883298144305e-01, + 2.00247379954717363848e-01, + 1.93230023999986955108e-01, + 1.86247812628430653437e-01, + 1.79302198461779749294e-01, + 1.72394618743085786816e-01, + 1.65526494951356295537e-01, + 1.58699232422028796430e-01, + 1.51914219973401071195e-01, + 1.45172829539132269838e-01, + 1.38476415806921215879e-01, + 1.31826315863480453272e-01, + 1.25223848845901208904e-01, + 1.18670315599523901184e-01, + 1.12166998342411894374e-01, + 1.05715160336527447260e-01, + 9.93160455657086521652e-02, + 9.29708784205405536216e-02, + 8.66808633902153846673e-02, + 8.04471847614677826321e-02, + 7.42710063246745516574e-02, + 6.81534710872001986415e-02, + 6.20957009940759641076e-02, + 5.60987966560835549235e-02, + 5.01638370853247708703e-02, + 4.42918794383505357026e-02, + 3.84839587669171534490e-02, + 3.27410877764400740086e-02, + 2.70642565922108620236e-02, + 2.14544325334371267788e-02, + 1.59125598951669576520e-02, + 1.04395597381551803740e-02, + 5.03632968672305773861e-03, +-2.96256265336385191805e-04, +-5.55734794075828358179e-03, +-1.07461191566687631893e-02, +-1.58617678942645466689e-02, +-2.09035164602743607498e-02, +-2.58706116401622790435e-02, +-3.07623248430414844568e-02, +-3.55779522382659724178e-02, +-4.03168148836769782428e-02, +-4.49782588454727128013e-02, +-4.95616553096875425699e-02, +-5.40664006852556791594e-02, +-5.84919166986474642345e-02, +-6.28376504800633867154e-02, +-6.71030746411782619276e-02, +-7.12876873444269476554e-02, +-7.53910123638282386738e-02, +-7.94125991373483691715e-02, +-8.33520228108008270906e-02, +-8.72088842732959695914e-02, +-9.09828101842390379872e-02, +-9.46734529918955292072e-02, +-9.82804909435327500589e-02, +-1.01803628087157427284e-01, +-1.05242594264867719844e-01, +-1.08597145097841310535e-01, +-1.11867061962988789681e-01, +-1.15052151961296145188e-01, +-1.18152247877890054228e-01, +-1.21167208133862752684e-01, +-1.24096916729885473063e-01, +-1.26941283181660202750e-01, +-1.29700242447243679900e-01, +-1.32373754846295377252e-01, +-1.34961805971292009287e-01, +-1.37464406590764143257e-01, +-1.39881592544604443917e-01, +-1.42213424631507739937e-01, +-1.44459988488595730827e-01, +-1.46621394463294696386e-01, +-1.48697777477524800682e-01, +-1.50689296884269657850e-01, +-1.52596136316595465399e-01, +-1.54418503529190731527e-01, +-1.56156630232500315270e-01, +-1.57810771919529219121e-01, +-1.59381207685401427021e-01, +-1.60868240039743037872e-01, +-1.62272194711985145998e-01, +-1.63593420449666626659e-01, +-1.64832288809824062392e-01, +-1.65989193943563151379e-01, +-1.67064552373901109572e-01, +-1.68058802766975601273e-01, +-1.68972405696717037360e-01, +-1.69805843403086798027e-01, +-1.70559619543971530131e-01, +-1.71234258940853617537e-01, +-1.71830307318344255307e-01, +-1.72348331037702334756e-01, +-1.72788916824434257702e-01, +-1.73152671490098081231e-01, +-1.73440221648409775845e-01, +-1.73652213425782242506e-01, +-1.73789312166397952319e-01, +-1.73852202131942051855e-01, +-1.73841586196111674845e-01, +-1.73758185534021086793e-01, +-1.73602739306629005878e-01, +-1.73376004340306061335e-01, +-1.73078754801670009478e-01, +-1.72711781867818603420e-01, +-1.72275893392080048372e-01, +-1.71771913565416961545e-01, +-1.71200682573611373538e-01, +-1.70563056250360139954e-01, +-1.69859905726417126370e-01, +-1.69092117074913228514e-01, +-1.68260590952989147473e-01, +-1.67366242239875284703e-01, +-1.66409999671557895518e-01, +-1.65392805472166642966e-01, +-1.64315614982222552021e-01, +-1.63179396283883837437e-01, +-1.61985129823331186483e-01, +-1.60733808030429803360e-01, +-1.59426434935813571281e-01, +-1.58064025785527417778e-01, +-1.56647606653372045704e-01, +-1.55178214051094831571e-01, +-1.53656894536566474008e-01, +-1.52084704320088470730e-01, +-1.50462708868975059140e-01, +-1.48791982510548842500e-01, +-1.47073608033699704256e-01, +-1.45308676289147314931e-01, +-1.43498285788550977715e-01, +-1.41643542302611558092e-01, +-1.39745558458309881988e-01, +-1.37805453335422323224e-01, +-1.35824352062461073398e-01, +-1.33803385412180564362e-01, +-1.31743689396791985313e-01, +-1.29646404863030306753e-01, +-1.27512677087215337002e-01, +-1.25343655370452389253e-01, +-1.23140492634104758984e-01, +-1.20904345015691472298e-01, +-1.18636371465341922127e-01, +-1.16337733342949820048e-01, +-1.14009594016166518338e-01, +-1.11653118459372716065e-01, +-1.09269472853762789066e-01, +-1.06859824188683741331e-01, +-1.04425339864360325337e-01, +-1.01967187296145456177e-01, +-9.94865335204263567803e-02, +-9.69845448023236023083e-02, +-9.44623862453117940641e-02, +-9.19212214028948121358e-02, +-8.93622118924671249296e-02, +-8.67865170114848205607e-02, +-8.41952933560805999447e-02, +-8.15896944422443981537e-02, +-7.89708703296961439522e-02, +-7.63399672485739477779e-02, +-7.36981272290610500697e-02, +-7.10464877340710454501e-02, +-6.83861812951113146042e-02, +-6.57183351514422919859e-02, +-6.30440708926501142129e-02, +-6.03645041047437408421e-02, +-5.76807440198948140342e-02, +-5.49938931699267691267e-02, +-5.23050470436661057994e-02, +-4.96152937482609926456e-02, +-4.69257136745778041798e-02, +-4.42373791667729082677e-02, +-4.15513541961495605492e-02, +-3.88686940393953503370e-02, +-3.61904449613011935938e-02, +-3.35176439020573244121e-02, +-3.08513181692228674602e-02, +-2.81924851344595717162e-02, +-2.55421519351213023585e-02, +-2.29013151807887539724e-02, +-2.02709606648342685609e-02, +-1.76520630811025022733e-02, +-1.50455857457888787787e-02, +-1.24524803245954687053e-02, +-9.87368656524285036313e-03, +-7.31013203541311037958e-03, +-4.76273186619807602227e-03, +-2.23238850112297869746e-03, + 2.80008549183706099625e-04, + 2.77358294660976899965e-03, + 5.24747175940274562800e-03, + 7.70082569017439908660e-03, + 1.01328092980087648006e-02, + 1.25426012146140665460e-02, + 1.49293943544662570388e-02, + 1.72923961188884665885e-02, + 1.96308285940195309527e-02, + 2.19439287426209730936e-02, + 2.42309485896793734561e-02, + 2.64911554017603391442e-02, + 2.87238318600733545660e-02, + 3.09282762272103349532e-02, + 3.31038025075217068327e-02, + 3.52497406010981520486e-02, + 3.73654364513253609004e-02, + 3.94502521859858221176e-02, + 4.15035662518817155542e-02, + 4.35247735429537541130e-02, + 4.55132855218787699125e-02, + 4.74685303351244439196e-02, + 4.93899529214478216765e-02, + 5.12770151138242716304e-02, + 5.31291957347935772660e-02, + 5.49459906852194576721e-02, + 5.67269130264521220797e-02, + 5.84714930558940249039e-02, + 6.01792783759655322551e-02, + 6.18498339564735599705e-02, + 6.34827421903864652641e-02, + 6.50776029430226859995e-02, + 6.66340335946605799577e-02, + 6.81516690765814614483e-02, + 6.96301619005592065115e-02, + 7.10691821818139612965e-02, + 7.24684176554465098175e-02, + 7.38275736863740761340e-02, + 7.51463732727930683319e-02, + 7.64245570431912463194e-02, + 7.76618832469397474272e-02, + 7.88581277384926976337e-02, + 8.00130839552289779837e-02, + 8.11265628889681067459e-02, + 8.21983930512013155623e-02, + 8.32284204320703352442e-02, + 8.42165084531432683868e-02, + 8.51625379140240473808e-02, + 8.60664069328434949702e-02, + 8.69280308806818224898e-02, + 8.77473423099686122839e-02, + 8.85242908769151987114e-02, + 8.92588432580306151420e-02, + 8.99509830607803234637e-02, + 9.06007107284422380511e-02, + 9.12080434392217309636e-02, + 9.17730149996878741270e-02, + 9.22956757325926607782e-02, + 9.27760923591415126443e-02, + 9.32143478757788968014e-02, + 9.36105414255621187669e-02, + 9.39647881641913207407e-02, + 9.42772191207702781046e-02, + 9.45479810533706027664e-02, + 9.47772362994778183598e-02, + 9.49651626213951355338e-02, + 9.51119530466846413441e-02, + 9.52178157037280176178e-02, + 9.52829736524876819148e-02, + 9.53076647105531166160e-02, + 9.52921412745576373871e-02, + 9.52366701370536278271e-02, + 9.51415322989309503177e-02, + 9.50070227774735681647e-02, + 9.48334504101390751707e-02, + 9.46211376541590265532e-02, + 9.43704203820504156086e-02, + 9.40816476731309581094e-02, + 9.37551816011396865758e-02, + 9.33913970180541563870e-02, + 9.29906813342047527948e-02, + 9.25534342947849225647e-02, + 9.20800677528557931506e-02, + 9.15710054389489019888e-02, + 9.10266827273659706599e-02, + 9.04475463992783224043e-02, + 8.98340544027328158361e-02, + 8.91866756096650198371e-02, + 8.85058895700238101867e-02, + 8.77921862631190763615e-02, + 8.70460658462897246546e-02, + 8.62680384010083983748e-02, + 8.54586236765221690659e-02, + 8.46183508311429133375e-02, + 8.37477581712920277068e-02, + 8.28473928884114751980e-02, + 8.19178107938471483651e-02, + 8.09595760518180135312e-02, + 7.99732609105757996648e-02, + 7.89594454318716387764e-02, + 7.79187172188340326784e-02, + 7.68516711423724852015e-02, + 7.57589090662164482692e-02, + 7.46410395707000073884e-02, + 7.34986776754032733461e-02, + 7.23324445607601979047e-02, + 7.11429672887474440213e-02, + 6.99308785227581580779e-02, + 6.86968162467783832748e-02, + 6.74414234839716131287e-02, + 6.61653480147834510694e-02, + 6.48692420946761771905e-02, + 6.35537621716019962559e-02, + 6.22195686033254202751e-02, + 6.08673253747022482973e-02, + 5.94976998150253330588e-02, + 5.81113623155428762890e-02, + 5.67089860472591994478e-02, + 5.52912466791220663653e-02, + 5.38588220967053943333e-02, + 5.24123921214928872869e-02, + 5.09526382308646275110e-02, + 4.94802432788957607945e-02, + 4.79958912180662375380e-02, + 4.65002668219884549017e-02, + 4.49940554092515265783e-02, + 4.34779425684853407241e-02, + 4.19526138847447563340e-02, + 4.04187546673120054463e-02, + 3.88770496790168534895e-02, + 3.73281828671714888124e-02, + 3.57728370962169389680e-02, + 3.42116938821758476141e-02, + 3.26454331290065291604e-02, + 3.10747328669506231447e-02, + 2.95002689929673225788e-02, + 2.79227150133440210622e-02, + 2.63427417885741359249e-02, + 2.47610172805882329528e-02, + 2.31782063024293799591e-02, + 2.15949702704538760989e-02, + 2.00119669591453143431e-02, + 1.84298502586232419709e-02, + 1.68492699349288496680e-02, + 1.52708713931675090641e-02, + 1.36952954435869880129e-02, + 1.21231780706691841254e-02, + 1.05551502053105091677e-02, + 8.99183750016553651196e-03, + 7.43386010822696258193e-03, + 5.88183246471273707412e-03, + 4.33636307232945251988e-03, + 2.79805428998205086427e-03, + 1.26750212499337003291e-03, +-2.54703971099550386531e-04, +-1.76798130311027175757e-03, +-3.27175412906725469539e-03, +-4.76545385331804925710e-03, +-6.24851921581533794464e-03, +-7.72039647752874400727e-03, +-9.18053960192777122884e-03, +-1.06284104324833178490e-02, +-1.20634788661366718077e-02, +-1.34852230226875247771e-02, +-1.48931294100519973078e-02, +-1.62866930853476296615e-02, +-1.76654178117594401476e-02, +-1.90288162111466874205e-02, +-2.03764099123495759369e-02, +-2.17077296951579609696e-02, +-2.30223156299061669505e-02, +-2.43197172126588360974e-02, +-2.55994934959561624976e-02, +-2.68612132150869431513e-02, +-2.81044549098614510063e-02, +-2.93288070418574950415e-02, +-3.05338681071131295974e-02, +-3.17192467442452205595e-02, +-3.28845618379712614776e-02, +-3.40294426180154721551e-02, +-3.51535287533818185945e-02, +-3.62564704419792716017e-02, +-3.73379284955845242022e-02, +-3.83975744201309962533e-02, +-3.94350904913155775322e-02, +-4.04501698255130062720e-02, +-4.14425164459938585870e-02, +-4.24118453444415760556e-02, +-4.33578825377650758921e-02, +-4.42803651202084772032e-02, +-4.51790413107587551789e-02, +-4.60536704958539877541e-02, +-4.69040232673985507672e-02, +-4.77298814560914094751e-02, +-4.85310381600771723054e-02, +-4.93072977689298017068e-02, +-5.00584759829825892696e-02, +-5.07843998280173986037e-02, +-5.14849076653303427964e-02, +-5.21598491971914657306e-02, +-5.28090854677170859488e-02, +-5.34324888591782357072e-02, +-5.40299430837655400572e-02, +-5.46013431708381041796e-02, +-5.51465954496810906171e-02, +-5.56656175277993395256e-02, +-5.61583382647804357779e-02, +-5.66246977417538960298e-02, +-5.70646472264832865795e-02, +-5.74781491341238848225e-02, +-5.78651769836829588112e-02, +-5.82257153502198851469e-02, +-5.85597598128258789441e-02, +-5.88673168984241990120e-02, +-5.91484040214318093631e-02, +-5.94030494193287308957e-02, +-5.96312920841784027681e-02, +-5.98331816901454746627e-02, +-6.00087785170606569096e-02, +-6.01581533700810480725e-02, +-6.02813874954959694197e-02, +-6.03785724927326447609e-02, +-6.04498102226119424230e-02, +-6.04952127119116611631e-02, +-6.05149020542914278797e-02, +-6.05090103076376881197e-02, +-6.04776793878847099273e-02, +-6.04210609593744951695e-02, +-6.03393163218124903291e-02, +-6.02326162938837256222e-02, +-6.01011410935896536745e-02, +-5.99450802153716350018e-02, +-5.97646323040843391317e-02, +-5.95600050258849322837e-02, +-5.93314149361059764431e-02, +-5.90790873441773764507e-02, +-5.88032561756684640786e-02, +-5.85041638315173181950e-02, +-5.81820610445198463379e-02, +-5.78372067331465664064e-02, +-5.74698678527617162759e-02, +-5.70803192443151696800e-02, +-5.66688434805820984153e-02, +-5.62357307100216502471e-02, +-5.57812784983319834287e-02, +-5.53057916677746758127e-02, +-5.48095821343453915020e-02, +-5.42929687428649263015e-02, +-5.37562771000702349644e-02, +-5.31998394057807341695e-02, +-5.26239942822169029513e-02, +-5.20290866015511582754e-02, +-5.14154673117670768523e-02, +-5.07834932609073572141e-02, +-5.01335270197884388943e-02, +-4.94659367032617980353e-02, +-4.87810957901005926018e-02, +-4.80793829415919610204e-02, +-4.73611818189140221236e-02, +-4.66268808993793651418e-02, +-4.58768732916221277929e-02, +-4.51115565498113532672e-02, +-4.43313324869706107401e-02, +-4.35366069874822472774e-02, +-4.27277898188581847783e-02, +-4.19052944428566706558e-02, +-4.10695378260253277092e-02, +-4.02209402497498702544e-02, +-3.93599251198885058400e-02, +-3.84869187760717781921e-02, +-3.76023503007467674308e-02, +-3.67066513280452297319e-02, +-3.58002558525536487832e-02, +-3.48836000380640318119e-02, +-3.39571220263849699039e-02, +-3.30212617462878818553e-02, +-3.20764607226682249563e-02, +-3.11231618859974003277e-02, +-3.01618093821427596390e-02, +-2.91928483826300218251e-02, +-2.82167248954252464221e-02, +-2.72338855763107207109e-02, +-2.62447775409285488646e-02, +-2.52498481775659533444e-02, +-2.42495449607560524530e-02, +-2.32443152657647901516e-02, +-2.22346061840382018537e-02, +-2.12208643396787077773e-02, +-2.02035357070221716080e-02, +-1.91830654293842946256e-02, +-1.81598976390459701524e-02, +-1.71344752785447841659e-02, +-1.61072399233397958729e-02, +-1.50786316059164128556e-02, +-1.40490886413957953571e-02, +-1.30190474547137412242e-02, +-1.19889424094323342185e-02, +-1.09592056382471266657e-02, +-9.93026687525074697183e-03, +-8.90255329001433948211e-03, +-7.87648932354562125724e-03, +-6.85249652618241146540e-03, +-5.83099339747908569642e-03, +-4.81239522814202146106e-03, +-3.79711394406930576734e-03, +-2.78555795254968683455e-03, +-1.77813199067227692071e-03, +-7.75236976000132386663e-04, + 2.22730140442126654798e-04, + 1.21537651881706244492e-03, + 2.20231357271108733539e-03, + 3.18315710891246220898e-03, + 4.15752746468348553799e-03, + 5.12504964248380791986e-03, + 6.08535344210042478813e-03, + 7.03807359014245199208e-03, + 7.98284986685961206465e-03, + 8.91932723024580452476e-03, + 9.84715593738785290034e-03, + 1.07659916630240357766e-02, + 1.16754956152756248638e-02, + 1.25753346485176220604e-02, + 1.34651813733560731662e-02, + 1.43447142636787781933e-02, + 1.52136177607511777904e-02, + 1.60715823743268690360e-02, + 1.69183047807457617728e-02, + 1.77534879179936204430e-02, + 1.85768410776981605925e-02, + 1.93880799940382604618e-02, + 2.01869269295435888045e-02, + 2.09731107577651766649e-02, + 2.17463670427963037812e-02, + 2.25064381156266125894e-02, + 2.32530731473125917841e-02, + 2.39860282189490944815e-02, + 2.47050663884288181082e-02, + 2.54099577539762186418e-02, + 2.61004795144461655687e-02, + 2.67764160263764816605e-02, + 2.74375588577874841845e-02, + 2.80837068387202806741e-02, + 2.87146661085097808230e-02, + 2.93302501597869115513e-02, + 2.99302798792087168533e-02, + 3.05145835849139068774e-02, + 3.10829970607048658437e-02, + 3.16353635869560598226e-02, + 3.21715339682534032240e-02, + 3.26913665577675052742e-02, + 3.31947272783659833029e-02, + 3.36814896404726560331e-02, + 3.41515347566807569990e-02, + 3.46047513531298478462e-02, + 3.50410357776568884280e-02, + 3.54602920047340924858e-02, + 3.58624316372060172875e-02, + 3.62473739048404727803e-02, + 3.66150456597097023748e-02, + 3.69653813684179058385e-02, + 3.72983231011940682964e-02, + 3.76138205178691634178e-02, + 3.79118308507581658340e-02, + 3.81923188844700278732e-02, + 3.84552569326661666804e-02, + 3.87006248117945095277e-02, + 3.89284098118221136287e-02, + 3.91386066639944005252e-02, + 3.93312175056476295842e-02, + 3.95062518421033306848e-02, + 3.96637265056755394799e-02, + 3.98036656118202977761e-02, + 3.99261005124597820326e-02, + 4.00310697465144360585e-02, + 4.01186189876763035778e-02, + 4.01888009894591641258e-02, + 4.02416755275608953313e-02, + 4.02773093395744422041e-02, + 4.02957760620868618573e-02, + 4.02971561652026855072e-02, + 4.02815368845340013304e-02, + 4.02490121506946865737e-02, + 4.01996825163432602857e-02, + 4.01336550808131173329e-02, + 4.00510434123766412284e-02, + 3.99519674681838021790e-02, + 3.98365535119223901361e-02, + 3.97049340292425986809e-02, + 3.95572476409943238340e-02, + 3.93936390143226622396e-02, + 3.92142587716682866628e-02, + 3.90192633977227906761e-02, + 3.88088151443859719070e-02, + 3.85830819337740632546e-02, + 3.83422372593309676581e-02, + 3.80864600850902706997e-02, + 3.78159347431409609275e-02, + 3.75308508293468318096e-02, + 3.72314030973733209318e-02, + 3.69177913510723085255e-02, + 3.65902203352790472701e-02, + 3.62488996250740352911e-02, + 3.58940435135636018438e-02, + 3.55258708982338911042e-02, + 3.51446051659309519066e-02, + 3.47504740765239503175e-02, + 3.43437096453047957523e-02, + 3.39245480241803926136e-02, + 3.34932293817127510471e-02, + 3.30499977820627663383e-02, + 3.25951010628938789293e-02, + 3.21287907122915217251e-02, + 3.16513217447548164674e-02, + 3.11629525763171093267e-02, + 3.06639448988514501382e-02, + 3.01545635536184866710e-02, + 2.96350764041116987446e-02, + 2.91057542082603579181e-02, + 2.85668704900414009706e-02, + 2.80187014105628129368e-02, + 2.74615256386703497637e-02, + 2.68956242211381771345e-02, + 2.63212804524964143205e-02, + 2.57387797445546746833e-02, + 2.51484094956766456030e-02, + 2.45504589598617914414e-02, + 2.39452191156906725455e-02, + 2.33329825351894608321e-02, + 2.27140432526683408443e-02, + 2.20886966335908999093e-02, + 2.14572392435271874778e-02, + 2.08199687172471933905e-02, + 2.01771836280079629178e-02, + 1.95291833570884962312e-02, + 1.88762679636269269101e-02, + 1.82187380548123403767e-02, + 1.75568946564845403124e-02, + 1.68910390841945853846e-02, + 1.62214728147774996103e-02, + 1.55484973584896369464e-02, + 1.48724141317607399387e-02, + 1.41935243306124080076e-02, + 1.35121288047925294795e-02, + 1.28285279326754275003e-02, + 1.21430214969758445281e-02, + 1.14559085613274869858e-02, + 1.07674873477713456404e-02, + 1.00780551152029641815e-02, + 9.38790803882408146641e-03, + 8.69734109064560119429e-03, + 8.00664792108640895052e-03, + 7.31612074171312902482e-03, + 6.62605020916498532735e-03, + 5.93672531030635993593e-03, + 5.24843324865020312286e-03, + 4.56145933209378684481e-03, + 3.87608686200798923521e-03, + 3.19259702372048361982e-03, + 2.51126877843176705626e-03, + 1.83237875660391988202e-03, + 1.15620115285868549186e-03, + 4.83007622422852007059e-04, +-1.86932820843070034112e-04, +-8.53353904797455329115e-04, +-1.51599219771675255281e-03, +-2.17458720530792556924e-03, +-2.82888146600037857989e-03, +-3.47862064448672828401e-03, +-4.12355362347965707925e-03, +-4.76343259365718217635e-03, +-5.39801314176371720144e-03, +-6.02705433684159932323e-03, +-6.65031881456398799024e-03, +-7.26757285964317947813e-03, +-7.87858648628854928153e-03, +-8.48313351669007821576e-03, +-9.08099165750268083608e-03, +-9.67194257431004678072e-03, +-1.02557719640449674509e-02, +-1.08322696253466653482e-02, +-1.14012295268339416271e-02, +-1.19624498732761111452e-02, +-1.25157331696445651287e-02, +-1.30608862830260651078e-02, +-1.35977205023845738180e-02, +-1.41260515961539080687e-02, +-1.46456998676501564532e-02, +-1.51564902082884610246e-02, +-1.56582521485937077588e-02, +-1.61508199069943896020e-02, +-1.66340324363880263936e-02, +-1.71077334684716746149e-02, +-1.75717715558275228149e-02, +-1.80260001117568194329e-02, +-1.84702774478586080609e-02, +-1.89044668093441003975e-02, +-1.93284364080869922042e-02, +-1.97420594534034529732e-02, +-2.01452141805614354242e-02, +-2.05377838770183090977e-02, +-2.09196569063852221004e-02, +-2.12907267301215390176e-02, +-2.16508919269584217127e-02, +-2.20000562100566773860e-02, +-2.23381284419012192399e-02, +-2.26650226469371808558e-02, +-2.29806580219539050014e-02, +-2.32849589442222955349e-02, +-2.35778549773940013234e-02, +-2.38592808751701725145e-02, +-2.41291765827496146324e-02, +-2.43874872360661625048e-02, +-2.46341631588262027774e-02, +-2.48691598573592027865e-02, +-2.50924380132932847709e-02, +-2.53039634740697960691e-02, +-2.55037072413113186098e-02, +-2.56916454570593408291e-02, +-2.58677593878966008423e-02, +-2.60320354069717534162e-02, +-2.61844649739453247395e-02, +-2.63250446128731642459e-02, +-2.64537758880496950975e-02, +-2.65706653778289558776e-02, +-2.66757246464459155111e-02, +-2.67689702138592805492e-02, +-2.68504235236379437679e-02, +-2.69201109089152179621e-02, +-2.69780635564342181898e-02, +-2.70243174687087896191e-02, +-2.70589134243261995871e-02, +-2.70818969364167577707e-02, +-2.70933182093176481986e-02, +-2.70932320934577017257e-02, +-2.70816980384915410862e-02, +-2.70587800447114543156e-02, +-2.70245466127663376554e-02, +-2.69790706917171427270e-02, +-2.69224296254590607369e-02, +-2.68547050975419879237e-02, +-2.67759830744198866481e-02, +-2.66863537471611969587e-02, +-2.65859114716531889921e-02, +-2.64747547073322930800e-02, +-2.63529859544745573285e-02, +-2.62207116900796607939e-02, +-2.60780423023825730366e-02, +-2.59250920240284947471e-02, +-2.57619788639449828760e-02, +-2.55888245379471308827e-02, +-2.54057543981124761556e-02, +-2.52128973609604678519e-02, +-2.50103858344739478359e-02, +-2.47983556439997539222e-02, +-2.45769459570643403201e-02, +-2.43462992071435090080e-02, +-2.41065610164222128564e-02, +-2.38578801175844575078e-02, +-2.36004082746693114037e-02, +-2.33343002030331689300e-02, +-2.30597134884559483436e-02, +-2.27768085054302904524e-02, +-2.24857483346725776918e-02, +-2.21866986798954189675e-02, +-2.18798277838799307138e-02, +-2.15653063438876642366e-02, +-2.12433074264517691987e-02, +-2.09140063815867055519e-02, +-2.05775807564556566243e-02, +-2.02342102085360346642e-02, +-1.98840764183222142025e-02, +-1.95273630016047500257e-02, +-1.91642554213670816832e-02, +-1.87949408993371563925e-02, +-1.84196083272362247374e-02, +-1.80384481777610752862e-02, +-1.76516524153425696797e-02, +-1.72594144067167720724e-02, +-1.68619288313498413845e-02, +-1.64593915917550098760e-02, +-1.60519997237402040069e-02, +-1.56399513066264282679e-02, +-1.52234453734734331148e-02, +-1.48026818213531103502e-02, +-1.43778613217079923037e-02, +-1.39491852308316760523e-02, +-1.35168555005115483686e-02, +-1.30810745888681710658e-02, +-1.26420453714316226301e-02, +-1.21999710524887047813e-02, +-1.17550550767402828961e-02, +-1.13075010413035727252e-02, +-1.08575126080952908542e-02, +-1.04052934166326063736e-02, +-9.95104699728536351566e-03, +-9.49497668501652312967e-03, +-9.03728553364356763933e-03, +-8.57817623065582068875e-03, +-8.11785101262214349449e-03, +-7.65651158122056946231e-03, +-7.19435901992488725798e-03, +-6.73159371137851351291e-03, +-6.26841525548942068990e-03, +-5.80502238827697216589e-03, +-5.34161290150089295564e-03, +-4.87838356310490647849e-03, +-4.41553003850264462471e-03, +-3.95324681273798422126e-03, +-3.49172711354636287548e-03, +-3.03116283534747218975e-03, +-2.57174446419663202748e-03, +-2.11366100372138449731e-03, +-1.65709990207213789248e-03, +-1.20224697991074881177e-03, +-7.49286359465203312402e-04, +-2.98400394673150758020e-04, + 1.50230397559290287587e-04, + 5.96427404960260163468e-04, + 1.04001398633389997676e-03, + 1.48081553681653948010e-03, + 1.91865955192711671630e-03, + 2.35337569038958404136e-03, + 2.78479583570576333731e-03, + 3.21275415646031688166e-03, + 3.63708716533605539573e-03, + 4.05763377682291995208e-03, + 4.47423536360066955581e-03, + 4.88673581157838838457e-03, + 5.29498157357465894235e-03, + 5.69882172162047926506e-03, + 6.09810799787139853900e-03, + 6.49269486411187517899e-03, + 6.88243954983998491859e-03, + 7.26720209891677272618e-03, + 7.64684541476874993227e-03, + 8.02123530413159993580e-03, + 8.39024051932213063565e-03, + 8.75373279902990839019e-03, + 9.11158690761618844656e-03, + 9.46368067291306243327e-03, + 9.80989502251233651264e-03, + 1.01501140185368699670e-02, + 1.04842248908878447194e-02, + 1.08121180689596009528e-02, + 1.11336872118183785596e-02, + 1.14488292368375710328e-02, + 1.17574443467867335855e-02, + 1.20594360553697797084e-02, + 1.23547112112087492664e-02, + 1.26431800202723137322e-02, + 1.29247560667452802280e-02, + 1.31993563323394361153e-02, + 1.34669012140451026943e-02, + 1.37273145403230718842e-02, + 1.39805235857388930609e-02, + 1.42264590840399576116e-02, + 1.44650552396788801418e-02, + 1.46962497377853603536e-02, + 1.49199837525900817770e-02, + 1.51362019543059365262e-02, + 1.53448525144697818512e-02, + 1.55458871097522988158e-02, + 1.57392609242401407266e-02, + 1.59249326501989980909e-02, + 1.61028644873237487822e-02, + 1.62730221404839558996e-02, + 1.64353748159745995105e-02, + 1.65898952162792344411e-02, + 1.67365595333573702330e-02, + 1.68753474404654685292e-02, + 1.70062420825228405308e-02, + 1.71292300650343690127e-02, + 1.72443014415816948948e-02, + 1.73514496998961910423e-02, + 1.74506717465267233158e-02, + 1.75419678901157470585e-02, + 1.76253418232991503067e-02, + 1.77008006032431768062e-02, + 1.77683546308354950449e-02, + 1.78280176285450023266e-02, + 1.78798066169677284665e-02, + 1.79237418900749095885e-02, + 1.79598469891815541721e-02, + 1.79881486756524357207e-02, + 1.80086769023645003329e-02, + 1.80214647839439801036e-02, + 1.80265485657978320744e-02, + 1.80239675919585257136e-02, + 1.80137642717629609113e-02, + 1.79959840453853894826e-02, + 1.79706753482452019632e-02, + 1.79378895743111561878e-02, + 1.78976810383233188306e-02, + 1.78501069369546815080e-02, + 1.77952273089348571300e-02, + 1.77331049941585293384e-02, + 1.76638055918014250101e-02, + 1.75873974174670689996e-02, + 1.75039514593883366311e-02, + 1.74135413337067820883e-02, + 1.73162432388551425222e-02, + 1.72121359090659648006e-02, + 1.71013005670323306462e-02, + 1.69838208757447130248e-02, + 1.68597828895295613616e-02, + 1.67292750043147309125e-02, + 1.65923879071472879509e-02, + 1.64492145249898746862e-02, + 1.62998499728209574056e-02, + 1.61443915010654574782e-02, + 1.59829384423819872985e-02, + 1.58155921578329479449e-02, + 1.56424559824643004402e-02, + 1.54636351703211580993e-02, + 1.52792368389266484952e-02, + 1.50893699132506348831e-02, + 1.48941450691946284529e-02, + 1.46936746766213478105e-02, + 1.44880727419542387757e-02, + 1.42774548503756936596e-02, + 1.40619381076500047506e-02, + 1.38416410815988405458e-02, + 1.36166837432563775367e-02, + 1.33871874077307433104e-02, + 1.31532746747999255282e-02, + 1.29150693692685249875e-02, + 1.26726964811125480254e-02, + 1.24262821054400597609e-02, + 1.21759533822933443264e-02, + 1.19218384363212748234e-02, + 1.16640663163469111840e-02, + 1.14027669348586990772e-02, + 1.11380710074510391738e-02, + 1.08701099922405512027e-02, + 1.05990160292857588803e-02, + 1.03249218800347264402e-02, + 1.00479608668283364181e-02, + 9.76826681248407595326e-03, + 9.48597397998680001707e-03, + 9.20121701231205180171e-03, + 8.91413087240663405686e-03, + 8.62485078335300560382e-03, + 8.33351216874106057175e-03, + 8.04025059327335284154e-03, + 7.74520170362733365033e-03, + 7.44850116959968472363e-03, + 7.15028462555652392224e-03, + 6.85068761221313375642e-03, + 6.54984551876693164157e-03, + 6.24789352540736173808e-03, + 5.94496654622468298501e-03, + 5.64119917254172174859e-03, + 5.33672561668945780872e-03, + 5.03167965625017643561e-03, + 4.72619457878821046942e-03, + 4.42040312709122713147e-03, + 4.11443744494245557813e-03, + 3.80842902344421868274e-03, + 3.50250864791438413365e-03, + 3.19680634537424174582e-03, + 2.89145133264915015631e-03, + 2.58657196509964968506e-03, + 2.28229568600325869593e-03, + 1.97874897660506266980e-03, + 1.67605730685465247574e-03, + 1.37434508684857771554e-03, + 1.07373561899400072825e-03, + 7.74351050912206037222e-04, + 4.76312329096932108620e-04, + 1.79739153344913828647e-04, +-1.15250068026150436743e-04, +-4.08538262157430215240e-04, +-7.00009734810518881830e-04, +-9.89550212697529359140e-04, +-1.27704688496522110984e-03, +-1.56238844381914230262e-03, +-1.84546512427596291067e-03, +-2.12616874302977649017e-03, +-2.40439273642179809562e-03, +-2.68003219750039467159e-03, +-2.95298391216083011210e-03, +-3.22314639435426720723e-03, +-3.49041992035452591087e-03, +-3.75470656207426648626e-03, +-4.01591021941965966441e-03, +-4.27393665167596914500e-03, +-4.52869350791463860101e-03, +-4.78009035641408387002e-03, +-5.02803871308742881402e-03, +-5.27245206890878791856e-03, +-5.51324591633307794364e-03, +-5.75033777470175880286e-03, +-5.98364721463032038506e-03, +-6.21309588137129026331e-03, +-6.43860751714846711591e-03, +-6.66010798245885143193e-03, +-6.87752527633716734257e-03, +-7.09078955558135361203e-03, +-7.29983315293484570641e-03, +-7.50459059422442856246e-03, +-7.70499861445137022159e-03, +-7.90099617283428028169e-03, +-8.09252446680348673513e-03, +-8.27952694494581836748e-03, +-8.46194931890021165288e-03, +-8.63973957420479179992e-03, +-8.81284798009584514900e-03, +-8.98122709826090423468e-03, +-9.14483179054685624276e-03, +-9.30361922562642808254e-03, +-9.45754888462495800494e-03, +-9.60658256571109842037e-03, +-9.75068438765514661215e-03, +-9.88982079235872779677e-03, +-1.00239605463608785763e-02, +-1.01530747413246837108e-02, +-1.02771367935108499936e-02, +-1.03961224422430293518e-02, +-1.05100097473716045521e-02, +-1.06187790857425311958e-02, +-1.07224131466778661165e-02, +-1.08208969264758890494e-02, +-1.09142177219381259629e-02, +-1.10023651229317290939e-02, +-1.10853310039956218930e-02, +-1.11631095149994884197e-02, +-1.12356970708646971419e-02, +-1.13030923403568215463e-02, +-1.13652962339602110059e-02, +-1.14223118908440956359e-02, +-1.14741446649318026840e-02, +-1.15208021100836454503e-02, +-1.15622939644049946284e-02, +-1.15986321336910645080e-02, +-1.16298306740207010868e-02, +-1.16559057735113307669e-02, +-1.16768757332475214827e-02, +-1.16927609473963332182e-02, +-1.17035838825226608945e-02, +-1.17093690561177760784e-02, +-1.17101430143551586693e-02, +-1.17059343090872795129e-02, +-1.16967734740980097013e-02, +-1.16826930006248379257e-02, +-1.16637273121658596037e-02, +-1.16399127385864407935e-02, +-1.16112874895409699111e-02, +-1.15778916272246922003e-02, +-1.15397670384720374415e-02, +-1.14969574062164479888e-02, +-1.14495081803284975280e-02, +-1.13974665478479546959e-02, +-1.13408814026266253211e-02, +-1.12798033143984600957e-02, +-1.12142844972935168402e-02, +-1.11443787778127377519e-02, +-1.10701415622809114236e-02, +-1.09916298037944538957e-02, +-1.09089019686816925125e-02, +-1.08220180024931385970e-02, +-1.07310392955389764802e-02, +-1.06360286479915983754e-02, +-1.05370502345710423397e-02, +-1.04341695688310136247e-02, +-1.03274534670632443106e-02, +-1.02169700118386209270e-02, +-1.01027885152025192345e-02, +-9.98497948154308812008e-03, +-9.86361457015006402871e-03, +-9.73876655748246930488e-03, +-9.61050929916365190286e-03, +-9.47891769172138146105e-03, +-9.34406763409175583623e-03, +-9.20603598890469380922e-03, +-9.06490054356958417647e-03, +-8.92073997117914622990e-03, +-8.77363379124968326139e-03, +-8.62366233031589164704e-03, +-8.47090668239862398803e-03, +-8.31544866936306283078e-03, +-8.15737080118616487978e-03, +-7.99675623615058242533e-03, +-7.83368874098351944402e-03, +-7.66825265095798756787e-03, +-7.50053282997436773782e-03, +-7.33061463064018075525e-03, +-7.15858385436481461928e-03, +-6.98452671148786126409e-03, +-6.80852978145714965441e-03, +-6.63067997307481386826e-03, +-6.45106448482760802543e-03, +-6.26977076531890029770e-03, +-6.08688647381931853542e-03, +-5.90249944095203298716e-03, +-5.71669762953000513278e-03, +-5.52956909556100162373e-03, +-5.34120194943696596085e-03, +-5.15168431732329797079e-03, +-4.96110430276443595266e-03, +-4.76954994852103134756e-03, +-4.57710919865432410564e-03, +-4.38386986087277181340e-03, +-4.18991956915663876782e-03, +-3.99534574667439676410e-03, +-3.80023556900675307108e-03, +-3.60467592769156538676e-03, +-3.40875339410503987864e-03, +-3.21255418369197943973e-03, +-3.01616412055992575564e-03, +-2.81966860245005685598e-03, +-2.62315256609809257030e-03, +-2.42670045299875130826e-03, +-2.23039617558575898118e-03, +-2.03432308384080993632e-03, +-1.83856393234277533909e-03, +-1.64320084776991355742e-03, +-1.44831529686655904529e-03, +-1.25398805488530435195e-03, +-1.06029917451672204415e-03, +-8.67327955316482155854e-04, +-6.75152913641518712638e-04, +-4.83851753104545291573e-04, +-2.93501335557769932588e-04, +-1.04177652615230481180e-04, + 8.40442022771478958144e-05, + 2.71090061213828637746e-04, + 4.56886708636217294885e-04, + 6.41361907564611910364e-04, + 8.24444425246958221068e-04, + 1.00606405821750295726e-03, + 1.18615165675600578790e-03, + 1.36463914874257485378e-03, + 1.54145956289825905236e-03, + 1.71654705140769636706e-03, + 1.88983691191461173828e-03, + 2.06126560888645086675e-03, + 2.23077079434063144103e-03, + 2.39829132792830895110e-03, + 2.56376729636941056573e-03, + 2.72714003223500402184e-03, + 2.88835213207216685155e-03, + 3.04734747386685260462e-03, + 3.20407123384176817371e-03, + 3.35846990258462183704e-03, + 3.51049130050470068257e-03, + 3.66008459261367522647e-03, + 3.80720030262936314294e-03, + 3.95179032639856198800e-03, + 4.09380794463911311387e-03, + 4.23320783499702736619e-03, + 4.36994608342004212803e-03, + 4.50398019484403704799e-03, + 4.63526910319382156461e-03, + 4.76377318069614620610e-03, + 4.88945424650618146178e-03, + 5.01227557464674778470e-03, + 5.13220190126144337750e-03, + 5.24919943118207308480e-03, + 5.36323584381190321402e-03, + 5.47428029832571112767e-03, + 5.58230343818897148389e-03, + 5.68727739499729628703e-03, + 5.78917579163970574818e-03, + 5.88797374478673089110e-03, + 5.98364786670789981782e-03, + 6.07617626642060343345e-03, + 6.16553855017385084303e-03, + 6.25171582127166582804e-03, + 6.33469067923863194541e-03, + 6.41444721833308011821e-03, + 6.49097102541174898749e-03, + 6.56424917715103632687e-03, + 6.63427023662958338657e-03, + 6.70102424927795491810e-03, + 6.76450273820044644529e-03, + 6.82469869887525251023e-03, + 6.88160659323871527759e-03, + 6.93522234316026366108e-03, + 6.98554332331408935064e-03, + 7.03256835345506155222e-03, + 7.07629769010476809138e-03, + 7.11673301765615093362e-03, + 7.15387743890304877992e-03, + 7.18773546500291789924e-03, + 7.21831300488032408247e-03, + 7.24561735407938580650e-03, + 7.26965718307318129604e-03, + 7.29044252503875406940e-03, + 7.30798476310635155423e-03, + 7.32229661709144288850e-03, + 7.33339212971884264747e-03, + 7.34128665234775375920e-03, + 7.34599683020745793799e-03, + 7.34754058715258225737e-03, + 7.34593710994830336597e-03, + 7.34120683209452638829e-03, + 7.33337141719967496728e-03, + 7.32245374191355016119e-03, + 7.30847787843014878861e-03, + 7.29146907657012011139e-03, + 7.27145374545387114529e-03, + 7.24845943477565521351e-03, + 7.22251481568945107037e-03, + 7.19364966131744686118e-03, + 7.16189482689201083881e-03, + 7.12728222954231872138e-03, + 7.08984482773655864257e-03, + 7.04961660039112210374e-03, + 7.00663252565801673161e-03, + 6.96092855940177307472e-03, + 6.91254161337735619636e-03, + 6.86150953312070904788e-03, + 6.80787107556324582597e-03, + 6.75166588638215301593e-03, + 6.69293447709806265528e-03, + 6.63171820193170571955e-03, + 6.56805923443159328512e-03, + 6.50200054388410785683e-03, + 6.43358587151825807998e-03, + 6.36285970651646794888e-03, + 6.28986726184373092646e-03, + 6.21465444990643503531e-03, + 6.13726785805332464285e-03, + 6.05775472392990760317e-03, + 5.97616291069856791357e-03, + 5.89254088213594148099e-03, + 5.80693767761965816410e-03, + 5.71940288701587758180e-03, + 5.62998662548002196115e-03, + 5.53873950818146131014e-03, + 5.44571262496510149348e-03, + 5.35095751496040238082e-03, + 5.25452614115022934027e-03, + 5.15647086491062122543e-03, + 5.05684442053339500839e-03, + 4.95569988974256699088e-03, + 4.85309067621648645985e-03, + 4.74907048012647350216e-03, + 4.64369327270371719946e-03, + 4.53701327084515566163e-03, + 4.42908491176951992635e-03, + 4.31996282773485212186e-03, + 4.20970182082771107734e-03, + 4.09835683783572966160e-03, + 3.98598294521311340144e-03, + 3.87263530415101094040e-03, + 3.75836914576165720403e-03, + 3.64323974638825019007e-03, + 3.52730240304928790995e-03, + 3.41061240902878646739e-03, + 3.29322502962129748730e-03, + 3.17519547804233142826e-03, + 3.05657889151338601694e-03, + 2.93743030753160130203e-03, + 2.81780464033296821486e-03, + 2.69775665755896121301e-03, + 2.57734095713514719389e-03, + 2.45661194437134461702e-03, + 2.33562380929147129019e-03, + 2.21443050420279223534e-03, + 2.09308572151161147862e-03, + 1.97164287179554201940e-03, + 1.85015506213867531038e-03, + 1.72867507473943343883e-03, + 1.60725534579748128607e-03, + 1.48594794468843234732e-03, + 1.36480455343317803527e-03, + 1.24387644646943291808e-03, + 1.12321447073277739387e-03, + 1.00286902605367005473e-03, + 8.82890045877847201225e-04, + 7.63326978315998568199e-04, + 6.44228767529792380013e-04, + 5.25643835459782418976e-04, + 4.07620063901896608968e-04, + 2.90204776937506045247e-04, + 1.73444723723805766706e-04, + 5.73860616484244659592e-05, +-5.79256601447129809831e-05, +-1.72445516855139978872e-04, +-2.86129223744603178401e-04, +-3.98933151471683798521e-04, +-5.10814341036775051638e-04, +-6.21730518333987194034e-04, +-7.31640108305292775383e-04, +-8.40502248693749103720e-04, +-9.48276803391555388537e-04, +-1.05492437538016840815e-03, +-1.16040631925863960139e-03, +-1.26468475335793167046e-03, +-1.36772257143744795961e-03, +-1.46948345396231690001e-03, +-1.56993187895820992227e-03, +-1.66903313244173671925e-03, +-1.76675331842487395514e-03, +-1.86305936849075486246e-03, +-1.95791905094055886799e-03, +-2.05130097950870097026e-03, +-2.14317462164644121497e-03, +-2.23351030637205421117e-03, +-2.32227923168745655630e-03, +-2.40945347156019864382e-03, +-2.49500598247101752769e-03, +-2.57891060952624437755e-03, +-2.66114209213571661222e-03, +-2.74167606925580006200e-03, +-2.82048908419860059130e-03, +-2.89755858900738426376e-03, +-2.97286294839969704451e-03, +-3.04638144327833843006e-03, +-3.11809427381250833106e-03, +-3.18798256208930414976e-03, +-3.25602835433819615824e-03, +-3.32221462272949338845e-03, +-3.38652526674922864716e-03, +-3.44894511415224942069e-03, +-3.50945992149601917673e-03, +-3.56805637425754813494e-03, +-3.62472208653601482564e-03, +-3.67944560034401835918e-03, +-3.73221638449032109761e-03, +-3.78302483305743104600e-03, +-3.83186226347697993233e-03, +-3.87872091420681094562e-03, +-3.92359394201303914723e-03, +-3.96647541886111301701e-03, +-4.00736032841956212047e-03, +-4.04624456218095809173e-03, +-4.08312491520368761599e-03, +-4.11799908147960237043e-03, +-4.15086564893147550587e-03, +-4.18172409404541419592e-03, +-4.21057477614258761356e-03, +-4.23741893129556731340e-03, +-4.26225866589410255086e-03, +-4.28509694986558761776e-03, +-4.30593760955555893838e-03, +-4.32478532027361865092e-03, +-4.34164559851025946141e-03, +-4.35652479383043678834e-03, +-4.36943008044940375129e-03, +-4.38036944849687272935e-03, +-4.38935169497548655082e-03, +-4.39638641441941844384e-03, +-4.40148398925969356471e-03, +-4.40465557990201740657e-03, +-4.40591311452397972614e-03, +-4.40526927859759102890e-03, +-4.40273750414399336200e-03, +-4.39833195872687317957e-03, +-4.39206753419116562726e-03, +-4.38395983515392842489e-03, +-4.37402516725410826781e-03, +-4.36228052516814471251e-03, +-4.34874358039834783829e-03, +-4.33343266884099378305e-03, +-4.31636677814128347924e-03, +-4.29756553484226828249e-03, +-4.27704919133478460302e-03, +-4.25483861261575103258e-03, +-4.23095526286197242544e-03, +-4.20542119182673330285e-03, +-4.17825902106652539991e-03, +-4.14949193000528453179e-03, +-4.11914364184333848390e-03, +-4.08723840931864319803e-03, +-4.05380100032764340012e-03, +-4.01885668341308427420e-03, +-3.98243121312639048598e-03, +-3.94455081527187324114e-03, +-3.90524217204034265055e-03, +-3.86453240703949710971e-03, +-3.82244907022857112119e-03, +-3.77902012276458334344e-03, +-3.73427392176791782957e-03, +-3.68823920501411533363e-03, +-3.64094507555994461798e-03, +-3.59242098631046497328e-03, +-3.54269672453505143905e-03, +-3.49180239633924225512e-03, +-3.43976841109999795926e-03, +-3.38662546587152699790e-03, +-3.33240452976901182711e-03, +-3.27713682833726460339e-03, +-3.22085382791172753977e-03, +-3.16358721997866921757e-03, +-3.10536890554190866259e-03, +-3.04623097950279270868e-03, +-2.98620571506079835605e-03, +-2.92532554814109750294e-03, +-2.86362306185669341502e-03, +-2.80113097101106212072e-03, +-2.73788210664884781517e-03, +-2.67390940066071719841e-03, +-2.60924587044905360173e-03, +-2.54392460366138209102e-03, +-2.47797874299740972931e-03, +-2.41144147109654920225e-03, +-2.34434599551184728525e-03, +-2.27672553377682423265e-03, +-2.20861329857108918892e-03, +-2.14004248299099744321e-03, +-2.07104624593109319652e-03, +-2.00165769758243626206e-03, +-1.93190988505322330110e-03, +-1.86183577811795423693e-03, +-1.79146825509988766485e-03, +-1.72084008889326943795e-03, +-1.64998393312966343087e-03, +-1.57893230849462818527e-03, +-1.50771758919912264932e-03, +-1.43637198961127387532e-03, +-1.36492755105304883201e-03, +-1.29341612876705033125e-03, +-1.22186937905778840625e-03, +-1.15031874661246304344e-03, +-1.07879545200534983015e-03, +-1.00733047939059738862e-03, +-9.35954564387392199190e-04, +-8.64698182161781326270e-04, +-7.93591535709335898878e-04, +-7.22664544342259342231e-04, +-6.51946832385152269008e-04, +-5.81467718082645003419e-04, +-5.11256202723101406751e-04, +-4.41340959980976682391e-04, +-3.71750325482115011495e-04, +-3.02512286594312090893e-04, +-2.33654472446860898751e-04, +-1.65204144181543805632e-04, +-9.71881854382950145007e-05, +-2.96330930778333087529e-05, + 3.74350318557888840534e-05, + 1.03990492930665522531e-04, + 1.70008006877860913661e-04, + 2.35462711895771908792e-04, + 3.00330175705594570618e-04, + 3.64586403356421419591e-04, + 4.28207844777551787079e-04, + 4.91171402077186748311e-04, + 5.53454436585029511952e-04, + 6.15034775638214118408e-04, + 6.75890719108685204992e-04, + 7.36001045671158494674e-04, + 7.95345018810736208159e-04, + 8.53902392568785988461e-04, + 9.11653417026953884206e-04, + 9.68578843528107927274e-04, + 1.02465992963409239201e-03, + 1.07987844381954517861e-03, + 1.13421666990184857697e-03, + 1.18765741120669863183e-03, + 1.24018399446962118877e-03, + 1.29178027347317181048e-03, + 1.34243063242041153760e-03, + 1.39211998904448393775e-03, + 1.44083379745542361494e-03, + 1.48855805072399061464e-03, + 1.53527928320389963832e-03, + 1.58098457259274222282e-03, + 1.62566154173287799080e-03, + 1.66929836015300469068e-03, + 1.71188374535185877309e-03, + 1.75340696382495094506e-03, + 1.79385783183615881223e-03, + 1.83322671593499951850e-03, + 1.87150453322187351919e-03, + 1.90868275136241117781e-03, + 1.94475338835288632730e-03, + 1.97970901203875114180e-03, + 2.01354273938795765367e-03, + 2.04624823552140497340e-03, + 2.07781971250251560127e-03, + 2.10825192788842950831e-03, + 2.13754018304492627786e-03, + 2.16568032122775241954e-03, + 2.19266872543273649843e-03, + 2.21850231601753312277e-03, + 2.24317854809751244041e-03, + 2.26669540871874157159e-03, + 2.28905141381085521987e-03, + 2.31024560492300908704e-03, + 2.33027754574556848419e-03, + 2.34914731842113299123e-03, + 2.36685551964774167771e-03, + 2.38340325657774047483e-03, + 2.39879214251553785076e-03, + 2.41302429241780800814e-03, + 2.42610231819949092105e-03, + 2.43802932384921434983e-03, + 2.44880890035772524199e-03, + 2.45844512046309356806e-03, + 2.46694253321619750424e-03, + 2.47430615837057783779e-03, + 2.48054148060029584083e-03, + 2.48565444354972896537e-03, + 2.48965144371932805070e-03, + 2.49253932419119233338e-03, + 2.49432536819870756192e-03, + 2.49501729254406187306e-03, + 2.49462324086802481049e-03, + 2.49315177677595679884e-03, + 2.49061187682437026880e-03, + 2.48701292337218105022e-03, + 2.48236469730101589823e-03, + 2.47667737060877201499e-03, + 2.46996149888082565729e-03, + 2.46222801364318543901e-03, + 2.45348821460201170497e-03, + 2.44375376177385136151e-03, + 2.43303666751100867299e-03, + 2.42134928842652587602e-03, + 2.40870431722312039469e-03, + 2.39511477443066006163e-03, + 2.38059400005651662299e-03, + 2.36515564515335941637e-03, + 2.34881366330883401689e-03, + 2.33158230206161314751e-03, + 2.31347609424828503169e-03, + 2.29450984928561332182e-03, + 2.27469864439260342423e-03, + 2.25405781575686164908e-03, + 2.23260294964972971082e-03, + 2.21034987349466626252e-03, + 2.18731464689328946802e-03, + 2.16351355261355186160e-03, + 2.13896308754443764677e-03, + 2.11367995362164717843e-03, + 2.08768104872860673846e-03, + 2.06098345757712827012e-03, + 2.03360444257223585765e-03, + 2.00556143466523338278e-03, + 1.97687202419953838434e-03, + 1.94755395175337346625e-03, + 1.91762509898370150235e-03, + 1.88710347947544372464e-03, + 1.85600722960030926380e-03, + 1.82435459938927956557e-03, + 1.79216394342290039413e-03, + 1.75945371174334418141e-03, + 1.72624244079242210488e-03, + 1.69254874437936271916e-03, + 1.65839130468247841071e-03, + 1.62378886328829906069e-03, + 1.58876021227249563002e-03, + 1.55332418532590395277e-03, + 1.51749964892962602506e-03, + 1.48130549358308134279e-03, + 1.44476062508820820261e-03, + 1.40788395589385340219e-03, + 1.37069439650360901800e-03, + 1.33321084695073701146e-03, + 1.29545218834344489506e-03, + 1.25743727448406820806e-03, + 1.21918492356532437090e-03, + 1.18071390994699786103e-03, + 1.14204295601606406994e-03, + 1.10319072413361980722e-03, + 1.06417580867146756643e-03, + 1.02501672814153568618e-03, + 9.85731917420752321024e-04, + 9.46339720074761028661e-04, + 9.06858380782653099826e-04, + 8.67306037865940180828e-04, + 8.27700715924154601863e-04, + 7.88060318579825755218e-04, + 7.48402621335140681366e-04, + 7.08745264542995573667e-04, + 6.69105746494616255432e-04, + 6.29501416626196083105e-04, + 5.89949468846577432593e-04, + 5.50466934988384673337e-04, + 5.11070678384569518186e-04, + 4.71777387572266644969e-04, + 4.32603570126133903009e-04, + 3.93565546622840108093e-04, + 3.54679444738640930936e-04, + 3.15961193481461178213e-04, + 2.77426517559644606348e-04, + 2.39090931888283949464e-04, + 2.00969736235134577339e-04, + 1.63078010007227617185e-04, + 1.25430607179671989044e-04, + 8.80421513676910678318e-05, + 5.09270310433270975443e-05, + 1.40993948977051206995e-05, +-2.24268526499689963992e-05, +-5.86380557959355767418e-05, +-9.45208115468090933828e-05, +-1.30061973765318488264e-04, +-1.65248657065980185041e-04, +-2.00068240560348736649e-04, +-2.34508371450769772170e-04, +-2.68556968472767403858e-04, +-3.02202225185153135114e-04, +-3.35432613107714699702e-04, +-3.68236884706315019053e-04, +-4.00604076224976460123e-04, +-4.32523510365022737217e-04, +-4.63984798811095579957e-04, +-4.94977844604242624843e-04, +-5.25492844361963827582e-04, +-5.55520290345540247376e-04, +-5.85050972374773735341e-04, +-6.14075979590610184985e-04, +-6.42586702065795259929e-04, +-6.70574832264203037069e-04, +-6.98032366349193725621e-04, +-7.24951605341828033552e-04, +-7.51325156129156322866e-04, +-7.77145932323820387393e-04, +-8.02407154975299293648e-04, +-8.27102353133903219450e-04, +-8.51225364268258727699e-04, +-8.74770334537431802288e-04, +-8.97731718918501797773e-04, +-9.20104281190827605862e-04, +-9.41883093778050233848e-04, +-9.63063537449165905750e-04, +-9.83641300879760935652e-04, +-1.00361238007481306557e-03, +-1.02297307765449128208e-03, +-1.04172000200423238610e-03, +-1.05985006629069969386e-03, +-1.07736048734502422482e-03, +-1.09424878441514257174e-03, +-1.11051277778848088776e-03, +-1.12615058728708443934e-03, +-1.14116063063659394818e-03, +-1.15554162171100749217e-03, +-1.16929256865495575027e-03, +-1.18241277188544584124e-03, +-1.19490182197486941203e-03, +-1.20675959741726535404e-03, +-1.21798626227982297217e-03, +-1.22858226374166065384e-03, +-1.23854832952187280184e-03, +-1.24788546519901061629e-03, +-1.25659495142406364872e-03, +-1.26467834102919943727e-03, +-1.27213745603428412742e-03, +-1.27897438455362244883e-03, +-1.28519147760499177768e-03, +-1.29079134582336268501e-03, +-1.29577685608154116216e-03, +-1.30015112802015094483e-03, +-1.30391753048923449490e-03, +-1.30707967790388737521e-03, +-1.30964142651636395419e-03, +-1.31160687060702277167e-03, +-1.31298033859659005196e-03, +-1.31376638908218385492e-03, +-1.31396980679961724973e-03, +-1.31359559851441281067e-03, +-1.31264898884408520024e-03, +-1.31113541601419526274e-03, +-1.30906052755070225271e-03, +-1.30643017591116055581e-03, +-1.30325041405731484843e-03, +-1.29952749097163636725e-03, +-1.29526784712039586857e-03, +-1.29047810986578645812e-03, +-1.28516508882973415524e-03, +-1.27933577121191956356e-03, +-1.27299731706460124078e-03, +-1.26615705452684046764e-03, +-1.25882247502064623448e-03, +-1.25100122841167137044e-03, +-1.24270111813698665680e-03, +-1.23393009630251375940e-03, +-1.22469625875265661526e-03, +-1.21500784011470538623e-03, +-1.20487320882053006339e-03, +-1.19430086210808427544e-03, +-1.18329942100529298017e-03, +-1.17187762529875026674e-03, +-1.16004432848981092231e-03, +-1.14780849274044756403e-03, +-1.13517918381147498753e-03, +-1.12216556599544479457e-03, +-1.10877689704675665670e-03, +-1.09502252311132830878e-03, +-1.08091187365826806380e-03, +-1.06645445641585442931e-03, +-1.05165985231426076241e-03, +-1.03653771043727446592e-03, +-1.02109774298538512859e-03, +-1.00534972025243104707e-03, +-9.89303465618205854493e-04, +-9.72968850559070386023e-04, +-9.56355789678956110487e-04, +-9.39474235762757228438e-04, +-9.22334174854466432199e-04, +-9.04945621361946477522e-04, +-8.87318613190598128385e-04, +-8.69463206907894578697e-04, +-8.51389472940857513876e-04, +-8.33107490808391681729e-04, +-8.14627344390523211622e-04, +-7.95959117236444131487e-04, +-7.77112887913182157074e-04, +-7.58098725396869001399e-04, +-7.38926684508335205812e-04, +-7.19606801394884719458e-04, +-7.00149089059903611230e-04, +-6.80563532942129469604e-04, +-6.60860086546161931871e-04, +-6.41048667125920334890e-04, +-6.21139151422514545521e-04, +-6.01141371458319205383e-04, +-5.81065110388481308873e-04, +-5.60920098411564179222e-04, +-5.40716008740645473485e-04, +-5.20462453636329636791e-04, +-5.00168980502928035153e-04, +-4.79845068049252442000e-04, +-4.59500122515179752151e-04, +-4.39143473965308969373e-04, +-4.18784372650737749064e-04, +-3.98431985440370181519e-04, +-3.78095392322528038760e-04, +-3.57783582978218623466e-04, +-3.37505453426840712917e-04, +-3.17269802745462131330e-04, +-2.97085329862539673351e-04, +-2.76960630426857884294e-04, +-2.56904193752789059696e-04, +-2.36924399842341755311e-04, +-2.17029516485020210204e-04, +-1.97227696436049984184e-04, +-1.77526974673721080374e-04, +-1.57935265736364822877e-04, +-1.38460361139671443579e-04, +-1.19109926874780676581e-04, +-9.98915009877096604120e-05, +-8.08124912404658787314e-05, +-6.18801728543761411219e-05, +-4.31016863358901726119e-05, +-2.44840353852607290751e-05, +-6.03408488822807525549e-06, + 1.22414410087942923482e-05, + 3.03359607401630166279e-05, + 4.82430370786643698930e-05, + 6.59563788094303331657e-05, + 8.34698423199615796228e-05, + 1.00777433106333784039e-04, + 1.17873307195481496850e-04, + 1.34751772483674884346e-04, + 1.51407289991337552218e-04, + 1.67834475034225882872e-04, + 1.84028098311239825778e-04, + 1.99983086909011169297e-04, + 2.15694525223608961004e-04, + 2.31157655799539194473e-04, + 2.46367880086458945071e-04, + 2.61320759113890506518e-04, + 2.76012014084471178285e-04, + 2.90437526885940853344e-04, + 3.04593340522622661477e-04, + 3.18475659466672001308e-04, + 3.32080849929764377465e-04, + 3.45405440055728798956e-04, + 3.58446120034815369788e-04, + 3.71199742140139986053e-04, + 3.83663320687053425832e-04, + 3.95834031916090828447e-04, + 4.07709213800306149479e-04, + 4.19286365777668133727e-04, + 4.30563148409382728376e-04, + 4.41537382964913725693e-04, + 4.52207050934656925797e-04, + 4.62570293470961546242e-04, + 4.72625410758635230730e-04, + 4.82370861315684551149e-04, + 4.91805261225328150740e-04, + 5.00927383300294468485e-04, + 5.09736156180340470138e-04, + 5.18230663364083014855e-04, + 5.26410142176160977465e-04, + 5.34273982670858136115e-04, + 5.41821726473215733132e-04, + 5.49053065558819199977e-04, + 5.55967840973343140065e-04, + 5.62566041493084596781e-04, + 5.68847802227587348751e-04, + 5.74813403165606124842e-04, + 5.80463267665585255090e-04, + 5.85797960891953992807e-04, + 5.90818188198352634011e-04, + 5.95524793459205619046e-04, + 5.99918757350793364382e-04, + 6.04001195583171897330e-04, + 6.07773357084216074402e-04, + 6.11236622137123529822e-04, + 6.14392500472671181100e-04, + 6.17242629317575641247e-04, + 6.19788771400296852575e-04, + 6.22032812915646266330e-04, + 6.23976761449542352556e-04, + 6.25622743865282679096e-04, + 6.26973004152734866845e-04, + 6.28029901241785953013e-04, + 6.28795906781460817864e-04, + 6.29273602886090081127e-04, + 6.29465679849935955126e-04, + 6.29374933831637162034e-04, + 6.29004264509917614644e-04, + 6.28356672711923979618e-04, + 6.27435258015602670238e-04, + 6.26243216327530610385e-04, + 6.24783837437580067548e-04, + 6.23060502551831571320e-04, + 6.21076681805128117189e-04, + 6.18835931754663313292e-04, + 6.16341892855999597296e-04, + 6.13598286922899423257e-04, + 6.10608914572360016171e-04, + 6.07377652656219848941e-04, + 6.03908451680720608987e-04, + 6.00205333215381750360e-04, + 5.96272387292547546150e-04, + 5.92113769798962869678e-04, + 5.87733699860716260477e-04, + 5.83136457222883410056e-04, + 5.78326379625196070923e-04, + 5.73307860175058681823e-04, + 5.68085344719199331932e-04, + 5.62663329215264671791e-04, + 5.57046357104629347515e-04, + 5.51239016687691835844e-04, + 5.45245938502918582949e-04, + 5.39071792710859535452e-04, + 5.32721286484389919269e-04, + 5.26199161406370888652e-04, + 5.19510190875949965511e-04, + 5.12659177524647379116e-04, + 5.05650950643461694588e-04, + 4.98490363622070692395e-04, + 4.91182291401325650700e-04, + 4.83731627940122419548e-04, + 4.76143283697776802978e-04, + 4.68422183132952726740e-04, + 4.60573262220249240485e-04, + 4.52601465985464203410e-04, + 4.44511746060588389465e-04, + 4.36309058259498746754e-04, + 4.27998360175392566791e-04, + 4.19584608800889610671e-04, + 4.11072758171783069880e-04, + 4.02467757035333936928e-04, + 3.93774546544049656484e-04, + 3.84998057975832470683e-04, + 3.76143210481313700240e-04, + 3.67214908859312392543e-04, + 3.58218041361136620669e-04, + 3.49157477524604336044e-04, + 3.40038066038525694287e-04, + 3.30864632638427479810e-04, + 3.21641978034209344382e-04, + 3.12374875870502510550e-04, + 3.03068070720368721877e-04, + 2.93726276113044930307e-04, + 2.84354172596324122988e-04, + 2.74956405834251703824e-04, + 2.65537584740686090270e-04, + 2.56102279649332684359e-04, + 2.46655020520732712157e-04, + 2.37200295186851598233e-04, + 2.27742547633623577692e-04, + 2.18286176322046336163e-04, + 2.08835532548216017655e-04, + 1.99394918842769620351e-04, + 1.89968587410093434423e-04, + 1.80560738607737464008e-04, + 1.71175519466368710516e-04, + 1.61817022250571095152e-04, + 1.52489283060860649410e-04, + 1.43196280477158617963e-04, + 1.33941934244020521144e-04, + 1.24730103997818122337e-04, + 1.15564588036148766046e-04, + 1.06449122129624024050e-04, + 9.73873783762444747338e-05, + 8.83829640984437603628e-05, + 7.94394207830501368397e-05, + 7.05602230641164422306e-05, + 6.17487777488439845697e-05, + 5.30084228865277819307e-05, + 4.43424268807018922721e-05, + 3.57539876443504868529e-05, + 2.72462317982963840894e-05, + 1.88222139126731892130e-05, + 1.04849157914673770899e-05, + 2.23724580001398245952e-06, +-5.91796176458841909860e-06, +-1.39779472603022615363e-05, +-2.19400262443108254274e-05, +-2.98015899747312779436e-05, +-3.75601058699388188874e-05, +-4.52131179258346812058e-05, +-5.27582470911579511194e-05, +-6.01931916011169823111e-05, +-6.75157272696155086192e-05, +-7.47237077402686759994e-05, +-8.18150646965978259242e-05, +-8.87878080315813176041e-05, +-9.56400259770174112402e-05, +-1.02369885192932295447e-04, +-1.08975630817447491838e-04, +-1.15455586477445233109e-04, +-1.21808154260462635915e-04, +-1.28031814648165977134e-04, +-1.34125126411867404445e-04, +-1.40086726470483718130e-04, +-1.45915329711446663599e-04, +-1.51609728774925367391e-04, +-1.57168793801964925671e-04, +-1.62591472146915872604e-04, +-1.67876788054762332352e-04, +-1.73023842303760092562e-04, +-1.78031811814023872061e-04, +-1.82899949222519527144e-04, +-1.87627582425063416539e-04, +-1.92214114085866635134e-04, +-1.96659021115234305434e-04, +-2.00961854115964548605e-04, +-2.05122236799067813760e-04, +-2.09139865369424642018e-04, +-2.13014507881963919287e-04, +-2.16746003569016719827e-04, +-2.20334262139455170628e-04, +-2.23779263050288623272e-04, +-2.27081054751326671731e-04, +-2.30239753903598189230e-04, +-2.33255544572162539776e-04, +-2.36128677394024743099e-04, +-2.38859468721759089912e-04, +-2.41448299743606627134e-04, +-2.43895615580664562507e-04, +-2.46201924361897988517e-04, +-2.48367796277648787261e-04, +-2.50393862612362249915e-04, +-2.52280814757210175570e-04, +-2.54029403203337271477e-04, +-2.55640436516424906718e-04, +-2.57114780293308988878e-04, +-2.58453356101321892260e-04, +-2.59657140401130335366e-04, +-2.60727163453730896234e-04, +-2.61664508212373382850e-04, +-2.62470309200077975623e-04, +-2.63145751373508769710e-04, +-2.63692068973905575490e-04, +-2.64110544365773612825e-04, +-2.64402506864084673854e-04, +-2.64569331550674807438e-04, +-2.64612438080565591254e-04, +-2.64533289478916812908e-04, +-2.64333390929326621406e-04, +-2.64014288554176887285e-04, +-2.63577568187730454374e-04, +-2.63024854142685936189e-04, +-2.62357807970878796362e-04, +-2.61578127218826830911e-04, +-2.60687544178804346540e-04, +-2.59687824636131118095e-04, +-2.58580766613355161020e-04, +-2.57368199111998000473e-04, +-2.56051980852535184582e-04, +-2.54633999013272917245e-04, +-2.53116167968770410229e-04, +-2.51500428028467203686e-04, +-2.49788744176148520739e-04, +-2.47983104810888498049e-04, +-2.46085520490098991209e-04, +-2.44098022675305284133e-04, +-2.42022662481256641692e-04, +-2.39861509428983846149e-04, +-2.37616650203396260988e-04, +-2.35290187416002671578e-04, +-2.32884238373345356290e-04, +-2.30400933851706944807e-04, +-2.27842416878660760553e-04, +-2.25210841522004905167e-04, +-2.22508371686640725982e-04, +-2.19737179919906623887e-04, +-2.16899446225907947382e-04, +-2.13997356889345798732e-04, +-2.11033103309352538255e-04, +-2.08008880843819519632e-04, +-2.04926887664708660573e-04, +-2.01789323624807442155e-04, +-1.98598389136399967663e-04, +-1.95356284062287273917e-04, +-1.92065206619610498147e-04, +-1.88727352296894345393e-04, +-1.85344912784731391314e-04, +-1.81920074920499755819e-04, +-1.78455019647530454055e-04, +-1.74951920989073971512e-04, +-1.71412945037461607323e-04, +-1.67840248958807175192e-04, +-1.64235980013589989322e-04, +-1.60602274593463965847e-04, +-1.56941257274607583660e-04, +-1.53255039887926981963e-04, +-1.49545720606400077326e-04, +-1.45815383049865629223e-04, +-1.42066095407511174204e-04, +-1.38299909578337953649e-04, +-1.34518860329830815736e-04, +-1.30724964475093245915e-04, +-1.26920220068654472992e-04, +-1.23106605621173758290e-04, +-1.19286079333219134950e-04, +-1.15460578348350841244e-04, +-1.11632018025632952099e-04, +-1.07802291231779830637e-04, +-1.03973267653065606659e-04, +-1.00146793127148565233e-04, +-9.63246889949230804435e-05, +-9.25087514725346873358e-05, +-8.87007510436452450671e-05, +-8.49024318720545515026e-05, +-8.11155112347393549661e-05, +-7.73416789754019609908e-05, +-7.35825969785674924512e-05, +-6.98398986642887023612e-05, +-6.61151885034750767074e-05, +-6.24100415538899748772e-05, +-5.87260030168200428450e-05, +-5.50645878143974986741e-05, +-5.14272801876128782695e-05, +-4.78155333149380714058e-05, +-4.42307689515766361233e-05, +-4.06743770892715146635e-05, +-3.71477156366324749162e-05, +-3.36521101199027279356e-05, +-3.01888534041130525139e-05, +-2.67592054345224943665e-05, +-2.33643929982665948157e-05, +-2.00056095060906951114e-05, +-1.66840147940797201324e-05, +-1.34007349452439661363e-05, +-1.01568621308437851693e-05, +-6.95345447128813701427e-06, +-3.79153591650250810366e-06, +-6.72096145553293655593e-07, + 2.40390951459279597616e-06, + 5.43556015137456058426e-06, + 8.42196931017640123499e-06, + 1.13622850193110927676e-05, + 1.42556897966238257746e-05, + 1.71014006379341248229e-05, + 1.98986689875390831126e-05, + 2.26467806909793172563e-05, + 2.53450559303131682314e-05, + 2.79928491421220740245e-05, + 3.05895489185053302676e-05, + 3.31345778912925430443e-05, + 3.56273925997451632237e-05, + 3.80674833419947510364e-05, + 4.04543740105068599521e-05, + 4.27876219118044463113e-05, + 4.50668175707753267513e-05, + 4.72915845198089502860e-05, + 4.94615790730713200283e-05, + 5.15764900862005805371e-05, + 5.36360387017334339240e-05, + 5.56399780805481871900e-05, + 5.75880931196438774090e-05, + 5.94802001565561985590e-05, + 6.13161466607366493955e-05, + 6.30958109121965409621e-05, + 6.48191016677504891876e-05, + 6.64859578151715343739e-05, + 6.80963480156043240521e-05, + 6.96502703345347587470e-05, + 7.11477518616810702089e-05, + 7.25888483201263885920e-05, + 7.39736436650163245096e-05, + 7.53022496721903708853e-05, + 7.65748055170595645635e-05, + 7.77914773440878826866e-05, + 7.89524578272120806021e-05, + 8.00579657215541123884e-05, + 8.11082454067584148567e-05, + 8.21035664223097817662e-05, + 8.30442229951717527346e-05, + 8.39305335600990616227e-05, + 8.47628402729624154692e-05, + 8.55415085174379832356e-05, + 8.62669264054029689666e-05, + 8.69395042713942022743e-05, + 8.75596741614536786501e-05, + 8.81278893167311284636e-05, + 8.86446236521661512422e-05, + 8.91103712306026604075e-05, + 8.95256457326717546962e-05, + 8.98909799227875892661e-05, + 9.02069251115862640782e-05, + 9.04740506151490363976e-05, + 9.06929432113401867103e-05, + 9.08642065935940279782e-05, + 9.09884608224771455898e-05, + 9.10663417753510066833e-05, + 9.10985005944656069544e-05, + 9.10856031337957275460e-05, + 9.10283294049456589850e-05, + 9.09273730224310103125e-05, + 9.07834406486567112131e-05, + 9.05972514388884682737e-05, + 9.03695364865346147717e-05, + 9.01010382690298824038e-05, + 8.97925100946232214449e-05, + 8.94447155503604388049e-05, + 8.90584279515538464710e-05, + 8.86344297930203114553e-05, + 8.81735122023717546660e-05, + 8.76764743956322256668e-05, + 8.71441231354561004216e-05, + 8.65772721922116491981e-05, + 8.59767418081955635050e-05, + 8.53433581652348287718e-05, + 8.46779528559294970011e-05, + 8.39813623587842351167e-05, + 8.32544275174723505482e-05, + 8.24979930244696123580e-05, + 8.17129069092911340059e-05, + 8.09000200315580515319e-05, + 8.00601855791177764851e-05, + 7.91942585714318722121e-05, + 7.83030953684469709260e-05, + 7.73875531851490379041e-05, + 7.64484896120066966278e-05, + 7.54867621414943666810e-05, + 7.45032277008856680736e-05, + 7.34987421914997258445e-05, + 7.24741600345781298914e-05, + 7.14303337239639759421e-05, + 7.03681133857495075701e-05, + 6.92883463450485250238e-05, + 6.81918767000556897513e-05, + 6.70795449035298084342e-05, + 6.59521873518545653477e-05, + 6.48106359818019012913e-05, + 6.36557178751403541801e-05, + 6.24882548712000070136e-05, + 6.13090631875229413088e-05, + 6.01189530487050480105e-05, + 5.89187283235398522627e-05, + 5.77091861705600261078e-05, + 5.64911166920768371556e-05, + 5.52653025968012133018e-05, + 5.40325188711331935503e-05, + 5.27935324591918643858e-05, + 5.15491019516612150597e-05, + 5.02999772835162253098e-05, + 4.90468994406823114189e-05, + 4.77906001756943685883e-05, + 4.65318017323872241855e-05, + 4.52712165796745444508e-05, + 4.40095471544385224527e-05, + 4.27474856135762158195e-05, + 4.14857135952114382585e-05, + 4.02249019891050019768e-05, + 3.89657107162695045101e-05, + 3.77087885178019617646e-05, + 3.64547727529321324196e-05, + 3.52042892062907349744e-05, + 3.39579519043854685862e-05, + 3.27163629412759540162e-05, + 3.14801123134230239524e-05, + 3.02497777637023744978e-05, + 2.90259246345387218443e-05, + 2.78091057301432964695e-05, + 2.65998611878025348972e-05, + 2.53987183581919854364e-05, + 2.42061916946511448772e-05, + 2.30227826513813061706e-05, + 2.18489795905047869758e-05, + 2.06852576979222047276e-05, + 1.95320789079097866306e-05, + 1.83898918363816234168e-05, + 1.72591317227478167385e-05, + 1.61402203802856600485e-05, + 1.50335661549492530784e-05, + 1.39395638925266073790e-05, + 1.28585949140593193966e-05, + 1.17910269994264146578e-05, + 1.07372143790027249535e-05, + 9.69749773328629209753e-06, + 8.67220420039572420566e-06, + 7.66164739132314657512e-06, + 6.66612741284622437347e-06, + 5.68593089796976951548e-06, + 4.72133104379410701050e-06, + 3.77258765668374723169e-06, + 2.83994720461857994069e-06, + 1.92364287659795633360e-06, + 1.02389464897677183691e-06, + 1.40909358598783243636e-07, +-7.25119217400925882488e-07, +-1.57401027526573751796e-06, +-2.40559589188401177682e-06, +-3.21972092580435969379e-06, +-4.01624291213239929447e-06, +-4.79503195145223449727e-06, +-5.55597059291959898474e-06, +-6.29895371166915398527e-06, +-7.02388838068995278969e-06, +-7.73069373730662337714e-06, +-8.41930084443043260571e-06, +-9.08965254672049638874e-06, +-9.74170332181420186798e-06, +-1.03754191267770145960e-05, +-1.09907772399306088372e-05, +-1.15877660982095854786e-05, +-1.21663851302071818753e-05, +-1.27266445850638015879e-05, +-1.32685653573596831328e-05, +-1.37921788081646564831e-05, +-1.42975265824070264185e-05, +-1.47846604227169150120e-05, +-1.52536419799077777845e-05, +-1.57045426202454864190e-05, +-1.61374432296745794440e-05, +-1.65524340151509907705e-05, +-1.69496143032443776877e-05, +-1.73290923361651281922e-05, +-1.76909850653765942752e-05, +-1.80354179429455134585e-05, +-1.83625247107888849940e-05, +-1.86724471879742999741e-05, +-1.89653350562250020523e-05, +-1.92413456437866339777e-05, +-1.95006437078064384194e-05, +-1.97434012153796016272e-05, +-1.99697971234102591856e-05, +-2.01800171574394671614e-05, +-2.03742535895865872536e-05, +-2.05527050157544749519e-05, +-2.07155761322383869926e-05, +-2.08630775118898238230e-05, +-2.09954253799722451970e-05, +-2.11128413898529763743e-05, +-2.12155523986690494219e-05, +-2.13037902431062623279e-05, +-2.13777915154254429865e-05, +-2.14377973398712400380e-05, +-2.14840531495946086989e-05, +-2.15168084642204138245e-05, +-2.15363166681862903517e-05, +-2.15428347899803886579e-05, +-2.15366232824005027408e-05, +-2.15179458039577262574e-05, +-2.14870690015422825217e-05, +-2.14442622944694083432e-05, +-2.13897976600211963056e-05, +-2.13239494205938423077e-05, +-2.12469940325636042692e-05, +-2.11592098769767039874e-05, +-2.10608770521689021838e-05, +-2.09522771684173563140e-05, +-2.08336931447246940868e-05, +-2.07054090078323760555e-05, +-2.05677096935581607638e-05, +-2.04208808505498906150e-05, +-2.02652086465450858026e-05, +-2.01009795772225878085e-05, +-1.99284802777307897448e-05, +-1.97479973369733553508e-05, +-1.95598171147313057406e-05, +-1.93642255616965921713e-05, +-1.91615080424908975211e-05, +-1.89519491617392180451e-05, +-1.87358325932659067312e-05, +-1.85134409124775290410e-05, +-1.82850554319945745078e-05, +-1.80509560405904254164e-05, +-1.78114210454942761765e-05, +-1.75667270181107023892e-05, +-1.73171486432067083623e-05, +-1.70629585716134836285e-05, +-1.68044272764881711800e-05, +-1.65418229131769521309e-05, +-1.62754111827191523261e-05, +-1.60054551990284544996e-05, +-1.57322153597849753270e-05, +-1.54559492210684566130e-05, +-1.51769113757617390406e-05, +-1.48953533357483810943e-05, +-1.46115234179280960335e-05, +-1.43256666340692667526e-05, +-1.40380245845161517285e-05, +-1.37488353557644599467e-05, +-1.34583334219182035850e-05, +-1.31667495500361276861e-05, +-1.28743107093750131593e-05, +-1.25812399845332226092e-05, +-1.22877564924967183814e-05, +-1.19940753035859587103e-05, +-1.17004073663007361519e-05, +-1.14069594360560160192e-05, +-1.11139340078022052344e-05, +-1.08215292525168970740e-05, +-1.05299389575568482923e-05, +-1.02393524708539662493e-05, +-9.94995464893742348120e-06, +-9.66192580876271611343e-06, +-9.37544168332491989210e-06, +-9.09067338103246418157e-06, +-8.80778734881422739372e-06, +-8.52694533893248795902e-06, +-8.24830437947059051977e-06, +-7.97201674846333152320e-06, +-7.69822995163491404110e-06, +-7.42708670370925303302e-06, +-7.15872491325360909230e-06, +-6.89327767101633304933e-06, +-6.63087324171573705124e-06, +-6.37163505923899323223e-06, +-6.11568172520321447157e-06, +-5.86312701083429459631e-06, +-5.61407986211404469277e-06, +-5.36864440814655013182e-06, +-5.12691997269171846217e-06, +-4.88900108881444233564e-06, +-4.65497751659457443244e-06, +-4.42493426384305196255e-06, +-4.19895160976678087265e-06, +-3.97710513152554464493e-06, +-3.75946573362158312445e-06, +-3.54609968006129461300e-06, +-3.33706862922910230812e-06, +-3.13242967141053148128e-06, +-2.93223536890220278037e-06, +-2.73653379864365903313e-06, +-2.54536859730841838172e-06, +-2.35877900878616331091e-06, +-2.17679993399191934131e-06, +-1.99946198293410626841e-06, +-1.82679152897453787459e-06, +-1.65881076521146377169e-06, +-1.49553776291791911430e-06, +-1.33698653196547020166e-06, +-1.18316708316432299485e-06, +-1.03408549244911473199e-06, +-8.89743966841013678409e-07, +-7.50140912114827378233e-07, +-6.15271002100918799020e-07, +-4.85125249549975873449e-07, +-3.59691078491283933177e-07, +-2.38952398011216803052e-07, +-1.22889677382464548894e-07, + 0 /* Need a final zero coefficient */ + diff --git a/libk3b/plugin/libsamplerate/float_cast.h b/libk3b/plugin/libsamplerate/float_cast.h new file mode 100644 index 0000000..af362e3 --- /dev/null +++ b/libk3b/plugin/libsamplerate/float_cast.h @@ -0,0 +1,203 @@ +/* +** Copyright (C) 2001-2003 Erik de Castro Lopo +** +** 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 2 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, write to the Free Software +** Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +/* Version 1.3 */ + + +/*============================================================================ +** On Intel Pentium processors (especially PIII and probably P4), converting +** from float to int is very slow. To meet the C specs, the code produced by +** most C compilers targeting Pentium needs to change the FPU rounding mode +** before the float to int conversion is performed. +** +** Changing the FPU rounding mode causes the FPU pipeline to be flushed. It +** is this flushing of the pipeline which is so slow. +** +** Fortunately the ISO C99 specifications define the functions lrint, lrintf, +** llrint and llrintf which fix this problem as a side effect. +** +** On Unix-like systems, the configure process should have detected the +** presence of these functions. If they weren't found we have to replace them +** here with a standard C cast. +*/ + +/* +** The C99 prototypes for lrint and lrintf are as follows: +** +** long int lrintf (float x) ; +** long int lrint (double x) ; +*/ + +#include "config.h" + +/* +** The presence of the required functions are detected during the configure +** process and the values HAVE_LRINT and HAVE_LRINTF are set accordingly in +** the config.h file. +*/ + +#define HAVE_LRINT_REPLACEMENT 0 + +#if (HAVE_LRINT && HAVE_LRINTF) + + /* + ** These defines enable functionality introduced with the 1999 ISO C + ** standard. They must be defined before the inclusion of math.h to + ** engage them. If optimization is enabled, these functions will be + ** inlined. With optimization switched off, you have to link in the + ** maths library using -lm. + */ + + #define _ISOC9X_SOURCE 1 + #define _ISOC99_SOURCE 1 + + #define __USE_ISOC9X 1 + #define __USE_ISOC99 1 + + #include + +#elif (defined (WIN32) || defined (_WIN32)) + + #undef HAVE_LRINT_REPLACEMENT + #define HAVE_LRINT_REPLACEMENT 1 + #include + + /* + ** Win32 doesn't seem to have these functions. + ** Therefore implement inline versions of these functions here. + */ + + __inline long int + lrint (double flt) + { int intgr; + + _asm + { fld flt + fistp intgr + } ; + + return intgr ; + } + + __inline long int + lrintf (float flt) + { int intgr; + + _asm + { fld flt + fistp intgr + } ; + + return intgr ; + } + +#elif (defined (__MWERKS__) && defined (macintosh)) + + /* This MacOS 9 solution was provided by Stephane Letz */ + + #undef HAVE_LRINT_REPLACEMENT + #define HAVE_LRINT_REPLACEMENT 1 + #include + + #undef lrint + #undef lrintf + + #define lrint double2int + #define lrintf float2int + + inline int + float2int (register float in) + { long res [2] ; + + asm + { fctiw in,in + stfd in,res + } + return res [1] ; + } /* float2int */ + + inline int + double2int (register double in) + { long res [2] ; + + asm + { fctiw in,in + stfd in,res + } + return res [1] ; + } /* double2int */ + +#elif (defined (__MACH__) && defined (__APPLE__)) + + /* For Apple MacOSX. */ + + #undef HAVE_LRINT_REPLACEMENT + #define HAVE_LRINT_REPLACEMENT 1 + #include + + #undef lrint + #undef lrintf + + #define lrint double2int + #define lrintf float2int + + inline static long int + float2int (register float in) + { int res [2] ; + + __asm__ __volatile__ + ( "fctiw %1, %1\n\t" + "stfd %1, %0" + : "=m" (res) /* Output */ + : "f" (in) /* Input */ + : "memory" + ) ; + + return res [1] ; + } /* lrintf */ + + inline static long int + double2int (register double in) + { int res [2] ; + + __asm__ __volatile__ + ( "fctiw %1, %1\n\t" + "stfd %1, %0" + : "=m" (res) /* Output */ + : "f" (in) /* Input */ + : "memory" + ) ; + + return res [1] ; + } /* lrint */ + +#else + #ifndef __sgi + #warning "Don't have the functions lrint() and lrintf()." + #warning "Replacing these functions with a standard C cast." + #endif + + #include + + #define lrint(dbl) ((int) (dbl)) + #define lrintf(flt) ((int) (flt)) + +#endif + + + diff --git a/libk3b/plugin/libsamplerate/high_qual_coeffs.h b/libk3b/plugin/libsamplerate/high_qual_coeffs.h new file mode 100644 index 0000000..229bc79 --- /dev/null +++ b/libk3b/plugin/libsamplerate/high_qual_coeffs.h @@ -0,0 +1,17116 @@ +/* +** Copyright (C) 2002,2003 Erik de Castro Lopo +** +** 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 2 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, write to the Free Software +** Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +/* +** f = make_filter (65, 128, 100.3) ; +** Pass band width : 0.0039062 (should be 0.0039062) +** Stop band atten. : 101.20 dB +** -3dB band width : 0.846 +** half length : 17087 +** increment : 128 +*/ + + 9.73822959712628111184e-01, + 9.73730227534126968614e-01, + 9.73452062795049033461e-01, + 9.72988560871685836950e-01, + 9.72339880681256651940e-01, + 9.71506244617024061760e-01, + 9.70487938457503807044e-01, + 9.69285311249795999977e-01, + 9.67898775167100988703e-01, + 9.66328805340476049146e-01, + 9.64575939664910952942e-01, + 9.62640778579811451365e-01, + 9.60523984823974497083e-01, + 9.58226283165186876190e-01, + 9.55748460104550945360e-01, + 9.53091363555660264772e-01, + 9.50255902498805649081e-01, + 9.47243046610318550904e-01, + 9.44053825867236739988e-01, + 9.40689330127495004774e-01, + 9.37150708685763667027e-01, + 9.33439169805209578712e-01, + 9.29555980225306610620e-01, + 9.25502464645995059911e-01, + 9.21280005188352291157e-01, + 9.16890040832049391106e-01, + 9.12334066829837087020e-01, + 9.07613634099317501125e-01, + 9.02730348592271192310e-01, + 8.97685870641828032035e-01, + 8.92481914287746591619e-01, + 8.87120246580144211634e-01, + 8.81602686861939210949e-01, + 8.75931106030353401337e-01, + 8.70107425777795429056e-01, + 8.64133617812459453589e-01, + 8.58011703058984220860e-01, + 8.51743750839512703266e-01, + 8.45331878035551986805e-01, + 8.38778248230970913113e-01, + 8.32085070836509732572e-01, + 8.25254600196225540643e-01, + 8.18289134676235541122e-01, + 8.11191015736170029093e-01, + 8.03962626983747541409e-01, + 7.96606393212902830214e-01, + 7.89124779425847022729e-01, + 7.81520289839554460620e-01, + 7.73795466877067239508e-01, + 7.65952890144075193568e-01, + 7.57995175391232733908e-01, + 7.49924973462656851986e-01, + 7.41744969231072803773e-01, + 7.33457880520075322650e-01, + 7.25066457013996301662e-01, + 7.16573479155810266761e-01, + 7.07981757033636860399e-01, + 6.99294129256251117965e-01, + 6.90513461818149987259e-01, + 6.81642646954653708136e-01, + 6.72684601987533770107e-01, + 6.63642268161698578588e-01, + 6.54518609473419998857e-01, + 6.45316611490632463521e-01, + 6.36039280165809350898e-01, + 6.26689640641951539735e-01, + 6.17270736052177193542e-01, + 6.07785626313482429950e-01, + 5.98237386915153934730e-01, + 5.88629107702400733437e-01, + 5.78963891655698170702e-01, + 5.69244853666411754212e-01, + 5.59475119309209012464e-01, + 5.49657823611788054485e-01, + 5.39796109822496594788e-01, + 5.29893128176318617406e-01, + 5.19952034659813655537e-01, + 5.09975989775514948477e-01, + 4.99968157306331650869e-01, + 4.89931703080488667457e-01, + 4.79869793737535021982e-01, + 4.69785595495954833023e-01, + 4.59682272922913082169e-01, + 4.49562987706663808041e-01, + 4.39430897432148248605e-01, + 4.29289154360313895964e-01, + 4.19140904211673437363e-01, + 4.08989284954621334922e-01, + 3.98837425599043837732e-01, + 3.88688444995713366925e-01, + 3.78545450641997294206e-01, + 3.68411537494394758507e-01, + 3.58289786788378861182e-01, + 3.48183264866087693878e-01, + 3.38095022012320112204e-01, + 3.28028091299366553191e-01, + 3.17985487441129255348e-01, + 3.07970205657046469661e-01, + 2.97985220546282070231e-01, + 2.88033484972657738421e-01, + 2.78117928960799731808e-01, + 2.68241458603957205753e-01, + 2.58406954983961600902e-01, + 2.48617273103761360353e-01, + 2.38875240832987723039e-01, + 2.29183657866993378827e-01, + 2.19545294699780346726e-01, + 2.09962891611264163005e-01, + 2.00439157669269424344e-01, + 1.90976769746686869667e-01, + 1.81578371554184297976e-01, + 1.72246572688870225321e-01, + 1.62983947699301107148e-01, + 1.53793035167208436143e-01, + 1.44676336806320998685e-01, + 1.35636316578646581865e-01, + 1.26675399828566487281e-01, + 1.17795972435093473929e-01, + 1.09000379982627515485e-01, + 1.00290926950544131979e-01, + 9.16698759219308212387e-02, + 8.31394468117901269677e-02, + 7.47018161150024284645e-02, + 6.63591161743508073378e-02, + 5.81134344688867474082e-02, + 4.99668129229093108123e-02, + 4.19212472358281990070e-02, + 3.39786862331567796058e-02, + 2.61410312388884458201e-02, + 1.84101354694814652035e-02, + 1.07878034496857889285e-02, + 3.27579045041895364904e-03, +-4.12419805110235924983e-03, +-1.14105068887806991584e-02, +-1.85815317024259456236e-02, +-2.56357194097392264431e-02, +-3.25715686553301464468e-02, +-3.93876302366183567161e-02, +-4.60825075064776670808e-02, +-5.26548567524927901840e-02, +-5.91033875527125010518e-02, +-6.54268631077873363822e-02, +-7.16241005493989252306e-02, +-7.76939712248916614090e-02, +-8.36354009580342477870e-02, +-8.94473702858456093390e-02, +-9.51289146714309197250e-02, +-1.00679124692788404816e-01, +-1.06097146207554629549e-01, +-1.11382180493666688159e-01, +-1.16533484365933040494e-01, +-1.21550370268516991223e-01, +-1.26432206343341957400e-01, +-1.31178416474445280748e-01, +-1.35788480308313530553e-01, +-1.40261933250244968940e-01, +-1.44598366436796466061e-01, +-1.48797426684381700612e-01, +-1.52858816414098541703e-01, +-1.56782293552872986631e-01, +-1.60567671411021850592e-01, +-1.64214818536340179111e-01, +-1.67723658544838616358e-01, +-1.71094169928257461288e-01, +-1.74326385838498049141e-01, +-1.77420393849128360531e-01, +-1.80376335694119815933e-01, +-1.83194406983985758064e-01, +-1.85874856899509832697e-01, +-1.88417987863249564162e-01, +-1.90824155189017602430e-01, +-1.93093766709557357331e-01, +-1.95227282382623990031e-01, +-1.97225213875713484279e-01, +-1.99088124129663118778e-01, +-2.00816626901390404836e-01, +-2.02411386286012268121e-01, +-2.03873116218622224549e-01, +-2.05202579955993086314e-01, +-2.06400589538496825881e-01, +-2.07468005232528396320e-01, +-2.08405734953734406156e-01, +-2.09214733671363894985e-01, +-2.09896002794046132589e-01, +-2.10450589537331811396e-01, +-2.10879586273321456558e-01, +-2.11184129862729524918e-01, +-2.11365400969725530933e-01, +-2.11424623359909302778e-01, +-2.11363063181782606659e-01, +-2.11182028232088397912e-01, +-2.10882867205385543530e-01, +-2.10466968928249342774e-01, +-2.09935761578479540557e-01, +-2.09290711889717429006e-01, +-2.08533324341858283812e-01, +-2.07665140337684211991e-01, +-2.06687737366111012882e-01, +-2.05602728152473046563e-01, +-2.04411759796272074485e-01, +-2.03116512896803713684e-01, +-2.01718700667107064817e-01, +-2.00220068036660509003e-01, +-1.98622390743273286029e-01, +-1.96927474414606312747e-01, +-1.95137153639780930314e-01, +-1.93253291031515200826e-01, +-1.91277776279251604530e-01, +-1.89212525193726166517e-01, +-1.87059478743444584925e-01, +-1.84820602083524743176e-01, +-1.82497883577372205233e-01, +-1.80093333811659150889e-01, +-1.77608984605069908369e-01, +-1.75046888011289869524e-01, +-1.72409115316711214483e-01, +-1.69697756033324376190e-01, +-1.66914916887274944468e-01, +-1.64062720803562822613e-01, +-1.61143305887356008688e-01, +-1.58158824402401171350e-01, +-1.55111441747006084668e-01, +-1.52003335428069458191e-01, +-1.48836694033641553370e-01, +-1.45613716204482351868e-01, +-1.42336609605105829379e-01, +-1.39007589894771910188e-01, +-1.35628879698910465024e-01, +-1.32202707581443923424e-01, +-1.28731307018481316851e-01, +-1.25216915373852127891e-01, +-1.21661772876947515964e-01, +-1.18068121603333617275e-01, +-1.14438204458597023172e-01, +-1.10774264165883040700e-01, +-1.07078542257586659114e-01, +-1.03353278071642365465e-01, +-9.96007077528702211566e-02, +-9.58230632598184722815e-02, +-9.20225713775505993475e-02, +-8.82014527368129436224e-02, +-8.43619208400154807492e-02, +-8.05061810944624617337e-02, +-7.66364298532504761852e-02, +-7.27548534642616651080e-02, +-6.88636273276640731300e-02, +-6.49649149623320182334e-02, +-6.10608670815911136476e-02, +-5.71536206786884617981e-02, +-5.32452981223815041689e-02, +-4.93380062630371721277e-02, +-4.54338355496189602589e-02, +-4.15348591579423748188e-02, +-3.76431321305677607514e-02, +-3.37606905286930644716e-02, +-2.98895505964036217739e-02, +-2.60317079376298707305e-02, +-2.21891367061550388862e-02, +-1.83637888090092127324e-02, +-1.45575931235783270074e-02, +-1.07724547287478406021e-02, +-7.01025415039811198442e-03, +-3.27284662155273445641e-03, + 4.37938642517908310794e-04, + 4.12029915395035594566e-03, + 7.77245984641533344678e-03, + 1.13926737534469080249e-02, + 1.49792226707046640527e-02, + 1.85304178019153227563e-02, + 2.20446003882424183817e-02, + 2.55201423208448671676e-02, + 2.89554467363942642788e-02, + 3.23489485953257979722e-02, + 3.56991152426125377128e-02, + 3.90044469508545738057e-02, + 4.22634774454904785235e-02, + 4.54747744119432459331e-02, + 4.86369399845229810619e-02, + 5.17486112169195516808e-02, + 5.48084605341252126265e-02, + 5.78151961656372809228e-02, + 6.07675625598040544673e-02, + 6.36643407791787629968e-02, + 6.65043488767638746317e-02, + 6.92864422530337364936e-02, + 7.20095139936314521112e-02, + 7.46724951876515663507e-02, + 7.72743552264206767788e-02, + 7.98141020827076302924e-02, + 8.22907825702981904348e-02, + 8.47034825838767768680e-02, + 8.70513273191783898408e-02, + 8.93334814733681981114e-02, + 9.15491494256309712441e-02, + 9.36975753979484987655e-02, + 9.57780435960658566019e-02, + 9.77898783306437036078e-02, + 9.97324441186170501661e-02, + 1.01605145764776208517e-01, + 1.03407428423609545898e-01, + 1.05138777641444206012e-01, + 1.06798719378940032421e-01, + 1.08386820013995285872e-01, + 1.09902686325133475131e-01, + 1.11345965455456150095e-01, + 1.12716344857240108324e-01, + 1.14013552217288011148e-01, + 1.15237355363129817531e-01, + 1.16387562150195578159e-01, + 1.17464020330083573906e-01, + 1.18466617400054957665e-01, + 1.19395280433899547701e-01, + 1.20249975894323096748e-01, + 1.21030709427012495016e-01, + 1.21737525636550936170e-01, + 1.22370507844354617366e-01, + 1.22929777828819461472e-01, + 1.23415495547866391202e-01, + 1.23827858844088756207e-01, + 1.24167103132708178670e-01, + 1.24433501072553173716e-01, + 1.24627362220290069383e-01, + 1.24749032668130088730e-01, + 1.24798894665256510095e-01, + 1.24777366223214461471e-01, + 1.24684900705517007213e-01, + 1.24521986401729317651e-01, + 1.24289146086293156301e-01, + 1.23986936562369309822e-01, + 1.23615948190973698462e-01, + 1.23176804405697795652e-01, + 1.22670161213299697134e-01, + 1.22096706680470845630e-01, + 1.21457160407075034914e-01, + 1.20752272986177383585e-01, + 1.19982825451170740938e-01, + 1.19149628710327484815e-01, + 1.18253522969096608319e-01, + 1.17295377140480550082e-01, + 1.16276088243826986046e-01, + 1.15196580792372674229e-01, + 1.14057806169890793568e-01, + 1.12860741996784086361e-01, + 1.11606391485979145051e-01, + 1.10295782788982596467e-01, + 1.08929968332454704671e-01, + 1.07510024145666946427e-01, + 1.06037049179214082351e-01, + 1.04512164615345154450e-01, + 1.02936513170294341446e-01, + 1.01311258388983055356e-01, + 9.96375839324763756810e-02, + 9.79166928585712137423e-02, + 9.61498068959035084857e-02, + 9.43381657119597566430e-02, + 9.24830261753778609668e-02, + 9.05856616129300240559e-02, + 8.86473610615743090602e-02, + 8.66694285159709948418e-02, + 8.46531821718525673282e-02, + 8.25999536656427529868e-02, + 8.05110873107188207420e-02, + 7.83879393307109761935e-02, + 7.62318770902338793682e-02, + 7.40442783234440127238e-02, + 7.18265303608213723230e-02, + 6.95800293545625059277e-02, + 6.73061795029863685347e-02, + 6.50063922743394223547e-02, + 6.26820856303954981881e-02, + 6.03346832502406754672e-02, + 5.79656137546301838959e-02, + 5.55763099313076533448e-02, + 5.31682079616711544823e-02, + 5.07427466491714163066e-02, + 4.83013666498223193102e-02, + 4.58455097052048524131e-02, + 4.33766178783417805098e-02, + 4.08961327928156204159e-02, + 3.84054948755038344510e-02, + 3.59061426032981009793e-02, + 3.33995117541749445000e-02, + 3.08870346629779371495e-02, + 2.83701394822698481357e-02, + 2.58502494486117818939e-02, + 2.33287821546176998844e-02, + 2.08071488271321346220e-02, + 1.82867536118745781237e-02, + 1.57689928648852076276e-02, + 1.32552544511122961240e-02, + 1.07469170504618516393e-02, + 8.24534947164058847069e-03, + 5.75190997410870291651e-03, + 3.26794559845353929303e-03, + 7.94791505500461897306e-04, +-1.66622967554532603295e-03, +-4.11380848962069559788e-03, +-6.54664928870115660209e-03, +-8.96347085478857441565e-03, +-1.13630070127026094190e-02, +-1.37440072324107598334e-02, +-1.61052372206219249207e-02, +-1.84454795013846463425e-02, +-2.07635339854373018875e-02, +-2.30582185280550702733e-02, +-2.53283694751598974226e-02, +-2.75728421974516593740e-02, +-2.97905116123358577884e-02, +-3.19802726934248146562e-02, +-3.41410409673992970570e-02, +-3.62717529980220235175e-02, +-3.83713668571045649069e-02, +-4.04388625822339128901e-02, +-4.24732426210736174754e-02, +-4.44735322620624928813e-02, +-4.64387800513385851087e-02, +-4.83680581957297989204e-02, +-5.02604629516505974074e-02, +-5.21151149997620341536e-02, +-5.39311598052534396652e-02, +-5.57077679636137287900e-02, +-5.74441355317703919448e-02, +-5.91394843444778550712e-02, +-6.07930623158483146584e-02, +-6.24041437259244130553e-02, +-6.39720294922026394557e-02, +-6.54960474260223579623e-02, +-6.69755524737441765293e-02, +-6.84099269426502037961e-02, +-6.97985807115074213813e-02, +-7.11409514257386743630e-02, +-7.24365046771608261933e-02, +-7.36847341682554390907e-02, +-7.48851618609372993163e-02, +-7.60373381098108092058e-02, +-7.71408417798946782762e-02, +-7.81952803488157183187e-02, +-7.92002899934755172362e-02, +-8.01555356612003028216e-02, +-8.10607111253977136167e-02, +-8.19155390257452209468e-02, +-8.27197708929510444609e-02, +-8.34731871581248646708e-02, +-8.41755971468178959549e-02, +-8.48268390577856662427e-02, +-8.54267799265437804968e-02, +-8.59753155737910251810e-02, +-8.64723705387828583957e-02, +-8.69178979977427990100e-02, +-8.73118796674136471436e-02, +-8.76543256938471931905e-02, +-8.79452745265522362050e-02, +-8.81847927781117119084e-02, +-8.83729750694022264668e-02, +-8.85099438605464611252e-02, +-8.85958492677388215197e-02, +-8.86308688660923243985e-02, +-8.86152074786611815282e-02, +-8.85490969517982173809e-02, +-8.84327959170169153325e-02, +-8.82665895395295801995e-02, +-8.80507892536431108210e-02, +-8.77857324851982756542e-02, +-8.74717823612454203897e-02, +-8.71093274071546297410e-02, +-8.66987812313650407781e-02, +-8.62405821979837367008e-02, +-8.57351930874506312774e-02, +-8.51831007454873639917e-02, +-8.45848157205629364030e-02, +-8.39408718901024919479e-02, +-8.32518260756789918453e-02, +-8.25182576474303292047e-02, +-8.17407681179471573563e-02, +-8.09199807258840636548e-02, +-8.00565400095505641520e-02, +-7.91511113707415864260e-02, +-7.82043806290729365260e-02, +-7.72170535670915342275e-02, +-7.61898554664313942819e-02, +-7.51235306352922710404e-02, +-7.40188419275257664109e-02, +-7.28765702536047221827e-02, +-7.16975140837712299202e-02, +-7.04824889436477669546e-02, +-6.92323269026086512978e-02, +-6.79478760552057331479e-02, +-6.66299999959486799472e-02, +-6.52795772877406560442e-02, +-6.38975009242730290770e-02, +-6.24846777866859409700e-02, +-6.10420280948025528733e-02, +-5.95704848532464525945e-02, +-5.80709932927548425075e-02, +-5.65445103069988283528e-02, +-5.49920038852278469932e-02, +-5.34144525410520376596e-02, +-5.18128447376807535485e-02, +-5.01881783099329334408e-02, +-4.85414598833405000478e-02, +-4.68737042906593598390e-02, +-4.51859339861135078653e-02, +-4.34791784576844600463e-02, +-4.17544736377706837693e-02, +-4.00128613125346824231e-02, +-3.82553885302546123337e-02, +-3.64831070090038678266e-02, +-3.46970725439699687054e-02, +-3.28983444147356932086e-02, +-3.10879847928346199348e-02, +-2.92670581498969371859e-02, +-2.74366306667012324616e-02, +-2.55977696434401616465e-02, +-2.37515429115148085648e-02, +-2.18990182471639621697e-02, +-2.00412627872342125057e-02, +-1.81793424474003748048e-02, +-1.63143213431318143125e-02, +-1.44472612137104394064e-02, +-1.25792208495948080321e-02, +-1.07112555234262843418e-02, +-8.84441642496919776251e-03, +-6.97975010027273440327e-03, +-5.11829789534247545785e-03, +-3.26109540460238272672e-03, +-1.40917192442717876394e-03, + 4.36450087979504280662e-04, + 2.27475555008947467189e-03, + 4.10473728366783034011e-03, + 5.92539653824247346953e-03, + 7.73574350816149444027e-03, + 9.53479784298774321605e-03, + 1.13215891509725555958e-02, + 1.30951574953684958535e-02, + 1.48545538833333903156e-02, + 1.65988407471903930135e-02, + 1.83270924178097725787e-02, + 2.00383955898867233136e-02, + 2.17318497788877018628e-02, + 2.34065677694524146291e-02, + 2.50616760550354221448e-02, + 2.66963152685791259289e-02, + 2.83096406040205736399e-02, + 2.99008222284305145988e-02, + 3.14690456845965957355e-02, + 3.30135122838646696830e-02, + 3.45334394890581680704e-02, + 3.60280612873039099431e-02, + 3.74966285525929615696e-02, + 3.89384093979178655398e-02, + 4.03526895168305685391e-02, + 4.17387725142676843659e-02, + 4.30959802265037661417e-02, + 4.44236530300948923022e-02, + 4.57211501396783959184e-02, + 4.69878498945072997639e-02, + 4.82231500336007049001e-02, + 4.94264679593977643290e-02, + 5.05972409898094652170e-02, + 5.17349265985714082405e-02, + 5.28390026438036938816e-02, + 5.39089675846917554258e-02, + 5.49443406862122687984e-02, + 5.59446622118279432434e-02, + 5.69094936040880627903e-02, + 5.78384176530744725797e-02, + 5.87310386526413361064e-02, + 5.95869825444026307570e-02, + 6.04058970494284683261e-02, + 6.11874517876177664855e-02, + 6.19313383847234916191e-02, + 6.26372705670065754724e-02, + 6.33049842435138704344e-02, + 6.39342375759682501890e-02, + 6.45248110362744708990e-02, + 6.50765074516480857003e-02, + 6.55891520373845793301e-02, + 6.60625924172834749770e-02, + 6.64966986317623437452e-02, + 6.68913631336883612866e-02, + 6.72465007719728613544e-02, + 6.75620487629735172463e-02, + 6.78379666497569006056e-02, + 6.80742362492841729393e-02, + 6.82708615875821517305e-02, + 6.84278688229765230666e-02, + 6.85453061574607669382e-02, + 6.86232437362914587942e-02, + 6.86617735358941577717e-02, + 6.86610092401827576403e-02, + 6.86210861053920678776e-02, + 6.85421608135311638543e-02, + 6.84244113145758836581e-02, + 6.82680366575164482290e-02, + 6.80732568103898511014e-02, + 6.78403124694252068760e-02, + 6.75694648574412526365e-02, + 6.72609955116377500328e-02, + 6.69152060609276150283e-02, + 6.65324179929640407982e-02, + 6.61129724110185862385e-02, + 6.56572297808763333249e-02, + 6.51655696679120516324e-02, + 6.46383904645234791397e-02, + 6.40761091080973010925e-02, + 6.34791607896909026998e-02, + 6.28479986536143592213e-02, + 6.21830934881068692066e-02, + 6.14849334072996994704e-02, + 6.07540235246672929992e-02, + 5.99908856181665117724e-02, + 5.91960577872764140417e-02, + 5.83700941021449495882e-02, + 5.75135642450580880647e-02, + 5.66270531444532515541e-02, + 5.57111606016933366692e-02, + 5.47665009108296851892e-02, + 5.37937024715815850784e-02, + 5.27934073957626870399e-02, + 5.17662711073889059143e-02, + 5.07129619367031950206e-02, + 4.96341607083598743144e-02, + 4.85305603240058919257e-02, + 4.74028653395071053467e-02, + 4.62517915370636301109e-02, + 4.50780654924642990022e-02, + 4.38824241377281029641e-02, + 4.26656143193894568655e-02, + 4.14283923526756400757e-02, + 4.01715235718370783369e-02, + 3.88957818768817381594e-02, + 3.76019492769772492591e-02, + 3.62908154307766822599e-02, + 3.49631771839265942381e-02, + 3.36198381040227756156e-02, + 3.22616080132712215733e-02, + 3.08893025191169512400e-02, + 2.95037425431055044811e-02, + 2.81057538482372380739e-02, + 2.66961665650768086022e-02, + 2.52758147168840839603e-02, + 2.38455357440239580635e-02, + 2.24061700279218310727e-02, + 2.09585604148223095256e-02, + 1.95035517396166743764e-02, + 1.80419903499945237513e-02, + 1.65747236311830255240e-02, + 1.51025995315297069388e-02, + 1.36264660891878813115e-02, + 1.21471709601575494908e-02, + 1.06655609479410495855e-02, + 9.18248153506075540098e-03, + 7.69877641669523653245e-03, + 6.21528703667832953944e-03, + 4.73285212611389023013e-03, + 3.25230724484593071086e-03, + 1.77448432603104764606e-03, + 3.00211224053546050453e-04, +-1.16968873398075085164e-03, +-2.63439719293501574751e-03, +-4.09310121028114842767e-03, +-5.54499369246326881400e-03, +-6.98927382675401144552e-03, +-8.42514750838012187184e-03, +-9.85182776269834421801e-03, +-1.12685351622023224166e-02, +-1.26744982381468297011e-02, +-1.40689538865774264181e-02, +-1.54511477685608713400e-02, +-1.68203347044119586040e-02, +-1.81757790617144907031e-02, +-1.95167551369457396848e-02, +-2.08425475305089903666e-02, +-2.21524515149872230912e-02, +-2.34457733964363347623e-02, +-2.47218308685369890509e-02, +-2.59799533594318662888e-02, +-2.72194823710760064328e-02, +-2.84397718109379513129e-02, +-2.96401883158870678436e-02, +-3.08201115681125577261e-02, +-3.19789346029227747326e-02, +-3.31160641082781370681e-02, +-3.42309207159130005071e-02, +-3.53229392839145145411e-02, +-3.63915691706218277779e-02, +-3.74362744997228866217e-02, +-3.84565344164232020274e-02, +-3.94518433345735566875e-02, +-4.04217111746440760367e-02, +-4.13656635924379983971e-02, +-4.22832421984465703368e-02, +-4.31740047677477145616e-02, +-4.40375254403603463849e-02, +-4.48733949119690250784e-02, +-4.56812206149411689782e-02, +-4.64606268895620885817e-02, +-4.72112551454219875335e-02, +-4.79327640128901638628e-02, +-4.86248294846227807620e-02, +-4.92871450470508051800e-02, +-4.99194218018040730689e-02, +-5.05213885770312357004e-02, +-5.10927920285815725943e-02, +-5.16333967310192848421e-02, +-5.21429852584503056301e-02, +-5.26213582551397357490e-02, +-5.30683344959132635710e-02, +-5.34837509363331325973e-02, +-5.38674627526497529217e-02, +-5.42193433715342787416e-02, +-5.45392844896020398404e-02, +-5.48271960827455065446e-02, +-5.50830064052948084607e-02, +-5.53066619790379757071e-02, +-5.54981275721307884541e-02, +-5.56573861679344195075e-02, +-5.57844389238277491017e-02, +-5.58793051200398085965e-02, +-5.59420220985603691699e-02, +-5.59726451921854703531e-02, +-5.59712476437655773176e-02, +-5.59379205157255615655e-02, +-5.58727725899317365088e-02, +-5.57759302579874938210e-02, +-5.56475374020423893540e-02, +-5.54877552662062720201e-02, +-5.52967623186622694864e-02, +-5.50747541045816801919e-02, +-5.48219430899443069261e-02, +-5.45385584963738595521e-02, +-5.42248461271042508924e-02, +-5.38810681841958433180e-02, +-5.35075030771247142636e-02, +-5.31044452228734698007e-02, +-5.26722048376558060756e-02, +-5.22111077204129997442e-02, +-5.17214950282209942611e-02, +-5.12037230437547910555e-02, +-5.06581629349584436350e-02, +-5.00852005070748507176e-02, +-4.94852359471897595977e-02, +-4.88586835614527661975e-02, +-4.82059715051387852047e-02, +-4.75275415057165098731e-02, +-4.68238485790967787215e-02, +-4.60953607392339606563e-02, +-4.53425587012589517699e-02, +-4.45659355783224117586e-02, +-4.37659965723364227652e-02, +-4.29432586587956896529e-02, +-4.20982502658717866462e-02, +-4.12315109479716793150e-02, +-4.03435910539542696984e-02, +-3.94350513902031810098e-02, +-3.85064628787541649024e-02, +-3.75584062106811000792e-02, +-3.65914714949422334445e-02, +-3.56062579028932485459e-02, +-3.46033733086755293518e-02, +-3.35834339256887229319e-02, +-3.25470639393581201437e-02, +-3.14948951364113841067e-02, +-3.04275665308768074324e-02, +-2.93457239870188353603e-02, +-2.82500198394295444493e-02, +-2.71411125104896906735e-02, +-2.60196661254226829785e-02, +-2.48863501251557692195e-02, +-2.37418388772132477049e-02, +-2.25868112848582602847e-02, +-2.14219503947065334493e-02, +-2.02479430030328977352e-02, +-1.90654792609915822721e-02, +-1.78752522789717531448e-02, +-1.66779577303104824260e-02, +-1.54742934545847657390e-02, +-1.42649590607015902544e-02, +-1.30506555300084672172e-02, +-1.18320848196448689948e-02, +-1.06099494663520910881e-02, +-9.38495219096077346044e-03, +-8.15779550377599728395e-03, +-6.92918131107302364552e-03, +-5.69981052292132129439e-03, +-4.47038266255170985142e-03, +-3.24159547747867194528e-03, +-2.01414455258872894527e-03, +-7.88722925405390719311e-04, + 4.33979296259515102616e-04, + 1.65327531406484059748e-03, + 2.86848201610344138643e-03, + 4.07892035086573293695e-03, + 5.28391569800646006272e-03, + 6.48279823571479112132e-03, + 7.67490330449144362440e-03, + 8.85957176714050748112e-03, + 1.00361503647855877797e-02, + 1.12039920687220222878e-02, + 1.23624564279179102733e-02, + 1.35109099119845744302e-02, + 1.46487262494354297110e-02, + 1.57752867610552773014e-02, + 1.68899806882093564409e-02, + 1.79922055159205465658e-02, + 1.90813672905472929420e-02, + 2.01568809318992299418e-02, + 2.12181705396309386313e-02, + 2.22646696937574897768e-02, + 2.32958217491361675722e-02, + 2.43110801237692714105e-02, + 2.53099085807794131620e-02, + 2.62917815039164816382e-02, + 2.72561841664596578305e-02, + 2.82026129933784439063e-02, + 2.91305758166261995201e-02, + 3.00395921234366258812e-02, + 3.09291932975059961908e-02, + 3.17989228529399620138e-02, + 3.26483366608550443222e-02, + 3.34770031685240748720e-02, + 3.42845036109633918842e-02, + 3.50704322148587890884e-02, + 3.58343963947392735170e-02, + 3.65760169413035240993e-02, + 3.72949282018151320739e-02, + 3.79907782524846540650e-02, + 3.86632290627611160949e-02, + 3.93119566514606166852e-02, + 3.99366512346636878816e-02, + 4.05370173653198731523e-02, + 4.11127740644999239983e-02, + 4.16636549442422551848e-02, + 4.21894083219462659451e-02, + 4.26897973262660088145e-02, + 4.31645999944682140503e-02, + 4.36136093612174424727e-02, + 4.40366335387612217733e-02, + 4.44334957884889164559e-02, + 4.48040345838451384286e-02, + 4.51481036645831335097e-02, + 4.54655720823471248826e-02, + 4.57563242375793044481e-02, + 4.60202599077495430602e-02, + 4.62572942669144740457e-02, + 4.64673578966120978673e-02, + 4.66503967881086306635e-02, + 4.68063723360144789964e-02, + 4.69352613232939530619e-02, + 4.70370558976949404428e-02, + 4.71117635396342340770e-02, + 4.71594070215737987128e-02, + 4.71800243589305737246e-02, + 4.71736687525673714649e-02, + 4.71404085229153516079e-02, + 4.70803270357842834626e-02, + 4.69935226199208050391e-02, + 4.68801084763797309973e-02, + 4.67402125797770004456e-02, + 4.65739775714988368804e-02, + 4.63815606449435313685e-02, + 4.61631334228796152974e-02, + 4.59188818270049037285e-02, + 4.56490059397985786793e-02, + 4.53537198587595224986e-02, + 4.50332515431300858810e-02, + 4.46878426532076045152e-02, + 4.43177483823498988280e-02, + 4.39232372817854738178e-02, + 4.35045910783411482470e-02, + 4.30621044852065107400e-02, + 4.25960850058553150421e-02, + 4.21068527312480900271e-02, + 4.15947401304457009541e-02, + 4.10600918347645213458e-02, + 4.05032644156081075848e-02, + 3.99246261561139251239e-02, + 3.93245568167555487049e-02, + 3.87034473950466154091e-02, + 3.80616998794914215831e-02, + 3.73997269979330568268e-02, + 3.67179519604542980993e-02, + 3.60168081969824901978e-02, + 3.52967390897612337541e-02, + 3.45581977008463520074e-02, + 3.38016464947914485606e-02, + 3.30275570566867723854e-02, + 3.22364098057202272396e-02, + 3.14286937044311875944e-02, + 3.06049059638265272265e-02, + 2.97655517445348863359e-02, + 2.89111438541742558905e-02, + 2.80422024411093630258e-02, + 2.71592546847793693543e-02, + 2.62628344827749958534e-02, + 2.53534821348480460257e-02, + 2.44317440240356988090e-02, + 2.34981722950843643916e-02, + 2.25533245303600957121e-02, + 2.15977634234290963300e-02, + 2.06320564504986307675e-02, + 1.96567755399048478548e-02, + 1.86724967398384719686e-02, + 1.76797998844943696217e-02, + 1.66792682588392839060e-02, + 1.56714882621848752842e-02, + 1.46570490707573775069e-02, + 1.36365422994567421500e-02, + 1.26105616629926826217e-02, + 1.15797026365911225748e-02, + 1.05445621164599462327e-02, + 9.50573808020578961409e-03, + 8.46382924739110323320e-03, + 7.41943474041982693745e-03, + 6.37315374594339158210e-03, + 5.32558517697237672472e-03, + 4.27732733588230377986e-03, + 3.22897757850148679412e-03, + 2.18113197946379544154e-03, + 1.13438499901297824499e-03, + 8.93291514401199637785e-05, +-9.53445324662180308285e-04, +-1.99335079414908163467e-03, +-3.02980255089889101774e-03, +-4.06221914103327592926e-03, +-5.09002268361045690642e-03, +-6.11263918861550906853e-03, +-7.12949887207463706834e-03, +-8.14003646812562139945e-03, +-9.14369153787539246103e-03, +-1.01399087748766797423e-02, +-1.11281383070643315192e-02, +-1.21078359949849043153e-02, +-1.30784637261652115364e-02, +-1.40394897054589556235e-02, +-1.49903887412209321783e-02, +-1.59306425271560810064e-02, +-1.68597399196934796817e-02, +-1.77771772107420643338e-02, +-1.86824583956837868282e-02, +-1.95750954364632238913e-02, +-2.04546085196391988492e-02, +-2.13205263092617232357e-02, +-2.21723861944465271134e-02, +-2.30097345315165013879e-02, +-2.38321268805886041231e-02, +-2.46391282364846579689e-02, +-2.54303132538467105417e-02, +-2.62052664663464558725e-02, +-2.69635824998752660075e-02, +-2.77048662796101873018e-02, +-2.84287332308504510359e-02, +-2.91348094735277007850e-02, +-2.98227320102924450818e-02, +-3.04921489080843266528e-02, +-3.11427194730996177718e-02, +-3.17741144190714572271e-02, +-3.23860160287801970846e-02, +-3.29781183087202514614e-02, +-3.35501271368501066683e-02, +-3.41017604033561905208e-02, +-3.46327481443660725735e-02, +-3.51428326685533573559e-02, +-3.56317686765738189658e-02, +-3.60993233732840035355e-02, +-3.65452765726929293399e-02, +-3.69694207956033291107e-02, +-3.73715613599018697810e-02, +-3.77515164634644601049e-02, +-3.81091172596444149878e-02, +-3.84442079253161372865e-02, +-3.87566457214516685292e-02, +-3.90463010462121923316e-02, +-3.93130574805393290250e-02, +-3.95568118262348833447e-02, +-3.97774741365262002324e-02, +-3.99749677391120911141e-02, +-4.01492292516929735746e-02, +-4.03002085899928502721e-02, +-4.04278689682822170437e-02, +-4.05321868924172351578e-02, +-4.06131521454162341955e-02, +-4.06707677655930785465e-02, +-4.07050500172784421316e-02, +-4.07160283541586343059e-02, +-4.07037453752667754969e-02, +-4.06682567736679767556e-02, +-4.06096312778803508747e-02, +-4.05279505860795044581e-02, +-4.04233092931398294012e-02, +-4.02958148105644620163e-02, +-4.01455872793672688403e-02, +-3.99727594759664850432e-02, +-3.97774767111586519119e-02, +-3.95598967222433872681e-02, +-3.93201895583720484328e-02, +-3.90585374591997241955e-02, +-3.87751347269212551239e-02, +-3.84701875917762628476e-02, +-3.81439140711113400251e-02, +-3.77965438220935409652e-02, +-3.74283179881668356948e-02, +-3.70394890393534528816e-02, +-3.66303206065006978220e-02, +-3.62010873095778978881e-02, +-3.57520745801320274926e-02, +-3.52835784780144504080e-02, +-3.47959055024906621645e-02, +-3.42893723978519651685e-02, +-3.37643059536492443073e-02, +-3.32210427996700446984e-02, +-3.26599291957861484481e-02, +-3.20813208167984795227e-02, +-3.14855825324110299990e-02, +-3.08730881824660075008e-02, +-3.02442203475766398235e-02, +-2.95993701152947666366e-02, +-2.89389368419537100496e-02, +-2.82633279103284111577e-02, +-2.75729584832571511521e-02, +-2.68682512533715799063e-02, +-2.61496361890828643570e-02, +-2.54175502769729139141e-02, +-2.46724372607451357398e-02, +-2.39147473768850267473e-02, +-2.31449370871867204924e-02, +-2.23634688083034216532e-02, +-2.15708106384762607344e-02, +-2.07674360816027074594e-02, +-1.99538237688046717067e-02, +-1.91304571776571320785e-02, +-1.82978243492389613944e-02, +-1.74564176031696584313e-02, +-1.66067332507972391376e-02, +-1.57492713066995013160e-02, +-1.48845351986653506166e-02, +-1.40130314763233891628e-02, +-1.31352695185807718387e-02, +-1.22517612400427650804e-02, +-1.13630207965765197414e-02, +-1.04695642901892153193e-02, +-9.57190947338527192700e-03, +-8.67057545317061195700e-03, +-7.76608239487228645126e-03, +-6.85895122593805847688e-03, +-5.94970333988319773771e-03, +-5.03886030055244581866e-03, +-4.12694354685914054082e-03, +-3.21447409816993977597e-03, +-2.30197226049791555877e-03, +-1.38995733366734314576e-03, +-4.78947319613120116137e-04, + 4.30541368021724365611e-04, + 1.33799419283328071238e-03, + 2.24289878298409997917e-03, + 3.14474521675841243995e-03, + 4.04302630618200674328e-03, + 4.93723787855436784672e-03, + 5.82687905573941924281e-03, + 6.71145253105821966433e-03, + 7.59046484363825723490e-03, + 8.46342665006433181318e-03, + 9.32985299318577973593e-03, + 1.01892635679366270335e-02, + 1.10411829840201432262e-02, + 1.18851410253191149685e-02, + 1.27206729058918742437e-02, + 1.35473195224164386086e-02, + 1.43646277029455919638e-02, + 1.51721504518438701781e-02, + 1.59694471907719792725e-02, + 1.67560839955920790056e-02, + 1.75316338290704282210e-02, + 1.82956767692504761180e-02, + 1.90478002333781711031e-02, + 1.97875991972636944283e-02, + 2.05146764099610016963e-02, + 2.12286426036550797403e-02, + 2.19291166986495568436e-02, + 2.26157260033451115722e-02, + 2.32881064091071711408e-02, + 2.39459025799248388655e-02, + 2.45887681367592640658e-02, + 2.52163658364931847489e-02, + 2.58283677453865524731e-02, + 2.64244554069528701790e-02, + 2.70043200041730317718e-02, + 2.75676625159635493856e-02, + 2.81141938678234649951e-02, + 2.86436350765866577783e-02, + 2.91557173892062447551e-02, + 2.96501824155063799238e-02, + 3.01267822548387659287e-02, + 3.05852796165800439043e-02, + 3.10254479344173710043e-02, + 3.14470714743682391856e-02, + 3.18499454364842490839e-02, + 3.22338760501942114822e-02, + 3.25986806632450124011e-02, + 3.29441878242012764488e-02, + 3.32702373584682215002e-02, + 3.35766804378105562789e-02, + 3.38633796433344125276e-02, + 3.41302090219154988238e-02, + 3.43770541360479547910e-02, + 3.46038121071011867125e-02, + 3.48103916519715006483e-02, + 3.49967131131205394512e-02, + 3.51627084819939664251e-02, + 3.53083214158219776957e-02, + 3.54335072478019763587e-02, + 3.55382329906705415890e-02, + 3.56224773336756214692e-02, + 3.56862306329609538236e-02, + 3.57294948953816096648e-02, + 3.57522837557707126588e-02, + 3.57546224476834179073e-02, + 3.57365477676438725307e-02, + 3.56981080329308309018e-02, + 3.56393630329330246553e-02, + 3.55603839741180857703e-02, + 3.54612534186531380698e-02, + 3.53420652167257473564e-02, + 3.52029244326149889921e-02, + 3.50439472645631341918e-02, + 3.48652609585071091014e-02, + 3.46670037157273194794e-02, + 3.44493245944778661571e-02, + 3.42123834056644454682e-02, + 3.39563506026385533709e-02, + 3.36814071651815385988e-02, + 3.33877444777541942944e-02, + 3.30755642020896523103e-02, + 3.27450781442136518162e-02, + 3.23965081159751852602e-02, + 3.20300857911755970653e-02, + 3.16460525563882003053e-02, + 3.12446593565609519183e-02, + 3.08261665354972284880e-02, + 3.03908436713170998500e-02, + 2.99389694069978791469e-02, + 2.94708312760984421363e-02, + 2.89867255237756110686e-02, + 2.84869569232016131566e-02, + 2.79718385874915022316e-02, + 2.74416917772590980562e-02, + 2.68968457039136660258e-02, + 2.63376373288174668585e-02, + 2.57644111584257248793e-02, + 2.51775190355282320331e-02, + 2.45773199267213977859e-02, + 2.39641797062345729419e-02, + 2.33384709362384548670e-02, + 2.27005726437677947394e-02, + 2.20508700943889204837e-02, + 2.13897545627447401018e-02, + 2.07176231001132207798e-02, + 2.00348782991160503930e-02, + 1.93419280557122104380e-02, + 1.86391853286192524242e-02, + 1.79270678963008890661e-02, + 1.72059981116597301987e-02, + 1.64764026545822124536e-02, + 1.57387122824750626260e-02, + 1.49933615789394694695e-02, + 1.42407887007263995321e-02, + 1.34814351231214504812e-02, + 1.27157453839016106739e-02, + 1.19441668260144781555e-02, + 1.11671493391258293271e-02, + 1.03851451001812210978e-02, + 9.59860831313457708858e-03, + 8.80799494798568949339e-03, + 8.01376247928074769700e-03, + 7.21636962422106571780e-03, + 6.41627608052837850733e-03, + 5.61394226421643282449e-03, + 4.80982904741692092465e-03, + 4.00439749640451800317e-03, + 3.19810860997276008924e-03, + 2.39142305830572152181e-03, + 1.58480092248966769435e-03, + 7.78701434814883992376e-04, +-2.64172799899629922237e-05, +-8.30098462447035776932e-04, +-1.63188697479669402902e-03, +-2.43132955610078941786e-03, +-3.22797507584321246785e-03, +-4.02137478588284608128e-03, +-4.81108257062173427093e-03, +-5.59665519525267239620e-03, +-6.37765255194445643272e-03, +-7.15363790383393653022e-03, +-7.92417812668915269581e-03, +-8.68884394811023953731e-03, +-9.44721018414002543240e-03, +-1.01988559731527404090e-02, +-1.09433650068938154165e-02, +-1.16803257585482624797e-02, +-1.24093317077095619677e-02, +-1.31299815621298259644e-02, +-1.38418794761330250093e-02, +-1.45446352655703541046e-02, +-1.52378646192042489088e-02, +-1.59211893064089386740e-02, +-1.65942373810739063344e-02, +-1.72566433816031643278e-02, +-1.79080485269053901742e-02, +-1.85481009082684548950e-02, +-1.91764556770177840850e-02, +-1.97927752278625780635e-02, +-2.03967293778293395912e-02, +-2.09879955406921600569e-02, +-2.15662588968082193086e-02, +-2.21312125582700525150e-02, +-2.26825577292899260851e-02, +-2.32200038617330316304e-02, +-2.37432688057198117149e-02, +-2.42520789552232059194e-02, +-2.47461693885826818085e-02, +-2.52252840038678892431e-02, +-2.56891756490234268728e-02, +-2.61376062467286660040e-02, +-2.65703469139121004061e-02, +-2.69871780758624488228e-02, +-2.73878895748791845177e-02, +-2.77722807734117477230e-02, +-2.81401606516388999579e-02, +-2.84913478994407130818e-02, +-2.88256710027211988934e-02, +-2.91429683240446539549e-02, +-2.94430881775452554794e-02, +-2.97258888980813616720e-02, +-2.99912389046026704731e-02, +-3.02390167577045836100e-02, +-3.04691112113477519108e-02, +-3.06814212587221760153e-02, +-3.08758561722402014027e-02, +-3.10523355376465907962e-02, +-3.12107892822333435334e-02, +-3.13511576971570726791e-02, +-3.14733914538524867099e-02, +-3.15774516145448311266e-02, +-3.16633096368639233020e-02, +-3.17309473725677151923e-02, +-3.17803570603852336696e-02, +-3.18115413129928040203e-02, +-3.18245130981409940496e-02, +-3.18192957139523252552e-02, +-3.17959227584129339172e-02, +-3.17544380930855907330e-02, +-3.16948958010739717528e-02, +-3.16173601392711264846e-02, +-3.15219054849285862385e-02, +-3.14086162765858309398e-02, +-3.12775869494028441187e-02, +-3.11289218649403939820e-02, +-3.09627352354390518452e-02, +-3.07791510426457977367e-02, +-3.05783029512460211019e-02, +-3.03603342169560183605e-02, +-3.01253975893385171625e-02, +-2.98736552094041353522e-02, +-2.96052785020640661651e-02, +-2.93204480635056198568e-02, +-2.90193535435597504968e-02, +-2.87021935231378082232e-02, +-2.83691753868116139370e-02, +-2.80205151906207892976e-02, +-2.76564375251866501060e-02, +-2.72771753742177547331e-02, +-2.68829699684970599427e-02, +-2.64740706354380586629e-02, +-2.60507346443026310823e-02, +-2.56132270471758974328e-02, +-2.51618205157945855344e-02, +-2.46967951743263178233e-02, +-2.42184384282035404523e-02, +-2.37270447891129755702e-02, +-2.32229156962464287906e-02, +-2.27063593339205324617e-02, +-2.21776904456732447402e-02, +-2.16372301449491780123e-02, +-2.10853057224852889762e-02, +-2.05222504505109502870e-02, +-1.99484033838788939186e-02, +-1.93641091582448833519e-02, +-1.87697177854121780016e-02, +-1.81655844459648781186e-02, +-1.75520692793087393357e-02, +-1.69295371712437116296e-02, +-1.62983575391910488761e-02, +-1.56589041152024530112e-02, +-1.50115547268741284653e-02, +-1.43566910762958008241e-02, +-1.36946985171622712812e-02, +-1.30259658301738225072e-02, +-1.23508849968591849500e-02, +-1.16698509719491937131e-02, +-1.09832614544311153726e-02, +-1.02915166574176798753e-02, +-9.59501907696169199780e-03, +-8.89417325994698755587e-03, +-8.18938557119236638926e-03, +-7.48106395989599822632e-03, +-6.76961772555855368499e-03, +-6.05545728351598779721e-03, +-5.33899393021318099950e-03, +-4.62063960835571319735e-03, +-3.90080667206999139041e-03, +-3.17990765220415401091e-03, +-2.45835502190418740687e-03, +-1.73656096259670639399e-03, +-1.01493713050778409414e-03, +-2.93894423852804689834e-04, + 4.26157249173980906629e-04, + 1.14480920148214617565e-03, + 1.86165419710703351590e-03, + 2.57628668004443710932e-03, + 3.28830300177243139287e-03, + 3.99730164732982774095e-03, + 4.70288345982820387564e-03, + 5.40465186327331818111e-03, + 6.10221308357093879249e-03, + 6.79517636759518171841e-03, + 7.48315420020127710504e-03, + 8.16576251905792339925e-03, + 8.84262092718743515640e-03, + 9.51335290309166317635e-03, + 1.01775860083515076043e-02, + 1.08349520925866381338e-02, + 1.14850874956621031020e-02, + 1.21276332470322649459e-02, + 1.27622352621157286734e-02, + 1.33885445355916270910e-02, + 1.40062173315140241908e-02, + 1.46149153701442997833e-02, + 1.52143060113965177677e-02, + 1.58040624348002624322e-02, + 1.63838638158842961334e-02, + 1.69533954988862062274e-02, + 1.75123491656954573259e-02, + 1.80604230009418498248e-02, + 1.85973218531409432985e-02, + 1.91227573918102446149e-02, + 1.96364482604763183893e-02, + 2.01381202254901497950e-02, + 2.06275063205740884220e-02, + 2.11043469870254470078e-02, + 2.15683902095024221390e-02, + 2.20193916473261919187e-02, + 2.24571147612263599669e-02, + 2.28813309354701996390e-02, + 2.32918195953102993845e-02, + 2.36883683196934501092e-02, + 2.40707729491726543647e-02, + 2.44388376889697125915e-02, + 2.47923752071377255513e-02, + 2.51312067277732788251e-02, + 2.54551621192373560276e-02, + 2.57640799773376678872e-02, + 2.60578077034374286369e-02, + 2.63362015774511563915e-02, + 2.65991268256962030969e-02, + 2.68464576835671930866e-02, + 2.70780774530085012464e-02, + 2.72938785547578652291e-02, + 2.74937625753404746298e-02, + 2.76776403087958637605e-02, + 2.78454317931197334324e-02, + 2.79970663414113134226e-02, + 2.81324825677129637669e-02, + 2.82516284075390901320e-02, + 2.83544611330882809219e-02, + 2.84409473631392593906e-02, + 2.85110630676332979516e-02, + 2.85647935669472025078e-02, + 2.86021335258679100522e-02, + 2.86230869422767590649e-02, + 2.86276671305612032126e-02, + 2.86158966997688939127e-02, + 2.85878075265257568238e-02, + 2.85434407227408461216e-02, + 2.84828465981240355753e-02, + 2.84060846175463004026e-02, + 2.83132233532735408388e-02, + 2.82043404321091033260e-02, + 2.80795224774836003900e-02, + 2.79388650465300265868e-02, + 2.77824725621904008999e-02, + 2.76104582403968873416e-02, + 2.74229440123787519823e-02, + 2.72200604421439854019e-02, + 2.70019466391913931513e-02, + 2.67687501665088492531e-02, + 2.65206269439171582469e-02, + 2.62577411468211084633e-02, + 2.59802651004316341454e-02, + 2.56883791695271083977e-02, + 2.53822716438199466604e-02, + 2.50621386190043350661e-02, + 2.47281838735542228158e-02, + 2.43806187413515146334e-02, + 2.40196619802195698856e-02, + 2.36455396364462083758e-02, + 2.32584849053751770154e-02, + 2.28587379881527788528e-02, + 2.24465459447181145403e-02, + 2.20221625431206817491e-02, + 2.15858481052626192953e-02, + 2.11378693491531578774e-02, + 2.06784992277722831644e-02, + 2.02080167646385595870e-02, + 1.97267068861813506253e-02, + 1.92348602510139590760e-02, + 1.87327730762112433516e-02, + 1.82207469606941833973e-02, + 1.76990887058239218521e-02, + 1.71681101333155360089e-02, + 1.66281279005709090035e-02, + 1.60794633135482208097e-02, + 1.55224421372705916056e-02, + 1.49573944040871566891e-02, + 1.43846542198004401919e-02, + 1.38045595677690705744e-02, + 1.32174521111029039805e-02, + 1.26236769930632777847e-02, + 1.20235826357873512582e-02, + 1.14175205374468860531e-02, + 1.08058450679664186378e-02, + 1.01889132634121089283e-02, + 9.56708461917343822023e-03, + 8.94072088205428300300e-03, + 8.31018584139599399141e-03, + 7.67584511934790540699e-03, + 7.03806596040880416698e-03, + 6.39721702035818493709e-03, + 5.75366815469682043455e-03, + 5.10779020672127558739e-03, + 4.45995479534525007814e-03, + 3.81053410279771258631e-03, + 3.15990066231072903868e-03, + 2.50842714592023827147e-03, + 1.85648615250139353144e-03, + 1.20444999615454471746e-03, + 5.52690495064260415084e-04, +-9.84212390521464980473e-05, +-7.48515010783776918966e-04, +-1.39722175004304473983e-03, +-2.04417372013348868851e-03, +-2.68900472475985721083e-03, +-3.33135031386035986023e-03, +-3.97084798814866836436e-03, +-4.60713740224857979527e-03, +-5.23986056631194768718e-03, +-5.86866204600630658739e-03, +-6.49318916075832062301e-03, +-7.11309218015082015546e-03, +-7.72802451835431433724e-03, +-8.33764292649709012895e-03, +-8.94160768285747094286e-03, +-9.53958278078098804997e-03, +-1.01312361142165130445e-02, +-1.07162396607681370542e-02, +-1.12942696621660988721e-02, +-1.18650068020553327297e-02, +-1.24281363810071557308e-02, +-1.29833484886548687631e-02, +-1.35303381728667914546e-02, +-1.40688056058569672252e-02, +-1.45984562471500062958e-02, +-1.51190010033104265535e-02, +-1.56301563843482677063e-02, +-1.61316446567209455243e-02, +-1.66231939928469449330e-02, +-1.71045386170529077619e-02, +-1.75754189478743681752e-02, +-1.80355817366393243739e-02, +-1.84847802022550938839e-02, +-1.89227741621333586663e-02, +-1.93493301591808192219e-02, +-1.97642215847910959758e-02, +-2.01672287977736237885e-02, +-2.05581392391563748390e-02, +-2.09367475428056254438e-02, +-2.13028556418044003051e-02, +-2.16562728705364630766e-02, +-2.19968160624214870147e-02, +-2.23243096432573610854e-02, +-2.26385857201165559272e-02, +-2.29394841657579208472e-02, +-2.32268526985093780313e-02, +-2.35005469575834645413e-02, +-2.37604305737897300577e-02, +-2.40063752356104789798e-02, +-2.42382607506086561466e-02, +-2.44559751021389444603e-02, +-2.46594145013394015764e-02, +-2.48484834343765149944e-02, +-2.50230947049280248728e-02, +-2.51831694718824584955e-02, +-2.53286372822437155783e-02, +-2.54594360992264553967e-02, +-2.55755123255348194855e-02, +-2.56768208218174157076e-02, +-2.57633249202947785250e-02, +-2.58349964335584103559e-02, +-2.58918156585436348704e-02, +-2.59337713756803804610e-02, +-2.59608608432293705426e-02, +-2.59730897868132928896e-02, +-2.59704723841564268094e-02, +-2.59530312450472130936e-02, +-2.59207973865424462501e-02, +-2.58738102034334269130e-02, +-2.58121174339979962686e-02, +-2.57357751210636476191e-02, +-2.56448475684109972184e-02, +-2.55394072925489191983e-02, +-2.54195349698946651551e-02, +-2.52853193793951269708e-02, +-2.51368573406296827444e-02, +-2.49742536474338513997e-02, +-2.47976209970892889911e-02, +-2.46070799151258470805e-02, +-2.44027586757840746212e-02, +-2.41847932181901530135e-02, +-2.39533270582963850326e-02, +-2.37085111966422665275e-02, +-2.34505040219958535430e-02, +-2.31794712109343950535e-02, +-2.28955856234271913630e-02, +-2.25990271944861188802e-02, +-2.22899828219497650461e-02, +-2.19686462504703923504e-02, +-2.16352179517750840831e-02, +-2.12899050012748461413e-02, +-2.09329209510937253036e-02, +-2.05644856995994759763e-02, +-2.01848253575104240320e-02, +-1.97941721106610450664e-02, +-1.93927640795097180892e-02, +-1.89808451754700721614e-02, +-1.85586649541545842257e-02, +-1.81264784656151936582e-02, +-1.76845461016740639060e-02, +-1.72331334404288091799e-02, +-1.67725110880316378992e-02, +-1.63029545178296972341e-02, +-1.58247439069643912324e-02, +-1.53381639705272194985e-02, +-1.48435037933645017777e-02, +-1.43410566596358455410e-02, +-1.38311198802215200299e-02, +-1.33139946180815798432e-02, +-1.27899857116674387641e-02, +-1.22594014964915645066e-02, +-1.17225536249535751410e-02, +-1.11797568845337768478e-02, +-1.06313290144546303273e-02, +-1.00775905209177212701e-02, +-9.51886449102469674177e-03, +-8.95547640548645211556e-03, +-8.38775395023088309043e-03, +-7.81602682701561073120e-03, +-7.24062656315801675411e-03, +-6.66188632048521009454e-03, +-6.08014070362140109788e-03, +-5.49572556771589591090e-03, +-4.90897782572374818955e-03, +-4.32023525535186938423e-03, +-3.72983630577348361859e-03, +-3.13811990422953454236e-03, +-2.54542526261991586267e-03, +-1.95209168419812327012e-03, +-1.35845837047655643853e-03, +-7.64864228454678000274e-04, +-1.71647678275262160000e-04, + 4.20853538580006714207e-04, + 1.01230255044841479378e-03, + 1.60236354589089790082e-03, + 2.19070196323387957060e-03, + 2.77698467914542839949e-03, + 3.36088019613725542609e-03, + 3.94205882888990985502e-03, + 4.52019288929302043289e-03, + 5.09495687010455642479e-03, + 5.66602762711795274880e-03, + 6.23308455974283786433e-03, + 6.79580978989625592024e-03, + 7.35388833910371412378e-03, + 7.90700830371526483531e-03, + 8.45486102813735630745e-03, + 8.99714127598559912369e-03, + 9.53354739906401085769e-03, + 1.00637815040785765647e-02, + 1.05875496169915012112e-02, + 1.11045618449284663742e-02, + 1.16145325355499640790e-02, + 1.21171804337962679687e-02, + 1.26122288359273460739e-02, + 1.30994057407662432141e-02, + 1.35784439980698272421e-02, + 1.40490814539434016872e-02, + 1.45110610932224059350e-02, + 1.49641311787415132173e-02, + 1.54080453874216524723e-02, + 1.58425629430952868981e-02, + 1.62674487460044807363e-02, + 1.66824734989000737773e-02, + 1.70874138296747413168e-02, + 1.74820524104663498066e-02, + 1.78661780731680860934e-02, + 1.82395859212837498087e-02, + 1.86020774380712544671e-02, + 1.89534605909168415994e-02, + 1.92935499318850137151e-02, + 1.96221666943946111694e-02, + 1.99391388859692132718e-02, + 2.02443013770143460939e-02, + 2.05374959855790205354e-02, + 2.08185715580545618875e-02, + 2.10873840457748047694e-02, + 2.13437965774761310989e-02, + 2.15876795275838501142e-02, + 2.18189105802902433284e-02, + 2.20373747893947494192e-02, + 2.22429646338771422331e-02, + 2.24355800691775179867e-02, + 2.26151285741611890456e-02, + 2.27815251937450065356e-02, + 2.29346925771693951890e-02, + 2.30745610118978684844e-02, + 2.32010684531324534730e-02, + 2.33141605489318240463e-02, + 2.34137906609261335633e-02, + 2.34999198806205046586e-02, + 2.35725170412852368107e-02, + 2.36315587254308061282e-02, + 2.36770292678692914623e-02, + 2.37089207543672679523e-02, + 2.37272330158955317703e-02, + 2.37319736184848778526e-02, + 2.37231578487003234856e-02, + 2.37008086947469512329e-02, + 2.36649568232238372012e-02, + 2.36156405515453339528e-02, + 2.35529058160507051567e-02, + 2.34768061358264293337e-02, + 2.33874025722661145477e-02, + 2.32847636843980104748e-02, + 2.31689654800100834631e-02, + 2.30400913626058086170e-02, + 2.28982320742268929958e-02, + 2.27434856341802542345e-02, + 2.25759572737094099670e-02, + 2.23957593666531708243e-02, + 2.22030113561352687723e-02, + 2.19978396773321642488e-02, + 2.17803776763693009155e-02, + 2.15507655253935614947e-02, + 2.13091501338791566855e-02, + 2.10556850562188986598e-02, + 2.07905303956600374937e-02, + 2.05138527046431831669e-02, + 2.02258248816056598884e-02, + 1.99266260643129536345e-02, + 1.96164415197817541825e-02, + 1.92954625308645287551e-02, + 1.89638862795599161259e-02, + 1.86219157271243600238e-02, + 1.82697594910530766721e-02, + 1.79076317190069930763e-02, + 1.75357519597588440430e-02, + 1.71543450312383258249e-02, + 1.67636408857523670768e-02, + 1.63638744724620595339e-02, + 1.59552855971977040894e-02, + 1.55381187796942588780e-02, + 1.51126231083333045085e-02, + 1.46790520924749527676e-02, + 1.42376635124681055061e-02, + 1.37887192674271304160e-02, + 1.33324852208636900064e-02, + 1.28692310442640404228e-02, + 1.23992300587048714933e-02, + 1.19227590745975605552e-02, + 1.14400982296555958628e-02, + 1.09515308251813669321e-02, + 1.04573431607620833533e-02, + 9.95782436747753331441e-03, + 9.45326623971061603957e-03, + 8.94396306566137833105e-03, + 8.43021145666009164010e-03, + 7.91231017538069313078e-03, + 7.39055996305047670919e-03, + 6.86526336575661762229e-03, + 6.33672455995178390137e-03, + 5.80524917725282890713e-03, + 5.27114412864063391212e-03, + 4.73471742815538901294e-03, + 4.19627801619143914885e-03, + 3.65613558249144616347e-03, + 3.11460038894114266822e-03, + 2.57198309226452578868e-03, + 2.02859456672282133238e-03, + 1.48474572691466213253e-03, + 9.40747350779479814438e-04, + 3.96909902906757746776e-04, +-1.46456641755227459385e-04, +-6.89042973683567970891e-04, +-1.23054062396519788870e-03, +-1.77064213877926087543e-03, +-2.30904125308122910865e-03, +-2.84543306338863035906e-03, +-3.37951419957442612471e-03, +-3.91098299557036087337e-03, +-4.43953965888237763598e-03, +-4.96488643882942240482e-03, +-5.48672779340401636783e-03, +-6.00477055466794654159e-03, +-6.51872409258721658559e-03, +-7.02830047721765636265e-03, +-7.53321463914807636086e-03, +-8.03318452811570618555e-03, +-8.52793126970340098492e-03, +-9.01717932003300026711e-03, +-9.50065661837041358639e-03, +-9.97809473755507415904e-03, +-1.04492290321770483347e-02, +-1.09137987844132033910e-02, +-1.13715473474486038208e-02, +-1.18222222864012831839e-02, +-1.22655755166751010560e-02, +-1.27013634396638160073e-02, +-1.31293470757343818528e-02, +-1.35492921944166400117e-02, +-1.39609694417272556244e-02, +-1.43641544645633414262e-02, +-1.47586280320936603927e-02, +-1.51441761540860777430e-02, +-1.55205901961063368055e-02, +-1.58876669915270080091e-02, +-1.62452089502858505743e-02, +-1.65930241643379994265e-02, +-1.69309265097449777870e-02, +-1.72587357453450260247e-02, +-1.75762776079578519894e-02, +-1.78833839040674798249e-02, +-1.81798925979421467647e-02, +-1.84656478961397856053e-02, +-1.87405003283600303521e-02, +-1.90043068245987142872e-02, +-1.92569307885670955305e-02, +-1.94982421673372645354e-02, +-1.97281175171806696933e-02, +-1.99464400655660206718e-02, +-2.01530997692852438530e-02, +-2.03479933686821802541e-02, +-2.05310244379545009386e-02, +-2.07021034315073952647e-02, +-2.08611477263374693603e-02, +-2.10080816604267042735e-02, +-2.11428365671300945439e-02, +-2.12653508055429402157e-02, +-2.13755697868347541157e-02, +-2.14734459965394662573e-02, +-2.15589390127965130350e-02, +-2.16320155205337663618e-02, +-2.16926493215929237779e-02, +-2.17408213407943202988e-02, +-2.17765196279432124427e-02, +-2.17997393557822147225e-02, +-2.18104828138950025684e-02, +-2.18087593985702259125e-02, +-2.17945855986363228041e-02, +-2.17679849772805522612e-02, +-2.17289881498666827275e-02, +-2.16776327577697588977e-02, +-2.16139634382471537699e-02, +-2.15380317903683393688e-02, +-2.14498963370269787876e-02, +-2.13496224830621826596e-02, +-2.12372824695176258547e-02, +-2.11129553240687953264e-02, +-2.09767268076514190600e-02, +-2.08286893573265061153e-02, +-2.06689420254178614356e-02, +-2.04975904149630808182e-02, +-2.03147466115173279400e-02, +-2.01205291113544029735e-02, +-1.99150627461096366155e-02, +-1.96984786039120784995e-02, +-1.94709139470550414430e-02, +-1.92325121262560613800e-02, +-1.89834224915587240767e-02, +-1.87238002999316095754e-02, +-1.84538066196213920711e-02, +-1.81736082313160018931e-02, +-1.78833775261818227198e-02, +-1.75832924008327562415e-02, +-1.72735361492968621244e-02, +-1.69542973520454935688e-02, +-1.66257697621504420271e-02, +-1.62881521886383481834e-02, +-1.59416483771111401613e-02, +-1.55864668877057875596e-02, +-1.52228209704614383946e-02, +-1.48509284381741404196e-02, +-1.44710115368087768872e-02, +-1.40832968135484268984e-02, +-1.36880149825567599964e-02, +-1.32854007885348044532e-02, +-1.28756928681500511930e-02, +-1.24591336094203239404e-02, +-1.20359690091351341501e-02, +-1.16064485283965002776e-02, +-1.11708249463664966578e-02, +-1.07293542123018670331e-02, +-1.02822952959679969620e-02, +-9.82991003651416048181e-03, +-9.37246298989989796990e-03, +-8.91022127496175937733e-03, +-8.44345441820766075269e-03, +-7.97243419742989060939e-03, +-7.49743448422606276194e-03, +-7.01873108552144003153e-03, +-6.53660158417858263430e-03, +-6.05132517879274946238e-03, +-5.56318252275954730490e-03, +-5.07245556271012591060e-03, +-4.57942737640496932289e-03, +-4.08438201018109132978e-03, +-3.58760431604305358652e-03, +-3.08937978849174819246e-03, +-2.58999440118657569057e-03, +-2.08973444352780410305e-03, +-1.58888635726068356765e-03, +-1.08773657318487516898e-03, +-5.86571348070346666216e-04, +-8.56766018661410432358e-05, + 4.14662244703500838458e-04, + 9.14160432062568030845e-04, + 1.41253402313765564872e-03, + 1.90950006404986844660e-03, + 2.40477674405564865318e-03, + 2.89808355464306636670e-03, + 3.38914144770032432427e-03, + 3.87767299266011901057e-03, + 4.36340253253783821180e-03, + 4.84605633877375780588e-03, + 5.32536276479152106272e-03, + 5.80105239818985360389e-03, + 6.27285821148045302093e-03, + 6.74051571128982465742e-03, + 7.20376308593877450609e-03, + 7.66234135132374139660e-03, + 8.11599449501146374963e-03, + 8.56446961847351709296e-03, + 9.00751707737854762081e-03, + 9.44489061986596677156e-03, + 9.87634752272530808126e-03, + 1.03016487254043390825e-02, + 1.07205589617752304610e-02, + 1.11328468895841945635e-02, + 1.15382852175153500368e-02, + 1.19366508297968510616e-02, + 1.23277249082861840856e-02, + 1.27112930519620286746e-02, + 1.30871453937629941139e-02, + 1.34550767147076835023e-02, + 1.38148865552336977403e-02, + 1.41663793236976622014e-02, + 1.45093644019762355729e-02, + 1.48436562481129210450e-02, + 1.51690744959529933561e-02, + 1.54854440517186581205e-02, + 1.57925951874666216368e-02, + 1.60903636313842884897e-02, + 1.63785906548734767896e-02, + 1.66571231563775630502e-02, + 1.69258137419078108499e-02, + 1.71845208022262455061e-02, + 1.74331085866468830925e-02, + 1.76714472734152173994e-02, + 1.78994130366322383441e-02, + 1.81168881096860183433e-02, + 1.83237608451629584161e-02, + 1.85199257712043326152e-02, + 1.87052836442837197573e-02, + 1.88797414983780387221e-02, + 1.90432126905080711943e-02, + 1.91956169426277314938e-02, + 1.93368803798427274510e-02, + 1.94669355649397177177e-02, + 1.95857215292121362993e-02, + 1.96931837995691326471e-02, + 1.97892744219159630314e-02, + 1.98739519807974267251e-02, + 1.99471816152978105585e-02, + 2.00089350311917421599e-02, + 2.00591905093446473685e-02, + 2.00979329103609591356e-02, + 2.01251536754834259302e-02, + 2.01408508237461286727e-02, + 2.01450289453875622248e-02, + 2.01376991915322746396e-02, + 2.01188792601508376068e-02, + 2.00885933783103917682e-02, + 2.00468722807307861422e-02, + 1.99937531846619727383e-02, + 1.99292797611018770998e-02, + 1.98535021023752838998e-02, + 1.97664766860958553141e-02, + 1.96682663355367028102e-02, + 1.95589401764357864733e-02, + 1.94385735902649521567e-02, + 1.93072481639931514685e-02, + 1.91650516363770367922e-02, + 1.90120778408122484415e-02, + 1.88484266447838007263e-02, + 1.86742038859517046900e-02, + 1.84895213049142380368e-02, + 1.82944964746886706841e-02, + 1.80892527269562349013e-02, + 1.78739190751135354485e-02, + 1.76486301341811334387e-02, + 1.74135260376162073759e-02, + 1.71687523510813504213e-02, + 1.69144599832216704915e-02, + 1.66508050935038308393e-02, + 1.63779489971747002630e-02, + 1.60960580673943053076e-02, + 1.58053036346042924398e-02, + 1.55058618831906466079e-02, + 1.51979137455046566657e-02, + 1.48816447933020276628e-02, + 1.45572451266690657684e-02, + 1.42249092604983910781e-02, + 1.38848360085833399946e-02, + 1.35372283653998979475e-02, + 1.31822933856448436252e-02, + 1.28202420616024131972e-02, + 1.24512891984102161413e-02, + 1.20756532873008502055e-02, + 1.16935563768882661712e-02, + 1.13052239425808411649e-02, + 1.09108847541921957086e-02, + 1.05107707418293280094e-02, + 1.01051168601380188944e-02, + 9.69416095097974661599e-03, + 9.27814360462589186873e-03, + 8.85730801954525207020e-03, + 8.43189986086877521498e-03, + 8.00216711761173211948e-03, + 7.56835995873902413200e-03, + 7.13073058815158738327e-03, + 6.68953309868379475400e-03, + 6.24502332519116971910e-03, + 5.79745869681476747037e-03, + 5.34709808850850412676e-03, + 4.89420167191210314650e-03, + 4.43903076565723645613e-03, + 3.98184768519108632512e-03, + 3.52291559220632970878e-03, + 3.06249834375802321845e-03, + 2.60086034116042237249e-03, + 2.13826637874443706636e-03, + 1.67498149256396322397e-03, + 1.21127080913929915072e-03, + 7.47399394318058719021e-04, + 2.83632102346346049587e-04, +-1.79766574769843468212e-04, +-6.42532657524515324506e-04, +-1.10440282870957989618e-03, +-1.56511458266390263150e-03, +-2.02440637389199361643e-03, +-2.48201776496643914185e-03, +-2.93768957363143169009e-03, +-3.39116401902536928475e-03, +-3.84218486693827703318e-03, +-4.29049757402515802296e-03, +-4.73584943089246784842e-03, +-5.17798970397907992042e-03, +-5.61666977614957031034e-03, +-6.05164328592657299599e-03, +-6.48266626527806404806e-03, +-6.90949727588800570455e-03, +-7.33189754383248466774e-03, +-7.74963109258556843290e-03, +-8.16246487428337087755e-03, +-8.57016889917199681248e-03, +-8.97251636316816550409e-03, +-9.36928377346218227428e-03, +-9.76025107209459868995e-03, +-1.01452017574365904035e-02, +-1.05239230035099728261e-02, +-1.08962057770798960432e-02, +-1.12618449524549517349e-02, +-1.16206394239357687498e-02, +-1.19723922158460008985e-02, +-1.23169105900894394756e-02, +-1.26540061511731961180e-02, +-1.29834949486409296365e-02, +-1.33051975768588605364e-02, +-1.36189392721043061457e-02, +-1.39245500069003491639e-02, +-1.42218645815492452517e-02, +-1.45107227128146703404e-02, +-1.47909691197041746891e-02, +-1.50624536063089509152e-02, +-1.53250311416544826582e-02, +-1.55785619365223330923e-02, +-1.58229115171997537781e-02, +-1.60579507961227489765e-02, +-1.62835561393713836031e-02, +-1.64996094309859363258e-02, +-1.67059981340693386453e-02, +-1.69026153486439532914e-02, +-1.70893598662360153562e-02, +-1.72661362211572987080e-02, +-1.74328547384603599335e-02, +-1.75894315785435489952e-02, +-1.77357887783837660234e-02, +-1.78718542893771675795e-02, +-1.79975620117707353629e-02, +-1.81128518256681338150e-02, +-1.82176696185966900676e-02, +-1.83119673096232941922e-02, +-1.83957028700091167195e-02, +-1.84688403403957639159e-02, +-1.85313498445167090800e-02, +-1.85832075994299093791e-02, +-1.86243959222697728906e-02, +-1.86549032335186701359e-02, +-1.86747240567995964611e-02, +-1.86838590151944261564e-02, +-1.86823148240932573882e-02, +-1.86701042805831954330e-02, +-1.86472462493857613075e-02, +-1.86137656453560576542e-02, +-1.85696934125556128992e-02, +-1.85150664999163827584e-02, +-1.84499278335122293693e-02, +-1.83743262854581951293e-02, +-1.82883166394587175219e-02, +-1.81919595530277734829e-02, +-1.80853215164069915100e-02, +-1.79684748082077037912e-02, +-1.78414974478062274277e-02, +-1.77044731445240056955e-02, +-1.75574912436227900669e-02, +-1.74006466691516183121e-02, +-1.72340398636801027388e-02, +-1.70577767249556339069e-02, +-1.68719685395252033677e-02, +-1.66767319133613971249e-02, +-1.64721886995365836281e-02, +-1.62584659229890703125e-02, +-1.60356957024269768108e-02, +-1.58040151694183554631e-02, +-1.55635663847157393325e-02, +-1.53144962518665349316e-02, +-1.50569564281600679762e-02, +-1.47911032329673657743e-02, +-1.45170975535258116318e-02, +-1.42351047482265624655e-02, +-1.39452945474637136913e-02, +-1.36478409521007416211e-02, +-1.33429221296188608992e-02, +-1.30307203080056444033e-02, +-1.27114216674486905923e-02, +-1.23852162298968091619e-02, +-1.20522977465561034055e-02, +-1.17128635833847836306e-02, +-1.13671146046554968900e-02, +-1.10152550546535922538e-02, +-1.06574924375795083986e-02, +-1.02940373957274844408e-02, +-9.92510358600978345733e-03, +-9.55090755489973984582e-03, +-9.17166861186629808755e-03, +-8.78760870137362294641e-03, +-8.39895227351954501427e-03, +-8.00592615338992057150e-03, +-7.60875940920200354023e-03, +-7.20768321931454427481e-03, +-6.80293073818321551022e-03, +-6.39473696133400267699e-03, +-5.98333858943855649570e-03, +-5.56897389156482680583e-03, +-5.15188256768454866386e-03, +-4.73230561051499881708e-03, +-4.31048516677632470584e-03, +-3.88666439794171014385e-03, +-3.46108734056119323949e-03, +-3.03399876624102851630e-03, +-2.60564404135369374893e-03, +-2.17626898656492900885e-03, +-1.74611973625276640544e-03, +-1.31544259790159325310e-03, +-8.84483911549698064228e-04, +-4.53489909372157390909e-04, +-2.27065754763732153979e-05, + 4.07620494008173754521e-04, + 8.37246230468182989909e-04, + 1.26592623189187344218e-03, + 1.69341690142426519808e-03, + 2.11947558531578586147e-03, + 2.54386071017997711027e-03, + 2.96633191949158747311e-03, + 3.38665020924181978113e-03, + 3.80457806267612890991e-03, + 4.21987958404042469429e-03, + 4.63232063125803249226e-03, + 5.04166894746706922836e-03, + 5.44769429133779015118e-03, + 5.85016856610528698801e-03, + 6.24886594723963670339e-03, + 6.64356300868360755141e-03, + 7.03403884758925946469e-03, + 7.42007520748272191013e-03, + 7.80145659978820089214e-03, + 8.17797042364491223732e-03, + 8.54940708395133565356e-03, + 8.91556010756844319332e-03, + 9.27622625762106536862e-03, + 9.63120564583299677841e-03, + 9.98030184283307808535e-03, + 1.03233219863735226768e-02, + 1.06600768874003729025e-02, + 1.09903811339163819116e-02, + 1.13140531925830963023e-02, + 1.16309155080034538898e-02, + 1.19407945996319476284e-02, + 1.22435211562607008245e-02, + 1.25389301280292575491e-02, + 1.28268608159079269826e-02, + 1.31071569586075614006e-02, + 1.33796668168697750756e-02, + 1.36442432550884507059e-02, + 1.39007438202245533349e-02, + 1.41490308179680942396e-02, + 1.43889713861080018736e-02, + 1.46204375650716145163e-02, + 1.48433063655967166505e-02, + 1.50574598334992579285e-02, + 1.52627851115045704011e-02, + 1.54591744981103021428e-02, + 1.56465255034476218021e-02, + 1.58247409021165554022e-02, + 1.59937287829656459015e-02, + 1.61534025957906987592e-02, + 1.63036811949317031467e-02, + 1.64444888797439722761e-02, + 1.65757554319247296659e-02, + 1.66974161496777871727e-02, + 1.68094118786993561299e-02, + 1.69116890399709611514e-02, + 1.70041996543472719028e-02, + 1.70869013639282085748e-02, + 1.71597574502064462165e-02, + 1.72227368489833373988e-02, + 1.72758141620482467971e-02, + 1.73189696656185082579e-02, + 1.73521893155377665563e-02, + 1.73754647492341991744e-02, + 1.73887932844398809817e-02, + 1.73921779146764994561e-02, + 1.73856273015124823678e-02, + 1.73691557636001317477e-02, + 1.73427832625017742940e-02, + 1.73065353853169359710e-02, + 1.72604433241233257146e-02, + 1.72045438522471921816e-02, + 1.71388792973795056618e-02, + 1.70634975115566134285e-02, + 1.69784518380263448056e-02, + 1.68838010750209793764e-02, + 1.67796094364609134353e-02, + 1.66659465096161037156e-02, + 1.65428872097501365734e-02, + 1.64105117317781858122e-02, + 1.62689054989683147545e-02, + 1.61181591087189469980e-02, + 1.59583682754456043784e-02, + 1.57896337706140629797e-02, + 1.56120613599556659623e-02, + 1.54257617379032624383e-02, + 1.52308504592903026092e-02, + 1.50274478683518758482e-02, + 1.48156790250726522890e-02, + 1.45956736289267492018e-02, + 1.43675659400543699606e-02, + 1.41314946979236334690e-02, + 1.38876030375264993694e-02, + 1.36360384031594637777e-02, + 1.33769524598382864855e-02, + 1.31105010024045141870e-02, + 1.28368438623721048408e-02, + 1.25561448125739872489e-02, + 1.22685714696633887261e-02, + 1.19742951945275791920e-02, + 1.16734909906738484192e-02, + 1.13663374006453127274e-02, + 1.10530164005323595922e-02, + 1.07337132926358554130e-02, + 1.04086165963493543218e-02, + 1.00779179373233617606e-02, + 9.74181193497532758874e-03, + 9.40049608841225445288e-03, + 9.05417066083279500899e-03, + 8.70303856247552944103e-03, + 8.34730523218016502718e-03, + 7.98717851763572177226e-03, + 7.62286855437785230982e-03, + 7.25458764361144089333e-03, + 6.88255012892701172750e-03, + 6.50697227198192371805e-03, + 6.12807212721856470888e-03, + 5.74606941569283727334e-03, + 5.36118539808457146567e-03, + 4.97364274696218688909e-03, + 4.58366541837830314410e-03, + 4.19147852286664863303e-03, + 3.79730819591561500129e-03, + 3.40138146799415100677e-03, + 3.00392613420201199520e-03, + 2.60517062362004749726e-03, + 2.20534386843704386522e-03, + 1.80467517292383881899e-03, + 1.40339408233299683948e-03, + 1.00173025179804741150e-03, + 5.99913315305479412538e-04, + 1.98172754814968598257e-04, +-2.03262230396802987941e-04, +-6.04162854095924620711e-04, +-1.00430087308224437644e-03, +-1.40344871673197396644e-03, +-1.80137961602673795508e-03, +-2.19786773199013999239e-03, +-2.59268828346089896114e-03, +-2.98561767413182141753e-03, +-3.37643361878200423329e-03, +-3.76491526863040370035e-03, +-4.15084333574143593548e-03, +-4.53400021641445216680e-03, +-4.91417011348194241599e-03, +-5.29113915745588105771e-03, +-5.66469552644815847742e-03, +-6.03462956480155590655e-03, +-6.40073390036281514998e-03, +-6.76280356033400701504e-03, +-7.12063608563857919354e-03, +-7.47403164373383350344e-03, +-7.82279313981379918752e-03, +-8.16672632633589495876e-03, +-8.50563991081211730194e-03, +-8.83934566180608928543e-03, +-9.16765851307686438498e-03, +-9.49039666581114917110e-03, +-9.80738168888878152074e-03, +-1.01184386171277399674e-02, +-1.04233960474500557403e-02, +-1.07220862329222184350e-02, +-1.10143451746142415071e-02, +-1.13000127112285256303e-02, +-1.15789326064506051250e-02, +-1.18509526339738002071e-02, +-1.21159246601509965058e-02, +-1.23737047242299964128e-02, +-1.26241531161297524527e-02, +-1.28671344517128152796e-02, +-1.31025177455174803715e-02, +-1.33301764809086713964e-02, +-1.35499886776097172580e-02, +-1.37618369565811367317e-02, +-1.39656086022109764133e-02, +-1.41611956217838150934e-02, +-1.43484948021984325128e-02, +-1.45274077639039357612e-02, +-1.46978410120258608934e-02, +-1.48597059846577242426e-02, +-1.50129190982918585967e-02, +-1.51574017903672395718e-02, +-1.52930805589124932387e-02, +-1.54198869992662364325e-02, +-1.55377578378534803027e-02, +-1.56466349630057406650e-02, +-1.57464654528072754702e-02, +-1.58372015999561979727e-02, +-1.59188009336289001960e-02, +-1.59912262383383775577e-02, +-1.60544455697791341175e-02, +-1.61084322676517156803e-02, +-1.61531649654640882541e-02, +-1.61886275973061356803e-02, +-1.62148094015971411253e-02, +-1.62317049218069497929e-02, +-1.62393140041536092333e-02, +-1.62376417922817130324e-02, +-1.62266987189277553383e-02, +-1.62065004945800873737e-02, +-1.61770680931431522220e-02, +-1.61384277346172493040e-02, +-1.60906108648061207944e-02, +-1.60336541320681771894e-02, +-1.59675993611263326855e-02, +-1.58924935239547066024e-02, +-1.58083887077626328299e-02, +-1.57153420800955900827e-02, +-1.56134158510770112288e-02, +-1.55026772328152578212e-02, +-1.53831983960010937329e-02, +-1.52550564237238350102e-02, +-1.51183332625351458250e-02, +-1.49731156707911920722e-02, +-1.48194951643046812090e-02, +-1.46575679593417048524e-02, +-1.44874349129977750272e-02, +-1.43092014609884597698e-02, +-1.41229775528962445130e-02, +-1.39288775849084438263e-02, +-1.37270203300904457960e-02, +-1.35175288662355702618e-02, +-1.33005305013339011205e-02, +-1.30761566967065763489e-02, +-1.28445429878512040744e-02, +-1.26058289030446593615e-02, +-1.23601578797534680798e-02, +-1.21076771789009329794e-02, +-1.18485377970418380433e-02, +-1.15828943764964987367e-02, +-1.13109051134989493925e-02, +-1.10327316644120605738e-02, +-1.07485390500640064226e-02, +-1.04584955582669985458e-02, +-1.01627726445692283253e-02, +-9.86154483130371323218e-03, +-9.55498960498988268719e-03, +-9.24328731215033269630e-03, +-8.92662105360215486771e-03, +-8.60517657728362625469e-03, +-8.27914216968341290515e-03, +-7.94870854592883563372e-03, +-7.61406873860231547119e-03, +-7.27541798534921645147e-03, +-6.93295361534090708033e-03, +-6.58687493466020984600e-03, +-6.23738311067596751247e-03, +-5.88468105547270119854e-03, +-5.52897330840119299866e-03, +-5.17046591782320454772e-03, +-4.80936632211110496465e-03, +-4.44588322997643489720e-03, +-4.08022650019468531568e-03, +-3.71260702079436550813e-03, +-3.34323658778045351356e-03, +-2.97232778346277022249e-03, +-2.60009385445763652536e-03, +-2.22674858943125442146e-03, +-1.85250619666033739495e-03, +-1.47758118147215886107e-03, +-1.10218822363969577716e-03, +-7.26542054800227666764e-04, +-3.50857335965947274205e-04, + 2.46514648028058004550e-05, + 3.99770194491305848588e-04, + 7.74285136923100344129e-04, + 1.14798313418393348531e-03, + 1.52065170760259482478e-03, + 1.89207917822773732594e-03, + 2.26205478672706098917e-03, + 2.63036881264248683862e-03, + 2.99681269293534556161e-03, + 3.36117913975389048103e-03, + 3.72326225735529307836e-03, + 4.08285765811985511958e-03, + 4.43976257758913958607e-03, + 4.79377598846415613199e-03, + 5.14469871350105301122e-03, + 5.49233353723946847447e-03, + 5.83648531650244987989e-03, + 6.17696108960405759064e-03, + 6.51357018420694721533e-03, + 6.84612432376711325249e-03, + 7.17443773250708155542e-03, + 7.49832723886042704087e-03, + 7.81761237732933426947e-03, + 8.13211548869811375051e-03, + 8.44166181854820452113e-03, + 8.74607961402130464068e-03, + 9.04520021877286591050e-03, + 9.33885816606978835797e-03, + 9.62689126997642689865e-03, + 9.90914071458013148708e-03, + 1.01854511412086366773e-02, + 1.04556707335903883299e-02, + 1.07196513009111780990e-02, + 1.09772483587224512630e-02, + 1.12283212076583951283e-02, + 1.14727330099153260884e-02, + 1.17103508634570831898e-02, + 1.19410458739028241953e-02, + 1.21646932240592649255e-02, + 1.23811722410611373818e-02, + 1.25903664610832344978e-02, + 1.27921636915890018366e-02, + 1.29864560710836914048e-02, + 1.31731401263407224556e-02, + 1.33521168270687006635e-02, + 1.35232916379940497353e-02, + 1.36865745683296211738e-02, + 1.38418802186039205382e-02, + 1.39891278248280535867e-02, + 1.41282412999769145523e-02, + 1.42591492727635726218e-02, + 1.43817851236876445564e-02, + 1.44960870183408006145e-02, + 1.46019979379505230460e-02, + 1.46994657071504129797e-02, + 1.47884430189622918805e-02, + 1.48688874569784020702e-02, + 1.49407615147348158541e-02, + 1.50040326122672287162e-02, + 1.50586731098424179975e-02, + 1.51046603188603172779e-02, + 1.51419765099236949824e-02, + 1.51706089180728420640e-02, + 1.51905497451859678587e-02, + 1.52017961595458175883e-02, + 1.52043502925764267841e-02, + 1.51982192327537388166e-02, + 1.51834150166969984036e-02, + 1.51599546174485608208e-02, + 1.51278599299513004384e-02, + 1.50871577537351683751e-02, + 1.50378797728247023263e-02, + 1.49800625328825147420e-02, + 1.49137474156039364498e-02, + 1.48389806103799235665e-02, + 1.47558130832480607908e-02, + 1.46643005431505314001e-02, + 1.45645034055218620950e-02, + 1.44564867532300453390e-02, + 1.43403202948947962325e-02, + 1.42160783206099778503e-02, + 1.40838396550982923594e-02, + 1.39436876083266405452e-02, + 1.37957099236124917929e-02, + 1.36399987232554212313e-02, + 1.34766504517241942490e-02, + 1.33057658164359091102e-02, + 1.31274497261638489060e-02, + 1.29418112271095040594e-02, + 1.27489634366789363756e-02, + 1.25490234750032566419e-02, + 1.23421123942442402532e-02, + 1.21283551057263516704e-02, + 1.19078803049420742233e-02, + 1.16808203944710996269e-02, + 1.14473114048624195760e-02, + 1.12074929135256729645e-02, + 1.09615079616787580025e-02, + 1.07095029694022052941e-02, + 1.04516276488501973219e-02, + 1.01880349156695994978e-02, + 9.91888079867737047779e-03, + 9.64432434785405211242e-03, + 9.36452754070147760923e-03, + 9.07965518702451984678e-03, + 8.78987483218966227094e-03, + 8.49535665891908500780e-03, + 8.19627338767603061398e-03, + 7.89280017569949157719e-03, + 7.58511451474948479590e-03, + 7.27339612761909639488e-03, + 6.95782686347547630473e-03, + 6.63859059209071476759e-03, + 6.31587309702252765881e-03, + 5.98986196780740103029e-03, + 5.66074649122982193061e-03, + 5.32871754172747295192e-03, + 4.99396747099837244599e-03, + 4.65668999687305143476e-03, + 4.31708009151461624686e-03, + 3.97533386901183748152e-03, + 3.63164847243082006614e-03, + 3.28622196038877781299e-03, + 2.93925319321392116909e-03, + 2.59094171876164420382e-03, + 2.24148765794563754883e-03, + 1.89109159005432995830e-03, + 1.53995443791703993247e-03, + 1.18827735298423120720e-03, + 8.36261600388259543348e-04, + 4.84108444050918994457e-04, + 1.32019031902150203511e-04, +-2.19805718726241933539e-04, +-5.71165235461442008166e-04, +-9.21859404947263896997e-04, +-1.27168868652862017930e-03, +-1.62045422549978823494e-03, +-1.96795796585350459343e-03, +-2.31400276246625583032e-03, +-2.65839249265560281787e-03, +-3.00093216704766258679e-03, +-3.34142803969362210681e-03, +-3.67968771736809294182e-03, +-4.01552026799475991758e-03, +-4.34873632813331280345e-03, +-4.67914820946864051104e-03, +-5.00657000424378773040e-03, +-5.33081768957552153132e-03, +-5.65170923059745127642e-03, +-5.96906468236742954181e-03, +-6.28270629048909966946e-03, +-6.59245859038667947338e-03, +-6.89814850517884731868e-03, +-7.19960544209851966563e-03, +-7.49666138740393440260e-03, +-7.78915099972798865430e-03, +-8.07691170181503576009e-03, +-8.35978377059490469769e-03, +-8.63761042554191810217e-03, +-8.91023791527316942618e-03, +-9.17751560233688937207e-03, +-9.43929604614376221994e-03, +-9.69543508399723329150e-03, +-9.94579191017774290329e-03, +-1.01902291530364327854e-02, +-1.04286129500589536817e-02, +-1.06608130208563391117e-02, +-1.08867027380436017653e-02, +-1.11061591959687958747e-02, +-1.13190632772547025708e-02, +-1.15252997171166309681e-02, +-1.17247571654230976768e-02, +-1.19173282464660659080e-02, +-1.21029096164066742036e-02, +-1.22814020183694711658e-02, +-1.24527103351532476838e-02, +-1.26167436395315489539e-02, +-1.27734152421167899277e-02, +-1.29226427367628814158e-02, +-1.30643480434822645969e-02, +-1.31984574488560428562e-02, +-1.33249016439166492742e-02, +-1.34436157594821689004e-02, +-1.35545393989273295354e-02, +-1.36576166683727209111e-02, +-1.37527962042781285584e-02, +-1.38400311984271696952e-02, +-1.39192794202912337870e-02, +-1.39905032367616116717e-02, +-1.40536696292427546601e-02, +-1.41087502080980680547e-02, +-1.41557212244426133818e-02, +-1.41945635792792845820e-02, +-1.42252628299752575947e-02, +-1.42478091940773932134e-02, +-1.42621975504671379131e-02, +-1.42684274378570910558e-02, +-1.42665030506319845394e-02, +-1.42564332320393345743e-02, +-1.42382314647362499815e-02, +-1.42119158586999447952e-02, +-1.41775091365116089059e-02, +-1.41350386160245498901e-02, +-1.40845361904284333693e-02, +-1.40260383057241797000e-02, +-1.39595859356245310251e-02, +-1.38852245538964112065e-02, +-1.38030041041644433580e-02, +-1.37129789671941813151e-02, +-1.36152079256764129561e-02, +-1.35097541265353955631e-02, +-1.33966850407841280013e-02, +-1.32760724209521549510e-02, +-1.31479922561130030401e-02, +-1.30125247245378994343e-02, +-1.28697541440061513640e-02, +-1.27197689198022458740e-02, +-1.25626614904315592192e-02, +-1.23985282710872991158e-02, +-1.22274695949040924925e-02, +-1.20495896520329080076e-02, +-1.18649964265733695590e-02, +-1.16738016314043534238e-02, +-1.14761206409479885049e-02, +-1.12720724219102334807e-02, +-1.10617794620386598187e-02, +-1.08453676969394192248e-02, +-1.06229664349969266796e-02, +-1.03947082804420436186e-02, +-1.01607290546128509884e-02, +-9.92116771545450623626e-03, +-9.67616627530844784777e-03, +-9.42586971703506318332e-03, +-9.17042590852275470159e-03, +-8.90998551563223703531e-03, +-8.64470191362698078819e-03, +-8.37473109714258721892e-03, +-8.10023158874558640852e-03, +-7.82136434613948418326e-03, +-7.53829266806671071527e-03, +-7.25118209896521460911e-03, +-6.96020033243441478554e-03, +-6.66551711356555987714e-03, +-6.36730414019388325786e-03, +-6.06573496313063138113e-03, +-5.76098488543169522103e-03, +-5.45323086076018610086e-03, +-5.14265139090599315841e-03, +-4.82942642251557672367e-03, +-4.51373724309595599630e-03, +-4.19576637635184213071e-03, +-3.87569747691505085002e-03, +-3.55371522452749104282e-03, +-3.23000521773942998738e-03, +-2.90475386718291829144e-03, +-2.57814828848035217795e-03, +-2.25037619485449289641e-03, +-1.92162578949469156631e-03, +-1.59208565774584761589e-03, +-1.26194465918040934528e-03, +-9.31391819614034682621e-04, +-6.00616223127062396486e-04, +-2.69806904154944583816e-04, + 6.08472602942396962656e-05, + 3.91157658230999324359e-04, + 7.20936050023826264892e-04, + 1.04999467542699867657e-03, + 1.37814636023528779528e-03, + 1.70520462250435696737e-03, + 2.03098377827778953097e-03, + 2.35529904676215007600e-03, + 2.67796665488591583565e-03, + 2.99880394118968215261e-03, + 3.31762945898433653930e-03, + 3.63426307872031237670e-03, + 3.94852608951128981885e-03, + 4.26024129975459756037e-03, + 4.56923313679098372364e-03, + 4.87532774554888699570e-03, + 5.17835308611915706711e-03, + 5.47813903020093976443e-03, + 5.77451745637115685522e-03, + 6.06732234411917498856e-03, + 6.35638986659726578504e-03, + 6.64155848203327753981e-03, + 6.92266902375569294359e-03, + 7.19956478878218397721e-03, + 7.47209162491841317327e-03, + 7.74009801632427347357e-03, + 8.00343516749617983619e-03, + 8.26195708562018661658e-03, + 8.51552066125116358108e-03, + 8.76398574727313937893e-03, + 9.00721523609652845177e-03, + 9.24507513505131058029e-03, + 9.47743463993477690266e-03, + 9.70416620667113177801e-03, + 9.92514562104791428498e-03, + 1.01402520664879789575e-02, + 1.03493681898213143316e-02, + 1.05523801650215433984e-02, + 1.07491777548722518970e-02, + 1.09396543705291681564e-02, + 1.11237071289475124292e-02, + 1.13012369081435404966e-02, + 1.14721484002587425371e-02, + 1.16363501624019635705e-02, + 1.17937546652395908869e-02, + 1.19442783393092378380e-02, + 1.20878416190330750107e-02, + 1.22243689844071853207e-02, + 1.23537890003452277554e-02, + 1.24760343536569357631e-02, + 1.25910418876418357670e-02, + 1.26987526342805939761e-02, + 1.27991118440086270452e-02, + 1.28920690130565843839e-02, + 1.29775779083439509604e-02, + 1.30555965899154108323e-02, + 1.31260874309076600724e-02, + 1.31890171350384308863e-02, + 1.32443567516100473014e-02, + 1.32920816880211477284e-02, + 1.33321717197816842077e-02, + 1.33646109980275606260e-02, + 1.33893880545334492682e-02, + 1.34064958042229027263e-02, + 1.34159315451764481197e-02, + 1.34176969561404253045e-02, + 1.34117980915397661673e-02, + 1.33982453740004014281e-02, + 1.33770535843872502568e-02, + 1.33482418493662668285e-02, + 1.33118336264995938689e-02, + 1.32678566868845784765e-02, + 1.32163430953490413505e-02, + 1.31573291882161602651e-02, + 1.30908555486537094698e-02, + 1.30169669796242129522e-02, + 1.29357124744537473754e-02, + 1.28471451850375104065e-02, + 1.27513223877034967413e-02, + 1.26483054467555582068e-02, + 1.25381597757181027092e-02, + 1.24209547963076202132e-02, + 1.22967638951557260707e-02, + 1.21656643783110817586e-02, + 1.20277374235470257274e-02, + 1.18830680305065279623e-02, + 1.17317449687113807555e-02, + 1.15738607234699020926e-02, + 1.14095114397158373110e-02, + 1.12387968638101957974e-02, + 1.10618202833434337712e-02, + 1.08786884649728424201e-02, + 1.06895115903328993823e-02, + 1.04944031900558870651e-02, + 1.02934800759447477037e-02, + 1.00868622713343389363e-02, + 9.87467293968604525878e-03, + 9.65703831145729371666e-03, + 9.43408760928757944564e-03, + 9.20595297154692439323e-03, + 8.97276937429128222667e-03, + 8.73467455167086133383e-03, + 8.49180891483720598489e-03, + 8.24431546939977458188e-03, + 7.99233973147535532722e-03, + 7.73602964238361088395e-03, + 7.47553548203802858269e-03, + 7.21100978108041128223e-03, + 6.94260723181349802963e-03, + 6.67048459797950268196e-03, + 6.39480062344236106775e-03, + 6.11571593982157112740e-03, + 5.83339297313448506416e-03, + 5.54799584949982379362e-03, + 5.25969029995765075675e-03, + 4.96864356445977841531e-03, + 4.67502429508827137272e-03, + 4.37900245855606801149e-03, + 4.08074923804454484794e-03, + 3.78043693443984004168e-03, + 3.47823886701886190315e-03, + 3.17432927364564567915e-03, + 2.86888321053426365720e-03, + 2.56207645163618802017e-03, + 2.25408538770850491381e-03, + 1.94508692512463700341e-03, + 1.63525838447931698427e-03, + 1.32477739905105789536e-03, + 1.01382181317911045614e-03, + 7.02569580610471595104e-04, + 3.91198662877513612512e-04, + 7.98869277630744821202e-05, +-2.31187952088860002205e-04, +-5.41848600360482837712e-04, +-8.51918037984115972261e-04, +-1.16121978375175968247e-03, +-1.46957795454782155081e-03, +-1.77681736514933067382e-03, +-2.08276362753950002732e-03, +-2.38724324967590261284e-03, +-2.69008373365854430367e-03, +-2.99111367324205812759e-03, +-3.29016285063819195061e-03, +-3.58706233255040498470e-03, +-3.88164456539251325612e-03, +-4.17374346963266494581e-03, +-4.46319453321069280205e-03, +-4.74983490397884282330e-03, +-5.03350348111142233826e-03, +-5.31404100543327127110e-03, +-5.59129014861656486318e-03, +-5.86509560119571633080e-03, +-6.13530415935167362795e-03, +-6.40176481041693050400e-03, +-6.66432881705371002456e-03, +-6.92284980005934951625e-03, +-7.17718381975063907108e-03, +-7.42718945588436395278e-03, +-7.67272788607022311613e-03, +-7.91366296262873900047e-03, +-8.14986128785674147912e-03, +-8.38119228765579413198e-03, +-8.60752828348398772718e-03, +-8.82874456259165676930e-03, +-9.04471944650279101319e-03, +-9.25533435770336740389e-03, +-9.46047388450147082317e-03, +-9.66002584402477111614e-03, +-9.85388134331765391805e-03, +-1.00419348385086572295e-02, +-1.02240841920141073418e-02, +-1.04002307277476988001e-02, +-1.05702792843059330957e-02, +-1.07341382661022052142e-02, +-1.08917196924194058932e-02, +-1.10429392443588056394e-02, +-1.11877163096573035983e-02, +-1.13259740253500613971e-02, +-1.14576393182570599599e-02, +-1.15826429432718831097e-02, +-1.17009195194323206701e-02, +-1.18124075637551975010e-02, +-1.19170495228175868374e-02, +-1.20147918020679297935e-02, +-1.21055847928538372338e-02, +-1.21893828971518514148e-02, +-1.22661445499873279080e-02, +-1.23358322395343555922e-02, +-1.23984125248859967938e-02, +-1.24538560514863300838e-02, +-1.25021375642184340987e-02, +-1.25432359181423137146e-02, +-1.25771340868788758516e-02, +-1.26038191686375488504e-02, +-1.26232823898858471240e-02, +-1.26355191066611412948e-02, +-1.26405288035257891421e-02, +-1.26383150901686648615e-02, +-1.26288856956566081235e-02, +-1.26122524603418419142e-02, +-1.25884313254311982350e-02, +-1.25574423202261184485e-02, +-1.25193095470420810711e-02, +-1.24740611638184551585e-02, +-1.24217293644305545874e-02, +-1.23623503567175385687e-02, +-1.22959643382403553680e-02, +-1.22226154697852723574e-02, +-1.21423518466312625047e-02, +-1.20552254675984453491e-02, +-1.19612922018975387228e-02, +-1.18606117538015195384e-02, +-1.17532476251614014656e-02, +-1.16392670757887554955e-02, +-1.15187410817310965927e-02, +-1.13917442914640253127e-02, +-1.12583549800273283181e-02, +-1.11186550011346148292e-02, +-1.09727297372832800770e-02, +-1.08206680478965637515e-02, +-1.06625622155284947856e-02, +-1.04985078901642363974e-02, +-1.03286040316486818491e-02, +-1.01529528502798636891e-02, +-9.97165974559921335085e-03, +-9.78483324341799902413e-03, +-9.59258493111724702684e-03, +-9.39502939125761923900e-03, +-9.19228413354054689488e-03, +-8.98446952515993303712e-03, +-8.77170871958610903762e-03, +-8.55412758382280251357e-03, +-8.33185462418275894769e-03, +-8.10502091062164677082e-03, +-7.87375999967769406307e-03, +-7.63820785606213713270e-03, +-7.39850277294432437381e-03, +-7.15478529097991495372e-03, +-6.90719811612892573005e-03, +-6.65588603631140588585e-03, +-6.40099583694948154333e-03, +-6.14267621544471731365e-03, +-5.88107769464080425842e-03, +-5.61635253532167481177e-03, +-5.34865464779504806714e-03, +-5.07813950261468052133e-03, +-4.80496404049110190093e-03, +-4.52928658144188898277e-03, +-4.25126673323850644282e-03, +-3.97106529919719845184e-03, +-3.68884418537053504483e-03, +-3.40476630719170527545e-03, +-3.11899549562579155026e-03, +-2.83169640288094461716e-03, +-2.54303440773591491603e-03, +-2.25317552053609778881e-03, +-1.96228628791152723623e-03, +-1.67053369727637865058e-03, +-1.37808508115876398453e-03, +-1.08510802141915333602e-03, +-7.91770253410941553598e-04, +-4.98239570138193856204e-04, +-2.04683726464174046067e-04, + 8.87296565722855913767e-05, + 3.81833187280424608996e-04, + 6.74459798627879405716e-04, + 9.66442843278491714280e-04, + 1.25761618830957477670e-03, + 1.54781430955123577679e-03, + 1.83687238549551422676e-03, + 2.12462639072184518788e-03, + 2.41091318878710377666e-03, + 2.69557062452432027663e-03, + 2.97843761570351769560e-03, + 3.25935424399821128960e-03, + 3.53816184520730405566e-03, + 3.81470309868363116265e-03, + 4.08882211591671436424e-03, + 4.36036452822079721725e-03, + 4.62917757347863778605e-03, + 4.89511018189369654513e-03, + 5.15801306069900780682e-03, + 5.41773877778122490978e-03, + 5.67414184416796703314e-03, + 5.92707879533384274229e-03, + 6.17640827128176569949e-03, + 6.42199109535173794788e-03, + 6.66369035171747361307e-03, + 6.90137146152226561152e-03, + 7.13490225761727499265e-03, + 7.36415305785760327534e-03, + 7.58899673691662904340e-03, + 7.80930879657879342681e-03, + 8.02496743447280412587e-03, + 8.23585361120545214608e-03, + 8.44185111586123922145e-03, + 8.64284662983217863430e-03, + 8.83872978893951791179e-03, + 9.02939324381753054272e-03, + 9.21473271852386519032e-03, + 9.39464706734555871082e-03, + 9.56903832976962673285e-03, + 9.73781178358892364477e-03, + 9.90087599611340699046e-03, + 1.00581428734606900116e-02, + 1.02095277078994902537e-02, + 1.03549492232184597862e-02, + 1.04943296180992785144e-02, + 1.06275946074688987242e-02, + 1.07546734618099455033e-02, + 1.08754990444085344187e-02, + 1.09900078465200706085e-02, + 1.10981400204346221383e-02, + 1.11998394104246661029e-02, + 1.12950535815609064139e-02, + 1.13837338463788559362e-02, + 1.14658352893853201365e-02, + 1.15413167893916573242e-02, + 1.16101410396627392763e-02, + 1.16722745658728050550e-02, + 1.17276877418591822522e-02, + 1.17763548031668534993e-02, + 1.18182538583788306064e-02, + 1.18533668982268927672e-02, + 1.18816798024796634742e-02, + 1.19031823446065308097e-02, + 1.19178681942160510920e-02, + 1.19257349172696772155e-02, + 1.19267839740727354947e-02, + 1.19210207150453346286e-02, + 1.19084543742781455433e-02, + 1.18890980608779301547e-02, + 1.18629687481103703039e-02, + 1.18300872603478539336e-02, + 1.17904782578316710134e-02, + 1.17441702192595375659e-02, + 1.16911954222092898115e-02, + 1.16315899214134987893e-02, + 1.15653935248972560695e-02, + 1.14926497679962574816e-02, + 1.14134058852708338005e-02, + 1.13277127803342991114e-02, + 1.12356249936141419643e-02, + 1.11372006680669592693e-02, + 1.10325015128680588988e-02, + 1.09215927650972884078e-02, + 1.08045431494469181682e-02, + 1.06814248359739724648e-02, + 1.05523133959240563579e-02, + 1.04172877556533635679e-02, + 1.02764301486764821764e-02, + 1.01298260658689662922e-02, + 9.97756420385554482211e-03, + 9.81973641161405612354e-03, + 9.65643763532623641832e-03, + 9.48776586151135747915e-03, + 9.31382205847339390836e-03, + 9.13471011609818910049e-03, + 8.95053678403625804783e-03, + 8.76141160830776546953e-03, + 8.56744686636650917833e-03, + 8.36875750066302069585e-03, + 8.16546105074440926874e-03, + 7.95767758393019740415e-03, + 7.74552962460837469971e-03, + 7.52914208218922759858e-03, + 7.30864217776142511412e-03, + 7.08415936949292109753e-03, + 6.85582527682011919762e-03, + 6.62377360346902248345e-03, + 6.38814005935512633366e-03, + 6.14906228140583120678e-03, + 5.90667975335047463342e-03, + 5.66113372452884365538e-03, + 5.41256712776044118796e-03, + 5.16112449632528166171e-03, + 4.90695188010295546555e-03, + 4.65019676091923093997e-03, + 4.39100796714859270553e-03, + 4.12953558762247860403e-03, + 3.86593088489268566291e-03, + 3.60034620790024339002e-03, + 3.33293490409898975416e-03, + 3.06385123108688468482e-03, + 2.79325026779358087312e-03, + 2.52128782527450854764e-03, + 2.24812035716717229308e-03, + 1.97390486985574153955e-03, + 1.69879883239866091155e-03, + 1.42296008626978756108e-03, + 1.14654675496503560654e-03, + 8.69717153525156449340e-04, + 5.92629698028697892917e-04, + 3.15442815104587483740e-04, + 3.83148515150130003753e-05, +-2.38596016135179852516e-04, +-5.15131871516745108372e-04, +-7.91135148467245652611e-04, +-1.06644872060530828545e-03, +-1.34091599061669417524e-03, +-1.61438097916256320837e-03, +-1.88668841335719902723e-03, +-2.15768381476730232091e-03, +-2.42721358688397208930e-03, +-2.69512510201327460183e-03, +-2.96126678754182314640e-03, +-3.22548821152533965809e-03, +-3.48764016755303369807e-03, +-3.74757475883982088538e-03, +-4.00514548149979391495e-03, +-4.26020730695223729528e-03, +-4.51261676341580680871e-03, +-4.76223201644600246940e-03, +-5.00891294846663153589e-03, +-5.25252123725567128532e-03, +-5.49292043333865411675e-03, +-5.72997603624744288736e-03, +-5.96355556960147161621e-03, +-6.19352865496984421323e-03, +-6.41976708447395284091e-03, +-6.64214489208741348802e-03, +-6.86053842359856183575e-03, +-7.07482640519247439614e-03, +-7.28489001061597037101e-03, +-7.49061292688948335977e-03, +-7.69188141852844651375e-03, +-7.88858439023906905796e-03, +-8.08061344805422777926e-03, +-8.26786295887581117181e-03, +-8.45023010839095374547e-03, +-8.62761495733049832424e-03, +-8.79992049603937377678e-03, +-8.96705269732801270310e-03, +-9.12892056757751840790e-03, +-9.28543619607121589743e-03, +-9.43651480252325272624e-03, +-9.58207478278219441925e-03, +-9.72203775268269676513e-03, +-9.85632859002284582306e-03, +-9.98487547464438525424e-03, +-1.01076099265952259326e-02, +-1.02244668423529874723e-02, +-1.03353845290914767713e-02, +-1.04403047369727476623e-02, +-1.05391726894459199226e-02, +-1.06319371115395251703e-02, +-1.07185502561315034592e-02, +-1.07989679281840673941e-02, +-1.08731495069313705004e-02, +-1.09410579660090354764e-02, +-1.10026598915155138930e-02, +-1.10579254979971536299e-02, +-1.11068286423497506604e-02, +-1.11493468356296306782e-02, +-1.11854612527701267194e-02, +-1.12151567401993432216e-02, +-1.12384218213567241285e-02, +-1.12552487001068551170e-02, +-1.12656332620508243397e-02, +-1.12695750737355805671e-02, +-1.12670773797639463265e-02, +-1.12581470978087311990e-02, +-1.12427948115352074887e-02, +-1.12210347614381672487e-02, +-1.11928848336002705749e-02, +-1.11583665463801332690e-02, +-1.11175050350392178033e-02, +-1.10703290343182984834e-02, +-1.10168708589748198801e-02, +-1.09571663822947782535e-02, +-1.08912550125919559835e-02, +-1.08191796677104181551e-02, +-1.07409867475466505593e-02, +-1.06567261046078953085e-02, +-1.05664510126258718442e-02, +-1.04702181332450312140e-02, +-1.03680874808063875486e-02, +-1.02601223852479897514e-02, +-1.01463894531454990044e-02, +-1.00269585269162232050e-02, +-9.90190264221126568989e-03, +-9.77129798352259666683e-03, +-9.63522383803080625930e-03, +-9.49376254772124616998e-03, +-9.34699945979887078518e-03, +-9.19502287542989238389e-03, +-9.03792399684144424910e-03, +-8.87579687281107691799e-03, +-8.70873834257845577667e-03, +-8.53684797821176177823e-03, +-8.36022802546492783959e-03, +-8.17898334315863943800e-03, +-7.99322134112125451399e-03, +-7.80305191672834696365e-03, +-7.60858739007534007337e-03, +-7.40994243782330200970e-03, +-7.20723402575608202564e-03, +-7.00058134008851255109e-03, +-6.79010571756536070176e-03, +-6.57593057439340850090e-03, +-6.35818133404676254922e-03, +-6.13698535398672032765e-03, +-5.91247185134246861643e-03, +-5.68477182759180490329e-03, +-5.45401799228807746683e-03, +-5.22034468587699671677e-03, +-4.98388780164810921841e-03, +-4.74478470686644573928e-03, +-4.50317416312886326102e-03, +-4.25919624599436445062e-03, +-4.01299226392974606181e-03, +-3.76470467662182433494e-03, +-3.51447701270230384446e-03, +-3.26245378693090131231e-03, +-3.00878041688648536350e-03, +-2.75360313921323108730e-03, +-2.49706892547035515587e-03, +-2.23932539763252707460e-03, +-1.98052074329282566320e-03, +-1.72080363061157654535e-03, +-1.46032312306425922019e-03, +-1.19922859403635969841e-03, +-9.37669641312056218428e-04, +-6.75796001507703134221e-04, +-4.13757464498088920954e-04, +-1.51703787884435286606e-04, + 1.10215388447121949347e-04, + 3.71850627627885114545e-04, + 6.33052780921098995522e-04, + 8.93673072601122806674e-04, + 1.15356318454689905743e-03, + 1.41257534050370911136e-03, + 1.67056238996633678491e-03, + 1.92737789163165596125e-03, + 2.18287619637864190730e-03, + 2.43691252972557228021e-03, + 2.68934307371902769912e-03, + 2.94002504820795344462e-03, + 3.18881679145808279857e-03, + 3.43557784005892952531e-03, + 3.68016900808052979666e-03, + 3.92245246543618079904e-03, + 4.16229181540278981438e-03, + 4.39955217126052674365e-03, + 4.63410023200553494727e-03, + 4.86580435709433288538e-03, + 5.09453464017795010221e-03, + 5.32016298178517119816e-03, + 5.54256316091259002704e-03, + 5.76161090548329372224e-03, + 5.97718396163549221811e-03, + 6.18916216179911122391e-03, + 6.39742749152663690154e-03, + 6.60186415503853565173e-03, + 6.80235863944797080477e-03, + 6.99879977762879034592e-03, + 7.19107880969246070213e-03, + 7.37908944304029295463e-03, + 7.56272791095595735972e-03, + 7.74189302970967625078e-03, + 7.91648625413953442587e-03, + 8.08641173168029268881e-03, + 8.25157635481136783606e-03, + 8.41188981189416006001e-03, + 8.56726463637145184415e-03, + 8.71761625430204217801e-03, + 8.86286303020573928979e-03, + 9.00292631119170398690e-03, + 9.13773046934988723844e-03, + 9.26720294237984125452e-03, + 9.39127427243598503215e-03, + 9.50987814316970984929e-03, + 9.62295141494749588229e-03, + 9.73043415822708555873e-03, + 9.83226968507381650364e-03, + 9.92840457880114421463e-03, + 1.00187887217194990935e-02, + 1.01033753209798602551e-02, + 1.01821209324982810823e-02, + 1.02549854829495166314e-02, + 1.03219322898189282134e-02, + 1.03829280795032750928e-02, + 1.04379430034503180302e-02, + 1.04869506523312169127e-02, + 1.05299280682385320435e-02, + 1.05668557549043577726e-02, + 1.05977176859349212640e-02, + 1.06225013110582688913e-02, + 1.06411975603831251286e-02, + 1.06538008466682248415e-02, + 1.06603090656027660321e-02, + 1.06607235940987827433e-02, + 1.06550492865989197139e-02, + 1.06432944694025734267e-02, + 1.06254709330158968877e-02, + 1.06015939225314811956e-02, + 1.05716821260445053426e-02, + 1.05357576611141614403e-02, + 1.04938460592794574611e-02, + 1.04459762486396531833e-02, + 1.03921805345111133156e-02, + 1.03324945781732863842e-02, + 1.02669573737173662475e-02, + 1.01956112230122235285e-02, + 1.01185017088040590805e-02, + 1.00356776659660425211e-02, + 9.94719115091608624413e-03, + 9.85309740922234687799e-03, + 9.75345484141500011777e-03, + 9.64832496702668768185e-03, + 9.53777238688333431349e-03, + 9.42186474366750112419e-03, + 9.30067268077903845647e-03, + 9.17426979951779277001e-03, + 9.04273261461393390581e-03, + 8.90614050813234511828e-03, + 8.76457568178037361994e-03, + 8.61812310764482544800e-03, + 8.46687047738961182097e-03, + 8.31090814994421903106e-03, + 8.15032909771297095491e-03, + 7.98522885133778372035e-03, + 7.81570544304719359852e-03, + 7.64185934862476878848e-03, + 7.46379342803140874429e-03, + 7.28161286471641980289e-03, + 7.09542510365326374588e-03, + 6.90533978813562872995e-03, + 6.71146869537252947074e-03, + 6.51392567091878173929e-03, + 6.31282656197840099516e-03, + 6.10828914962330098148e-03, + 5.90043307996295039036e-03, + 5.68937979430757592714e-03, + 5.47525245836473755529e-03, + 5.25817589051068290384e-03, + 5.03827648917754868096e-03, + 4.81568215940014407450e-03, + 4.59052223856344730063e-03, + 4.36292742139295433579e-03, + 4.13302968423510681123e-03, + 3.90096220866709446004e-03, + 3.66685930448303705129e-03, + 3.43085633209993298015e-03, + 3.19308962442840099660e-03, + 2.95369640825326627495e-03, + 2.71281472516826487051e-03, + 2.47058335211343968810e-03, + 2.22714172155590722779e-03, + 1.98262984136404274774e-03, + 1.73718821442020768774e-03, + 1.49095775801618085979e-03, + 1.24407972307950527406e-03, + 9.96695613276132701130e-04, + 7.48947104035837802997e-04, + 5.00975961545737855096e-04, + 2.52923961761159811490e-04, + 4.93280947509291801083e-06, +-2.42855942503384357196e-04, +-4.90300974016580110200e-04, +-7.37261278027570056415e-04, +-9.83596240843677242782e-04, +-1.22916572204938767329e-03, +-1.47383013410300081451e-03, +-1.71745052155293964798e-03, +-1.95988863982576476050e-03, +-2.20100703354622747807e-03, +-2.44066911434088866517e-03, +-2.67873923808214847372e-03, +-2.91508278153101421312e-03, +-3.14956621833333222718e-03, +-3.38205719432752276860e-03, +-3.61242460212125989991e-03, +-3.84053865489516728718e-03, +-4.06627095939203833663e-03, +-4.28949458805057831645e-03, +-4.51008415024378109953e-03, +-4.72791586258040994611e-03, +-4.94286761823193362270e-03, +-5.15481905524671577684e-03, +-5.36365162380991484375e-03, +-5.56924865241561605628e-03, +-5.77149541291191014308e-03, +-5.97027918438345836516e-03, +-6.16548931583604711143e-03, +-6.35701728764813140532e-03, +-6.54475677175619420523e-03, +-6.72860369053819660362e-03, +-6.90845627436653328401e-03, +-7.08421511779518033730e-03, +-7.25578323435132135910e-03, +-7.42306610990221913543e-03, +-7.58597175456684601896e-03, +-7.74441075314436476462e-03, +-7.89829631403181527116e-03, +-8.04754431660486060918e-03, +-8.19207335703401803850e-03, +-8.33180479251450362144e-03, +-8.46666278388312140701e-03, +-8.59657433660001440989e-03, +-8.72146934007399753097e-03, +-8.84128060530934949124e-03, +-8.95594390085470426488e-03, +-9.06539798703423320425e-03, +-9.16958464844403950411e-03, +-9.26844872469488080535e-03, +-9.36193813938749827552e-03, +-9.45000392730357963167e-03, +-9.53260025979855117606e-03, +-9.60968446838431425427e-03, +-9.68121706648877346224e-03, +-9.74716176938165805577e-03, +-9.80748551225691343747e-03, +-9.86215846646274103826e-03, +-9.91115405387120278202e-03, +-9.95444895938146258330e-03, +-9.99202314155041813881e-03, +-1.00238598413463411013e-02, +-1.00499455890222209875e-02, +-1.00702702091063772682e-02, +-1.00848268235089154332e-02, +-1.00936118527438327408e-02, +-1.00966250152679168361e-02, +-1.00938693249378146077e-02, +-1.00853510865886227682e-02, +-1.00710798897381062500e-02, +-1.00510686004214797040e-02, +-1.00253333511630630254e-02, +-9.99389352909173418749e-03, +-9.95677176220922943717e-03, +-9.91399390381976150510e-03, +-9.86558901513197826494e-03, +-9.81158934604420447656e-03, +-9.75203031412597010075e-03, +-9.68695048180868989451e-03, +-9.61639153180029321311e-03, +-9.54039824073970449403e-03, +-9.45901845110641917302e-03, +-9.37230304140389963719e-03, +-9.28030589463477509349e-03, +-9.18308386508685792204e-03, +-9.08069674345089207501e-03, +-8.97320722029071662917e-03, +-8.86068084788880529212e-03, +-8.74318600048899774446e-03, +-8.62079383296257897862e-03, +-8.49357823791978966410e-03, +-8.36161580129450403287e-03, +-8.22498575642871369851e-03, +-8.08376993668271683069e-03, +-7.93805272660061574108e-03, +-7.78792101165969724574e-03, +-7.63346412663362498818e-03, +-7.47477380259930785505e-03, +-7.31194411262098796500e-03, +-7.14507141614020412773e-03, +-6.97425430210722122754e-03, +-6.79959353088687573630e-03, +-6.62119197497169301864e-03, +-6.43915455853849138385e-03, +-6.25358819588309883253e-03, +-6.06460172876989358354e-03, +-5.87230586273140842124e-03, +-5.67681310235816811993e-03, +-5.47823768561213342299e-03, +-5.27669551720578392656e-03, +-5.07230410108449637774e-03, +-4.86518247205038317088e-03, +-4.65545112656870225393e-03, +-4.44323195279612039033e-03, +-4.22864815987201558140e-03, +-4.01182420651321949151e-03, +-3.79288572895385015307e-03, +-3.57195946827177420596e-03, +-3.34917319714373535808e-03, +-3.12465564607069309216e-03, +-2.89853642911835473334e-03, +-2.67094596921149977573e-03, +-2.44201542302870371753e-03, +-2.21187660553990271539e-03, +-1.98066191422849313675e-03, +-1.74850425304324988245e-03, +-1.51553695612283568887e-03, +-1.28189371133704578531e-03, +-1.04770848368741461600e-03, +-8.13115438614004488148e-04, +-5.78248865247532866513e-04, +-3.43243099654593679469e-04, +-1.08232448119056134180e-04, + 1.26648889498497872709e-04, + 3.61266896277643255724e-04, + 5.95487814588576617851e-04, + 8.29178222232456471966e-04, + 1.06220510832932932450e-03, + 1.29443594890761418982e-03, + 1.52573878215697851524e-03, + 1.75598228329790738422e-03, + 1.98503583902642517095e-03, + 2.21276962149356305753e-03, + 2.43905466177587538015e-03, + 2.66376292279626092005e-03, + 2.88676737165370449201e-03, + 3.10794205132203151670e-03, + 3.32716215167451348847e-03, + 3.54430407979887786632e-03, + 3.75924552955919340572e-03, + 3.97186555036659408313e-03, + 4.18204461512168643861e-03, + 4.38966468728887570377e-03, + 4.59460928706578036751e-03, + 4.79676355661041737416e-03, + 4.99601432429057183693e-03, + 5.19225016791701170921e-03, + 5.38536147692926601277e-03, + 5.57524051349589811616e-03, + 5.76178147249606278230e-03, + 5.94488054035048445189e-03, + 6.12443595266757775941e-03, + 6.30034805067354337221e-03, + 6.47251933639503632123e-03, + 6.64085452656393640525e-03, + 6.80526060521449791679e-03, + 6.96564687494400421736e-03, + 7.12192500680845601291e-03, + 7.27400908882688563423e-03, + 7.42181567306544106438e-03, + 7.56526382127895545560e-03, + 7.70427514908233069396e-03, + 7.83877386862820088598e-03, + 7.96868682976907029281e-03, + 8.09394355968027362502e-03, + 8.21447630092295155713e-03, + 8.33022004792652141780e-03, + 8.44111258187129308295e-03, + 8.54709450395172223858e-03, + 8.64810926700426002567e-03, + 8.74410320548165559407e-03, + 8.83502556375806609446e-03, + 8.92082852275120734287e-03, + 9.00146722484649296214e-03, + 9.07689979711120281669e-03, + 9.14708737278599470777e-03, + 9.21199411104400324446e-03, + 9.27158721500605589871e-03, + 9.32583694800504132971e-03, + 9.37471664808996879570e-03, + 9.41820274076340252511e-03, + 9.45627474994699748767e-03, + 9.48891530716929401668e-03, + 9.51611015897272857766e-03, + 9.53784817253677981441e-03, + 9.55412133951539892240e-03, + 9.56492477808816750351e-03, + 9.57025673322536851728e-03, + 9.57011857516825228953e-03, + 9.56451479612665210472e-03, + 9.55345300519767903769e-03, + 9.53694392150929680374e-03, + 9.51500136559463131902e-03, + 9.48764224900292864329e-03, + 9.45488656215475072042e-03, + 9.41675736044983967277e-03, + 9.37328074863657233207e-03, + 9.32448586345385396768e-03, + 9.27040485455623772260e-03, + 9.21107286373510844579e-03, + 9.14652800244862389245e-03, + 9.07681132767460333022e-03, + 9.00196681610215994340e-03, + 8.92204133667740678648e-03, + 8.83708462152045341742e-03, + 8.74714923523178117248e-03, + 8.65229054260652913344e-03, + 8.55256667477650479869e-03, + 8.44803849380110737088e-03, + 8.33876955572694297802e-03, + 8.22482607214039367072e-03, + 8.10627687023531343091e-03, + 7.98319335141973659975e-03, + 7.85564944848663425370e-03, + 7.72372158137452947957e-03, + 7.58748861154383627547e-03, + 7.44703179499617545084e-03, + 7.30243473396576317502e-03, + 7.15378332730893639474e-03, + 7.00116571962369673571e-03, + 6.84467224912835292550e-03, + 6.68439539432962807203e-03, + 6.52042971951210560688e-03, + 6.35287181908096316302e-03, + 6.18182026079089775444e-03, + 6.00737552789352719645e-03, + 5.82963996023949920094e-03, + 5.64871769436637964634e-03, + 5.46471460260989760210e-03, + 5.27773823127398664101e-03, + 5.08789773789389884046e-03, + 4.89530382763052763356e-03, + 4.70006868883239992823e-03, + 4.50230592780280144960e-03, + 4.30213050280925293073e-03, + 4.09965865737595570178e-03, + 3.89500785289395058675e-03, + 3.68829670059122758860e-03, + 3.47964489290170791991e-03, + 3.26917313427090060543e-03, + 3.05700307144005523768e-03, + 2.84325722324815094444e-03, + 2.62805890999240517047e-03, + 2.41153218238787615466e-03, + 2.19380175016706995342e-03, + 1.97499291036058082296e-03, + 1.75523147530006872613e-03, + 1.53464370038409927272e-03, + 1.31335621165009405059e-03, + 1.09149593319219089145e-03, + 8.69190014465733669022e-04, + 6.46565757523822519717e-04, + 4.23750544222993737447e-04, + 2.00871763442388796871e-04, +-2.19432616430028802536e-05, +-2.44567346193297504003e-04, +-4.66873516198418401623e-04, +-6.88735080792504629141e-04, +-9.10025704351406588243e-04, +-1.13061947832844914008e-03, +-1.35039099278848459193e-03, +-1.56921540760134731185e-03, +-1.78696852325255445618e-03, +-2.00352685123184786134e-03, +-2.21876768395961026376e-03, +-2.43256916421236753928e-03, +-2.64481035400563951540e-03, +-2.85537130289943187622e-03, +-3.06413311568427739612e-03, +-3.27097801941039290421e-03, +-3.47578942972392133937e-03, +-3.67845201647113524343e-03, +-3.87885176853450686779e-03, +-4.07687605786403312047e-03, +-4.27241370266879562367e-03, +-4.46535502973073768207e-03, +-4.65559193580989804512e-03, +-4.84301794810346793868e-03, +-5.02752828372539546653e-03, +-5.20901990817508944720e-03, +-5.38739159276095062184e-03, +-5.56254397094743408686e-03, +-5.73437959359436588702e-03, +-5.90280298305815697563e-03, +-6.06772068612327578757e-03, +-6.22904132573793255234e-03, +-6.38667565152189597305e-03, +-6.54053658902132174086e-03, +-6.69053928768123529203e-03, +-6.83660116751098716203e-03, +-6.97864196441732535098e-03, +-7.11658377417776714241e-03, +-7.25035109503333486530e-03, +-7.37987086887549603720e-03, +-7.50507252100559608954e-03, +-7.62588799844512044840e-03, +-7.74225180677637174476e-03, +-7.85410104549275414620e-03, +-7.96137544184076853537e-03, +-8.06401738313571557482e-03, +-8.16197194753211924256e-03, +-8.25518693323474758716e-03, +-8.34361288613344465048e-03, +-8.42720312584763903141e-03, +-8.50591377016694447089e-03, +-8.57970375787523234501e-03, +-8.64853486994612667693e-03, +-8.71237174909944220302e-03, +-8.77118191770899502391e-03, +-8.82493579405169495389e-03, +-8.87360670689150109192e-03, +-8.91717090839015333326e-03, +-8.95560758533894135658e-03, +-8.98889886870667467744e-03, +-9.01702984149947012193e-03, +-9.03998854492910064451e-03, +-9.05776598288827831940e-03, +-9.07035612473096330977e-03, +-9.07775590635802147321e-03, +-9.07996522960853764961e-03, +-9.07698695995886803423e-03, +-9.06882692253164167384e-03, +-9.05549389641891432079e-03, +-9.03699960732328583246e-03, +-9.01335871852335275556e-03, +-8.98458882016932476600e-03, +-8.95071041691646723804e-03, +-8.91174691390494294607e-03, +-8.86772460109508213477e-03, +-8.81867263596835572470e-03, +-8.76462302460546613392e-03, +-8.70561060115330326292e-03, +-8.64167300569398770527e-03, +-8.57285066052993274810e-03, +-8.49918674489946214534e-03, +-8.42072716813898301813e-03, +-8.33752054130776007468e-03, +-8.24961814729350748077e-03, +-8.15707390941654633676e-03, +-8.05994435855085684939e-03, +-7.95828859878412557538e-03, +-7.85216827163510294740e-03, +-7.74164751885155454081e-03, +-7.62679294381024292654e-03, +-7.50767357154260520785e-03, +-7.38436080740939235212e-03, +-7.25692839445000407311e-03, +-7.12545236943096498700e-03, +-6.99001101761916477512e-03, +-6.85068482630888687945e-03, +-6.70755643712759620778e-03, +-6.56071059715018171238e-03, +-6.41023410885009203158e-03, +-6.25621577891687877943e-03, +-6.09874636596976875402e-03, +-5.93791852719933836713e-03, +-5.77382676396723509143e-03, +-5.60656736639539039074e-03, +-5.43623835697979850695e-03, +-5.26293943325864543858e-03, +-5.08677190957020682743e-03, +-4.90783865793382578085e-03, +-4.72624404808862780270e-03, +-4.54209388672411652765e-03, +-4.35549535594014370493e-03, +-4.16655695096843255165e-03, +-3.97538841719484881826e-03, +-3.78210068651828800954e-03, +-3.58680581308160571774e-03, +-3.38961690841329795279e-03, +-3.19064807601676572041e-03, +-2.99001434544510355171e-03, +-2.78783160589872848825e-03, +-2.58421653938650406832e-03, +-2.37928655348473936521e-03, +-2.17315971373707597994e-03, +-1.96595467573080053339e-03, +-1.75779061689126871355e-03, +-1.54878716803180682161e-03, +-1.33906434469759582327e-03, +-1.12874247834651849839e-03, +-9.17942147402158120997e-04, +-7.06784108220954348026e-04, +-4.95389226012176797989e-04, +-2.83878405750408527308e-04, +-7.23725231191953317922e-05, + 1.39007644472942073393e-04, + 3.50141486766494293426e-04, + 5.60908629376450848514e-04, + 7.71189002326557382014e-04, + 9.80862908357632698117e-04, + 1.18981109096850837074e-03, + 1.39791480215185285468e-03, + 1.60505586978618446266e-03, + 1.81111676464667430489e-03, + 2.01598066699498323223e-03, + 2.21953153271216372527e-03, + 2.42165415893787249260e-03, + 2.62223424917535025483e-03, + 2.82115847782954658890e-03, + 3.01831455413943379809e-03, + 3.21359128546936040696e-03, + 3.40687863992359188381e-03, + 3.59806780824958004350e-03, + 3.78705126499338838933e-03, + 3.97372282887472824675e-03, + 4.15797772234820922632e-03, + 4.33971263031428678564e-03, + 4.51882575795083032272e-03, + 4.69521688763073485884e-03, + 4.86878743489439942682e-03, + 5.03944050344600283364e-03, + 5.20708093914320439138e-03, + 5.37161538294856407555e-03, + 5.53295232281637763133e-03, + 5.69100214448343532520e-03, + 5.84567718113605111485e-03, + 5.99689176192734485493e-03, + 6.14456225931638965604e-03, + 6.28860713520388876080e-03, + 6.42894698583886935878e-03, + 6.56550458547169348000e-03, + 6.69820492872941122137e-03, + 6.82697527169041310652e-03, + 6.95174517163579808177e-03, + 7.07244652545614607003e-03, + 7.18901360669207869364e-03, + 7.30138310118917405883e-03, + 7.40949414134865064208e-03, + 7.51328833895314410901e-03, + 7.61270981655247976766e-03, + 7.70770523739102830091e-03, + 7.79822383386149457080e-03, + 7.88421743446952177914e-03, + 7.96564048929547866007e-03, + 8.04245009393938191378e-03, + 8.11460601193707622980e-03, + 8.18207069563602756856e-03, + 8.24480930551941583462e-03, + 8.30278972796945347046e-03, + 8.35598259146062144476e-03, + 8.40436128117489321399e-03, + 8.44790195203182735229e-03, + 8.48658354012752670636e-03, + 8.52038777257667530318e-03, + 8.54929917575385743544e-03, + 8.57330508193055763899e-03, + 8.59239563430499141139e-03, + 8.60656379042347950692e-03, + 8.61580532399272396027e-03, + 8.62011882508288869442e-03, + 8.61950569872288463458e-03, + 8.61397016188992017960e-03, + 8.60351923889614116081e-03, + 8.58816275517627555902e-03, + 8.56791332948142643489e-03, + 8.54278636448400040260e-03, + 8.51280003580121708007e-03, + 8.47797527944401177469e-03, + 8.43833577770019410691e-03, + 8.39390794346085364341e-03, + 8.34472090300016587638e-03, + 8.29080647722033568792e-03, + 8.23219916137209704876e-03, + 8.16893610326531807719e-03, + 8.10105707998175217366e-03, + 8.02860447310570039814e-03, + 7.95162324248711339936e-03, + 7.87016089855287724608e-03, + 7.78426747318477444543e-03, + 7.69399548918007353260e-03, + 7.59939992831438169973e-03, + 7.50053819802581206444e-03, + 7.39747009674054673695e-03, + 7.29025777786024634097e-03, + 7.17896571243396234424e-03, + 7.06366065053597690093e-03, + 6.94441158137212768281e-03, + 6.82128969214047548714e-03, + 6.69436832566827795532e-03, + 6.56372293685217843284e-03, + 6.42943104792645641482e-03, + 6.29157220258638738564e-03, + 6.15022791899296188828e-03, + 6.00548164168810023889e-03, + 5.85741869244729099903e-03, + 5.70612622009830997016e-03, + 5.55169314933761943315e-03, + 5.39421012857201238877e-03, + 5.23376947681718652367e-03, + 5.07046512968433327889e-03, + 4.90439258448602602436e-03, + 4.73564884449306690989e-03, + 4.56433236237605791802e-03, + 4.39054298286334701573e-03, + 4.21438188464811746420e-03, + 4.03595152158122121716e-03, + 3.85535556318054341285e-03, + 3.67269883449336575001e-03, + 3.48808725534603724164e-03, + 3.30162777901616766654e-03, + 3.11342833036215701700e-03, + 2.92359774344746591729e-03, + 2.73224569869404739636e-03, + 2.53948265960054347934e-03, + 2.34541980906500472509e-03, + 2.15016898534491464681e-03, + 1.95384261769374848600e-03, + 1.75655366171025071990e-03, + 1.55841553443768969338e-03, + 1.35954204925029724198e-03, + 1.16004735056427139318e-03, + 9.60045848410695946279e-04, + 7.59652152908002432571e-04, + 5.58981008670681638398e-04, + 3.58147229193453995114e-04, + 1.57265631246792758451e-04, +-4.35490306794674293363e-05, +-2.44182129843599320107e-04, +-4.44519232597282950344e-04, +-6.44446163569028346828e-04, +-8.43849070649477944230e-04, +-1.04261448974139812711e-03, +-1.24062940923833162771e-03, +-1.43778133419359788019e-03, +-1.63395835014485757766e-03, +-1.82904918655875121242e-03, +-2.02294327985625636140e-03, +-2.21553083598718210043e-03, +-2.40670289251588859908e-03, +-2.59635138018404895352e-03, +-2.78436918391547104032e-03, +-2.97065020322924595864e-03, +-3.15508941202569071979e-03, +-3.33758291771281195501e-03, +-3.51802801964081748518e-03, +-3.69632326680855837625e-03, +-3.87236851481334142661e-03, +-4.04606498200982094005e-03, +-4.21731530484743474818e-03, +-4.38602359235502371748e-03, +-4.55209547974291459105e-03, +-4.71543818109126672972e-03, +-4.87596054109631048268e-03, +-5.03357308584660798761e-03, +-5.18818807259795525266e-03, +-5.33971953852289266118e-03, +-5.48808334840551401146e-03, +-5.63319724125592186798e-03, +-5.77498087581854776390e-03, +-5.91335587494941708475e-03, +-6.04824586883698656764e-03, +-6.17957653704386423305e-03, +-6.30727564934618813858e-03, +-6.43127310534771529787e-03, +-6.55150097284682483151e-03, +-6.66789352493667251270e-03, +-6.78038727581722639598e-03, +-6.88892101529996712939e-03, +-6.99343584198691605586e-03, +-7.09387519510564119873e-03, +-7.19018488498349497839e-03, +-7.28231312214434444580e-03, +-7.37021054501293959582e-03, +-7.45383024621102448920e-03, +-7.53312779743236203556e-03, +-7.60806127288360129618e-03, +-7.67859127127740528906e-03, +-7.74468093636805719054e-03, +-7.80629597601776963056e-03, +-7.86340467978466871324e-03, +-7.91597793502309132752e-03, +-7.96398924148845367699e-03, +-8.00741472443937570003e-03, +-8.04623314623062815820e-03, +-8.08042591639200093179e-03, +-8.10997710018770794071e-03, +-8.13487342565317322896e-03, +-8.15510428910632897970e-03, +-8.17066175913122756669e-03, +-8.18154057903300313548e-03, +-8.18773816776408903950e-03, +-8.18925461932203113680e-03, +-8.18609270062076350982e-03, +-8.17825784783763644337e-03, +-8.16575816123921681411e-03, +-8.14860439849041627569e-03, +-8.12680996645165354408e-03, +-8.10039091146990027081e-03, +-8.06936590817051296876e-03, +-8.03375624675719754442e-03, +-7.99358581882871586932e-03, +-7.94888110172140179011e-03, +-7.89967114138754450403e-03, +-7.84598753382080051078e-03, +-7.78786440504017178632e-03, +-7.72533838964500462615e-03, +-7.65844860795453739877e-03, +-7.58723664174604933708e-03, +-7.51174650860678399383e-03, +-7.43202463491451133931e-03, +-7.34811982746492921986e-03, +-7.26008324376091473962e-03, +-7.16796836098336151433e-03, +-7.07183094366188418067e-03, +-6.97172901006430818793e-03, +-6.86772279732582834055e-03, +-6.75987472533817052023e-03, +-6.64824935942080145340e-03, +-6.53291337179604837682e-03, +-6.41393550189129496575e-03, +-6.29138651549170698635e-03, +-6.16533916276751359220e-03, +-6.03586813520128485228e-03, +-5.90305002144024624361e-03, +-5.76696326209861012679e-03, +-5.62768810353925751089e-03, +-5.48530655065889230504e-03, +-5.33990231870646887141e-03, +-5.19156078416207946574e-03, +-5.04036893470575456805e-03, +-4.88641531830454143442e-03, +-4.72978999144895145140e-03, +-4.57058446656796041330e-03, +-4.40889165865240156839e-03, +-4.24480583112071818697e-03, +-4.07842254095536725644e-03, +-3.90983858314355049030e-03, +-3.73915193445415730208e-03, +-3.56646169658344580969e-03, +-3.39186803870199487382e-03, +-3.21547213943741911138e-03, +-3.03737612832535950474e-03, +-2.85768302676162435152e-03, +-2.67649668849279489050e-03, +-2.49392173967607306759e-03, +-2.31006351854499665868e-03, +-2.12502801471515026521e-03, +-1.93892180816497236052e-03, +-1.75185200792604364207e-03, +-1.56392619051968551937e-03, +-1.37525233817362515544e-03, +-1.18593877685428585739e-03, +-9.96094114151082135611e-04, +-8.05827177048465143755e-04, +-6.15246949619699455385e-04, +-4.24462510679590970634e-04, +-2.33582971431131201836e-04, +-4.27174131418600218075e-05, + 1.48025175115281873829e-04, + 3.38535958618741729398e-04, + 5.28706319021235741570e-04, + 7.18427916200129542020e-04, + 9.07592749900823655106e-04, + 1.09609322113959862730e-03, + 1.28382219332944988964e-03, + 1.47067305309492128707e-03, + 1.65653977074134688835e-03, + 1.84131696034424701021e-03, + 2.02489993942486920173e-03, + 2.20718478817801639844e-03, + 2.38806840821935862512e-03, + 2.56744858081750862433e-03, + 2.74522402457949956170e-03, + 2.92129445255769277026e-03, + 3.09556062874293989526e-03, + 3.26792442391583577016e-03, + 3.43828887082240275061e-03, + 3.60655821864397721499e-03, + 3.77263798673060360075e-03, + 3.93643501756839753886e-03, + 4.09785752894968862553e-03, + 4.25681516531844095913e-03, + 4.41321904826232503521e-03, + 4.56698182612100180705e-03, + 4.71801772268583795300e-03, + 4.86624258496219565945e-03, + 5.01157392996826912823e-03, + 5.15393099054442353768e-03, + 5.29323476014809113366e-03, + 5.42940803660817671028e-03, + 5.56237546481617214228e-03, + 5.69206357833054472223e-03, + 5.81840083986934729354e-03, + 5.94131768067147035539e-03, + 6.06074653870333594774e-03, + 6.17662189569052801769e-03, + 6.28888031295409682953e-03, + 6.39746046603201657527e-03, + 6.50230317806734740144e-03, + 6.60335145194352116094e-03, + 6.70055050115188084031e-03, + 6.79384777937258772795e-03, + 6.88319300875362728720e-03, + 6.96853820687349644752e-03, + 7.04983771237240302437e-03, + 7.12704820923858520243e-03, + 7.20012874973695923136e-03, + 7.26904077596829921448e-03, + 7.33374814004676342516e-03, + 7.39421712288685674397e-03, + 7.45041645158874780291e-03, + 7.50231731541360375576e-03, + 7.54989338034125958415e-03, + 7.59312080220247119511e-03, + 7.63197823837959577614e-03, + 7.66644685807015349721e-03, + 7.69651035110831445440e-03, + 7.72215493534070089587e-03, + 7.74336936255298931286e-03, + 7.76014492294555859042e-03, + 7.77247544815607566138e-03, + 7.78035731282916958457e-03, + 7.78378943473276123377e-03, + 7.78277327342252397968e-03, + 7.77731282745607217788e-03, + 7.76741463015983343160e-03, + 7.75308774395181993927e-03, + 7.73434375322510497819e-03, + 7.71119675579651046859e-03, + 7.68366335292724762090e-03, + 7.65176263792180597761e-03, + 7.61551618331250072119e-03, + 7.57494802663899804984e-03, + 7.53008465483087727904e-03, + 7.48095498720392076963e-03, + 7.42759035708089564165e-03, + 7.37002449204788440129e-03, + 7.30829349285897541394e-03, + 7.24243581100231150621e-03, + 7.17249222494118019583e-03, + 7.09850581504455676457e-03, + 7.02052193722279248289e-03, + 6.93858819528464596665e-03, + 6.85275441203157895803e-03, + 6.76307259910770459943e-03, + 6.66959692562291064227e-03, + 6.57238368556857608521e-03, + 6.47149126404455293793e-03, + 6.36698010231910756229e-03, + 6.25891266174058436000e-03, + 6.14735338652398939641e-03, + 6.03236866543420662684e-03, + 5.91402679238786036647e-03, + 5.79239792599798089534e-03, + 5.66755404808486160789e-03, + 5.53956892117803134656e-03, + 5.40851804503346585140e-03, + 5.27447861219351547823e-03, + 5.13752946261299917735e-03, + 4.99775103738003996512e-03, + 4.85522533155877469846e-03, + 4.71003584618005094464e-03, + 4.56226753940958736772e-03, + 4.41200677692144428016e-03, + 4.25934128150591128498e-03, + 4.10436008194120516279e-03, + 3.94715346115854636561e-03, + 3.78781290373112009690e-03, + 3.62643104271654281509e-03, + 3.46310160588530037765e-03, + 3.29791936136483157180e-03, + 3.13098006273033763885e-03, + 2.96238039357679455374e-03, + 2.79221791160092977502e-03, + 2.62059099222753267427e-03, + 2.44759877181191781020e-03, + 2.27334109045146740002e-03, + 2.09791843443869838876e-03, + 1.92143187839023546828e-03, + 1.74398302708383490592e-03, + 1.56567395703608109106e-03, + 1.38660715785749919481e-03, + 1.20688547341501702971e-03, + 1.02661204283784578128e-03, + 8.45890241399772859106e-04, + 6.64823621311828307986e-04, + 4.83515852459311156267e-04, + 3.02070663116303390200e-04, + 1.20591780673772898239e-04, +-6.08171275885414341889e-05, +-2.42052513649585246663e-04, +-4.23011007780704729672e-04, +-6.03589477433417857279e-04, +-7.83685085946226591899e-04, +-9.63195351037734169043e-04, +-1.14201820305262708236e-03, +-1.32005204292819870032e-03, +-1.49719579984629639312e-03, +-1.67334898854166894480e-03, +-1.84841176623110319682e-03, +-2.02228498913186371597e-03, +-2.19487026853879690913e-03, +-2.36607002642698479797e-03, +-2.53578755054913694555e-03, +-2.70392704899653085748e-03, +-2.87039370419339950197e-03, +-3.03509372629227804768e-03, +-3.19793440594374599878e-03, +-3.35882416640786475581e-03, +-3.51767261497890407207e-03, +-3.67439059369556366569e-03, +-3.82889022930704356340e-03, +-3.98108498246762219919e-03, +-4.13088969613195546721e-03, +-4.27822064312436464023e-03, +-4.42299557285530213491e-03, +-4.56513375715911651903e-03, +-4.70455603522795286209e-03, +-4.84118485761577625054e-03, +-4.97494432928909796621e-03, +-5.10576025170110612411e-03, +-5.23356016386354247483e-03, +-5.35827338239640901113e-03, +-5.47983104053158340957e-03, +-5.59816612604972611844e-03, +-5.71321351812927209768e-03, +-5.82491002308763421852e-03, +-5.93319440899438971249e-03, +-6.03800743913827410447e-03, +-6.13929190432966741947e-03, +-6.23699265402067378611e-03, +-6.33105662622569179826e-03, +-6.42143287622725950775e-03, +-6.50807260405082601412e-03, +-6.59092918069416680571e-03, +-6.66995817309711056670e-03, +-6.74511736783881075269e-03, +-6.81636679354884200688e-03, +-6.88366874202207389838e-03, +-6.94698778802482330014e-03, +-7.00629080778204620106e-03, +-7.06154699613719197271e-03, +-7.11272788237445920123e-03, +-7.15980734469658271213e-03, +-7.20276162335014690646e-03, +-7.24156933239256637991e-03, +-7.27621147009427024499e-03, +-7.30667142797224253986e-03, +-7.33293499844991664843e-03, +-7.35499038114030730118e-03, +-7.37282818775028547797e-03, +-7.38644144560350775219e-03, +-7.39582559978183007310e-03, +-7.40097851388428658315e-03, +-7.40190046940486859328e-03, +-7.39859416373013153989e-03, +-7.39106470675889026811e-03, +-7.37931961614715723613e-03, +-7.36336881118193880419e-03, +-7.34322460528822728437e-03, +-7.31890169717512584224e-03, +-7.29041716062642924934e-03, +-7.25779043294308163353e-03, +-7.22104330204492456807e-03, +-7.18019989224008559070e-03, +-7.13528664867118991161e-03, +-7.08633232044840466468e-03, +-7.03336794247966679700e-03, +-6.97642681600977102030e-03, +-6.91554448788011654620e-03, +-6.85075872852217854225e-03, +-6.78210950869807035341e-03, +-6.70963897500246285455e-03, +-6.63339142414092006877e-03, +-6.55341327599992442415e-03, +-6.46975304552541326253e-03, +-6.38246131342605754061e-03, +-6.29159069572002467574e-03, +-6.19719581214200551655e-03, +-6.09933325343054149464e-03, +-5.99806154751515805540e-03, +-5.89344112462262485069e-03, +-5.78553428132379601867e-03, +-5.67440514354219504439e-03, +-5.56011962854616095114e-03, +-5.44274540594681839611e-03, +-5.32235185772599213305e-03, +-5.19901003731562585258e-03, +-5.07279262775460568907e-03, +-4.94377389894712446911e-03, +-4.81202966404692660668e-03, +-4.67763723499383179960e-03, +-4.54067537722822531232e-03, +-4.40122426361012723806e-03, +-4.25936542756916083213e-03, +-4.11518171551450429035e-03, +-3.96875723852973399941e-03, +-3.82017732338308995885e-03, +-3.66952846288120431220e-03, +-3.51689826559387639163e-03, +-3.36237540498054293669e-03, +-3.20604956794714058416e-03, +-3.04801140286350535219e-03, +-2.88835246707072135566e-03, +-2.72716517391074315599e-03, +-2.56454273930563836012e-03, +-2.40057912792011364511e-03, +-2.23536899893777120732e-03, +-2.06900765148108206626e-03, +-1.90159096970791930900e-03, +-1.73321536761559679037e-03, +-1.56397773358425175305e-03, +-1.39397537469151283109e-03, +-1.22330596083027954082e-03, +-1.05206746866192031586e-03, +-8.80358125436270775623e-04, +-7.08276352712239277640e-04, +-5.35920710009009110958e-04, +-3.63389838422367814508e-04, +-1.90782404235573607330e-04, +-1.81970425606722737690e-05, + 1.54267698961177570456e-04, + 3.26513416366015622218e-04, + 4.98441905449340362869e-04, + 6.69955217690751999443e-04, + 8.40955715991319185942e-04, + 1.01134613018985628115e-03, + 1.18102961232867528438e-03, + 1.34990979163519928159e-03, + 1.51789082919096310863e-03, + 1.68487747225296133520e-03, + 1.85077510820205867401e-03, + 2.01548981808303672575e-03, + 2.17892842970867023702e-03, + 2.34099857029698189825e-03, + 2.50160871861258458579e-03, + 2.66066825658141034583e-03, + 2.81808752035150444221e-03, + 2.97377785076984252691e-03, + 3.12765164324742489868e-03, + 3.27962239698395725818e-03, + 3.42960476352574062178e-03, + 3.57751459462877022255e-03, + 3.72326898939903325192e-03, + 3.86678634068614995867e-03, + 4.00798638070307827741e-03, + 4.14679022584586980810e-03, + 4.28312042068948461981e-03, + 4.41690098113505479061e-03, + 4.54805743668363141041e-03, + 4.67651687181444911112e-03, + 4.80220796644356944655e-03, + 4.92506103544097621760e-03, + 5.04500806718418456226e-03, + 5.16198276112742483052e-03, + 5.27592056436465041414e-03, + 5.38675870716774727459e-03, + 5.49443623747928808210e-03, + 5.59889405434115926957e-03, + 5.70007494024133646443e-03, + 5.79792359236085651231e-03, + 5.89238665270259628914e-03, + 5.98341273708859113650e-03, + 6.07095246300716831489e-03, + 6.15495847629641840842e-03, + 6.23538547664926560282e-03, + 6.31219024192670834228e-03, + 6.38533165126559023456e-03, + 6.45477070696955871482e-03, + 6.52047055517085416554e-03, + 6.58239650525249079399e-03, + 6.64051604802040618125e-03, + 6.69479887261659797199e-03, + 6.74521688216371366476e-03, + 6.79174420813415374160e-03, + 6.83435722343555315111e-03, + 6.87303455420689574096e-03, + 6.90775709031867489462e-03, + 6.93850799457300902728e-03, + 6.96527271059846700418e-03, + 6.98803896943703088673e-03, + 7.00679679481976212113e-03, + 7.02153850712936879186e-03, + 7.03225872604836682589e-03, + 7.03895437189253850990e-03, + 7.04162466562946627591e-03, + 7.04027112758361280076e-03, + 7.03489757482926060528e-03, + 7.02551011727416043623e-03, + 7.01211715243688429866e-03, + 6.99472935892183310391e-03, + 6.97335968859667636177e-03, + 6.94802335747783921666e-03, + 6.91873783532993662237e-03, + 6.88552283398612303966e-03, + 6.84840029439715090170e-03, + 6.80739437241735696749e-03, + 6.76253142333664569730e-03, + 6.71383998516838706450e-03, + 6.66135076070345499843e-03, + 6.60509659834187211336e-03, + 6.54511247171371459558e-03, + 6.48143545810195200602e-03, + 6.41410471568024109779e-03, + 6.34316145958003368976e-03, + 6.26864893680093449718e-03, + 6.19061239997995525763e-03, + 6.10909908003542511529e-03, + 6.02415815770170753884e-03, + 5.93584073397201983369e-03, + 5.84419979946794454495e-03, + 5.74929020275181338478e-03, + 5.65116861760294342948e-03, + 5.54989350927625503529e-03, + 5.44552509976333788677e-03, + 5.33812533207639414862e-03, + 5.22775783357706802512e-03, + 5.11448787837056554478e-03, + 4.99838234878814680062e-03, + 4.87950969598033648666e-03, + 4.75793989964418302663e-03, + 4.63374442690764765801e-03, + 4.50699619039651548646e-03, + 4.37776950550668349227e-03, + 4.24614004690850900536e-03, + 4.11218480430692711475e-03, + 3.97598203748505876071e-03, + 3.83761123065512682953e-03, + 3.69715304614688265381e-03, + 3.55468927745570878116e-03, + 3.41030280168198429019e-03, + 3.26407753138687091454e-03, + 3.11609836589335845169e-03, + 2.96645114206062080267e-03, + 2.81522258455971620753e-03, + 2.66250025568077076238e-03, + 2.50837250469876198167e-03, + 2.35292841682855887256e-03, + 2.19625776179852754202e-03, + 2.03845094207133958539e-03, + 1.87959894074250246331e-03, + 1.71979326914796590980e-03, + 1.55912591420826569452e-03, + 1.39768928554081183456e-03, + 1.23557616237141834267e-03, + 1.07287964027444793387e-03, + 9.09693077772073983855e-04, + 7.46110042824598817396e-04, + 5.82224259240568249411e-04, + 4.18129553038750639577e-04, + 2.53919798792089188456e-04, + 8.96888659844675517445e-05, +-7.44694345896905772258e-05, +-2.38461404350935065157e-04, +-4.02193510356873369562e-04, +-5.65572438589027263849e-04, +-7.28505147074144480956e-04, +-8.90898918810926966801e-04, +-1.05266141447140325338e-03, +-1.21370072484502889917e-03, +-1.37392542300045520862e-03, +-1.53324461613069552152e-03, +-1.69156799705494180486e-03, +-1.84880589534694829770e-03, +-2.00486932806183924816e-03, +-2.15967005003114657924e-03, +-2.31312060369968800280e-03, +-2.46513436847466778021e-03, +-2.61562560955978882365e-03, +-2.76450952624671683969e-03, +-2.91170229963722427408e-03, +-3.05712113976792237979e-03, +-3.20068433211290236454e-03, +-3.34231128343639950426e-03, +-3.48192256697167851556e-03, +-3.61943996689886252766e-03, +-3.75478652209826086611e-03, +-3.88788656915454566149e-03, +-4.01866578458679943320e-03, +-4.14705122628237707327e-03, +-4.27297137411052248279e-03, +-4.39635616969335368820e-03, +-4.51713705531228693069e-03, +-4.63524701192860166116e-03, +-4.75062059629599835880e-03, +-4.86319397714623982004e-03, +-4.97290497042671315875e-03, +-5.07969307357067009767e-03, +-5.18349949878208187543e-03, +-5.28426720531614563942e-03, +-5.38194093073713492048e-03, +-5.47646722113816729338e-03, +-5.56779446030545265012e-03, +-5.65587289781075818612e-03, +-5.74065467601772051742e-03, +-5.82209385598695533526e-03, +-5.90014644226589859283e-03, +-5.97477040655035752242e-03, +-6.04592571020508891960e-03, +-6.11357432563106647366e-03, +-6.17768025646842598719e-03, +-6.23820955662453009022e-03, +-6.29513034811653680867e-03, +-6.34841283772002301644e-03, +-6.39802933241444878737e-03, +-6.44395425361771970879e-03, +-6.48616415020282759824e-03, +-6.52463771028981894679e-03, +-6.55935577180693108607e-03, +-6.59030133181688366345e-03, +-6.61745955460281767846e-03, +-6.64081777851058003420e-03, +-6.66036552154464483316e-03, +-6.67609448571504417863e-03, +-6.68799856013396580579e-03, +-6.69607382286100619867e-03, +-6.70031854149736628978e-03, +-6.70073317252893423113e-03, +-6.69732035942032649656e-03, +-6.69008492946125080808e-03, +-6.67903388936833767447e-03, +-6.66417641964580503844e-03, +-6.64552386770900921364e-03, +-6.62308973977570117353e-03, +-6.59688969153084895508e-03, +-6.56694151757089734922e-03, +-6.53326513963461280587e-03, +-6.49588259362816715370e-03, +-6.45481801545267231540e-03, +-6.41009762564318658074e-03, +-6.36174971282886698998e-03, +-6.30980461602472040422e-03, +-6.25429470576554895345e-03, +-6.19525436409436129626e-03, +-6.13271996341689488996e-03, +-6.06672984423554158967e-03, +-5.99732429177634272788e-03, +-5.92454551152269380532e-03, +-5.84843760367088558172e-03, +-5.76904653652344102249e-03, +-5.68642011883526560245e-03, +-5.60060797112928252656e-03, +-5.51166149599965557448e-03, +-5.41963384741940817219e-03, +-5.32457989907073915570e-03, +-5.22655621171772520606e-03, +-5.12562099963942419123e-03, +-5.02183409614448406089e-03, +-4.91525691818681109702e-03, +-4.80595243010374650883e-03, +-4.69398510649735815209e-03, +-4.57942089428194781808e-03, +-4.46232717391857429401e-03, +-4.34277271986037178425e-03, +-4.22082766023175893350e-03, +-4.09656343576443940369e-03, +-3.97005275801442028549e-03, +-3.84136956688634241541e-03, +-3.71058898748600606704e-03, +-3.57778728632999511172e-03, +-3.44304182693580453772e-03, +-3.30643102481900002035e-03, +-3.16803430192340654270e-03, +-3.02793204051044796687e-03, +-2.88620553653542132044e-03, +-2.74293695253627518860e-03, +-2.59820927006318425079e-03, +-2.45210624167601677625e-03, +-2.30471234253809770590e-03, +-2.15611272163192388071e-03, +-2.00639315262918054017e-03, +-1.85563998443917131317e-03, +-1.70394009146592178422e-03, +-1.55138082360318694218e-03, +-1.39804995599510811267e-03, +-1.24403563859131600054e-03, +-1.08942634552675727232e-03, +-9.34310824353430722893e-04, +-7.78778045154488265424e-04, +-6.22917149569355557345e-04, +-4.66817399759168381000e-04, +-3.10568127341177748629e-04, +-1.54258682322715390484e-04, + 2.02161793800758804308e-06, + 1.58183539713823383393e-04, + 3.14137983804192602675e-04, + 4.69796036316565991924e-04, + 6.25069019303870366394e-04, + 7.79868541228004980535e-04, + 9.34106547223279145772e-04, + 1.08769536912991875675e-03, + 1.24054777526851588154e-03, + 1.39257701992830692887e-03, + 1.54369689254121996921e-03, + 1.69382176651257680342e-03, + 1.84286664768265498297e-03, + 1.99074722239030730067e-03, + 2.13737990511212458747e-03, + 2.28268188564996954079e-03, + 2.42657117584086636994e-03, + 2.56896665576163141242e-03, + 2.70978811940393539068e-03, + 2.84895631979290410787e-03, + 2.98639301352399176917e-03, + 3.12202100469403682342e-03, + 3.25576418820130086482e-03, + 3.38754759238860721909e-03, + 3.51729742100961384824e-03, + 3.64494109449081107530e-03, + 3.77040729046844522859e-03, + 3.89362598357706262905e-03, + 4.01452848446753798178e-03, + 4.13304747803329777800e-03, + 4.24911706082250345551e-03, + 4.36267277761673982761e-03, + 4.47365165715500091859e-03, + 4.58199224698366443242e-03, + 4.68763464741256234702e-03, + 4.79052054456022714107e-03, + 4.89059324246701558614e-03, + 4.98779769426149852812e-03, + 5.08208053236177022260e-03, + 5.17339009769468647498e-03, + 5.26167646791786663280e-03, + 5.34689148462896227804e-03, + 5.42898877954677526458e-03, + 5.50792379965109931556e-03, + 5.58365383126675513675e-03, + 5.65613802307947735604e-03, + 5.72533740807081026336e-03, + 5.79121492436091966222e-03, + 5.85373543494751170241e-03, + 5.91286574633094908632e-03, + 5.96857462601572963390e-03, + 6.02083281887862576537e-03, + 6.06961306239588074124e-03, + 6.11489010072096151466e-03, + 6.15664069760550429489e-03, + 6.19484364815777593938e-03, + 6.22947978943221101350e-03, + 6.26053200984478218361e-03, + 6.28798525741010132240e-03, + 6.31182654679610100068e-03, + 6.33204496519319988412e-03, + 6.34863167699579490633e-03, + 6.36157992729387798680e-03, + 6.37088504417378069522e-03, + 6.37654443982793583956e-03, + 6.37855761047346776077e-03, + 6.37692613508076319023e-03, + 6.37165367291377907760e-03, + 6.36274595988404155500e-03, + 6.35021080372164415523e-03, + 6.33405807796656641212e-03, + 6.31429971478498618803e-03, + 6.29094969661516800058e-03, + 6.26402404664898240089e-03, + 6.23354081815498742292e-03, + 6.19952008265027120631e-03, + 6.16198391692862612601e-03, + 6.12095638895326834422e-03, + 6.07646354262293339477e-03, + 6.02853338142123572341e-03, + 5.97719585095891989962e-03, + 5.92248282042035986694e-03, + 5.86442806292514912103e-03, + 5.80306723481761356498e-03, + 5.73843785389547937636e-03, + 5.67057927659296145267e-03, + 5.59953267413014401516e-03, + 5.52534100764390679467e-03, + 5.44804900231556955836e-03, + 5.36770312051036008194e-03, + 5.28435153394469885046e-03, + 5.19804409489867894761e-03, + 5.10883230648978472338e-03, + 5.01676929202641425087e-03, + 4.92190976345897174271e-03, + 4.82430998894739331007e-03, + 4.72402775956395210022e-03, + 4.62112235515180647810e-03, + 4.51565450935827780027e-03, + 4.40768637386434840308e-03, + 4.29728148183127715148e-03, + 4.18450471058511973971e-03, + 4.06942224356152213588e-03, + 3.95210153153399603582e-03, + 3.83261125314650298243e-03, + 3.71102127477429544200e-03, + 3.58740260973707415088e-03, + 3.46182737688722997824e-03, + 3.33436875859757829790e-03, + 3.20510095817370162935e-03, + 3.07409915671442122986e-03, + 2.94143946944645578653e-03, + 2.80719890155818000560e-03, + 2.67145530355801606032e-03, + 2.53428732618405597871e-03, + 2.39577437488870843840e-03, + 2.25599656392876232389e-03, + 2.11503467008288762591e-03, + 1.97297008602663600726e-03, + 1.82988477338951447716e-03, + 1.68586121552325774765e-03, + 1.54098237000600303548e-03, + 1.39533162091338329772e-03, + 1.24899273087909832951e-03, + 1.10204979297680240487e-03, + 9.54587182448630219150e-04, + 8.06689508308766145897e-04, + 6.58441564849216722996e-04, + 5.09928283076855021032e-04, + 3.61234682107735086132e-04, + 2.12445820547849437534e-04, + 6.36467478874062951924e-05, +-8.50775440627651754989e-05, +-2.33642169667408998316e-04, +-3.81962397863639291536e-04, +-5.29953700435123313019e-04, +-6.77531800134304070492e-04, +-8.24612718624688793498e-04, +-9.71112824217015813653e-04, +-1.11694887937219939321e-03, +-1.26203808794284771423e-03, +-1.40629814212836251781e-03, +-1.54964726911566716763e-03, +-1.69200427737972594958e-03, +-1.83328860261746241604e-03, +-1.97342035328964800558e-03, +-2.11232035574377557952e-03, +-2.24991019889414630914e-03, +-2.38611227843281599459e-03, +-2.52084984054647175469e-03, +-2.65404702511572903115e-03, +-2.78562890837174507302e-03, +-2.91552154498523870621e-03, +-3.04365200956643270486e-03, +-3.16994843755161225321e-03, +-3.29434006545274672348e-03, +-3.41675727044862646842e-03, +-3.53713160929501439778e-03, +-3.65539585653244531588e-03, +-3.77148404196936751220e-03, +-3.88533148742125408054e-03, +-3.99687484268407104693e-03, +-4.10605212072268164342e-03, +-4.21280273205412725268e-03, +-4.31706751830841783946e-03, +-4.41878878494509144681e-03, +-4.51791033311113327670e-03, +-4.61437749061991125260e-03, +-4.70813714203596311164e-03, +-4.79913775784764073951e-03, +-4.88732942271308690857e-03, +-4.97266386276206447808e-03, +-5.05509447194163030054e-03, +-5.13457633738856073641e-03, +-5.21106626381633106920e-03, +-5.28452279690304685400e-03, +-5.35490624566773484178e-03, +-5.42217870382271597413e-03, +-5.48630407009116985440e-03, +-5.54724806747858376760e-03, +-5.60497826148812720165e-03, +-5.65946407726994771964e-03, +-5.71067681569638677108e-03, +-5.75858966835306532173e-03, +-5.80317773143970965649e-03, +-5.84441801857288768113e-03, +-5.88228947248397703723e-03, +-5.91677297560679570088e-03, +-5.94785135954983314177e-03, +-5.97550941344791256699e-03, +-5.99973389119013312404e-03, +-6.02051351752001286111e-03, +-6.03783899300595460619e-03, +-6.05170299787924879931e-03, +-6.06210019473904081905e-03, +-6.06902723012296262811e-03, +-6.07248273494360914920e-03, +-6.07246732379158708770e-03, +-6.06898359310613279977e-03, +-6.06203611821533403653e-03, +-6.05163144924839458555e-03, +-6.03777810592327594807e-03, +-6.02048657121333555264e-03, +-5.99976928389753336873e-03, +-5.97564062999924889424e-03, +-5.94811693311943397167e-03, +-5.91721644367056848202e-03, +-5.88295932701797356923e-03, +-5.84536765053670151482e-03, +-5.80446536959165673014e-03, +-5.76027831244998057142e-03, +-5.71283416413511518916e-03, +-5.66216244923269020756e-03, +-5.60829451365809760616e-03, +-5.55126350539837404990e-03, +-5.49110435423857436155e-03, +-5.42785375048610279486e-03, +-5.36155012270514343825e-03, +-5.29223361447536504165e-03, +-5.21994606018790722329e-03, +-5.14473095989484690421e-03, +-5.06663345322490039219e-03, +-4.98570029238308044806e-03, +-4.90197981424923389521e-03, +-4.81552191159239240809e-03, +-4.72637800341784222735e-03, +-4.63460100446517250100e-03, +-4.54024529387421233589e-03, +-4.44336668303834617794e-03, +-4.34402238266374564335e-03, +-4.24227096905429278129e-03, +-4.13817234964060018387e-03, +-4.03178772777628563473e-03, +-3.92317956681902026833e-03, +-3.81241155351897623854e-03, +-3.69954856073620007989e-03, +-3.58465660950824235517e-03, +-3.46780283048990500827e-03, +-3.34905542478881141852e-03, +-3.22848362421805775910e-03, +-3.10615765099010905648e-03, +-2.98214867687515662251e-03, +-2.85652878184750828178e-03, +-2.72937091224384606111e-03, +-2.60074883845852087780e-03, +-2.47073711219897686545e-03, +-2.33941102332713016590e-03, +-2.20684655631157985653e-03, +-2.07312034631475673035e-03, +-1.93830963494213536630e-03, +-1.80249222567671618656e-03, +-1.66574643902788789573e-03, +-1.52815106741598333122e-03, +-1.38978532982251450426e-03, +-1.25072882622996486672e-03, +-1.11106149187807385498e-03, +-9.70863551362263440571e-04, +-8.30215472601808523491e-04, +-6.89197920702451245073e-04, +-5.47891711741154406080e-04, +-4.06377766498845327103e-04, +-2.64737064168374847291e-04, +-1.23050596061868546460e-04, + 1.86006806518760801038e-05, + 1.60135889158271910344e-04, + 3.01474279126209918772e-04, + 4.42535272731790253753e-04, + 5.83238510548296702242e-04, + 7.23503897278638991204e-04, + 8.63251647300782411557e-04, + 1.00240233000493386348e-03, + 1.14087691489260295227e-03, + 1.27859681641420436932e-03, + 1.41548393851902284610e-03, + 1.55146071889291931739e-03, + 1.68645017285750319601e-03, + 1.82037593690758878195e-03, + 1.95316231186109341353e-03, + 2.08473430559764265693e-03, + 2.21501767536104888362e-03, + 2.34393896960388269796e-03, + 2.47142556934688362516e-03, + 2.59740572903363739141e-03, + 2.72180861685599774502e-03, + 2.84456435452711767914e-03, + 2.96560405648055866804e-03, + 3.08485986847369889757e-03, + 3.20226500557270433653e-03, + 3.31775378949923562683e-03, + 3.43126168531712261514e-03, + 3.54272533743877921647e-03, + 3.65208260493136678895e-03, + 3.75927259610300519913e-03, + 3.86423570235000643155e-03, + 3.96691363124569706944e-03, + 4.06724943885357868856e-03, + 4.16518756124574941052e-03, + 4.26067384521043503870e-03, + 4.35365557813031326534e-03, + 4.44408151701685457530e-03, + 4.53190191668225664939e-03, + 4.61706855703673899743e-03, + 4.69953476949353052966e-03, + 4.77925546246841040365e-03, + 4.85618714595966241565e-03, + 4.93028795519530847746e-03, + 5.00151767333411288730e-03, + 5.06983775320908342660e-03, + 5.13521133810092809957e-03, + 5.19760328153088136532e-03, + 5.25698016606174298865e-03, + 5.31331032109820002030e-03, + 5.36656383967527069595e-03, + 5.41671259422796692179e-03, + 5.46373025133245135421e-03, + 5.50759228541199737789e-03, + 5.54827599139992924671e-03, + 5.58576049635388805631e-03, + 5.62002677001447251137e-03, + 5.65105763430437738060e-03, + 5.67883777176233280753e-03, + 5.70335373290816339403e-03, + 5.72459394253559995802e-03, + 5.74254870493012391924e-03, + 5.75721020800935671946e-03, + 5.76857252638474007206e-03, + 5.77663162334343931875e-03, + 5.78138535175009606049e-03, + 5.78283345386879782390e-03, + 5.78097756010611391053e-03, + 5.77582118667672138324e-03, + 5.76736973219383122768e-03, + 5.75563047318704626432e-03, + 5.74061255855102051116e-03, + 5.72232700292902695532e-03, + 5.70078667903584773713e-03, + 5.67600630892513106918e-03, + 5.64800245420722570738e-03, + 5.61679350522356971021e-03, + 5.58239966918474238289e-03, + 5.54484295727977402612e-03, + 5.50414717076463597123e-03, + 5.46033788603883952356e-03, + 5.41344243871932310347e-03, + 5.36348990672138540431e-03, + 5.31051109235732010649e-03, + 5.25453850346318130510e-03, + 5.19560633356600486132e-03, + 5.13375044110239622114e-03, + 5.06900832770268514743e-03, + 5.00141911555166893133e-03, + 4.93102352384138312158e-03, + 4.85786384432904984332e-03, + 4.78198391601513880800e-03, + 4.70342909895635295087e-03, + 4.62224624722982427999e-03, + 4.53848368106374473741e-03, + 4.45219115815146792431e-03, + 4.36341984416594753926e-03, + 4.27222228249233334368e-03, + 4.17865236319510044427e-03, + 4.08276529124071765886e-03, + 3.98461755399166870500e-03, + 3.88426688799294646953e-03, + 3.78177224506918985281e-03, + 3.67719375775360296163e-03, + 3.57059270406730406081e-03, + 3.46203147167215485522e-03, + 3.35157352141467277523e-03, + 3.23928335028530935830e-03, + 3.12522645381305575613e-03, + 3.00946928791781488297e-03, + 2.89207923024227455538e-03, + 2.77312454098672077352e-03, + 2.65267432326827179087e-03, + 2.53079848302840103302e-03, + 2.40756768851164678139e-03, + 2.28305332933951632760e-03, + 2.15732747520132111738e-03, + 2.03046283418941569954e-03, + 1.90253271079930631401e-03, + 1.77361096362036439224e-03, + 1.64377196274210417119e-03, + 1.51309054689958370071e-03, + 1.38164198038311938042e-03, + 1.24950190973654160810e-03, + 1.11674632027006139751e-03, + 9.83451492411185164075e-04, + 8.49693957919833188497e-04, + 7.15550455992367039418e-04, + 5.81097889279802068928e-04, + 4.46413279844896004802e-04, + 3.11573725084547952131e-04, + 1.76656353640993331018e-04, + 4.17382813286828151375e-05, +-9.31034328996876200512e-05, +-2.27791830921029737336e-04, +-3.62250099320780654093e-04, +-4.96401613154530668010e-04, +-6.30169979571938514672e-04, +-7.63479081274113916857e-04, +-8.96253119781942569726e-04, +-1.02841665849006422100e-03, +-1.15989466548260746100e-03, +-1.29061255608525294117e-03, +-1.42049623513107697685e-03, +-1.54947213891506270153e-03, +-1.67746727681411891310e-03, +-1.80440927254837480201e-03, +-1.93022640506252275011e-03, +-2.05484764900032337159e-03, +-2.17820271475373814299e-03, +-2.30022208806093461653e-03, +-2.42083706913298482913e-03, +-2.53997981128547666713e-03, +-2.65758335905543320934e-03, +-2.77358168577903838048e-03, +-2.88790973061320895704e-03, +-3.00050343497665914297e-03, +-3.11129977839202497697e-03, +-3.22023681370834334581e-03, +-3.32725370168476981825e-03, +-3.43229074491519740159e-03, +-3.53528942107627329461e-03, +-3.63619241547926243599e-03, +-3.73494365290821112024e-03, +-3.83148832872629279550e-03, +-3.92577293923390257396e-03, +-4.01774531126125340058e-03, +-4.10735463097804467947e-03, +-4.19455147190698693360e-03, +-4.27928782212313139899e-03, +-4.36151711062546069975e-03, +-4.44119423286594081079e-03, +-4.51827557542231091070e-03, +-4.59271903980044363808e-03, +-4.66448406535440850823e-03, +-4.73353165131090974221e-03, +-4.79982437788653917843e-03, +-4.86332642648651045092e-03, +-4.92400359897397343206e-03, +-4.98182333599925253331e-03, +-5.03675473437993799497e-03, +-5.08876856352186244387e-03, +-5.13783728087296304166e-03, +-5.18393504640126713545e-03, +-5.22703773609024553021e-03, +-5.26712295444329344635e-03, +-5.30417004599272740029e-03, +-5.33816010580571553151e-03, +-5.36907598898301533646e-03, +-5.39690231914530423041e-03, +-5.42162549590326486165e-03, +-5.44323370130771460457e-03, +-5.46171690527704530721e-03, +-5.47706686999947442440e-03, +-5.48927715330848470243e-03, +-5.49834311103008545329e-03, +-5.50426189830165689398e-03, +-5.50703246986195688040e-03, +-5.50665557931325801155e-03, +-5.50313377735658394718e-03, +-5.49647140900193838936e-03, +-5.48667460975575324578e-03, +-5.47375130078852495386e-03, +-5.45771118308641025457e-03, +-5.43856573059035668105e-03, +-5.41632818232791902330e-03, +-5.39101353354278986507e-03, +-5.36263852582782342415e-03, +-5.33122163626806137848e-03, +-5.29678306560053737545e-03, +-5.25934472539848259925e-03, +-5.21893022428794508411e-03, +-5.17556485320526133559e-03, +-5.12927556970489868793e-03, +-5.08009098132678089954e-03, +-5.02804132803355476738e-03, +-4.97315846372916019885e-03, +-4.91547583686848584689e-03, +-4.85502847017122741990e-03, +-4.79185293945155309919e-03, +-4.72598735157650148841e-03, +-4.65747132156595338576e-03, +-4.58634594884884446570e-03, +-4.51265379268859113254e-03, +-4.43643884679333078136e-03, +-4.35774651312552125521e-03, +-4.27662357492689104710e-03, +-4.19311816897408994737e-03, +-4.10727975708242813713e-03, +-4.01915909687342119000e-03, +-3.92880821182439374240e-03, +-3.83628036061678823893e-03, +-3.74163000580234744730e-03, +-3.64491278180403876011e-03, +-3.54618546227291209921e-03, +-3.44550592681680360740e-03, +-3.34293312712312645080e-03, +-3.23852705249417973515e-03, +-3.13234869481537631791e-03, +-3.02446001297665325452e-03, +-2.91492389676846486157e-03, +-2.80380413027231812501e-03, +-2.69116535476798942814e-03, +-2.57707303117848647925e-03, +-2.46159340207523572031e-03, +-2.34479345326362147856e-03, +-2.22674087497457245249e-03, +-2.10750402268079263524e-03, +-1.98715187756321907606e-03, +-1.86575400664854376166e-03, +-1.74338052264242380010e-03, +-1.62010204348048895799e-03, +-1.49598965162051219212e-03, +-1.37111485310015116836e-03, +-1.24554953638238521431e-03, +-1.11936593101341890638e-03, +-9.92636566116329244550e-04, +-8.65434228744452519431e-04, +-7.37831922117954900481e-04, +-6.09902823768643741718e-04, +-4.81720243615482051399e-04, +-3.53357581995873909833e-04, +-2.24888287676710109473e-04, +-9.63858158682636068570e-05, + 3.20764137345539367911e-05, + 1.60425058858032064824e-04, + 2.88586896482438703439e-04, + 4.16488864574161247057e-04, + 5.44058103695506324778e-04, + 6.71221998467804803826e-04, + 7.97908218864774886926e-04, + 9.24044761311549125993e-04, + 1.04955998956755358967e-03, + 1.17438267536891884947e-03, + 1.29844203880782817391e-03, + 1.42166778842579637730e-03, + 1.54399016099864027675e-03, + 1.66533996098952152137e-03, + 1.78564859964935114707e-03, + 1.90484813374091114212e-03, + 2.02287130386640369786e-03, + 2.13965157237518523517e-03, + 2.25512316083227538563e-03, + 2.36922108702373405281e-03, + 2.48188120148188241104e-03, + 2.59304022350648980672e-03, + 2.70263577666357253729e-03, + 2.81060642374125237153e-03, + 2.91689170114364185876e-03, + 3.02143215270252868399e-03, + 3.12416936288921476272e-03, + 3.22504598940713581648e-03, + 3.32400579514743541032e-03, + 3.42099367948939334788e-03, + 3.51595570892898222001e-03, + 3.60883914701814589171e-03, + 3.69959248359746136620e-03, + 3.78816546330745101967e-03, + 3.87450911336219023379e-03, + 3.95857577056929390430e-03, + 4.04031910758215120211e-03, + 4.11969415836998739677e-03, + 4.19665734289097897003e-03, + 4.27116649095604910408e-03, + 4.34318086526945621589e-03, + 4.41266118363398390095e-03, + 4.47956964030860743664e-03, + 4.54386992650717726205e-03, + 4.60552725002660520714e-03, + 4.66450835399471325227e-03, + 4.72078153472709621807e-03, + 4.77431665868354501020e-03, + 4.82508517851539756732e-03, + 4.87306014819507884311e-03, + 4.91821623721916140887e-03, + 4.96052974387923596711e-03, + 4.99997860759186524976e-03, + 5.03654242028247437629e-03, + 5.07020243681679735892e-03, + 5.10094158447498870201e-03, + 5.12874447146327485519e-03, + 5.15359739445947657999e-03, + 5.17548834518845573410e-03, + 5.19440701602455999486e-03, + 5.21034480461868027695e-03, + 5.22329481754779667568e-03, + 5.23325187298585500772e-03, + 5.24021250239507709739e-03, + 5.24417495123738995610e-03, + 5.24513917870653937486e-03, + 5.24310685648145778648e-03, + 5.23808136650251530281e-03, + 5.23006779777264278752e-03, + 5.21907294218578940437e-03, + 5.20510528938584581676e-03, + 5.18817502065979652137e-03, + 5.16829400186912500670e-03, + 5.14547577542429773745e-03, + 5.11973555130774103661e-03, + 5.09109019715092269570e-03, + 5.05955822737205133249e-03, + 5.02515979138124391917e-03, + 4.98791666086073268160e-03, + 4.94785221612767823346e-03, + 4.90499143158841868773e-03, + 4.85936086029322127783e-03, + 4.81098861760061516368e-03, + 4.75990436396146916753e-03, + 4.70613928683348472365e-03, + 4.64972608173691136918e-03, + 4.59069893246278216276e-03, + 4.52909349044612261070e-03, + 4.46494685331585636212e-03, + 4.39829754263475290049e-03, + 4.32918548084257250735e-03, + 4.25765196741618740656e-03, + 4.18373965426069652218e-03, + 4.10749252034667798605e-03, + 4.02895584560788132256e-03, + 3.94817618411542111539e-03, + 3.86520133654418484789e-03, + 3.78008032194739225507e-03, + 3.69286334885604366693e-03, + 3.60360178572117573551e-03, + 3.51234813071479813271e-03, + 3.41915598090793311503e-03, + 3.32408000084427699555e-03, + 3.22717589052724015269e-03, + 3.12850035283901645525e-03, + 3.02811106041162708680e-03, + 2.92606662196800764927e-03, + 2.82242654815364601290e-03, + 2.71725121687837328777e-03, + 2.61060183818851918036e-03, + 2.50254041868949728133e-03, + 2.39312972554039504053e-03, + 2.28243325004017514127e-03, + 2.17051517082786447205e-03, + 2.05744031671671037328e-03, + 1.94327412918531700070e-03, + 1.82808262454552442576e-03, + 1.71193235581180232437e-03, + 1.59489037429026681535e-03, + 1.47702419091290675264e-03, + 1.35840173733748205247e-03, + 1.23909132683596356558e-03, + 1.11916161499407847656e-03, + 9.98681560244074617572e-04, + 8.77720384254470167330e-04, + 7.56347532198058721681e-04, + 6.34632632921996054504e-04, + 5.12645459042746680714e-04, + 3.90455886987906247536e-04, + 2.68133857008314943106e-04, + 1.45749333184361831153e-04, + 2.33722634472747536666e-05, +-9.89274603607503039181e-05, +-2.21080042364225074413e-04, +-3.43015822447986784560e-04, +-4.64665315944092405156e-04, +-5.85959253188382740186e-04, +-7.06828618925680403524e-04, +-8.27204691540118683922e-04, +-9.47019082088787164143e-04, +-1.06620377311637771697e-03, +-1.18469115722925682696e-03, +-1.30241407540605423285e-03, +-1.41930585502448507011e-03, +-1.53530034758192469001e-03, +-1.65033196608840252578e-03, +-1.76433572211173142659e-03, +-1.87724726245334949150e-03, +-1.98900290543319513067e-03, +-2.09953967676512883930e-03, +-2.20879534500175757350e-03, +-2.31670845652815794724e-03, +-2.42321837008570468985e-03, +-2.52826529080659367574e-03, +-2.63179030373909264226e-03, +-2.73373540684600496026e-03, +-2.83404354345699518308e-03, +-2.93265863415691175817e-03, +-3.02952560809236284833e-03, +-3.12459043367923185522e-03, +-3.21780014869336387223e-03, +-3.30910288972877109082e-03, +-3.39844792100587331576e-03, +-3.48578566251492739242e-03, +-3.57106771747796791425e-03, +-3.65424689911476559614e-03, +-3.73527725669808635320e-03, +-3.81411410088312429617e-03, +-3.89071402829827646050e-03, +-3.96503494538289445737e-03, +-4.03703609145932267727e-03, +-4.10667806102655782996e-03, +-4.17392282526347826316e-03, +-4.23873375272956244564e-03, +-4.30107562925237472268e-03, +-4.36091467699083017162e-03, +-4.41821857266369143885e-03, +-4.47295646493412607514e-03, +-4.52509899094063333669e-03, +-4.57461829196504320139e-03, +-4.62148802823035640547e-03, +-4.66568339281999474449e-03, +-4.70718112471093987764e-03, +-4.74595952091446966065e-03, +-4.78199844771800587628e-03, +-4.81527935102211632201e-03, +-4.84578526576791637770e-03, +-4.87350082444968323026e-03, +-4.89841226470876054538e-03, +-4.92050743600499964486e-03, +-4.93977580536274565870e-03, +-4.95620846218847079662e-03, +-4.96979812215835037303e-03, +-4.98053913017405553570e-03, +-4.98842746238571579237e-03, +-4.99346072728172954425e-03, +-4.99563816584549461736e-03, +-4.99496065077936236831e-03, +-4.99143068479745467825e-03, +-4.98505239798852691629e-03, +-4.97583154425139829319e-03, +-4.96377549680547796446e-03, +-4.94889324277973576688e-03, +-4.93119537688388714231e-03, +-4.91069409416598247342e-03, +-4.88740318186142198853e-03, +-4.86133801033847897516e-03, +-4.83251552314631609847e-03, +-4.80095422617195580206e-03, +-4.76667417591256168535e-03, +-4.72969696687120574191e-03, +-4.69004571808321647775e-03, +-4.64774505878175377138e-03, +-4.60282111321146884114e-03, +-4.55530148459956044787e-03, +-4.50521523829377698589e-03, +-4.45259288407801132742e-03, +-4.39746635767579701487e-03, +-4.33986900145311854660e-03, +-4.27983554433203870759e-03, +-4.21740208092733371431e-03, +-4.15260604991831393240e-03, +-4.08548621166932371396e-03, +-4.01608262511158123353e-03, +-3.94443662390054836098e-03, +-3.87059079186303405321e-03, +-3.79458893774812806160e-03, +-3.71647606929711776455e-03, +-3.63629836664845860345e-03, +-3.55410315509214558630e-03, +-3.46993887719018040405e-03, +-3.38385506427993278805e-03, +-3.29590230737648436782e-03, +-3.20613222749113312843e-03, +-3.11459744538398987032e-03, +-3.02135155076756461295e-03, +-2.92644907097984593655e-03, +-2.82994543914506487339e-03, +-2.73189696184072483912e-03, +-2.63236078628936763860e-03, +-2.53139486709509815843e-03, +-2.42905793254300297890e-03, +-2.32540945048183896743e-03, +-2.22050959380982104382e-03, +-2.11441920558280097714e-03, +-2.00719976376547218355e-03, +-1.89891334564696082597e-03, +-1.78962259193952521845e-03, +-1.67939067058208314070e-03, +-1.56828124026987358701e-03, +-1.45635841373061535042e-03, +-1.34368672076823521266e-03, +-1.23033107109642224179e-03, +-1.11635671698205856534e-03, +-1.00182921572098456581e-03, +-8.86814391967279472273e-04, +-7.71378299937657582568e-04, +-6.55587185513229354222e-04, +-5.39507448258485936346e-04, +-4.23205603382631467824e-04, +-3.06748243661661022710e-04, +-1.90202001344411987527e-04, +-7.36335100648440309687e-05, + 4.28906332185422347128e-05, + 1.59303906234412831922e-04, + 2.75539899338800254799e-04, + 3.91532353363562794085e-04, + 5.07215197350502681149e-04, + 6.22522586150107753653e-04, + 7.37388937863388033329e-04, + 8.51748971105957086540e-04, + 9.65537742072175879035e-04, + 1.07869068137969592591e-03, + 1.19114363067259008272e-03, + 1.30283287896230275983e-03, + 1.41369519868671613717e-03, + 1.52366788146634829677e-03, + 1.63268877353659261353e-03, + 1.74069631083787878384e-03, + 1.84762955374296743323e-03, + 1.95342822140135439005e-03, + 2.05803272568219793037e-03, + 2.16138420469669332441e-03, + 2.26342455588016133738e-03, + 2.36409646861654226466e-03, + 2.46334345638605676718e-03, + 2.56110988841841760721e-03, + 2.65734102083372766834e-03, + 2.75198302725402016780e-03, + 2.84498302886748277024e-03, + 2.93628912392977997961e-03, + 3.02585041668512657459e-03, + 3.11361704569121855099e-03, + 3.19954021153272608058e-03, + 3.28357220390771429100e-03, + 3.36566642807112174907e-03, + 3.44577743062223634807e-03, + 3.52386092462112724549e-03, + 3.59987381401977125581e-03, + 3.67377421739513865956e-03, + 3.74552149097084462886e-03, + 3.81507625091497340475e-03, + 3.88240039490136924424e-03, + 3.94745712292331966259e-03, + 4.01021095734782184045e-03, + 4.07062776219968818631e-03, + 4.12867476166478130500e-03, + 4.18432055780340594886e-03, + 4.23753514746243783312e-03, + 4.28828993837902447406e-03, + 4.33655776446637518384e-03, + 4.38231290027339768361e-03, + 4.42553107461083304608e-03, + 4.46618948333678180557e-03, + 4.50426680129448111373e-03, + 4.53974319339683820423e-03, + 4.57260032485135199665e-03, + 4.60282137052065234983e-03, + 4.63039102341378759620e-03, + 4.65529550230404237654e-03, + 4.67752255846963938685e-03, + 4.69706148155405248112e-03, + 4.71390310454339756668e-03, + 4.72803980785840502477e-03, + 4.73946552255972292089e-03, + 4.74817573266493424267e-03, + 4.75416747657694122031e-03, + 4.75743934762336718319e-03, + 4.75799149370748075683e-03, + 4.75582561607138833149e-03, + 4.75094496717288084647e-03, + 4.74335434767782487125e-03, + 4.73306010257048929979e-03, + 4.72007011638460489966e-03, + 4.70439380755864264283e-03, + 4.68604212191906475959e-03, + 4.66502752529606660309e-03, + 4.64136399527643843388e-03, + 4.61506701209918757806e-03, + 4.58615354869955273859e-03, + 4.55464205990770056726e-03, + 4.52055247080917176061e-03, + 4.48390616427393924603e-03, + 4.44472596766223859710e-03, + 4.40303613871486330955e-03, + 4.35886235063746938639e-03, + 4.31223167638676834618e-03, + 4.26317257216925812185e-03, + 4.21171486016196257307e-03, + 4.15788971046581433411e-03, + 4.10172962230226281072e-03, + 4.04326840446501793724e-03, + 3.98254115503794432068e-03, + 3.91958424039167124125e-03, + 3.85443527347131180763e-03, + 3.78713309138849164512e-03, + 3.71771773232995421388e-03, + 3.64623041179842725945e-03, + 3.57271349819778243767e-03, + 3.49721048777782827360e-03, + 3.41976597895377260397e-03, + 3.34042564601502072266e-03, + 3.25923621223874176306e-03, + 3.17624542242462160752e-03, + 3.09150201486607309476e-03, + 3.00505569277494284652e-03, + 2.91695709517621800527e-03, + 2.82725776728985633834e-03, + 2.73601013041636529841e-03, + 2.64326745134584257038e-03, + 2.54908381130463648420e-03, + 2.45351407446147209979e-03, + 2.35661385600897553202e-03, + 2.25843948984021103410e-03, + 2.15904799583798876969e-03, + 2.05849704679780722699e-03, + 1.95684493500119767798e-03, + 1.85415053846056882350e-03, + 1.75047328685429747983e-03, + 1.64587312717267382142e-03, + 1.54041048909200266152e-03, + 1.43414625010112694974e-03, + 1.32714170039615556723e-03, + 1.21945850756623999298e-03, + 1.11115868108982397341e-03, + 1.00230453666194673813e-03, + 8.92958660373076220512e-04, + 7.83183872760047513316e-04, + 6.73043192749742938061e-04, + 5.62599801516196619360e-04, + 4.51917006271797402298e-04, + 3.41058204013367112766e-04, + 2.30086845243956402514e-04, + 1.19066397690317975016e-04, + 8.06031003876342309552e-06, +-1.02868024292534745090e-04, +-2.13655303322282262481e-04, +-3.24238352595229727994e-04, +-4.34554161172920089696e-04, +-5.44539917503692838356e-04, +-6.54133045151543304589e-04, +-7.63271238365370997651e-04, +-8.71892497466585482749e-04, +-9.79935164035776202357e-04, +-1.08733795587835245164e-03, +-1.19404000174937055881e-03, +-1.29998087581786859156e-03, +-1.40510063185121983863e-03, +-1.50933983710020702684e-03, +-1.61263960586564250761e-03, +-1.71494163272752683097e-03, +-1.81618822541869504202e-03, +-1.91632233732264294253e-03, +-2.01528759957979742429e-03, +-2.11302835278164621163e-03, +-2.20948967823741222391e-03, +-2.30461742879315041599e-03, +-2.39835825918845125734e-03, +-2.49065965593134232975e-03, +-2.58146996667703255632e-03, +-2.67073842909245186619e-03, +-2.75841519919107873438e-03, +-2.84445137912224619431e-03, +-2.92879904439931598031e-03, +-3.01141127055178960126e-03, +-3.09224215918633147174e-03, +-3.17124686344243166339e-03, +-3.24838161282851346778e-03, +-3.32360373742473678635e-03, +-3.39687169143964044424e-03, +-3.46814507610627249454e-03, +-3.53738466190720588292e-03, +-3.60455241011424683262e-03, +-3.66961149363298272039e-03, +-3.73252631713888970155e-03, +-3.79326253649527652539e-03, +-3.85178707744242114497e-03, +-3.90806815354677143659e-03, +-3.96207528340193453065e-03, +-4.01377930707108587782e-03, +-4.06315240176249869997e-03, +-4.11016809672954883115e-03, +-4.15480128738748670514e-03, +-4.19702824863931681781e-03, +-4.23682664740382061708e-03, +-4.27417555433919245378e-03, +-4.30905545475612165168e-03, +-4.34144825871471493756e-03, +-4.37133731030028924863e-03, +-4.39870739607276222544e-03, +-4.42354475268612757494e-03, +-4.44583707367407054284e-03, +-4.46557351539804588125e-03, +-4.48274470215558658998e-03, +-4.49734273044633849070e-03, +-4.50936117239380054866e-03, +-4.51879507832192439665e-03, +-4.52564097848520176248e-03, +-4.52989688395227449447e-03, +-4.53156228664297524439e-03, +-4.53063815851947795238e-03, +-4.52712694993263019272e-03, +-4.52103258712507720396e-03, +-4.51236046889318294373e-03, +-4.50111746241027566029e-03, +-4.48731189821427022685e-03, +-4.47095356436308811326e-03, +-4.45205369976202098431e-03, +-4.43062498666702171690e-03, +-4.40668154236938374585e-03, +-4.38023891006674489373e-03, +-4.35131404892644905319e-03, +-4.31992532334727567106e-03, +-4.28609249142686190431e-03, +-4.24983669264115699465e-03, +-4.21118043474420344213e-03, +-4.17014757989600526322e-03, +-4.12676333002717343063e-03, +-4.08105421144885384399e-03, +-4.03304805871769478376e-03, +-3.98277399776586060048e-03, +-3.93026242830538889012e-03, +-3.87554500551830520202e-03, +-3.81865462104316469652e-03, +-3.75962538326934676142e-03, +-3.69849259695105700083e-03, +-3.63529274215302917322e-03, +-3.57006345254048127261e-03, +-3.50284349302629844855e-03, +-3.43367273678861842368e-03, +-3.36259214167245173294e-03, +-3.28964372598887933724e-03, +-3.21487054372729570695e-03, +-3.13831665919360848840e-03, +-3.06002712109050643147e-03, +-2.98004793605501560813e-03, +-2.89842604166773779029e-03, +-2.81520927895077040931e-03, +-2.73044636437046704669e-03, +-2.64418686136011710577e-03, +-2.55648115138037068314e-03, +-2.46738040453385034864e-03, +-2.37693654975105290658e-03, +-2.28520224456495602700e-03, +-2.19223084449187820971e-03, +-2.09807637203635911904e-03, +-2.00279348533807409136e-03, +-1.90643744647894558715e-03, +-1.80906408946890644336e-03, +-1.71072978792818604712e-03, +-1.61149142248648530144e-03, +-1.51140634791550681169e-03, +-1.41053236001619538946e-03, +-1.30892766227735197690e-03, +-1.20665083232744858345e-03, +-1.10376078819640946992e-03, +-1.00031675440937460608e-03, +-8.96378227929317322395e-04, +-7.92004943969952133684e-04, +-6.87256841697829728294e-04, +-5.82194029843374478810e-04, +-4.76876752240620047432e-04, +-3.71365353315354857280e-04, +-2.65720243541443139953e-04, +-1.60001864885065504330e-04, +-5.42706562566359684624e-05, + 5.14129810098762333082e-05, + 1.56988717630401143676e-04, + 2.62396330778088919793e-04, + 3.67575738403138686013e-04, + 4.72467033447351674163e-04, + 5.77010517933939639720e-04, + 6.81146736911458490320e-04, + 7.84816512234211456633e-04, + 8.87960976159937634238e-04, + 9.90521604744005372892e-04, + 1.09244025101365264951e-03, + 1.19365917790164059384e-03, + 1.29412109092141174894e-03, + 1.39376917056518003293e-03, + 1.49254710440663968495e-03, + 1.59039911889015199951e-03, + 1.68727001078853872801e-03, + 1.78310517831170383361e-03, + 1.87785065184860474295e-03, + 1.97145312432514584547e-03, + 2.06385998116165444646e-03, + 2.15501932981150296637e-03, + 2.24488002886593339402e-03, + 2.33339171670872728634e-03, + 2.42050483970316981583e-03, + 2.50617067989698880798e-03, + 2.59034138222976727944e-03, + 2.67296998122616528970e-03, + 2.75401042716228762475e-03, + 2.83341761168887876915e-03, + 2.91114739289797088209e-03, + 2.98715661981875787653e-03, + 3.06140315632929442893e-03, + 3.13384590447068249811e-03, + 3.20444482715097822209e-03, + 3.27316097022614747175e-03, + 3.33995648394608485657e-03, + 3.40479464375383631194e-03, + 3.46763987042658736876e-03, + 3.52845774954753865424e-03, + 3.58721505029781922991e-03, + 3.64387974355847871905e-03, + 3.69842101931248078139e-03, + 3.75080930333746573671e-03, + 3.80101627318009003750e-03, + 3.84901487340377030863e-03, + 3.89477933010077409515e-03, + 3.93828516466203197577e-03, + 3.97950920679663710383e-03, + 4.01842960679405468427e-03, + 4.05502584702343085721e-03, + 4.08927875266308724772e-03, + 4.12117050165479448243e-03, + 4.15068463387839852591e-03, + 4.17780605954134933583e-03, + 4.20252106677934406803e-03, + 4.22481732846414353988e-03, + 4.24468390821542990859e-03, + 4.26211126561366546173e-03, + 4.27709126061177457440e-03, + 4.28961715714353680751e-03, + 4.29968362592737362443e-03, + 4.30728674646440722745e-03, + 4.31242400823038558866e-03, + 4.31509431106120045635e-03, + 4.31529796473259855127e-03, + 4.31303668773473300457e-03, + 4.30831360524300700093e-03, + 4.30113324628681858303e-03, + 4.29150154011852507513e-03, + 4.27942581178534283554e-03, + 4.26491477690706718290e-03, + 4.24797853566351822641e-03, + 4.22862856599543705111e-03, + 4.20687771602348218464e-03, + 4.18274019569020352044e-03, + 4.15623156763024730748e-03, + 4.12736873727475445106e-03, + 4.09616994219598982985e-03, + 4.06265474069904698046e-03, + 4.02684399966749852207e-03, + 3.98875988167053836808e-03, + 3.94842583133988254962e-03, + 3.90586656102404668894e-03, + 3.86110803572960138361e-03, + 3.81417745735749278216e-03, + 3.76510324824506480840e-03, + 3.71391503402302824294e-03, + 3.66064362579748142634e-03, + 3.60532100166869413568e-03, + 3.54798028759637515753e-03, + 3.48865573762383116702e-03, + 3.42738271347229261563e-03, + 3.36419766351780209421e-03, + 3.29913810116290494648e-03, + 3.23224258261611266038e-03, + 3.16355068409222362283e-03, + 3.09310297844691411973e-03, + 3.02094101125942446004e-03, + 2.94710727637745740354e-03, + 2.87164519093818793039e-03, + 2.79459906988119548971e-03, + 2.71601409996710457459e-03, + 2.63593631331708773413e-03, + 2.55441256048993380751e-03, + 2.47149048311133935976e-03, + 2.38721848607121494082e-03, + 2.30164570930673547527e-03, + 2.21482199918544885378e-03, + 2.12679787950668637911e-03, + 2.03762452213744876123e-03, + 1.94735371729998175613e-03, + 1.85603784352819439415e-03, + 1.76372983731039952200e-03, + 1.67048316243592642229e-03, + 1.57635177906330727939e-03, + 1.48139011252795978722e-03, + 1.38565302190747641209e-03, + 1.28919576836194387306e-03, + 1.19207398326919835826e-03, + 1.09434363617172251450e-03, + 9.96061002553666387932e-04, + 8.97282631468103723978e-04, + 7.98065313031665838489e-04, + 6.98466045805186700954e-04, + 5.98542004080726075879e-04, + 4.98350505091392156909e-04, + 3.97948976164492736543e-04, + 2.97394921836138706028e-04, + 1.96745890946085639616e-04, + 9.60594437324946328737e-05, +-4.60688105713253110850e-06, +-1.05195599015863548308e-04, +-2.05649312873547269803e-04, +-3.05910745218120614427e-04, +-4.05922771124209050102e-04, +-5.05628450670332911694e-04, +-6.04971061326233742333e-04, +-7.03894130191895397823e-04, +-8.02341466069983314836e-04, +-9.00257191353478103575e-04, +-9.97585773710441469850e-04, +-1.09427205754784526159e-03, +-1.19026129523734734011e-03, +-1.28549917808361388767e-03, +-1.37993186702002005456e-03, +-1.47350602301274868564e-03, +-1.56616883715618676436e-03, +-1.65786806044407471726e-03, +-1.74855203319811505248e-03, +-1.83816971413744510017e-03, +-1.92667070907424605244e-03, +-2.01400529921775661019e-03, +-2.10012446907152346490e-03, +-2.18497993390813667614e-03, +-2.26852416680606251351e-03, +-2.35071042523344675770e-03, +-2.43149277716405484012e-03, +-2.51082612671079579217e-03, +-2.58866623926247820323e-03, +-2.66496976610981501504e-03, +-2.73969426854743253880e-03, +-2.81279824143723829188e-03, +-2.88424113622183812475e-03, +-2.95398338337400341927e-03, +-3.02198641426984970434e-03, +-3.08821268247472897547e-03, +-3.15262568442887820136e-03, +-3.21518997952162247436e-03, +-3.27587120954407487808e-03, +-3.33463611750868180184e-03, +-3.39145256582575700330e-03, +-3.44628955382705274429e-03, +-3.49911723462676847382e-03, +-3.54990693131099601179e-03, +-3.59863115244673462817e-03, +-3.64526360690210944615e-03, +-3.68977921797001727142e-03, +-3.73215413678737884667e-03, +-3.77236575504307771953e-03, +-3.81039271696794737063e-03, +-3.84621493059991411204e-03, +-3.87981357831906903399e-03, +-3.91117112664715865095e-03, +-3.94027133530578613924e-03, +-3.96709926552936235911e-03, +-3.99164128762850064364e-03, +-4.01388508779965472173e-03, +-4.03381967417829664230e-03, +-4.05143538213234219447e-03, +-4.06672387879341342559e-03, +-4.07967816682406215351e-03, +-4.09029258741918071846e-03, +-4.09856282254066582593e-03, +-4.10448589638437531107e-03, +-4.10806017607942119269e-03, +-4.10928537161966977997e-03, +-4.10816253502826328470e-03, +-4.10469405875612397550e-03, +-4.09888367331595702275e-03, +-4.09073644415366196453e-03, +-4.08025876775947385355e-03, +-4.06745836702175275756e-03, +-4.05234428582641227623e-03, +-4.03492688290585550803e-03, +-4.01521782494141353526e-03, +-3.99323007892370650251e-03, +-3.96897790377597620148e-03, +-3.94247684124562208785e-03, +-3.91374370606971909436e-03, +-3.88279657542071584067e-03, +-3.84965477763883840226e-03, +-3.81433888025815110920e-03, +-3.77687067733369942479e-03, +-3.73727317607745312261e-03, +-3.69557058281119732435e-03, +-3.65178828824497432592e-03, +-3.60595285208962579651e-03, +-3.55809198701380119054e-03, +-3.50823454195329457322e-03, +-3.45641048478445914172e-03, +-3.40265088437114587849e-03, +-3.34698789199610203388e-03, +-3.28945472218769140865e-03, +-3.23008563295407733276e-03, +-3.16891590543550479703e-03, +-3.10598182298758417746e-03, +-3.04132064970752489380e-03, +-2.97497060841662606598e-03, +-2.90697085811037359698e-03, +-2.83736147089205630045e-03, +-2.76618340840093044491e-03, +-2.69347849775016792359e-03, +-2.61928940698839384654e-03, +-2.54365962009905433386e-03, +-2.46663341155241517058e-03, +-2.38825582042492129409e-03, +-2.30857262410112847040e-03, +-2.22763031157348617012e-03, +-2.14547605635553037887e-03, +-2.06215768902437597554e-03, +-1.97772366940784189923e-03, +-1.89222305843385276043e-03, +-1.80570548965651076455e-03, +-1.71822114047665615993e-03, +-1.62982070307368252966e-03, +-1.54055535506404249653e-03, +-1.45047672990482020075e-03, +-1.35963688705958486193e-03, +-1.26808828194214899543e-03, +-1.17588373565714085327e-03, +-1.08307640455412444898e-03, +-9.89719749612947034476e-04, +-8.95867505677916593256e-04, +-8.01573650558492470548e-04, +-7.06892374014246962534e-04, +-6.11878046641902415860e-04, +-5.16585188682274517973e-04, +-4.21068438765152331434e-04, +-3.25382522609281570492e-04, +-2.29582221697126570396e-04, +-1.33722341940000448565e-04, +-3.78576823531001234436e-05, + 5.79569962416860487149e-05, + 1.53667002468926312949e-04, + 2.49217745588539837595e-04, + 3.44554766605055051796e-04, + 4.39623769277135254159e-04, + 5.34370651012117960608e-04, + 6.28741533626295430459e-04, + 7.22682793954151111819e-04, + 8.16141094289066942359e-04, + 9.09063412638226858026e-04, + 1.00139707277458692852e-03, + 1.09308977406887886975e-03, + 1.18408962108478813154e-03, + 1.27434515292056300961e-03, + 1.36380537228036891051e-03, + 1.45241977425964634632e-03, + 1.54013837482673316033e-03, + 1.62691173898619058195e-03, + 1.71269100860800766242e-03, + 1.79742792990551444876e-03, + 1.88107488054797562099e-03, + 1.96358489639263892462e-03, + 2.04491169781978020942e-03, + 2.12500971565807118477e-03, + 2.20383411668426208024e-03, + 2.28134082868343369618e-03, + 2.35748656505591286728e-03, + 2.43222884895690980023e-03, + 2.50552603695564177905e-03, + 2.57733734220062273013e-03, + 2.64762285707839271562e-03, + 2.71634357535300218975e-03, + 2.78346141377399823244e-03, + 2.84893923314137337971e-03, + 2.91274085881481313576e-03, + 2.97483110065697737429e-03, + 3.03517577239990551941e-03, + 3.09374171042274635074e-03, + 3.15049679193164094970e-03, + 3.20540995253164491541e-03, + 3.25845120318029885659e-03, + 3.30959164651485658951e-03, + 3.35880349254337635945e-03, + 3.40606007369155918199e-03, + 3.45133585919722533919e-03, + 3.49460646884427843240e-03, + 3.53584868602997270254e-03, + 3.57504047015665300802e-03, + 3.61216096834317094977e-03, + 3.64719052644881403663e-03, + 3.68011069940423060295e-03, + 3.71090426084389433947e-03, + 3.73955521203543422501e-03, + 3.76604879010044787946e-03, + 3.79037147552388660465e-03, + 3.81251099894702218107e-03, + 3.83245634724140764663e-03, + 3.85019776886061934965e-03, + 3.86572677846735036217e-03, + 3.87903616083361702654e-03, + 3.89011997401263057497e-03, + 3.89897355178084716390e-03, + 3.90559350534943564709e-03, + 3.90997772434472940645e-03, + 3.91212537705771124658e-03, + 3.91203690996272997887e-03, + 3.90971404650655458141e-03, + 3.90515978516874822171e-03, + 3.89837839679519444422e-03, + 3.88937542120674139765e-03, + 3.87815766308545256322e-03, + 3.86473318714143513133e-03, + 3.84911131256343097898e-03, + 3.83130260675695194506e-03, + 3.81131887837403860592e-03, + 3.78917316963920574116e-03, + 3.76487974797630508064e-03, + 3.73845409694197614373e-03, + 3.70991290647096740377e-03, + 3.67927406243961268098e-03, + 3.64655663555414144908e-03, + 3.61178086957013007655e-03, + 3.57496816885076278136e-03, + 3.53614108527169294233e-03, + 3.49532330447974940585e-03, + 3.45253963151448796734e-03, + 3.40781597580096327210e-03, + 3.36117933552288828195e-03, + 3.31265778138546554757e-03, + 3.26228043977774525078e-03, + 3.21007747534444651261e-03, + 3.15608007297777824404e-03, + 3.10032041923983094425e-03, + 3.04283168322677004605e-03, + 2.98364799688597944274e-03, + 2.92280443479772233245e-03, + 2.86033699343400974954e-03, + 2.79628256990564587336e-03, + 2.73067894021140553096e-03, + 2.66356473700054630430e-03, + 2.59497942686348799513e-03, + 2.52496328716229770719e-03, + 2.45355738241618799925e-03, + 2.38080354025428783324e-03, + 2.30674432695083695896e-03, + 2.23142302255665983882e-03, + 2.15488359564151290768e-03, + 2.07717067766201215345e-03, + 1.99832953697007134966e-03, + 1.91840605247694541945e-03, + 1.83744668698823622119e-03, + 1.75549846022528331473e-03, + 1.67260892154870227308e-03, + 1.58882612239931203697e-03, + 1.50419858847373826526e-03, + 1.41877529164945908116e-03, + 1.33260562167547579916e-03, + 1.24573935764636829771e-03, + 1.15822663927488351057e-03, + 1.07011793797963318704e-03, + 9.81464027805968499546e-04, + 8.92315956194724064533e-04, + 8.02725014617197869804e-04, + 7.12742709092594579033e-04, + 6.22420730605006554577e-04, + 5.31810925436872606979e-04, + 4.40965265435949780974e-04, + 3.49935818232817224746e-04, + 2.58774717425973744146e-04, + 1.67534132751585059917e-04, + 7.62662402549235993827e-05, +-1.49768075193361299620e-05, +-1.06142911301720894524e-04, +-1.97180054818197052647e-04, +-2.88036334442900109586e-04, +-3.78659988762671830508e-04, +-4.68999428038859239934e-04, +-5.59003263548750505343e-04, +-6.48620336790735633678e-04, +-7.37799748534993023869e-04, +-8.26490887705368343190e-04, +-9.14643460074474100654e-04, +-1.00220751675647416767e-03, +-1.08913348248064457101e-03, +-1.17537218363183721542e-03, +-1.26087487603843595614e-03, +-1.34559327249569936173e-03, +-1.42947957000680455318e-03, +-1.51248647672699333688e-03, +-1.59456723859538701364e-03, +-1.67567566564024317960e-03, +-1.75576615794077609337e-03, +-1.83479373123439024051e-03, +-1.91271404215155051663e-03, +-1.98948341306622901448e-03, +-2.06505885654718109729e-03, +-2.13939809939708890443e-03, +-2.21245960626475536570e-03, +-2.28420260281900038002e-03, +-2.35458709846996828985e-03, +-2.42357390862588594968e-03, +-2.49112467647214820554e-03, +-2.55720189426249895279e-03, +-2.62176892410749236631e-03, +-2.68479001825172808662e-03, +-2.74623033882684950205e-03, +-2.80605597707006462066e-03, +-2.86423397199746590513e-03, +-2.92073232852189295164e-03, +-2.97552003500548174764e-03, +-3.02856708023718085299e-03, +-3.07984446982606822549e-03, +-3.12932424200147371596e-03, +-3.17697948281127698356e-03, +-3.22278434071057110627e-03, +-3.26671404053182311278e-03, +-3.30874489683027862494e-03, +-3.34885432659656149396e-03, +-3.38702086132979581640e-03, +-3.42322415846545938939e-03, +-3.45744501215092866347e-03, +-3.48966536336403100604e-03, +-3.51986830936835840347e-03, +-3.54803811250142776476e-03, +-3.57416020829039995585e-03, +-3.59822121289160232194e-03, +-3.62020892984994159536e-03, +-3.64011235617500532313e-03, +-3.65792168773078438943e-03, +-3.67362832393644143589e-03, +-3.68722487177608991560e-03, +-3.69870514911562918089e-03, +-3.70806418732541956396e-03, +-3.71529823320771324796e-03, +-3.72040475022829665933e-03, +-3.72338241905218391911e-03, +-3.72423113738358209715e-03, +-3.72295201911065475747e-03, +-3.71954739275624172296e-03, +-3.71402079923576107501e-03, +-3.70637698892428832029e-03, +-3.69662191803482587105e-03, +-3.68476274431051497790e-03, +-3.67080782203360296914e-03, +-3.65476669635465692756e-03, +-3.63665009694570488807e-03, +-3.61646993098150822468e-03, +-3.59423927545334974051e-03, +-3.56997236882036642416e-03, +-3.54368460200365923210e-03, +-3.51539250872874575737e-03, +-3.48511375522234101432e-03, +-3.45286712927017321387e-03, +-3.41867252864195810338e-03, +-3.38255094889135894329e-03, +-3.34452447053745815023e-03, +-3.30461624563659203332e-03, +-3.26285048375162325951e-03, +-3.21925243732817121037e-03, +-3.17384838648557959795e-03, +-3.12666562323245288482e-03, +-3.07773243511595077232e-03, +-3.02707808831462633209e-03, +-2.97473281018491211153e-03, +-2.92072777127162135427e-03, +-2.86509506679312160940e-03, +-2.80786769761221183597e-03, +-2.74907955070388763247e-03, +-2.68876537913161550372e-03, +-2.62696078154390838186e-03, +-2.56370218120280770127e-03, +-2.49902680455817757105e-03, +-2.43297265937776879124e-03, +-2.36557851244843493979e-03, +-2.29688386686014139187e-03, +-2.22692893888647245465e-03, +-2.15575463447475546355e-03, +-2.08340252536062418495e-03, +-2.00991482481939400667e-03, +-1.93533436306957584878e-03, +-1.85970456234225522789e-03, +-1.78306941163151812420e-03, +-1.70547344113878836074e-03, +-1.62696169642893568967e-03, +-1.54757971231007083503e-03, +-1.46737348645403320284e-03, +-1.38638945277216006635e-03, +-1.30467445456199375615e-03, +-1.22227571743970366350e-03, +-1.13924082207588254177e-03, +-1.05561767674710021286e-03, +-9.71454489722374482305e-04, +-8.86799741498446592036e-04, +-8.01702156900612784851e-04, +-7.16210677064451489704e-04, +-6.30374431316047391209e-04, +-5.44242708964845500752e-04, +-4.57864931026830763918e-04, +-3.71290621893513930751e-04, +-2.84569380963795102567e-04, +-1.97750854252763154373e-04, +-1.10884705997269506742e-04, +-2.40205902709113495357e-05, + 6.27918773732192452876e-05, + 1.49503148216553689897e-04, + 2.36063768629587555480e-04, + 3.22424408250847381943e-04, + 4.08535888074242200738e-04, + 4.94349208428819172911e-04, + 5.79815576835024100270e-04, + 6.64886435721643610786e-04, + 7.49513489987693693958e-04, + 8.33648734393532949913e-04, + 9.17244480766279870337e-04, + 1.00025338500262374157e-03, + 1.08262847385585773974e-03, + 1.16432317148991437694e-03, + 1.24529132578744816673e-03, + 1.32548723439501444157e-03, + 1.40486567049264701387e-03, + 1.48338190827135567480e-03, + 1.56099174810615912330e-03, + 1.63765154140913405528e-03, + 1.71331821514903869137e-03, + 1.78794929602366808354e-03, + 1.86150293427143464359e-03, + 1.93393792710878204520e-03, + 2.00521374178037978947e-03, + 2.07529053820916823889e-03, + 2.14412919123365373897e-03, + 2.21169131241997444365e-03, + 2.27793927143706215546e-03, + 2.34283621698181060769e-03, + 2.40634609724435857836e-03, + 2.46843367990040021484e-03, + 2.52906457162119062410e-03, + 2.58820523708867778964e-03, + 2.64582301750689681194e-03, + 2.70188614859793313494e-03, + 2.75636377807397716516e-03, + 2.80922598257490408261e-03, + 2.86044378406247841104e-03, + 2.90998916566214413729e-03, + 2.95783508694383865181e-03, + 3.00395549863343705108e-03, + 3.04832535674689130908e-03, + 3.09092063613944411163e-03, + 3.13171834346257340134e-03, + 3.17069652952171746399e-03, + 3.20783430102820335192e-03, + 3.24311183173923859094e-03, + 3.27651037297958976080e-03, + 3.30801226353996018562e-03, + 3.33760093894684218077e-03, + 3.36526094009848182609e-03, + 3.39097792126302451446e-03, + 3.41473865743472130771e-03, + 3.43653105104400240569e-03, + 3.45634413801872283564e-03, + 3.47416809319318680913e-03, + 3.48999423506242021850e-03, + 3.50381502987956103268e-03, + 3.51562409509444421737e-03, + 3.52541620213190926708e-03, + 3.53318727850884806152e-03, + 3.53893440928911917967e-03, + 3.54265583787610402466e-03, + 3.54435096614294726028e-03, + 3.54402035390087273917e-03, + 3.54166571770637159458e-03, + 3.53728992900847680203e-03, + 3.53089701163765857378e-03, + 3.52249213863829475218e-03, + 3.51208162844697177607e-03, + 3.49967294041929766896e-03, + 3.48527466970839335317e-03, + 3.46889654149831836577e-03, + 3.45054940459623565863e-03, + 3.43024522438756772347e-03, + 3.40799707515864217997e-03, + 3.38381913179134578146e-03, + 3.35772666083566971931e-03, + 3.32973601096507977951e-03, + 3.29986460282096893265e-03, + 3.26813091825231636506e-03, + 3.23455448895733962272e-03, + 3.19915588453362383092e-03, + 3.16195669994496055336e-03, + 3.12297954241108925363e-03, + 3.08224801772958309845e-03, + 3.03978671603739392451e-03, + 2.99562119702084100892e-03, + 2.94977797458266955549e-03, + 2.90228450097598702356e-03, + 2.85316915041365507313e-03, + 2.80246120216355544194e-03, + 2.75019082313949451285e-03, + 2.69638904999837305393e-03, + 2.64108777075355415781e-03, + 2.58431970591592842859e-03, + 2.52611838917400372689e-03, + 2.46651814762340482884e-03, + 2.40555408155839313758e-03, + 2.34326204383680314694e-03, + 2.27967861883065755005e-03, + 2.21484110097475844769e-03, + 2.14878747292579150296e-03, + 2.08155638334478173060e-03, + 2.01318712431581723840e-03, + 1.94371960841423544429e-03, + 1.87319434543773495790e-03, + 1.80165241881343461162e-03, + 1.72913546169589605814e-03, + 1.65568563276817190023e-03, + 1.58134559176179804313e-03, + 1.50615847470803379538e-03, + 1.43016786893666826216e-03, + 1.35341778783496088576e-03, + 1.27595264538327276757e-03, + 1.19781723048013573688e-03, + 1.11905668107298707052e-03, + 1.03971645810893640986e-03, + 9.59842319320685158357e-04, + 8.79480292862680045757e-04, + 7.98676650812700722817e-04, + 7.17477882554103476610e-04, + 6.35930668054020351715e-04, + 5.54081851052870642121e-04, + 4.71978412180657619888e-04, + 3.89667442014872736876e-04, + 3.07196114096923401319e-04, + 2.24611657920471623987e-04, + 1.41961331909191799819e-04, + 5.92923963973368171269e-05, +-2.33479133692958273222e-05, +-1.05912414198647058736e-04, +-1.88354001866488713528e-04, +-2.70625677966048025676e-04, +-3.52680576676401690700e-04, +-4.34471991434995103831e-04, +-5.15953401499023248805e-04, +-5.97078498380584432939e-04, +-6.77801212140594598610e-04, +-7.58075737526550121580e-04, +-8.37856559939326346609e-04, +-9.17098481214296688997e-04, +-9.95756645202195691743e-04, +-1.07378656313515804741e-03, +-1.15114413876416595180e-03, +-1.22778569325242541826e-03, +-1.30366798981191894975e-03, +-1.37874825806924973352e-03, +-1.45298421814578576985e-03, +-1.52633410443975465511e-03, +-1.59875668909689456869e-03, +-1.67021130515527735372e-03, +-1.74065786935308415041e-03, +-1.81005690458521380053e-03, +-1.87836956199671648374e-03, +-1.94555764270060572822e-03, +-2.01158361910792719829e-03, +-2.07641065585818058656e-03, +-2.14000263033844919519e-03, +-2.20232415277983682028e-03, +-2.26334058592000822788e-03, +-2.32301806422092246146e-03, +-2.38132351263152302820e-03, +-2.43822466488363524817e-03, +-2.49369008131333563458e-03, +-2.54768916619557087705e-03, +-2.60019218458394001450e-03, +-2.65117027864584945199e-03, +-2.70059548348453026811e-03, +-2.74844074243833736901e-03, +-2.79467992185021508675e-03, +-2.83928782529839322801e-03, +-2.88224020728095487592e-03, +-2.92351378634650351657e-03, +-2.96308625766492647960e-03, +-3.00093630502965393395e-03, +-3.03704361228680124254e-03, +-3.07138887418407363628e-03, +-3.10395380663392372531e-03, +-3.13472115638562150164e-03, +-3.16367471010103352980e-03, +-3.19079930282948481812e-03, +-3.21608082587721087059e-03, +-3.23950623406747337252e-03, +-3.26106355238757342555e-03, +-3.28074188201942212179e-03, +-3.29853140575076496377e-03, +-3.31442339276444199875e-03, +-3.32841020280317178778e-03, +-3.34048528970836431165e-03, +-3.35064320433112964454e-03, +-3.35887959681426418596e-03, +-3.36519121824467148246e-03, +-3.36957592167543267675e-03, +-3.37203266251754653349e-03, +-3.37256149830169856332e-03, +-3.37116358781047254292e-03, +-3.36784118958214327699e-03, +-3.36259765978729266434e-03, +-3.35543744947994172431e-03, +-3.34636610122527418040e-03, +-3.33539024510636330015e-03, +-3.32251759411259645072e-03, +-3.30775693891291596924e-03, +-3.29111814201739957125e-03, +-3.27261213133083796178e-03, +-3.25225089310266250384e-03, +-3.23004746427743008250e-03, +-3.20601592425105112044e-03, +-3.18017138603743105413e-03, +-3.15252998685158682818e-03, +-3.12310887811450286003e-03, +-3.09192621488647281444e-03, +-3.05900114473474978721e-03, +-3.02435379604281111970e-03, +-2.98800526576807482307e-03, +-2.94997760665555814816e-03, +-2.91029381391519391745e-03, +-2.86897781137080603100e-03, +-2.82605443708909163589e-03, +-2.78154942849715867623e-03, +-2.73548940699755568570e-03, +-2.68790186208995533074e-03, +-2.63881513500899191754e-03, +-2.58825840188760128782e-03, +-2.53626165645667129775e-03, +-2.48285569229048054193e-03, +-2.42807208460824822810e-03, +-2.37194317164358134745e-03, +-2.31450203559181158161e-03, +-2.25578248314654231793e-03, +-2.19581902563767547218e-03, +-2.13464685878131952071e-03, +-2.07230184205435888356e-03, +-2.00882047770541138920e-03, +-1.94423988941450141647e-03, +-1.87859780061385762441e-03, +-1.81193251248255946667e-03, +-1.74428288162779420063e-03, +-1.67568829746571096480e-03, +-1.60618865931505343768e-03, +-1.53582435321696704651e-03, +-1.46463622849387254017e-03, +-1.39266557406221786267e-03, +-1.31995409451166924308e-03, +-1.24654388596452171158e-03, +-1.17247741173051502755e-03, +-1.09779747777003140220e-03, +-1.02254720797977159512e-03, +-9.46770019316456627398e-04, +-8.70509596771090981941e-04, +-7.93809868209522859206e-04, +-7.16714979093283142790e-04, +-6.39269267095267379464e-04, +-5.61517236624901622949e-04, +-4.83503533277372383840e-04, +-4.05272918221601325187e-04, +-3.26870242541634718064e-04, +-2.48340421546139789206e-04, +-1.69728409060813500292e-04, +-9.10791717177389864102e-05, +-1.24376632583528602298e-05, + 6.61512011385834202077e-05, + 1.44642570486082041627e-04, + 2.22991683562456983764e-04, + 3.01153894413956873654e-04, + 3.79084697772648165047e-04, + 4.56739754373683643027e-04, + 5.34074916159440896482e-04, + 6.11046251354811493887e-04, + 6.87610069400060091790e-04, + 7.63722945726494719700e-04, + 8.39341746362165606193e-04, + 9.14423652352394037562e-04, + 9.88926183981333204245e-04, + 1.06280722478213824657e-03, + 1.13602504532090125416e-03, + 1.20853832674150526647e-03, + 1.28030618405801659317e-03, + 1.35128818918151915977e-03, + 1.42144439366839823308e-03, + 1.49073535117733935521e-03, + 1.55912213962240372468e-03, + 1.62656638300974010561e-03, + 1.69303027294565532589e-03, + 1.75847658980445606218e-03, + 1.82286872354303674040e-03, + 1.88617069415219075317e-03, + 1.94834717173209578771e-03, + 2.00936349618086648045e-03, + 2.06918569648611430298e-03, + 2.12778050960779879092e-03, + 2.18511539894190561298e-03, + 2.24115857235570323583e-03, + 2.29587899978361603334e-03, + 2.34924643037442331187e-03, + 2.40123140918023199666e-03, + 2.45180529337806233856e-03, + 2.50094026801512278949e-03, + 2.54860936126915377242e-03, + 2.59478645921546943742e-03, + 2.63944632009264395014e-03, + 2.68256458805902911827e-03, + 2.72411780643292029958e-03, + 2.76408343040847976832e-03, + 2.80243983924151687792e-03, + 2.83916634789766180597e-03, + 2.87424321815756868281e-03, + 2.90765166917223739917e-03, + 2.93937388746383842716e-03, + 2.96939303636573146555e-03, + 2.99769326489773184699e-03, + 3.02425971607121193627e-03, + 3.04907853462010837095e-03, + 3.07213687415372471712e-03, + 3.09342290372770093235e-03, + 3.11292581382988705480e-03, + 3.13063582177805889775e-03, + 3.14654417652693004295e-03, + 3.16064316288211652126e-03, + 3.17292610511905577922e-03, + 3.18338737000537549265e-03, + 3.19202236922536521438e-03, + 3.19882756120557767629e-03, + 3.20380045234103065510e-03, + 3.20693959762191095619e-03, + 3.20824460066048821466e-03, + 3.20771611311912148781e-03, + 3.20535583353980316201e-03, + 3.20116650557659455922e-03, + 3.19515191563226816363e-03, + 3.18731688990105815895e-03, + 3.17766729081954413250e-03, + 3.16621001292834072099e-03, + 3.15295297814715538495e-03, + 3.13790513046660092533e-03, + 3.12107643006004570677e-03, + 3.10247784681945935892e-03, + 3.08212135331927200924e-03, + 3.06001991721279766046e-03, + 3.03618749306580832173e-03, + 3.01063901363274712478e-03, + 2.98339038058057295921e-03, + 2.95445845466603060347e-03, + 2.92386104537267895939e-03, + 2.89161690001368777356e-03, + 2.85774569230700953987e-03, + 2.82226801043036334277e-03, + 2.78520534456247253682e-03, + 2.74658007391870816194e-03, + 2.70641545328861908917e-03, + 2.66473559908350773537e-03, + 2.62156547490237238143e-03, + 2.57693087662487496647e-03, + 2.53085841704014631939e-03, + 2.48337551002058860156e-03, + 2.43451035425012096355e-03, + 2.38429191651639985419e-03, + 2.33274991457697866704e-03, + 2.27991479960949847833e-03, + 2.22581773825620892956e-03, + 2.17049059427346612006e-03, + 2.11396590979692159534e-03, + 2.05627688623344091062e-03, + 1.99745736479101619609e-03, + 1.93754180665763118922e-03, + 1.87656527284175219002e-03, + 1.81456340368482097088e-03, + 1.75157239805861998823e-03, + 1.68762899225976484990e-03, + 1.62277043861255095177e-03, + 1.55703448379367948885e-03, + 1.49045934689147926804e-03, + 1.42308369721128166394e-03, + 1.35494663184088722126e-03, + 1.28608765298868091623e-03, + 1.21654664510756371255e-03, + 1.14636385181799576628e-03, + 1.07557985264340023011e-03, + 1.00423553957145047719e-03, + 9.32372093454700246948e-04, + 8.60030960264205842671e-04, + 7.87253827209889473632e-04, + 7.14082598740849215993e-04, + 6.40559372440761354631e-04, + 5.66726414830463851718e-04, + 4.92626137092837322433e-04, + 4.18301070733919581456e-04, + 3.43793843193061820010e-04, + 2.69147153417339558834e-04, + 1.94403747414189487621e-04, + 1.19606393795037383994e-04, + 4.47978593251173554416e-05, +-2.99791155070713611101e-05, +-1.04681840886644762128e-04, +-1.79267702021634553217e-04, +-2.53694183430834704039e-04, +-3.27918893156363931707e-04, +-4.01899586887169662890e-04, +-4.75594191979749616409e-04, +-5.48960831362461866741e-04, +-6.21957847309750270874e-04, +-6.94543825073334680428e-04, +-7.66677616355743358524e-04, +-8.38318362614142603174e-04, +-9.09425518181231052305e-04, +-9.79958873188954042791e-04, +-1.04987857628321295568e-03, +-1.11914515711671069299e-03, +-1.18771954860611567151e-03, +-1.25556310894265384798e-03, +-1.32263764334250685968e-03, +-1.38890542552527339500e-03, +-1.45432921890835268122e-03, +-1.51887229750536853490e-03, +-1.58249846651689705240e-03, +-1.64517208260199325476e-03, +-1.70685807381915056156e-03, +-1.76752195922558370811e-03, +-1.82712986812380161379e-03, +-1.88564855894518047276e-03, +-1.94304543775902804383e-03, +-1.99928857639786617534e-03, +-2.05434673018880555040e-03, +-2.10818935528026517312e-03, +-2.16078662555535365442e-03, +-2.21210944912246043961e-03, +-2.26212948437317816139e-03, +-2.31081915559989232653e-03, +-2.35815166816356804741e-03, +-2.40410102320373414084e-03, +-2.44864203188258338501e-03, +-2.49175032915539568928e-03, +-2.53340238705979841141e-03, +-2.57357552751657147824e-03, +-2.61224793463516640271e-03, +-2.64939866651717941329e-03, +-2.68500766655144999101e-03, +-2.71905577419492448452e-03, +-2.75152473523297344538e-03, +-2.78239721151426859513e-03, +-2.81165679015500094215e-03, +-2.83928799220713222809e-03, +-2.86527628078656016949e-03, +-2.88960806865697647852e-03, +-2.91227072526506090486e-03, +-2.93325258322398594105e-03, +-2.95254294424161442545e-03, +-2.97013208449042583406e-03, +-2.98601125941669364242e-03, +-3.00017270798633986159e-03, +-3.01260965636595103370e-03, +-3.02331632103655656429e-03, +-3.03228791133956007003e-03, +-3.03952063145331409857e-03, +-3.04501168179985596748e-03, +-3.04875925988140573583e-03, +-3.05076256054652829655e-03, +-3.05102177568631911103e-03, +-3.04953809336118561099e-03, +-3.04631369635912632385e-03, +-3.04135176018685343333e-03, +-3.03465645049527405624e-03, +-3.02623291994119940004e-03, +-3.01608730448767094895e-03, +-3.00422671914520132003e-03, +-2.99065925315701369377e-03, +-2.97539396463139928575e-03, +-2.95844087462449664011e-03, +-2.93981096067755893683e-03, +-2.91951614981275815730e-03, +-2.89756931099181044148e-03, +-2.87398424704220179990e-03, +-2.84877568605616283970e-03, +-2.82195927226750430117e-03, +-2.79355155641210087594e-03, +-2.76356998557781771697e-03, +-2.73203289255012551212e-03, +-2.69895948465983821080e-03, +-2.66436983213977395327e-03, +-2.62828485599736526648e-03, +-2.59072631541029923391e-03, +-2.55171679465334083972e-03, +-2.51127968956342670012e-03, +-2.46943919355152629105e-03, +-2.42622028316987056393e-03, +-2.38164870324227831086e-03, +-2.33575095156724138815e-03, +-2.28855426320279282948e-03, +-2.24008659434175860792e-03, +-2.19037660578759365432e-03, +-2.13945364604031535577e-03, +-2.08734773400249444888e-03, +-2.03408954131547529270e-03, +-1.97971037433622041798e-03, +-1.92424215576537916382e-03, +-1.86771740593727280343e-03, +-1.81016922378279560696e-03, +-1.75163126747638459545e-03, +-1.69213773477834518097e-03, +-1.63172334308366137785e-03, +-1.57042330918990852978e-03, +-1.50827332879462073199e-03, +-1.44530955573546056152e-03, +-1.38156858098379938318e-03, +-1.31708741140545613178e-03, +-1.25190344829938021362e-03, +-1.18605446572830376673e-03, +-1.11957858865226037894e-03, +-1.05251427087881964557e-03, +-9.84900272842268017723e-04, +-9.16775639224670039346e-04, +-8.48179676431708726506e-04, +-7.79151929936275832941e-04, +-7.09732161502877071865e-04, +-6.39960326305943926796e-04, +-5.69876549955214807899e-04, +-4.99521105441456947371e-04, +-4.28934390015275781964e-04, +-3.58156902013427212109e-04, +-2.87229217644762195236e-04, +-2.16191967749079295199e-04, +-1.45085814543370996213e-04, +-7.39514283676623567637e-05, +-2.82946444373383170840e-06, + 6.82394603388270838424e-05, + 1.39214790597688687322e-04, + 2.10056055579472498182e-04, + 2.80722892215425577894e-04, + 3.51175068097857930472e-04, + 4.21372504364276407804e-04, + 4.91275298476219653143e-04, + 5.60843746879846811494e-04, + 6.30038367535434352430e-04, + 6.98819922302998017792e-04, + 7.67149439171379990757e-04, + 8.34988234318114982448e-04, + 9.02297933988172430955e-04, + 9.69040496177550657667e-04, + 1.03517823211224553603e-03, + 1.10067382750771766003e-03, + 1.16549036359852469825e-03, + 1.22959133792568584519e-03, + 1.29294068487057216450e-03, + 1.35550279592269035112e-03, + 1.41724253967147762606e-03, + 1.47812528150976737508e-03, + 1.53811690303841180558e-03, + 1.59718382116064388891e-03, + 1.65529300685696286952e-03, + 1.71241200362764220237e-03, + 1.76850894559496454178e-03, + 1.82355257525374002750e-03, + 1.87751226086060006570e-03, + 1.93035801345242652959e-03, + 1.98206050348444977674e-03, + 2.03259107707881624474e-03, + 2.08192177187458684826e-03, + 2.13002533247049928231e-03, + 2.17687522545193749141e-03, + 2.22244565399375279199e-03, + 2.26671157203132793423e-03, + 2.30964869799124257813e-03, + 2.35123352807515510060e-03, + 2.39144334908883470295e-03, + 2.43025625080947474746e-03, + 2.46765113788514900417e-03, + 2.50360774125928499736e-03, + 2.53810662911404865891e-03, + 2.57112921732736803004e-03, + 2.60265777943738526798e-03, + 2.63267545610921865559e-03, + 2.66116626409909065240e-03, + 2.68811510471097300096e-03, + 2.71350777174133141537e-03, + 2.73733095890790929794e-03, + 2.75957226675855411477e-03, + 2.78022020905670675522e-03, + 2.79926421864012953122e-03, + 2.81669465275010289657e-03, + 2.83250279782839122292e-03, + 2.84668087377948006433e-03, + 2.85922203769641003479e-03, + 2.87012038704810915068e-03, + 2.87937096232720231986e-03, + 2.88696974915680091081e-03, + 2.89291367985583221592e-03, + 2.89720063446215116837e-03, + 2.89982944121351280883e-03, + 2.90079987648640116524e-03, + 2.90011266419314345591e-03, + 2.89776947463821947862e-03, + 2.89377292283466130279e-03, + 2.88812656628207459208e-03, + 2.88083490220782285907e-03, + 2.87190336427351573453e-03, + 2.86133831874895577796e-03, + 2.84914706015623872201e-03, + 2.83533780638680265804e-03, + 2.81991969329480843959e-03, + 2.80290276877008005807e-03, + 2.78429798629470500945e-03, + 2.76411719798695795433e-03, + 2.74237314713741920855e-03, + 2.71907946024148436046e-03, + 2.69425063853359278432e-03, + 2.66790204902807304155e-03, + 2.64004991507226990932e-03, + 2.61071130641776349285e-03, + 2.57990412881558845576e-03, + 2.54764711314187488125e-03, + 2.51395980406045370728e-03, + 2.47886254822925330629e-03, + 2.44237648205756618242e-03, + 2.40452351902155575872e-03, + 2.36532633654565121670e-03, + 2.32480836245730617881e-03, + 2.28299376102392148624e-03, + 2.23990741857956789096e-03, + 2.19557492874996457166e-03, + 2.15002257728523623811e-03, + 2.10327732650867141317e-03, + 2.05536679939101810111e-03, + 2.00631926325935171576e-03, + 1.95616361315094399245e-03, + 1.90492935482074665296e-03, + 1.85264658741337391243e-03, + 1.79934598580928591972e-03, + 1.74505878265607109780e-03, + 1.68981675009393424863e-03, + 1.63365218118834728926e-03, + 1.57659787107846988304e-03, + 1.51868709785361530318e-03, + 1.45995360316849881639e-03, + 1.40043157260870475105e-03, + 1.34015561581719584022e-03, + 1.27916074639499105850e-03, + 1.21748236158513117693e-03, + 1.15515622175421423141e-03, + 1.09221842968186999730e-03, + 1.02870540967075650360e-03, + 9.64653886488606908747e-04, + 9.00100864155625344717e-04, + 8.35083604587965547955e-04, + 7.69639606110740720837e-04, + 7.03806581852404870327e-04, + 6.37622438033560502181e-04, + 5.71125252161062339600e-04, + 5.04353251142653142593e-04, + 4.37344789331979761672e-04, + 3.70138326518233945050e-04, + 3.02772405872475636971e-04, + 2.35285631863361933882e-04, + 1.67716648154917370023e-04, + 1.00104115498995325769e-04, + 3.24866896350573601776e-05, +-3.50970007900988141157e-05, +-1.02608376270067855503e-04, +-1.70008928441366460871e-04, +-2.37260242028708613496e-04, +-3.04324016719330044459e-04, +-3.71162088955520488940e-04, +-4.37736453631852389604e-04, +-5.04009285684787491054e-04, +-5.69942961563439155249e-04, +-6.35500080568199678457e-04, +-7.00643486045153811477e-04, +-7.65336286425376288202e-04, +-8.29541876096107381675e-04, +-8.93223956092492241653e-04, +-9.56346554598112288600e-04, +-1.01887404724274391321e-03, +-1.08077117718591146113e-03, +-1.14200307497491554062e-03, +-1.20253527816616481716e-03, +-1.26233375069880002922e-03, +-1.32136490200969610419e-03, +-1.37959560587909771390e-03, +-1.43699321899669958842e-03, +-1.49352559923677944212e-03, +-1.54916112363357523669e-03, +-1.60386870604548384400e-03, +-1.65761781449959505821e-03, +-1.71037848820545417342e-03, +-1.76212135422995869009e-03, +-1.81281764382279454370e-03, +-1.86243920838466956759e-03, +-1.91095853506853020909e-03, +-1.95834876200555885878e-03, +-2.00458369314743039755e-03, +-2.04963781271666782222e-03, +-2.09348629925715234990e-03, +-2.13610503927705698904e-03, +-2.17747064047668550252e-03, +-2.21756044455409095234e-03, +-2.25635253958129250451e-03, +-2.29382577194474921237e-03, +-2.32995975784284353738e-03, +-2.36473489433514528352e-03, +-2.39813236993652442383e-03, +-2.43013417475133235504e-03, +-2.46072311014130552798e-03, +-2.48988279792284553787e-03, +-2.51759768908801960866e-03, +-2.54385307204538875167e-03, +-2.56863508037586708854e-03, +-2.59193070009968232204e-03, +-2.61372777645068558178e-03, +-2.63401502015447874783e-03, +-2.65278201320723284670e-03, +-2.67001921415216522324e-03, +-2.68571796285115840450e-03, +-2.69987048474913367627e-03, +-2.71246989462914107200e-03, +-2.72351019985639722365e-03, +-2.73298630310992796480e-03, +-2.74089400460035331406e-03, +-2.74723000377341628614e-03, +-2.75199190049820862497e-03, +-2.75517819574011687753e-03, +-2.75678829171838255668e-03, +-2.75682249154861379672e-03, +-2.75528199837085348636e-03, +-2.75216891396407340939e-03, +-2.74748623684835597061e-03, +-2.74123785987614347961e-03, +-2.73342856731443109575e-03, +-2.72406403141984849309e-03, +-2.71315080850912087457e-03, +-2.70069633452742902113e-03, +-2.68670892011764299301e-03, +-2.67119774519362050691e-03, +-2.65417285302107976847e-03, +-2.63564514380968837812e-03, +-2.61562636782076193137e-03, +-2.59412911799431541299e-03, +-2.57116682210057310998e-03, +-2.54675373442056615300e-03, +-2.52090492696093165098e-03, +-2.49363628020824292311e-03, +-2.46496447342882049614e-03, +-2.43490697451945311766e-03, +-2.40348202941552966175e-03, +-2.37070865106279527260e-03, +-2.33660660795969189057e-03, +-2.30119641227629137537e-03, +-2.26449930755836560670e-03, +-2.22653725602254669996e-03, +-2.18733292545093653547e-03, +-2.14690967569279187940e-03, +-2.10529154478122275743e-03, +-2.06250323467321427379e-03, +-2.01857009662140480036e-03, +-1.97351811618623213668e-03, +-1.92737389789730405483e-03, +-1.88016464957305564146e-03, +-1.83191816630788313451e-03, +-1.78266281413625186578e-03, +-1.73242751338296301945e-03, +-1.68124172171028180012e-03, +-1.62913541687057699184e-03, +-1.57613907917578230551e-03, +-1.52228367369270224489e-03, +-1.46760063217584650445e-03, +-1.41212183474704526358e-03, +-1.35587959133381627010e-03, +-1.29890662287597178325e-03, +-1.24123604231228925124e-03, +-1.18290133535796414613e-03, +-1.12393634108397949545e-03, +-1.06437523230972224016e-03, +-1.00425249582011886888e-03, +-9.43602912418799676629e-04, +-8.82461536828750689118e-04, +-8.20863677452122195502e-04, +-7.58844876000883323576e-04, +-6.96440887009666122730e-04, +-6.33687657243661695526e-04, +-5.70621305011907871928e-04, +-5.07278099399384235432e-04, +-4.43694439428299856887e-04, +-3.79906833162163342851e-04, +-3.15951876763069777060e-04, +-2.51866233515757136346e-04, +-1.87686612828893105692e-04, +-1.23449749226707587929e-04, +-5.91923813425564756662e-05, + 5.04876907352367874530e-06, + 6.92370181212766702379e-05, + 1.33335740678748094525e-04, + 1.97308391280935971606e-04, + 2.61118524936681541647e-04, + 3.24729817871949365607e-04, + 3.88106088187632042828e-04, + 4.51211316420591741425e-04, + 5.14009665995129438193e-04, + 5.76465503554872784643e-04, + 6.38543419161980286940e-04, + 7.00208246353774092785e-04, + 7.61425082043918786609e-04, + 8.22159306257914143483e-04, + 8.82376601691744100360e-04, + 9.42042973081658576232e-04, + 1.00112476637558055551e-03, + 1.05958868769426566188e-03, + 1.11740182207199128042e-03, + 1.17453165196615329918e-03, + 1.23094607552536169578e-03, + 1.28661342460581668880e-03, + 1.34150248252584160767e-03, + 1.39558250154863013048e-03, + 1.44882322008345787619e-03, + 1.50119487959565409141e-03, + 1.55266824121634344422e-03, + 1.60321460204141557661e-03, + 1.65280581111278590707e-03, + 1.70141428507094454904e-03, + 1.74901302347134422581e-03, + 1.79557562375571026954e-03, + 1.84107629587033070663e-03, + 1.88548987652245613779e-03, + 1.92879184306802143982e-03, + 1.97095832702225181102e-03, + 2.01196612718603342132e-03, + 2.05179272238057222588e-03, + 2.09041628378424165433e-03, + 2.12781568686330919971e-03, + 2.16397052289168034464e-03, + 2.19886111005235902402e-03, + 2.23246850411500585495e-03, + 2.26477450868369997727e-03, + 2.29576168500963484834e-03, + 2.32541336136273067009e-03, + 2.35371364195842858874e-03, + 2.38064741543364153872e-03, + 2.40620036286810995776e-03, + 2.43035896534666076563e-03, + 2.45311051105864775732e-03, + 2.47444310193039576293e-03, + 2.49434565978784222526e-03, + 2.51280793204573761265e-03, + 2.52982049692079043884e-03, + 2.54537476816590630541e-03, + 2.55946299932366090960e-03, + 2.57207828749620934228e-03, + 2.58321457663059431131e-03, + 2.59286666031753468623e-03, + 2.60103018410256332446e-03, + 2.60770164730860518412e-03, + 2.61287840436931441054e-03, + 2.61655866567281477839e-03, + 2.61874149791569560408e-03, + 2.61942682396747910170e-03, + 2.61861542224603579751e-03, + 2.61630892560461673912e-03, + 2.61250981973162573271e-03, + 2.60722144106427262261e-03, + 2.60044797421789914901e-03, + 2.59219444893257419671e-03, + 2.58246673653929684211e-03, + 2.57127154594804412449e-03, + 2.55861641916043432848e-03, + 2.54450972630984205078e-03, + 2.52896066023234862910e-03, + 2.51197923057173110040e-03, + 2.49357625742245613346e-03, + 2.47376336451454867035e-03, + 2.45255297194462698260e-03, + 2.42995828845761051989e-03, + 2.40599330328385152544e-03, + 2.38067277753669032450e-03, + 2.35401223517576205571e-03, + 2.32602795354144506468e-03, + 2.29673695346632733560e-03, + 2.26615698896941598212e-03, + 2.23430653653983570320e-03, + 2.20120478401572821497e-03, + 2.16687161906578855050e-03, + 2.13132761727950238717e-03, + 2.09459402987411226829e-03, + 2.05669277102470907798e-03, + 2.01764640482596626161e-03, + 1.97747813189227050409e-03, + 1.93621177560486024995e-03, + 1.89387176801387676663e-03, + 1.85048313540364336473e-03, + 1.80607148352974512806e-03, + 1.76066298253653116292e-03, + 1.71428435156398707023e-03, + 1.66696284305293466847e-03, + 1.61872622675783670206e-03, + 1.56960277347651289311e-03, + 1.51962123850639114868e-03, + 1.46881084483655192582e-03, + 1.41720126608627463617e-03, + 1.36482260919915132126e-03, + 1.31170539690283571681e-03, + 1.25788054994554945182e-03, + 1.20337936911878791608e-03, + 1.14823351707673366670e-03, + 1.09247499996376496584e-03, + 1.03613614885946750573e-03, + 9.79249601052817287769e-04, + 9.21848281156024094984e-04, + 8.63965382068984373391e-04, + 8.05634345805350776497e-04, + 7.46888844191288077054e-04, + 6.87762759448037191978e-04, + 6.28290164669462083795e-04, + 5.68505304205851338083e-04, + 5.08442573965285464499e-04, + 4.48136501643423001973e-04, + 3.87621726894541677056e-04, + 3.26932981452717592256e-04, + 2.66105069217038663586e-04, + 2.05172846310758418649e-04, + 1.44171201126380563911e-04, + 8.31350343675788742547e-05, + 2.20992391004467811420e-05, +-3.89013191759796718742e-05, +-9.98318224274676811183e-05, +-1.60657519939763258031e-04, +-2.21343748119307129384e-04, +-2.81855950229735626421e-04, +-3.42159696050412485968e-04, +-4.02220701448342615129e-04, +-4.62004847850846784695e-04, +-5.21478201608437975934e-04, +-5.80607033236791485534e-04, +-6.39357836527398360783e-04, +-6.97697347514598421869e-04, +-7.55592563290745562223e-04, +-8.13010760656402635231e-04, +-8.69919514596503569252e-04, +-9.26286716571595044288e-04, +-9.82080592613842522434e-04, +-1.03726972121798914454e-03, +-1.09182305101626067265e-03, +-1.14570991822856215955e-03, +-1.19890006387727231750e-03, +-1.25136365075697989814e-03, +-1.30307128015050440427e-03, +-1.35399400828092701665e-03, +-1.40410336249047434758e-03, +-1.45337135713807666729e-03, +-1.50177050920588701921e-03, +-1.54927385360641156620e-03, +-1.59585495818171090726e-03, +-1.64148793838632899543e-03, +-1.68614747164579970896e-03, +-1.72980881138278994556e-03, +-1.77244780070314389073e-03, +-1.81404088573422256521e-03, +-1.85456512860821833531e-03, +-1.89399822008349183119e-03, +-1.93231849179640994586e-03, +-1.96950492813784778720e-03, +-2.00553717774697637041e-03, +-2.04039556461697076800e-03, +-2.07406109880563802386e-03, +-2.10651548674606337030e-03, +-2.13774114115079620635e-03, +-2.16772119050517375963e-03, +-2.19643948814392904120e-03, +-2.22388062090664783907e-03, +-2.25002991736723010133e-03, +-2.27487345563314293309e-03, +-2.29839807071028278881e-03, +-2.32059136142953635965e-03, +-2.34144169693150825881e-03, +-2.36093822270602455432e-03, +-2.37907086618326232483e-03, +-2.39583034187382639194e-03, +-2.41120815605485715877e-03, +-2.42519661100030125764e-03, +-2.43778880875283833138e-03, +-2.44897865443608397581e-03, +-2.45876085910516064756e-03, +-2.46713094213460307561e-03, +-2.47408523314259810866e-03, +-2.47962087345062007909e-03, +-2.48373581707827476711e-03, +-2.48642883127294603979e-03, +-2.48769949657436095780e-03, +-2.48754820641444327964e-03, +-2.48597616625299746435e-03, +-2.48298539225010744813e-03, +-2.47857870947639034181e-03, +-2.47275974966242300529e-03, +-2.46553294848908619713e-03, +-2.45690354242066423887e-03, +-2.44687756508286339413e-03, +-2.43546184318826561266e-03, +-2.42266399201183056655e-03, +-2.40849241041931304286e-03, +-2.39295627545196452554e-03, +-2.37606553647086871789e-03, +-2.35783090886447369364e-03, +-2.33826386732362018900e-03, +-2.31737663868781000251e-03, +-2.29518219436743642001e-03, +-2.27169424234655459999e-03, +-2.24692721877107516593e-03, +-2.22089627912754614472e-03, +-2.19361728901783497453e-03, +-2.16510681453538442881e-03, +-2.13538211224875490099e-03, +-2.10446111879856838367e-03, +-2.07236244011410305002e-03, +-2.03910534025573964012e-03, +-2.00470972989070942219e-03, +-1.96919615440774254875e-03, +-1.93258578167894933507e-03, +-1.89490038947546677803e-03, +-1.85616235254462648083e-03, +-1.81639462935595909568e-03, +-1.77562074852458812169e-03, +-1.73386479491910482434e-03, +-1.69115139546278155785e-03, +-1.64750570463616328315e-03, +-1.60295338968996568633e-03, +-1.55752061557586866242e-03, +-1.51123402960583901912e-03, +-1.46412074584717846748e-03, +-1.41620832926347625658e-03, +-1.36752477961040201301e-03, +-1.31809851509572971071e-03, +-1.26795835581320162112e-03, +-1.21713350695978428199e-03, +-1.16565354184613783825e-03, +-1.11354838471016369394e-03, +-1.06084829334356697123e-03, +-1.00758384154156217620e-03, +-9.53785901385918667879e-04, +-8.99485625371226915105e-04, +-8.44714428385682711276e-04, +-7.89503969555520172287e-04, +-7.33886133964478507875e-04, +-6.77893014258843288299e-04, +-6.21556892147806690219e-04, +-5.64910219810742480866e-04, +-5.07985601222065157219e-04, +-4.50815773403514705956e-04, +-3.93433587615536740044e-04, +-3.35871990498167328609e-04, +-2.78164005172315390892e-04, +-2.20342712312250957329e-04, +-1.62441231200158043299e-04, +-1.04492700773580143945e-04, +-4.65302606765986506319e-05, + 1.14129676744331286925e-05, + 6.93038999997214335376e-05, + 1.27109508029058849467e-04, + 1.84796838327256962358e-04, + 2.42333031062709627164e-04, + 2.99685338706966609285e-04, + 3.56821144656121883639e-04, + 4.13707981761937345928e-04, + 4.70313550763611239701e-04, + 5.26605738608316954405e-04, + 5.82552636651546872429e-04, + 6.38122558725952955180e-04, + 6.93284059068853498672e-04, + 7.48005950098214232938e-04, + 8.02257320027068118913e-04, + 8.56007550306428347843e-04, + 9.09226332886875140971e-04, + 9.61883687289077828758e-04, + 1.01394997747366656139e-03, + 1.06539592850096254475e-03, + 1.11619264297115245756e-03, + 1.16631161723606104411e-03, + 1.21572475737255643845e-03, + 1.26440439490956338907e-03, + 1.31232330229981257463e-03, + 1.35945470812689692131e-03, + 1.40577231203991388428e-03, + 1.45125029940738111550e-03, + 1.49586335568145547929e-03, + 1.53958668046561540123e-03, + 1.58239600127717565045e-03, + 1.62426758699731900969e-03, + 1.66517826100116947581e-03, + 1.70510541396065628053e-03, + 1.74402701631310862347e-03, + 1.78192163038870358960e-03, + 1.81876842219015340089e-03, + 1.85454717281811399567e-03, + 1.88923828953608337507e-03, + 1.92282281646894998711e-03, + 1.95528244492883035086e-03, + 1.98659952336315047752e-03, + 2.01675706691958021854e-03, + 2.04573876662207838895e-03, + 2.07352899815367369349e-03, + 2.10011283024123633634e-03, + 2.12547603263724084119e-03, + 2.14960508369503545609e-03, + 2.17248717753304627920e-03, + 2.19411023078435168249e-03, + 2.21446288892813546861e-03, + 2.23353453219959832005e-03, + 2.25131528107543575634e-03, + 2.26779600133197476938e-03, + 2.28296830867344077709e-03, + 2.29682457292811666866e-03, + 2.30935792181020602132e-03, + 2.32056224424581451771e-03, + 2.33043219326110580616e-03, + 2.33896318843187242878e-03, + 2.34615141789296230077e-03, + 2.35199383990705723768e-03, + 2.35648818399214129982e-03, + 2.35963295160742693446e-03, + 2.36142741639763483266e-03, + 2.36187162399587079545e-03, + 2.36096639138556364801e-03, + 2.35871330582219018365e-03, + 2.35511472331569049476e-03, + 2.35017376667488861117e-03, + 2.34389432311526155553e-03, + 2.33628104143192337830e-03, + 2.32733932873959879425e-03, + 2.31707534678196646130e-03, + 2.30549600781271638028e-03, + 2.29260897005103539067e-03, + 2.27842263271448887407e-03, + 2.26294613063242897391e-03, + 2.24618932844335367563e-03, + 2.22816281437991214193e-03, + 2.20887789364531414785e-03, + 2.18834658138542404587e-03, + 2.16658159526062063169e-03, + 2.14359634762239202599e-03, + 2.11940493729897636022e-03, + 2.09402214099534654534e-03, + 2.06746340431283176509e-03, + 2.03974483239339685059e-03, + 2.01088318019464239519e-03, + 1.98089584240138030097e-03, + 1.94980084297942022308e-03, + 1.91761682437821957652e-03, + 1.88436303638870564399e-03, + 1.85005932466290553585e-03, + 1.81472611890221816218e-03, + 1.77838442072136338791e-03, + 1.74105579119516714129e-03, + 1.70276233809558063745e-03, + 1.66352670282644788877e-03, + 1.62337204706380910935e-03, + 1.58232203910926546089e-03, + 1.54040083996521471633e-03, + 1.49763308913912528489e-03, + 1.45404389018587740061e-03, + 1.40965879599663345551e-03, + 1.36450379384215388784e-03, + 1.31860529018035092276e-03, + 1.27199009523587059159e-03, + 1.22468540736182600857e-03, + 1.17671879719162628813e-03, + 1.12811819159096510083e-03, + 1.07891185741895972300e-03, + 1.02912838510792908377e-03, + 9.78796672071337260299e-04, + 9.27945905949520053434e-04, + 8.76605547702895976370e-04, + 8.24805314562447990448e-04, + 7.72575162847333337356e-04, + 7.19945270659597320352e-04, + 6.66946020465617123510e-04, + 6.13607981575178514436e-04, + 5.59961892527424567705e-04, + 5.06038643393795593145e-04, + 4.51869258009022058478e-04, + 3.97484876139576502260e-04, + 3.42916735599798760004e-04, + 2.88196154326876910479e-04, + 2.33354512423656609626e-04, + 1.78423234180534077487e-04, + 1.23433770086348173567e-04, + 6.84175788386079240409e-05, + 1.34061093633470900020e-05, +-4.15692171451308774711e-05, +-9.64770251543709412689e-05, +-1.51286002683524126340e-04, +-2.05964919142553784092e-04, +-2.60482643110675150724e-04, +-3.14808160044301459275e-04, +-3.68910589903529524333e-04, +-4.22759204688063789518e-04, +-4.76323445872630008881e-04, +-5.29572941731087281150e-04, +-5.82477524540275987987e-04, +-6.35007247653846472989e-04, +-6.87132402435543243602e-04, +-7.38823535043645019879e-04, +-7.90051463056118570549e-04, +-8.40787291927532235911e-04, +-8.91002431268342548823e-04, +-9.40668610937454570224e-04, +-9.89757896938941268347e-04, +-1.03824270711407040668e-03, +-1.08609582661974403764e-03, +-1.13329042318477575535e-03, +-1.17980006213536797732e-03, +-1.22559872118147396639e-03, +-1.27066080495571239080e-03, +-1.31496115929677771621e-03, +-1.35847508526934588474e-03, +-1.40117835291272236839e-03, +-1.44304721471052890651e-03, +-1.48405841877397026707e-03, +-1.52418922173162092390e-03, +-1.56341740131789178406e-03, +-1.60172126865418262831e-03, +-1.63907968021530041879e-03, +-1.67547204947450902382e-03, +-1.71087835822147623158e-03, +-1.74527916754618566374e-03, +-1.77865562848291466208e-03, +-1.81098949230900328755e-03, +-1.84226312049221930059e-03, +-1.87245949428157002978e-03, +-1.90156222393633397329e-03, +-1.92955555758831764739e-03, +-1.95642438973256090409e-03, +-1.98215426934193923725e-03, +-2.00673140760134708499e-03, +-2.03014268525729749126e-03, +-2.05237565957906665723e-03, +-2.07341857092785582239e-03, +-2.09326034893013391766e-03, +-2.11189061825244484699e-03, +-2.12929970397441031132e-03, +-2.14547863655709580497e-03, +-2.16041915640460824299e-03, +-2.17411371801621297953e-03, +-2.18655549372708977660e-03, +-2.19773837703605891963e-03, +-2.20765698551850719430e-03, +-2.21630666332326515741e-03, +-2.22368348325234152507e-03, +-2.22978424842263864281e-03, +-2.23460649350903971591e-03, +-2.23814848556852345751e-03, +-2.24040922444509972219e-03, +-2.24138844275575217432e-03, +-2.24108660545765600580e-03, +-2.23950490899731862252e-03, +-2.23664528004239790415e-03, +-2.23251037379732560767e-03, +-2.22710357190395455765e-03, +-2.22042897992885809519e-03, +-2.21249142443891893065e-03, +-2.20329644966735498784e-03, +-2.19285031377223701976e-03, +-2.18115998469021890940e-03, +-2.16823313558786156391e-03, +-2.15407813991372407841e-03, +-2.13870406605424102225e-03, +-2.12212067159678200237e-03, +-2.10433839720351734126e-03, +-2.08536836009985638782e-03, +-2.06522234718151120880e-03, +-2.04391280774443356502e-03, +-2.02145284584207300324e-03, +-1.99785621227463244462e-03, +-1.97313729621508525403e-03, +-1.94731111647731430260e-03, +-1.92039331243139960170e-03, +-1.89240013457138639766e-03, +-1.86334843474168982726e-03, +-1.83325565602760116347e-03, +-1.80213982231590299880e-03, +-1.77001952753231455231e-03, +-1.73691392456148648374e-03, +-1.70284271385666495340e-03, +-1.66782613174552775577e-03, +-1.63188493843921685576e-03, +-1.59504040575159230717e-03, +-1.55731430453603003801e-03, +-1.51872889184707753063e-03, +-1.47930689783463205529e-03, +-1.43907151237822393368e-03, +-1.39804637146942033893e-03, +-1.35625554334995140730e-03, +-1.31372351441438970504e-03, +-1.27047517488496053938e-03, +-1.22653580426682431471e-03, +-1.18193105659301824634e-03, +-1.13668694546695714549e-03, +-1.09082982891158691320e-03, +-1.04438639403357878127e-03, +-9.97383641512322120098e-04, +-9.49848869921641547967e-04, +-9.01809659894115857315e-04, +-8.53293858136809635351e-04, +-8.04329561308134524146e-04, +-7.54945099763940303053e-04, +-7.05169021184243009770e-04, +-6.55030074088056891990e-04, +-6.04557191246998305335e-04, +-5.53779473006872830811e-04, +-5.02726170526861184003e-04, +-4.51426668945984269337e-04, +-3.99910470486500410799e-04, +-3.48207177503949535848e-04, +-2.96346475493580014358e-04, +-2.44358116062887999707e-04, +-1.92271899880109192792e-04, +-1.40117659608033219131e-04, +-8.79252428338516013985e-05, +-3.57244950035476513677e-05, + 1.64547576285501491889e-05, + 6.85827250253236744533e-05, + 1.20629670358623862633e-04, + 1.72565926956682051847e-04, + 2.24361915197526828099e-04, + 2.75988159339660512649e-04, + 3.27415304279563739234e-04, + 3.78614132226878525450e-04, + 4.29555579287748767834e-04, + 4.80210751946913818114e-04, + 5.30550943439215389429e-04, + 5.80547650001254260735e-04, + 6.30172586994006268639e-04, + 6.79397704887282211095e-04, + 7.28195205096961932327e-04, + 7.76537555666397547385e-04, + 8.24397506782311470346e-04, + 8.71748106117578472167e-04, + 9.18562713991485446999e-04, + 9.64815018338932312708e-04, + 1.01047904948097389682e-03, + 1.05552919468725366070e-03, + 1.09994021252330666759e-03, + 1.14368724697360216180e-03, + 1.18674584133354179757e-03, + 1.22909195186185872875e-03, + 1.27070196118612760081e-03, + 1.31155269145389143971e-03, + 1.35162141722206191954e-03, + 1.39088587807745310380e-03, + 1.42932429098146206170e-03, + 1.46691536233205330891e-03, + 1.50363829973637033906e-03, + 1.53947282348746166021e-03, + 1.57439917773903939602e-03, + 1.60839814137149570566e-03, + 1.64145103854408192304e-03, + 1.67353974892666301950e-03, + 1.70464671760622052225e-03, + 1.73475496466189292762e-03, + 1.76384809440413852129e-03, + 1.79191030427224506048e-03, + 1.81892639338610754944e-03, + 1.84488177074716187820e-03, + 1.86976246308427976328e-03, + 1.89355512234033978962e-03, + 1.91624703279555906599e-03, + 1.93782611782377474016e-03, + 1.95828094627808731512e-03, + 1.97760073850255548022e-03, + 1.99577537196677290074e-03, + 2.01279538652043366379e-03, + 2.02865198926522683279e-03, + 2.04333705904144154533e-03, + 2.05684315052714027094e-03, + 2.06916349794801935486e-03, + 2.08029201839576892777e-03, + 2.09022331475368274706e-03, + 2.09895267822806817423e-03, + 2.10647609048419644576e-03, + 2.11279022538611149090e-03, + 2.11789245033947156824e-03, + 2.12178082723701432605e-03, + 2.12445411300643061461e-03, + 2.12591175976064054517e-03, + 2.12615391455073503985e-03, + 2.12518141872201785439e-03, + 2.12299580687382158026e-03, + 2.11959930542408034673e-03, + 2.11499483077969572045e-03, + 2.10918598711416641414e-03, + 2.10217706375393116602e-03, + 2.09397303217547263096e-03, + 2.08457954261486583247e-03, + 2.07400292029235070942e-03, + 2.06225016125420471461e-03, + 2.04932892783467367551e-03, + 2.03524754374076423044e-03, + 2.02001498876324889209e-03, + 2.00364089311688611111e-03, + 1.98613553141360494464e-03, + 1.96750981627234018331e-03, + 1.94777529156955181953e-03, + 1.92694412533416631859e-03, + 1.90502910229207360684e-03, + 1.88204361606385760751e-03, + 1.85800166102108787677e-03, + 1.83291782380585869562e-03, + 1.80680727451872601141e-03, + 1.77968575758040859630e-03, + 1.75156958227263453466e-03, + 1.72247561296389362258e-03, + 1.69242125902588661998e-03, + 1.66142446444668846067e-03, + 1.62950369714685090912e-03, + 1.59667793800455284220e-03, + 1.56296666959689989698e-03, + 1.52838986466322470682e-03, + 1.49296797429780258443e-03, + 1.45672191587891005325e-03, + 1.41967306074082186274e-03, + 1.38184322159656857235e-03, + 1.34325463971886609367e-03, + 1.30392997188612789518e-03, + 1.26389227710180132407e-03, + 1.22316500309457604385e-03, + 1.18177197260732505350e-03, + 1.13973736948289701074e-03, + 1.09708572455475997058e-03, + 1.05384190135080434668e-03, + 1.01003108161856368016e-03, + 9.65678750680322895046e-04, + 9.20810682626568323406e-04, + 8.75452925356471657603e-04, + 8.29631785473724093875e-04, + 7.83373813047290703040e-04, + 7.36705786244772238558e-04, + 6.89654695848395987885e-04, + 6.42247729661416769283e-04, + 5.94512256815164243616e-04, + 5.46475811984593212202e-04, + 4.98166079522630966640e-04, + 4.49610877521255665294e-04, + 4.00838141809322300816e-04, + 3.51875909896002484617e-04, + 3.02752304869100116388e-04, + 2.53495519257492917930e-04, + 2.04133798866942952959e-04, + 1.54695426598542049934e-04, + 1.05208706259043055812e-04, + 5.57019463723481029365e-05, + 6.20344400145258794332e-06, +-4.32585314102668224909e-05, +-9.26557541683200246944e-05, +-1.41960058418968396079e-04, +-1.91143354193288721741e-04, +-2.40177643395536041327e-04, +-2.89035035725425371294e-04, +-3.37687764526517215750e-04, +-3.86108202550481673879e-04, +-4.34268877629523874194e-04, +-4.82142488247218933394e-04, +-5.29701918999288495597e-04, +-5.76920255935507784832e-04, +-6.23770801774083051734e-04, +-6.70227090979901799633e-04, +-7.16262904698151416615e-04, +-7.61852285534880065317e-04, +-8.06969552176199341267e-04, +-8.51589313837822735331e-04, +-8.95686484537168122258e-04, +-9.39236297179238443025e-04, +-9.82214317449158023227e-04, +-1.02459645750355089928e-03, +-1.06635898945237213818e-03, +-1.10747855862441241769e-03, +-1.14793219660866787669e-03, +-1.18769733406468773300e-03, +-1.22675181329402055441e-03, +-1.26507390056672754976e-03, +-1.30264229819540794213e-03, +-1.33943615635037714499e-03, +-1.37543508460907315874e-03, +-1.41061916323427321250e-03, +-1.44496895417330940836e-03, +-1.47846551177379173514e-03, +-1.51109039320902033797e-03, +-1.54282566860766408127e-03, +-1.57365393088206863802e-03, +-1.60355830525010312551e-03, +-1.63252245844455485396e-03, +-1.66053060760636725206e-03, +-1.68756752885559392630e-03, +-1.71361856553621906898e-03, +-1.73866963613010581773e-03, +-1.76270724183600984401e-03, +-1.78571847380921077363e-03, +-1.80769102005840930254e-03, +-1.82861317199587238881e-03, +-1.84847383063749628497e-03, +-1.86726251244936523530e-03, +-1.88496935483824668706e-03, +-1.90158512128234106521e-03, +-1.91710120610045944671e-03, +-1.93150963885675339658e-03, +-1.94480308839885176336e-03, +-1.95697486652746934985e-03, +-1.96801893129561937881e-03, +-1.97792988993586308158e-03, +-1.98670300141425048082e-03, +-1.99433417860976971991e-03, +-2.00081999011835322613e-03, +-2.00615766168074291520e-03, +-2.01034507723373218405e-03, +-2.01338077958435448037e-03, +-2.01526397070713597648e-03, +-2.01599451166439066346e-03, +-2.01557292214997766863e-03, +-2.01400037965709585719e-03, +-2.01127871827083996512e-03, +-2.00741042708658728663e-03, +-2.00239864825537024207e-03, +-1.99624717465765773305e-03, +-1.98896044720722623214e-03, +-1.98054355178687831532e-03, +-1.97100221581815275573e-03, +-1.96034280446718981242e-03, +-1.94857231648931650270e-03, +-1.93569837971491794798e-03, +-1.92172924617953493238e-03, +-1.90667378690126333891e-03, +-1.89054148630866990580e-03, +-1.87334243632268355843e-03, +-1.85508733009632424509e-03, +-1.83578745541577732087e-03, +-1.81545468776724309642e-03, +-1.79410148307337815980e-03, +-1.77174087010420694757e-03, +-1.74838644256665020488e-03, +-1.72405235087792502863e-03, +-1.69875329362731528234e-03, +-1.67250450873173686292e-03, +-1.64532176429031608451e-03, +-1.61722134914345358134e-03, +-1.58822006314201439985e-03, +-1.55833520713242958296e-03, +-1.52758457266367842983e-03, +-1.49598643142224508110e-03, +-1.46355952440134539153e-03, +-1.43032305081079724740e-03, +-1.39629665673392786875e-03, +-1.36150042353874842389e-03, +-1.32595485604938292078e-03, +-1.28968087048560815441e-03, +-1.25269978217663175389e-03, +-1.21503329305731573931e-03, +-1.17670347895322481742e-03, +-1.13773277666287834717e-03, +-1.09814397084380963379e-03, +-1.05796018071076876506e-03, +-1.01720484655352786697e-03, +-9.75901716082224163044e-04, +-9.34074830608162560291e-04, +-8.91748511068093702332e-04, +-8.48947343900121774093e-04, +-8.05696166779400137388e-04, +-7.62020054221886175734e-04, +-7.17944303064517799773e-04, +-6.73494417830223287419e-04, +-6.28696095985875375196e-04, +-5.83575213102809943477e-04, +-5.38157807926610857671e-04, +-4.92470067366625467893e-04, +-4.46538311412741039091e-04, +-4.00388977988523500975e-04, +-3.54048607749048280420e-04, +-3.07543828832976284295e-04, +-2.60901341576534541618e-04, +-2.14147903198978289919e-04, +-1.67310312467942520764e-04, +-1.20415394353891940199e-04, +-7.34899846812865148926e-05, +-2.65609147871840793706e-05, + 2.03450038059074316498e-05, + 6.72009946930133205637e-05, + 1.13980331857172184195e-04, + 1.60656354898604009258e-04, + 2.07202484214283008147e-04, + 2.53592236118117483629e-04, + 2.99799237895086720992e-04, + 3.45797242778839468078e-04, + 3.91560144845429106229e-04, + 4.37061993814294241171e-04, + 4.82277009748485958104e-04, + 5.27179597645008367682e-04, + 5.71744361908107438623e-04, + 6.15946120696525068264e-04, + 6.59759920136990252182e-04, + 7.03161048395523806745e-04, + 7.46125049599718473056e-04, + 7.88627737602340720367e-04, + 8.30645209580345455537e-04, + 8.72153859460560415377e-04, + 9.13130391164877785494e-04, + 9.53551831667496553602e-04, + 9.93395543856891161116e-04, + 1.03263923919528978652e-03, + 1.07126099016866677127e-03, + 1.10923924252022128127e-03, + 1.14655282726058328768e-03, + 1.18318097244805918271e-03, + 1.21910331473228323099e-03, + 1.25429991065521308224e-03, + 1.28875124770248187904e-03, + 1.32243825509993726680e-03, + 1.35534231434853292934e-03, + 1.38744526949258163359e-03, + 1.41872943711487042515e-03, + 1.44917761605398002535e-03, + 1.47877309683764539099e-03, + 1.50749967082781347223e-03, + 1.53534163907186548513e-03, + 1.56228382085535594075e-03, + 1.58831156195163563510e-03, + 1.61341074256387195449e-03, + 1.63756778495518346382e-03, + 1.66076966076276837624e-03, + 1.68300389799214892943e-03, + 1.70425858768773869599e-03, + 1.72452239027620483382e-03, + 1.74378454157939760671e-03, + 1.76203485849330421936e-03, + 1.77926374433060529266e-03, + 1.79546219382350027462e-03, + 1.81062179778474288683e-03, + 1.82473474742401477189e-03, + 1.83779383831785469647e-03, + 1.84979247403080490283e-03, + 1.86072466938634346195e-03, + 1.87058505338575297924e-03, + 1.87936887177368445838e-03, + 1.88707198924914281921e-03, + 1.89369089132102150393e-03, + 1.89922268580736391258e-03, + 1.90366510397775167036e-03, + 1.90701650133855821721e-03, + 1.90927585806080512588e-03, + 1.91044277905074734968e-03, + 1.91051749366339122978e-03, + 1.90950085505942339544e-03, + 1.90739433920622124437e-03, + 1.90420004352378135701e-03, + 1.89992068517663812051e-03, + 1.89455959901305625789e-03, + 1.88812073515295573110e-03, + 1.88060865622618881600e-03, + 1.87202853426315300560e-03, + 1.86238614723965899625e-03, + 1.85168787527840192179e-03, + 1.83994069650947789270e-03, + 1.82715218259254900957e-03, + 1.81333049390355882657e-03, + 1.79848437438895314942e-03, + 1.78262314609068240993e-03, + 1.76575670334532712838e-03, + 1.74789550666099805648e-03, + 1.72905057627572287561e-03, + 1.70923348540114126287e-03, + 1.68845635315613591676e-03, + 1.66673183719381174349e-03, + 1.64407312602717807851e-03, + 1.62049393105762528852e-03, + 1.59600847831119999759e-03, + 1.57063149988747046033e-03, + 1.54437822512650262292e-03, + 1.51726437149865382714e-03, + 1.48930613522309045725e-03, + 1.46052018162035729919e-03, + 1.43092363520500552576e-03, + 1.40053406952348629723e-03, + 1.36936949674445118327e-03, + 1.33744835700646668569e-03, + 1.30478950753013271321e-03, + 1.27141221150076761358e-03, + 1.23733612672830939165e-03, + 1.20258129409077482892e-03, + 1.16716812576892663492e-03, + 1.13111739327765117337e-03, + 1.09445021530241268400e-03, + 1.05718804534711313843e-03, + 1.01935265920083785798e-03, + 9.80966142230535508365e-04, + 9.42050876507689177730e-04, + 9.02629527775573197758e-04, + 8.62725032265359496712e-04, + 8.22360583368397595437e-04, + 7.81559618172762574431e-04, + 7.40345803871171343619e-04, + 6.98743024048840326648e-04, + 6.56775364859214197573e-04, + 6.14467101094864410517e-04, + 5.71842682162310611722e-04, + 5.28926717968548746641e-04, + 4.85743964727467576921e-04, + 4.42319310694356789340e-04, + 3.98677761836690037860e-04, + 3.54844427449443563551e-04, + 3.10844505723203393555e-04, + 2.66703269273363180372e-04, + 2.22446050638747323033e-04, + 1.78098227757677587350e-04, + 1.33685209430572742549e-04, + 8.92324207763590298084e-05, + 4.47652886917426873583e-05, + 3.09227321650505732558e-07, +-4.41103764515531808835e-05, +-8.84681774910541152872e-05, +-1.32738886852529214266e-04, +-1.76897286187552060842e-04, +-2.20918242094528819363e-04, +-2.64776720409321865164e-04, +-3.08447800427395421845e-04, +-3.51906689049402091746e-04, +-3.95128734842202674043e-04, +-4.38089442007342469865e-04, +-4.80764484249080186352e-04, +-5.23129718534129112967e-04, +-5.65161198735287346670e-04, +-6.06835189151545676724e-04, +-6.48128177896318104570e-04, +-6.89016890147269131690e-04, +-7.29478301249281038503e-04, +-7.69489649664180678720e-04, +-8.09028449758908115366e-04, +-8.48072504425961999630e-04, +-8.86599917528026388626e-04, +-9.24589106160850367731e-04, +-9.62018812726749862618e-04, +-9.98868116812330619769e-04, +-1.03511644686372960081e-03, +-1.07074359165286784289e-03, +-1.10572971152834206160e-03, +-1.14005534944471237715e-03, +-1.17370144176403299122e-03, +-1.20664932882368503703e-03, +-1.23888076526462546922e-03, +-1.27037793011433868158e-03, +-1.30112343661913792969e-03, +-1.33110034181987751598e-03, +-1.36029215586637268476e-03, +-1.38868285106535536630e-03, +-1.41625687065657750174e-03, +-1.44299913731265943770e-03, +-1.46889506135814513696e-03, +-1.49393054870271117275e-03, +-1.51809200848501517356e-03, +-1.54136636042246982434e-03, +-1.56374104186323185060e-03, +-1.58520401453656292236e-03, +-1.60574377099796661295e-03, +-1.62534934076566579299e-03, +-1.64401029614518693484e-03, +-1.66171675773892622320e-03, +-1.67845939963788895466e-03, +-1.69422945429279826236e-03, +-1.70901871706225839433e-03, +-1.72281955043516879847e-03, +-1.73562488792599364622e-03, +-1.74742823764018669758e-03, +-1.75822368550844964838e-03, +-1.76800589818810072879e-03, +-1.77677012563024231892e-03, +-1.78451220331139900031e-03, +-1.79122855412879207482e-03, +-1.79691618995835998736e-03, +-1.80157271287491316247e-03, +-1.80519631603399109167e-03, +-1.80778578421531151664e-03, +-1.80934049402758445960e-03, +-1.80986041377503045595e-03, +-1.80934610298588618299e-03, +-1.80779871160341876896e-03, +-1.80521997884027364349e-03, +-1.80161223169698209157e-03, +-1.79697838314586038136e-03, +-1.79132192998154664808e-03, +-1.78464695033966652855e-03, +-1.77695810088541257706e-03, +-1.76826061367380709712e-03, +-1.75856029268379684440e-03, +-1.74786351002833607871e-03, +-1.73617720184306720613e-03, +-1.72350886385598295499e-03, +-1.70986654664103516175e-03, +-1.69525885055866825345e-03, +-1.67969492038625377826e-03, +-1.66318443964190258721e-03, +-1.64573762460525812104e-03, +-1.62736521803862185451e-03, +-1.60807848261251156753e-03, +-1.58788919403957031612e-03, +-1.56680963392096320175e-03, +-1.54485258230964710331e-03, +-1.52203130999494277119e-03, +-1.49835957051309000103e-03, +-1.47385159188855594317e-03, +-1.44852206811105200211e-03, +-1.42238615035335702781e-03, +-1.39545943793505230687e-03, +-1.36775796903791223985e-03, +-1.33929821117795126197e-03, +-1.31009705144011874209e-03, +-1.28017178648149091390e-03, +-1.24954011230838865631e-03, +-1.21822011383393023938e-03, +-1.18623025422220701106e-03, +-1.15358936402481875548e-03, +-1.12031663011664538339e-03, +-1.08643158443716956497e-03, +-1.05195409254393249660e-03, +-1.01690434198485049264e-03, +-9.81302830496187097550e-04, +-9.45170354033052825121e-04, +-9.08527994639429640512e-04, +-8.71397108164778015985e-04, +-8.33799311834413085960e-04, +-7.95756471680627718197e-04, +-7.57290689842498644137e-04, +-7.18424291740831638675e-04, +-6.79179813136611995432e-04, +-6.39579987079505734443e-04, +-5.99647730754900086352e-04, +-5.59406132236475598166e-04, +-5.18878437151933970262e-04, +-4.78088035270234697639e-04, +-4.37058447017129952060e-04, +-3.95813309927481478661e-04, +-3.54376365041849988782e-04, +-3.12771443255252100824e-04, +-2.71022451625898674193e-04, +-2.29153359651793514821e-04, +-1.87188185523051535668e-04, +-1.45150982357815703074e-04, +-1.03065824429653753224e-04, +-6.09567933943611181980e-05, +-1.88479645237432815287e-05, + 2.32366070450612883841e-05, + 6.52729000375716606440e-05, + 1.07236940739442618243e-04, + 1.49104816654926491124e-04, + 1.90852690119197040226e-04, + 2.32456811856789096653e-04, + 2.73893534477760703088e-04, + 3.15139325904901243872e-04, + 3.56170782723636393866e-04, + 3.96964643447348004834e-04, + 4.37497801690561933553e-04, + 4.77747319242539513363e-04, + 5.17690439033898983090e-04, + 5.57304597988927475152e-04, + 5.96567439756349820155e-04, + 6.35456827311364227072e-04, + 6.73950855421827322786e-04, + 7.12027862971859829694e-04, + 7.49666445135031877037e-04, + 7.86845465391861000233e-04, + 8.23544067383306889127e-04, + 8.59741686594572016369e-04, + 8.95418061862311427494e-04, + 9.30553246699131696683e-04, + 9.65127620428410772438e-04, + 9.99121899124090018587e-04, + 1.03251714634870848247e-03, + 1.06529478368399947198e-03, + 1.09743660104794104639e-03, + 1.12892476679308227140e-03, + 1.15974183757998469332e-03, + 1.18987076802038013908e-03, + 1.21929492008520171109e-03, + 1.24799807227183364583e-03, + 1.27596442852571370294e-03, + 1.30317862691138467227e-03, + 1.32962574802824510904e-03, + 1.35529132316640921890e-03, + 1.38016134219821656921e-03, + 1.40422226120109406612e-03, + 1.42746100980768492357e-03, + 1.44986499827917236088e-03, + 1.47142212429823100381e-03, + 1.49212077947745262729e-03, + 1.51194985558042080918e-03, + 1.53089875045162937886e-03, + 1.54895737365219089698e-03, + 1.56611615179862813038e-03, + 1.58236603360162059878e-03, + 1.59769849460209630194e-03, + 1.61210554160250824594e-03, + 1.62557971679072794415e-03, + 1.63811410155455141995e-03, + 1.64970231998493792151e-03, + 1.66033854206613972274e-03, + 1.67001748655128297305e-03, + 1.67873442352191011920e-03, + 1.68648517663034331823e-03, + 1.69326612502385489591e-03, + 1.69907420494976057514e-03, + 1.70390691104087862832e-03, + 1.70776229728072394785e-03, + 1.71063897764836807952e-03, + 1.71253612644269893883e-03, + 1.71345347828618104098e-03, + 1.71339132780851089409e-03, + 1.71235052901041605485e-03, + 1.71033249430839581935e-03, + 1.70733919326115121499e-03, + 1.70337315097866446277e-03, + 1.69843744621518731933e-03, + 1.69253570914738513120e-03, + 1.68567211883928003494e-03, + 1.67785140039562329257e-03, + 1.66907882180561645095e-03, + 1.65936019047902743109e-03, + 1.64870184947697967330e-03, + 1.63711067343976380412e-03, + 1.62459406421430947211e-03, + 1.61115994618396237217e-03, + 1.59681676130369741735e-03, + 1.58157346384365333700e-03, + 1.56543951484419598813e-03, + 1.54842487628618539174e-03, + 1.53054000497979212497e-03, + 1.51179584617556041562e-03, + 1.49220382690190903063e-03, + 1.47177584903268165312e-03, + 1.45052428208925355928e-03, + 1.42846195578139154199e-03, + 1.40560215229139080610e-03, + 1.38195859830608975584e-03, + 1.35754545680155853417e-03, + 1.33237731858531225151e-03, + 1.30646919360115246027e-03, + 1.27983650200173999789e-03, + 1.25249506499428768340e-03, + 1.22446109546453757271e-03, + 1.19575118838507522302e-03, + 1.16638231101316865689e-03, + 1.13637179288388632040e-03, + 1.10573731560490210422e-03, + 1.07449690245847175561e-03, + 1.04266890781677537894e-03, + 1.01027200637724160967e-03, + 9.77325182223491746580e-04, + 9.43847717718836014267e-04, + 9.09859182238561756129e-04, + 8.75379420747673811856e-04, + 8.40428542230697460044e-04, + 8.05026907980306420144e-04, + 7.69195119751593810696e-04, + 7.32954007788833667922e-04, + 6.96324618731728513937e-04, + 6.59328203408161448926e-04, + 6.21986204520240414974e-04, + 5.84320244231672147536e-04, + 5.46352111662109520517e-04, + 5.08103750297240336353e-04, + 4.69597245320941603965e-04, + 4.30854810877143471967e-04, + 3.91898777268710394022e-04, + 3.52751578100453573074e-04, + 3.13435737374358550089e-04, + 2.73973856543509894194e-04, + 2.34388601532805235282e-04, + 1.94702689733898895181e-04, + 1.54938876981224293557e-04, + 1.15119944517208389599e-04, + 7.52686859541390425104e-05, + 3.54078942394808599795e-05, +-4.43965136725644293991e-06, +-4.42511982989445055948e-05, +-8.40040336590952227153e-05, +-1.23675497166556415483e-04, +-1.63242994059274422816e-04, +-2.02684007949782501144e-04, +-2.41976113625108971150e-04, +-2.81096989783838162574e-04, +-3.20024431703046653274e-04, +-3.58736363828217243860e-04, +-3.97210852278301535575e-04, +-4.35426117259783847756e-04, +-4.73360545382079051305e-04, +-5.10992701867309432294e-04, +-5.48301342648169556804e-04, +-5.85265426346414513459e-04, +-6.21864126125226549316e-04, +-6.58076841409443590199e-04, +-6.93883209466395465582e-04, +-7.29263116841149562630e-04, +-7.64196710639690078223e-04, +-7.98664409653720487083e-04, +-8.32646915320844871987e-04, +-8.66125222514040646153e-04, +-8.99080630154340944109e-04, +-9.31494751640883481870e-04, +-9.63349525092406142567e-04, +-9.94627223394778684981e-04, +-1.02531046404839951310e-03, +-1.05538221881074458820e-03, +-1.08482582312822528441e-03, +-1.11362498535213291090e-03, +-1.14176379573408177427e-03, +-1.16922673519527877718e-03, +-1.19599868386546836010e-03, +-1.22206492938624691758e-03, +-1.24741117497479086888e-03, +-1.27202354724320165595e-03, +-1.29588860376930693416e-03, +-1.31899334041485176428e-03, +-1.34132519838702510620e-03, +-1.36287207103959304329e-03, +-1.38362231040987894090e-03, +-1.40356473348816814667e-03, +-1.42268862821608036220e-03, +-1.44098375921079607451e-03, +-1.45844037321212166396e-03, +-1.47504920424929150333e-03, +-1.49080147852505740143e-03, +-1.50568891901449236279e-03, +-1.51970374977587058263e-03, +-1.53283869997163850300e-03, +-1.54508700759743169105e-03, +-1.55644242291698388023e-03, +-1.56689921160158636589e-03, +-1.57645215757227954816e-03, +-1.58509656554349596252e-03, +-1.59282826326696629569e-03, +-1.59964360347482673595e-03, +-1.60553946552108848557e-03, +-1.61051325672077034167e-03, +-1.61456291338620840613e-03, +-1.61768690156018470419e-03, +-1.61988421744570839506e-03, +-1.62115438753249706261e-03, +-1.62149746842027214430e-03, +-1.62091404633929480651e-03, +-1.61940523636864598667e-03, +-1.61697268135293863688e-03, +-1.61361855051833538548e-03, +-1.60934553778894714506e-03, +-1.60415685980480290408e-03, +-1.59805625364277783043e-03, +-1.59104797424202554224e-03, +-1.58313679153566032841e-03, +-1.57432798729054113616e-03, +-1.56462735165729103538e-03, +-1.55404117943255706651e-03, +-1.54257626603623507200e-03, +-1.53023990320586564598e-03, +-1.51703987441107932509e-03, +-1.50298444999091796934e-03, +-1.48808238201701193738e-03, +-1.47234289888582359565e-03, +-1.45577569964323665606e-03, +-1.43839094804500198903e-03, +-1.42019926635660867151e-03, +-1.40121172889639514399e-03, +-1.38143985532579059369e-03, +-1.36089560369062070010e-03, +-1.33959136321799648049e-03, +-1.31753994687265748795e-03, +-1.29475458367754288694e-03, +-1.27124891080319826590e-03, +-1.24703696543038513624e-03, +-1.22213317639110834699e-03, +-1.19655235559304484218e-03, +-1.17030968923203648052e-03, +-1.14342072879827219220e-03, +-1.11590138188130184350e-03, +-1.08776790277930086870e-03, +-1.05903688291816215454e-03, +-1.02972524108603069419e-03, +-9.99850213489021427335e-04, +-9.69429343633939504844e-04, +-9.38480472043964680448e-04, +-9.07021725813329186133e-04, +-8.75071508006883031112e-04, +-8.42648486911279294594e-04, +-8.09771585143337466368e-04, +-7.76459968622407611070e-04, +-7.42733035413201104179e-04, +-7.08610404445038041289e-04, +-6.74111904114616314332e-04, +-6.39257560778936587825e-04, +-6.04067587144468801964e-04, +-5.68562370559859918927e-04, +-5.32762461218706014771e-04, +-4.96688560279258763987e-04, +-4.60361507907912782377e-04, +-4.23802271253376780860e-04, +-3.87031932358470730920e-04, +-3.50071676016493139785e-04, +-3.12942777579159074532e-04, +-2.75666590723110279098e-04, +-2.38264535182076194354e-04, +-2.00758084451451004676e-04, +-1.63168753473010485957e-04, +-1.25518086305888461329e-04, +-8.78276437918047763126e-05, +-5.01189912206633324926e-05, +-1.24136860045527507159e-05, + 2.52667346337536352944e-05, + 6.29007659498319457100e-05, + 1.00466947938114190518e-04, + 1.37943877556209900086e-04, + 1.75310220906359231921e-04, + 2.12544725367042178004e-04, + 2.49626231667856310695e-04, + 2.86533685900810760391e-04, + 3.23246151461219666419e-04, + 3.59742820911436455861e-04, + 3.96003027760712372068e-04, + 4.32006258154472920323e-04, + 4.67732162466665663501e-04, + 5.03160566788037619604e-04, + 5.38271484304469029561e-04, + 5.73045126558938025356e-04, + 6.07461914590199476491e-04, + 6.41502489942463185145e-04, + 6.75147725539870118862e-04, + 7.08378736419115317274e-04, + 7.41176890315008965633e-04, + 7.73523818092431607665e-04, + 8.05401424019106036527e-04, + 8.36791895873423112462e-04, + 8.67677714881635517297e-04, + 8.98041665478958536263e-04, + 9.27866844889067626453e-04, + 9.57136672516743498666e-04, + 9.85834899148405139485e-04, + 1.01394561595543404760e-03, + 1.04145326329548363296e-03, + 1.06834263930647441546e-03, + 1.09459890828899372543e-03, + 1.12020760887248218077e-03, + 1.14515466196026915839e-03, + 1.16942637844957234711e-03, + 1.19300946672199316770e-03, + 1.21589103990064808375e-03, + 1.23805862286953697812e-03, + 1.25950015905194477768e-03, + 1.28020401694373142133e-03, + 1.30015899639822005152e-03, + 1.31935433465907368637e-03, + 1.33777971213847393650e-03, + 1.35542525793661992536e-03, + 1.37228155510049436815e-03, + 1.38833964561861015856e-03, + 1.40359103514923078820e-03, + 1.41802769747961950574e-03, + 1.43164207871396926761e-03, + 1.44442710118785071390e-03, + 1.45637616710717282889e-03, + 1.46748316190982897207e-03, + 1.47774245734831524007e-03, + 1.48714891429181411860e-03, + 1.49569788524642525128e-03, + 1.50338521659217202661e-03, + 1.51020725053600747730e-03, + 1.51616082677973940986e-03, + 1.52124328390220494439e-03, + 1.52545246045525904888e-03, + 1.52878669577304190583e-03, + 1.53124483049437549141e-03, + 1.53282620679826551459e-03, + 1.53353066835256834737e-03, + 1.53335855997613302801e-03, + 1.53231072701479021855e-03, + 1.53038851443190564161e-03, + 1.52759376561413247157e-03, + 1.52392882089336643460e-03, + 1.51939651578598348275e-03, + 1.51400017895056589190e-03, + 1.50774362986558999739e-03, + 1.50063117622853013297e-03, + 1.49266761107828566796e-03, + 1.48385820964260146428e-03, + 1.47420872591265969889e-03, + 1.46372538894702294843e-03, + 1.45241489890715028306e-03, + 1.44028442282717193852e-03, + 1.42734159012037307990e-03, + 1.41359448782537428478e-03, + 1.39905165559475546354e-03, + 1.38372208042934524870e-03, + 1.36761519116132632817e-03, + 1.35074085268957954850e-03, + 1.33310935997071780372e-03, + 1.31473143176951009180e-03, + 1.29561820417240587851e-03, + 1.27578122386814139279e-03, + 1.25523244119940383980e-03, + 1.23398420298978994322e-03, + 1.21204924515017141255e-03, + 1.18944068506927815715e-03, + 1.16617201379247414916e-03, + 1.14225708799397369063e-03, + 1.11771012174662520873e-03, + 1.09254567809480241866e-03, + 1.06677866043477544145e-03, + 1.04042430370825892544e-03, + 1.01349816541371835939e-03, + 9.86016116441160682393e-04, + 9.57994331735642526242e-04, + 9.29449280794978792072e-04, + 9.00397718007248429838e-04, + 8.70856672833736898155e-04, + 8.40843439843083260109e-04, + 8.10375568602425999827e-04, + 7.79470853431471315254e-04, + 7.48147323025479091436e-04, + 7.16423229952991972615e-04, + 6.84317040034933634675e-04, + 6.51847421610750755311e-04, + 6.19033234697776140604e-04, + 5.85893520050684464551e-04, + 5.52447488126856715678e-04, + 5.18714507964034747881e-04, + 4.84714095977265707355e-04, + 4.50465904680799719868e-04, + 4.15989711342059980889e-04, + 3.81305406573980180604e-04, + 3.46432982872289069957e-04, + 3.11392523104614979499e-04, + 2.76204188957184101297e-04, + 2.40888209347176124927e-04, + 2.05464868805964193327e-04, + 1.69954495840752130374e-04, + 1.34377451281002371951e-04, + 9.87541166164100474301e-05, + 6.31048823327933465369e-05, + 2.74501362534655310964e-05, +-8.18974810873998083655e-06, +-4.37944231806596304514e-05, +-7.93435789334627901382e-05, +-1.14816954455838874283e-04, +-1.50194349489415440680e-04, +-1.85455635919215376531e-04, +-2.20580769213464333118e-04, +-2.55549799805626501933e-04, +-2.90342884412502183315e-04, +-3.24940297281641648271e-04, +-3.59322441362583172488e-04, +-3.93469859394135197499e-04, +-4.27363244902898627587e-04, +-4.60983453105939474694e-04, +-4.94311511711763339541e-04, +-5.27328631613451729448e-04, +-5.60016217467949450198e-04, +-5.92355878155555572520e-04, +-6.24329437113732110647e-04, +-6.55918942539445706461e-04, +-6.87106677454311985491e-04, +-7.17875169626881314694e-04, +-7.48207201346719435846e-04, +-7.78085819044304792189e-04, +-8.07494342752076792701e-04, +-8.36416375400828135574e-04, +-8.64835811946538645517e-04, +-8.92736848322267452678e-04, +-9.20103990210890628799e-04, +-9.46922061632605917975e-04, +-9.73176213343664533485e-04, +-9.98851931040956823177e-04, +-1.02393504336819934561e-03, +-1.04841172971923139896e-03, +-1.07226852783420443203e-03, +-1.09549234118443920144e-03, +-1.11807044614193923544e-03, +-1.13999049892964587558e-03, +-1.16124054234865384944e-03, +-1.18180901227872168710e-03, +-1.20168474394853771157e-03, +-1.22085697797251154818e-03, +-1.23931536615045907561e-03, +-1.25704997702758545543e-03, +-1.27405130121131457410e-03, +-1.29031025644257271376e-03, +-1.30581819241839158958e-03, +-1.32056689536371330701e-03, +-1.33454859234959002240e-03, +-1.34775595535592540575e-03, +-1.36018210507637331112e-03, +-1.37182061446355658269e-03, +-1.38266551201276610521e-03, +-1.39271128478253266095e-03, +-1.40195288115051316068e-03, +-1.41038571330337893055e-03, +-1.41800565945951256505e-03, +-1.42480906582346297101e-03, +-1.43079274827126803893e-03, +-1.43595399376592503145e-03, +-1.44029056150241801561e-03, +-1.44380068378189055887e-03, +-1.44648306661469805943e-03, +-1.44833689005223324210e-03, +-1.44936180824753674604e-03, +-1.44955794924493913504e-03, +-1.44892591449903443759e-03, +-1.44746677812355745846e-03, +-1.44518208587075661954e-03, +-1.44207385384213272739e-03, +-1.43814456693148930849e-03, +-1.43339717700140213338e-03, +-1.42783510079440463525e-03, +-1.42146221758030649220e-03, +-1.41428286654118624127e-03, +-1.40630184389584447259e-03, +-1.39752439976549721300e-03, +-1.38795623478277815703e-03, +-1.37760349644625219347e-03, +-1.36647277522266587767e-03, +-1.35457110039932790077e-03, +-1.34190593568940877423e-03, +-1.32848517459267919869e-03, +-1.31431713551467539529e-03, +-1.29941055664714501944e-03, +-1.28377459061317523298e-03, +-1.26741879887994307423e-03, +-1.25035314594268138870e-03, +-1.23258799328333345374e-03, +-1.21413409310764655244e-03, +-1.19500258186405750038e-03, +-1.17520497354900595698e-03, +-1.15475315280194222242e-03, +-1.13365936779458078426e-03, +-1.11193622291853085743e-03, +-1.08959667127568366092e-03, +-1.06665400697560715411e-03, +-1.04312185724514980105e-03, +-1.01901417435390105257e-03, +-9.94345227361283657413e-04, +-9.69129593689562135808e-04, +-9.43382150527953696438e-04, +-9.17118066072678981768e-04, +-8.90352790608596130796e-04, +-8.63102047436990239826e-04, +-8.35381823655337134304e-04, +-8.07208360794198893050e-04, +-7.78598145316998046898e-04, +-7.49567898987517377586e-04, +-7.20134569111909820377e-04, +-6.90315318659743713467e-04, +-6.60127516270525181372e-04, +-6.29588726151278908240e-04, +-5.98716697871097070296e-04, +-5.67529356058555788274e-04, +-5.36044790008002544103e-04, +-5.04281243200707597792e-04, +-4.72257102746954785574e-04, +-4.39990888755171366542e-04, +-4.07501243634276436468e-04, +-3.74806921335187493566e-04, +-3.41926776538259847692e-04, +-3.08879753792126179272e-04, +-2.75684876610755174881e-04, +-2.42361236534725988821e-04, +-2.08927982163283266397e-04, +-1.75404308162909107092e-04, +-1.41809444259267161117e-04, +-1.08162644218829444537e-04, +-7.44831748259327543465e-05, +-4.07903048621291604812e-05, +-7.10329409388432176530e-06, + 2.65586177250463047000e-05, + 6.01762218302914552804e-05, + 9.37303513963725428056e-05, + 1.27201892452491753700e-04, + 1.60571794759468988462e-04, + 1.93821082639647593359e-04, + 2.26930865755815396869e-04, + 2.59882349831586946780e-04, + 2.92656847307690018770e-04, + 3.25235787928080961190e-04, + 3.57600729249660839303e-04, + 3.89733367070243196494e-04, + 4.21615545768098812836e-04, + 4.53229268547830762767e-04, + 4.84556707586572316029e-04, + 5.15580214074757778309e-04, + 5.46282328146297608759e-04, + 5.76645788691256379679e-04, + 6.06653543047546025234e-04, + 6.36288756564360792091e-04, + 6.65534822032997838703e-04, + 6.94375368979479354152e-04, + 7.22794272813854533910e-04, + 7.50775663831016056536e-04, + 7.78303936058092520403e-04, + 8.05363755943419535807e-04, + 8.31940070882321368144e-04, + 8.58018117574883202973e-04, + 8.83583430211330928851e-04, + 9.08621848479962369513e-04, + 9.33119525393878300641e-04, + 9.57062934931689960998e-04, + 9.80438879488230432754e-04, + 1.00323449713107977488e-03, + 1.02543726865899926387e-03, + 1.04703502445835567626e-03, + 1.06801595115381007736e-03, + 1.08836859804968565969e-03, + 1.10808188335835252139e-03, + 1.12714510021262159095e-03, + 1.14554792245836578428e-03, + 1.16328041022489597940e-03, + 1.18033301526926739412e-03, + 1.19669658609257542788e-03, + 1.21236237282488557888e-03, + 1.22732203187633261143e-03, + 1.24156763035219172911e-03, + 1.25509165022920821282e-03, + 1.26788699229131874430e-03, + 1.27994697982256044888e-03, + 1.29126536205536050946e-03, + 1.30183631737235691941e-03, + 1.31165445626020235083e-03, + 1.32071482401390893208e-03, + 1.32901290319023448333e-03, + 1.33654461580914787205e-03, + 1.34330632530221187430e-03, + 1.34929483820697367936e-03, + 1.35450740560668671242e-03, + 1.35894172431470653187e-03, + 1.36259593780313340884e-03, + 1.36546863687537654505e-03, + 1.36755886008250635531e-03, + 1.36886609388332716047e-03, + 1.36939027254837260295e-03, + 1.36913177780802522952e-03, + 1.36809143824524986725e-03, + 1.36627052843346185988e-03, + 1.36367076782027457811e-03, + 1.36029431935798012128e-03, + 1.35614378788172988514e-03, + 1.35122221823664079472e-03, + 1.34553309315501787302e-03, + 1.33908033088521731709e-03, + 1.33186828257363392043e-03, + 1.32390172940159678815e-03, + 1.31518587947901410308e-03, + 1.30572636449661312261e-03, + 1.29552923613923372595e-03, + 1.28460096226200824743e-03, + 1.27294842283218667331e-03, + 1.26057890563882179363e-03, + 1.24750010177327374725e-03, + 1.23372010088306036796e-03, + 1.21924738620211555243e-03, + 1.20409082936042593007e-03, + 1.18825968497621972837e-03, + 1.17176358503399751995e-03, + 1.15461253305178279151e-03, + 1.13681689804116217886e-03, + 1.11838740826359175386e-03, + 1.09933514478704010865e-03, + 1.07967153484642012021e-03, + 1.05940834501207096011e-03, + 1.03855767417023879713e-03, + 1.01713194631976918542e-03, + 9.95143903189260560158e-04, + 9.72606596679090784803e-04, + 9.49533381132751461845e-04, + 9.25937905442090168628e-04, + 9.01834104991060562725e-04, + 8.77236193442972891042e-04, + 8.52158654375306323994e-04, + 8.26616232768399242931e-04, + 8.00623926351481181481e-04, + 7.74196976812098437357e-04, + 7.47350860873750573281e-04, + 7.20101281246932219647e-04, + 6.92464157459100611118e-04, + 6.64455616568401037821e-04, + 6.36091983767215129672e-04, + 6.07389772880511497576e-04, + 5.78365676764722234753e-04, + 5.49036557612754723412e-04, + 5.19419437170334677249e-04, + 4.89531486870367453512e-04, + 4.59390017889853828105e-04, + 4.29012471135610442413e-04, + 3.98416407164879030761e-04, + 3.67619496046182284588e-04, + 3.36639507166480267224e-04, + 3.05494298990473505794e-04, + 2.74201808777935912304e-04, + 2.42780042265004216643e-04, + 2.11247063315343980641e-04, + 1.79620983547136846585e-04, + 1.47919951941878261405e-04, + 1.16162144440711673481e-04, + 8.43657535348246083538e-05, + 5.25489778551051491483e-05, + 2.07300117675779430298e-05, +-1.10729650196668325771e-05, +-4.28417978320822792019e-05, +-7.45583673808965783410e-05, +-1.06204600086071425293e-04, +-1.37762478364149087246e-04, +-1.69214050874914927148e-04, +-2.00541442721614891851e-04, +-2.31726865598118244574e-04, +-2.62752627878274269604e-04, +-2.93601144640412165671e-04, +-3.24254947622835021804e-04, +-3.54696695103594577137e-04, +-3.84909181699200184275e-04, +-4.14875348077196936039e-04, +-4.44578290576414924141e-04, +-4.74001270730014352076e-04, +-5.03127724685752076780e-04, +-5.31941272518206861690e-04, +-5.60425727427743720910e-04, +-5.88565104821016545078e-04, +-6.16343631268131183359e-04, +-6.43745753330938032602e-04, +-6.70756146258231328826e-04, +-6.97359722542432612299e-04, +-7.23541640333268576586e-04, +-7.49287311703654272145e-04, +-7.74582410763238315282e-04, +-7.99412881615075860547e-04, +-8.23764946151039185139e-04, +-8.47625111681623221935e-04, +-8.70980178395970995424e-04, +-8.93817246647941095888e-04, +-9.16123724064377706680e-04, +-9.37887332471280203011e-04, +-9.59096114634606271634e-04, +-9.79738440811607448275e-04, +-9.99803015109290834847e-04, +-1.01927888164651272128e-03, +-1.03815543051633853155e-03, +-1.05642240354548912901e-03, +-1.07406989984759745557e-03, +-1.09108838116762723279e-03, +-1.10746867701414018585e-03, +-1.12320198957698577993e-03, +-1.13827989842765417428e-03, +-1.15269436499997502028e-03, +-1.16643773684832734866e-03, +-1.17950275168172556868e-03, +-1.19188254117136706138e-03, +-1.20357063452954798910e-03, +-1.21456096185834725582e-03, +-1.22484785726622159678e-03, +-1.23442606175099434812e-03, +-1.24329072584775926144e-03, +-1.25143741204040113979e-03, +-1.25886209693559965317e-03, +-1.26556117319820459269e-03, +-1.27153145124719456523e-03, +-1.27677016071131685555e-03, +-1.28127495164393639428e-03, +-1.28504389549651746975e-03, +-1.28807548585040771913e-03, +-1.29036863890675851559e-03, +-1.29192269373445381593e-03, +-1.29273741227616803182e-03, +-1.29281297911274461153e-03, +-1.29215000098622341193e-03, +-1.29074950608205050485e-03, +-1.28861294307102769788e-03, +-1.28574217991181470426e-03, +-1.28213950241485154062e-03, +-1.27780761256874805798e-03, +-1.27274962663027619951e-03, +-1.26696907297930137261e-03, +-1.26046988974006066338e-03, +-1.25325642217039056117e-03, +-1.24533341982049493464e-03, +-1.23670603346324884178e-03, +-1.22737981179783643172e-03, +-1.21736069792890478670e-03, +-1.20665502562341490217e-03, +-1.19526951534740743209e-03, +-1.18321127008547502014e-03, +-1.17048777094514431553e-03, +-1.15710687254899267061e-03, +-1.14307679821747196908e-03, +-1.12840613494519497600e-03, +-1.11310382817380736260e-03, +-1.09717917636461301072e-03, +-1.08064182537422016558e-03, +-1.06350176263660047178e-03, +-1.04576931115505939590e-03, +-1.02745512330771390092e-03, +-1.00857017447020984660e-03, +-9.89125756459348273036e-04, +-9.69133470801857087144e-04, +-9.48605221831876478482e-04, +-9.27553209621573911299e-04, +-9.05989922748946536341e-04, +-8.83928130907113245029e-04, +-8.61380877359472856523e-04, +-8.38361471245136369995e-04, +-8.14883479739194086997e-04, +-7.90960720072537894904e-04, +-7.66607251415539741463e-04, +-7.41837366630958413780e-04, +-7.16665583900111865384e-04, +-6.91106638228288503237e-04, +-6.65175472833141076361e-04, +-6.38887230421945938666e-04, +-6.12257244362626436643e-04, +-5.85301029753312320944e-04, +-5.58034274396206606862e-04, +-5.30472829680567778236e-04, +-5.02632701380270412693e-04, +-4.74530040371252698900e-04, +-4.46181133274236403283e-04, +-4.17602393028139700758e-04, +-3.88810349399469656114e-04, +-3.59821639433645487551e-04, +-3.30652997853107073409e-04, +-3.01321247408244021881e-04, +-2.71843289186502834551e-04, +-2.42236092885274642951e-04, +-2.12516687054165319707e-04, +-1.82702149312243965380e-04, +-1.52809596545888838484e-04, +-1.22856175092848034355e-04, +-9.28590509181383036126e-05, +-6.28353997874044387486e-05, +-3.28023974433953014970e-05, +-2.77720979095154411141e-06, + 2.72230169033535440140e-05, + 5.71811657920477271538e-05, + 8.70801592019578094960e-05, + 1.16902968358433966434e-04, + 1.46632623073032026736e-04, + 1.76252221389186882524e-04, + 2.05744939180186014712e-04, + 2.35094039694530468169e-04, + 2.64282883042567088867e-04, + 2.93294935619551385558e-04, + 3.22113779459532194229e-04, + 3.50723121515214011305e-04, + 3.79106802857572401221e-04, + 4.07248807791192634405e-04, + 4.35133272879688717035e-04, + 4.62744495875839806538e-04, + 4.90066944551884237959e-04, + 5.17085265424790572163e-04, + 5.43784292371653644321e-04, + 5.70149055130390425110e-04, + 5.96164787680977456552e-04, + 6.21816936502533586587e-04, + 6.47091168701626482176e-04, + 6.71973380007443560867e-04, + 6.96449702628909074476e-04, + 7.20506512970012593690e-04, + 7.44130439198579488221e-04, + 7.67308368664491478525e-04, + 7.90027455163207908972e-04, + 8.12275126040571966018e-04, + 8.34039089134997737793e-04, + 8.55307339553189088961e-04, + 8.76068166275680644713e-04, + 8.96310158588609247332e-04, + 9.16022212337969966855e-04, + 9.35193536003619163739e-04, + 9.53813656588502287864e-04, + 9.71872425321206783247e-04, + 9.89360023167912576089e-04, + 1.00626696615104373536e-03, + 1.02258411047174220705e-03, + 1.03830265743327931904e-03, + 1.05341415816306632411e-03, + 1.06791051813036243917e-03, + 1.08178400145754450255e-03, + 1.09502723502257035167e-03, + 1.10763321235048616507e-03, + 1.11959529729188916186e-03, + 1.13090722748666861440e-03, + 1.14156311761065294014e-03, + 1.15155746240435427445e-03, + 1.16088513948151006439e-03, + 1.16954141191641532681e-03, + 1.17752193060865497330e-03, + 1.18482273642408174330e-03, + 1.19144026211101582494e-03, + 1.19737133399079663347e-03, + 1.20261317342187467987e-03, + 1.20716339803685892770e-03, + 1.21102002275194891440e-03, + 1.21418146054847906831e-03, + 1.21664652302620073833e-03, + 1.21841442072828740756e-03, + 1.21948476323806070595e-03, + 1.21985755904754564205e-03, + 1.21953321519817120717e-03, + 1.21851253669401512168e-03, + 1.21679672568812116337e-03, + 1.21438738044255738029e-03, + 1.21128649406303441106e-03, + 1.20749645300896710394e-03, + 1.20302003538006298602e-03, + 1.19786040898056927312e-03, + 1.19202112916260414589e-03, + 1.18550613644981912495e-03, + 1.17831975394308238227e-03, + 1.17046668450985027511e-03, + 1.16195200775891173579e-03, + 1.15278117680258848643e-03, + 1.14296001480831705549e-03, + 1.13249471134179986558e-03, + 1.12139181850401392637e-03, + 1.10965824686446259441e-03, + 1.09730126119316579933e-03, + 1.08432847599404177941e-03, + 1.07074785084228674831e-03, + 1.05656768552886740596e-03, + 1.04179661501472100617e-03, + 1.02644360419797825434e-03, + 1.01051794249726128137e-03, + 9.94029238254327297819e-04, + 9.76987412959428496231e-04, + 9.59402695302853094836e-04, + 9.41285615056165433402e-04, + 9.22646996786851249575e-04, + 9.03497953410057892502e-04, + 8.83849879581315145925e-04, + 8.63714444933994722302e-04, + 8.43103587165879497442e-04, + 8.22029504978451252585e-04, + 8.00504650873420757484e-04, + 7.78541723810587853530e-04, + 7.56153661731407702139e-04, + 7.33353633952590140861e-04, + 7.10155033434391397620e-04, + 6.86571468927704795654e-04, + 6.62616757005092820061e-04, + 6.38304913980008450068e-04, + 6.13650147719164789327e-04, + 5.88666849352420377441e-04, + 5.63369584885875388305e-04, + 5.37773086722076747342e-04, + 5.11892245092671863312e-04, + 4.85742099408737208668e-04, + 4.59337829533421374787e-04, + 4.32694746982132956003e-04, + 4.05828286055327270860e-04, + 3.78753994909039224618e-04, + 3.51487526568311297540e-04, + 3.24044629888701042706e-04, + 2.96441140471124468109e-04, + 2.68692971535064537448e-04, + 2.40816104755891792965e-04, + 2.12826581070915530529e-04, + 1.84740491459934620937e-04, + 1.56573967705388389718e-04, + 1.28343173137436734367e-04, + 1.00064293369274724200e-04, + 7.17535270279865756201e-05, + 4.34270764862388947451e-05, + 1.51011386001131606149e-05, +-1.32081045416696524620e-05, +-4.14844948516519899375e-05, +-6.97119074558447989051e-05, +-9.78742598787180241452e-05, +-1.25955521195249200029e-04, +-1.53939721145969320030e-04, +-1.81810959208852370795e-04, +-2.09553413623342002373e-04, +-2.37151350361132772252e-04, +-2.64589132039119191708e-04, +-2.91851226768812584828e-04, +-3.18922216937715912854e-04, +-3.45786807917504923019e-04, +-3.72429836694131806071e-04, +-3.98836280414924259936e-04, +-4.24991264848284251536e-04, +-4.50880072750091832195e-04, +-4.76488152133843997395e-04, +-5.01801124438317467692e-04, +-5.26804792589028771099e-04, +-5.51485148948722817865e-04, +-5.75828383152479162180e-04, +-5.99820889823062712923e-04, +-6.23449276162207780341e-04, +-6.46700369413619538528e-04, +-6.69561224193530326286e-04, +-6.92019129684716838985e-04, +-7.14061616690151953514e-04, +-7.35676464541983651108e-04, +-7.56851707862541919249e-04, +-7.77575643173267975865e-04, +-7.97836835348055277602e-04, +-8.17624123907448297453e-04, +-8.36926629150230058478e-04, +-8.55733758119046612582e-04, +-8.74035210396826049359e-04, +-8.91820983730703649786e-04, +-9.09081379480705491225e-04, +-9.25807007889788277297e-04, +-9.41988793172909236878e-04, +-9.57617978421671824096e-04, +-9.72686130322748202653e-04, +-9.87185143686923052483e-04, +-1.00110724578650659398e-03, +-1.01444500049902323544e-03, +-1.02719131225463187161e-03, +-1.03933942978544770035e-03, +-1.05088294967471814964e-03, +-1.06181581970400955479e-03, +-1.07213234199665663482e-03, +-1.08182717595588814667e-03, +-1.09089534099611235214e-03, +-1.09933221906604130548e-03, +-1.10713355696224189685e-03, +-1.11429546843220921015e-03, +-1.12081443606577282543e-03, +-1.12668731297399537551e-03, +-1.13191132425482891832e-03, +-1.13648406824482742922e-03, +-1.14040351755644074963e-03, +-1.14366801990044438496e-03, +-1.14627629869328028812e-03, +-1.14822745344909417364e-03, +-1.14952095995648801048e-03, +-1.15015667024007182777e-03, +-1.15013481230698852258e-03, +-1.14945598967880415094e-03, +-1.14812118070920518922e-03, +-1.14613173768805766059e-03, +-1.14348938573257991221e-03, +-1.14019622146641639096e-03, +-1.13625471148757692386e-03, +-1.13166769062629166132e-03, +-1.12643835999398341310e-03, +-1.12057028482466340680e-03, +-1.11406739211015104116e-03, +-1.10693396803060797873e-03, +-1.09917465518223384131e-03, +-1.09079444960363011567e-03, +-1.08179869760285343912e-03, +-1.07219309238717466423e-03, +-1.06198367049757311231e-03, +-1.05117680805022224028e-03, +-1.03977921678728496210e-03, +-1.02779793993942468629e-03, +-1.01524034790259534006e-03, +-1.00211413373173349912e-03, +-9.88427308454093486029e-04, +-9.74188196205089573972e-04, +-9.59405429189479725879e-04, +-9.44087942471171881302e-04, +-9.28244968594481583042e-04, +-9.11886032040267347637e-04, +-8.95020943520216660794e-04, +-8.77659794112658803340e-04, +-8.59812949243432501564e-04, +-8.41491042515366753467e-04, +-8.22704969390060901480e-04, +-8.03465880725650455872e-04, +-7.83785176174564036933e-04, +-7.63674497444838786334e-04, +-7.43145721429159210325e-04, +-7.22210953206033133382e-04, +-7.00882518916405724239e-04, +-6.79172958520581071529e-04, +-6.57095018439407888011e-04, +-6.34661644084213061485e-04, +-6.11885972279487986777e-04, +-5.88781323583261557639e-04, +-5.65361194509265800601e-04, +-5.41639249655565977945e-04, +-5.17629313744230818220e-04, +-4.93345363576712316218e-04, +-4.68801519909265351684e-04, +-4.44012039254113445412e-04, +-4.18991305609581871604e-04, +-3.93753822125390276140e-04, +-3.68314202707166818418e-04, +-3.42687163565271075971e-04, +-3.16887514712763855660e-04, +-2.90930151417445159289e-04, +-2.64830045612876889462e-04, +-2.38602237273343473298e-04, +-2.12261825757707105287e-04, +-1.85823961127170580662e-04, +-1.59303835441746181271e-04, +-1.32716674040886725835e-04, +-1.06077726812662281766e-04, +-7.94022594569434886792e-05, +-5.27055447474102572785e-05, +-2.60028537974079832656e-05, + 6.90552665357526391948e-07, + 2.73594330103061967382e-05, + 5.39885733967170351332e-05, + 8.05627964425661594961e-05, + 1.07066969865010061308e-04, + 1.33486015086968664006e-04, + 1.59804915805331028064e-04, + 1.86008726516105670021e-04, + 2.12082580990773740320e-04, + 2.38011700700330354344e-04, + 2.63781403181116572490e-04, + 2.89377110338554649482e-04, + 3.14784356683413138554e-04, + 3.39988797496425883184e-04, + 3.64976216916463994978e-04, + 3.89732535947750265582e-04, + 4.14243820381606571868e-04, + 4.38496288628281076592e-04, + 4.62476319454435203307e-04, + 4.86170459622126181851e-04, + 5.09565431424569481242e-04, + 5.32648140115051980069e-04, + 5.55405681224405362376e-04, + 5.77825347763134713856e-04, + 5.99894637304163990538e-04, + 6.21601258942250942466e-04, + 6.42933140126212003714e-04, + 6.63878433360159405340e-04, + 6.84425522770043840912e-04, + 7.04563030531877763050e-04, + 7.24279823158044638691e-04, + 7.43565017638393201127e-04, + 7.62407987432378152909e-04, + 7.80798368309418419284e-04, + 7.98726064033930863682e-04, + 8.16181251892069835503e-04, + 8.33154388057122906319e-04, + 8.49636212790671986259e-04, + 8.65617755476581307410e-04, + 8.81090339485367181512e-04, + 8.96045586865937618293e-04, + 9.10475422862473118477e-04, + 9.24372080253872034986e-04, + 9.37728103513655198570e-04, + 9.50536352787640661209e-04, + 9.62790007687844002875e-04, + 9.74482570900335833865e-04, + 9.85607871605071426957e-04, + 9.96160068706062381411e-04, + 1.00613365387018584458e-03, + 1.01552345437301723939e-03, + 1.02432463575029123783e-03, + 1.03253270425362076584e-03, + 1.04014350910924206067e-03, + 1.04715324457870439731e-03, + 1.05355845182046950481e-03, + 1.05935602055159754607e-03, + 1.06454319050862085752e-03, + 1.06911755270714466277e-03, + 1.07307705049946027105e-03, + 1.07641998042986067850e-03, + 1.07914499288730056890e-03, + 1.08125109255521835092e-03, + 1.08273763865848467007e-03, + 1.08360434500746525242e-03, + 1.08385127983937892479e-03, + 1.08347886545726241128e-03, + 1.08248787766686694993e-03, + 1.08087944501203837150e-03, + 1.07865504780918649262e-03, + 1.07581651698158585126e-03, + 1.07236603269432462238e-03, + 1.06830612279092259861e-03, + 1.06363966103263283235e-03, + 1.05836986514164428132e-03, + 1.05250029464946915324e-03, + 1.04603484855193525419e-03, + 1.03897776277230035648e-03, + 1.03133360743408474848e-03, + 1.02310728394540504521e-03, + 1.01430402189651124034e-03, + 1.00492937577281401564e-03, + 9.94989221484924961370e-04, + 9.84489752718325020209e-04, + 9.73437477104688721023e-04, + 9.61839212217239581185e-04, + 9.49702081392630992861e-04, + 9.37033509381853305618e-04, + 9.23841217832837061606e-04, + 9.10133220607474814970e-04, + 8.95917818935899651529e-04, + 8.81203596410921950570e-04, + 8.65999413825665684263e-04, + 8.50314403857379305478e-04, + 8.34157965600880913111e-04, + 8.17539758954521347464e-04, + 8.00469698862303906568e-04, + 7.82957949415445273941e-04, + 7.65014917816926143072e-04, + 7.46651248212579373396e-04, + 7.27877815392361849668e-04, + 7.08705718365645193080e-04, + 6.89146273814000625765e-04, + 6.69211009425744215821e-04, + 6.48911657115913286138e-04, + 6.28260146135471188311e-04, + 6.07268596074486536641e-04, + 5.85949309762400622446e-04, + 5.64314766070410454152e-04, + 5.42377612619488803404e-04, + 5.20150658398866173708e-04, + 4.97646866298883240425e-04, + 4.74879345562723338432e-04, + 4.51861344161378882325e-04, + 4.28606241096286539726e-04, + 4.05127538634095468555e-04, + 3.81438854478096842863e-04, + 3.57553913880674515205e-04, + 3.33486541701773307050e-04, + 3.09250654417399727884e-04, + 2.84860252083193681537e-04, + 2.60329410257538723227e-04, + 2.35672271888895488046e-04, + 2.10903039172021308919e-04, + 1.86035965377764900275e-04, + 1.61085346661131244934e-04, + 1.36065513852313800395e-04, + 1.10990824235409179101e-04, + 8.58756533195474008359e-05, + 6.07343866069771497630e-05, + 3.55814113632548241332e-05, + 1.04311083936491137648e-05, +-1.47021561691009029690e-05, +-3.98040390611660384779e-05, +-6.48602280634465855726e-05, +-8.98564501522054298295e-05, +-1.14778479619700933784e-04, +-1.39612146160650535745e-04, +-1.64343342919338251907e-04, +-1.88958034493250977151e-04, +-2.13442264888526227673e-04, +-2.37782165422681623619e-04, +-2.61963962570504571396e-04, +-2.85973985747828166135e-04, +-3.09798675029788052153e-04, +-3.33424588798768176210e-04, +-3.56838411317501760876e-04, +-3.80026960223441392147e-04, +-4.02977193940015090100e-04, +-4.25676219000628282361e-04, +-4.48111297281314371974e-04, +-4.70269853137984079287e-04, +-4.92139480444267647663e-04, +-5.13707949526006615523e-04, +-5.34963213988673739162e-04, +-5.55893417433529703382e-04, +-5.76486900059300605252e-04, +-5.96732205145306224443e-04, +-6.16618085412612730242e-04, +-6.36133509259657436812e-04, +-6.55267666868877677634e-04, +-6.74009976180998601758e-04, +-6.92350088733664401595e-04, +-7.10277895361227803138e-04, +-7.27783531752448681514e-04, +-7.44857383863318112810e-04, +-7.61490093181871590539e-04, +-7.77672561841829005844e-04, +-7.93395957582958798182e-04, +-8.08651718554891877494e-04, +-8.23431557962021757127e-04, +-8.37727468546858129381e-04, +-8.51531726909685537062e-04, +-8.64836897661822056639e-04, +-8.77635837410563617207e-04, +-8.89921698573554803210e-04, +-9.01687933020594461521e-04, +-9.12928295540940920420e-04, +-9.23636847134304576554e-04, +-9.33807958123846902805e-04, +-9.43436311089422422263e-04, +-9.52516903619767376157e-04, +-9.61045050882069389411e-04, +-9.69016388007670759208e-04, +-9.76426872292704612667e-04, +-9.83272785212578647254e-04, +-9.89550734249325901482e-04, +-9.95257654530941207952e-04, +-1.00039081028195663871e-03, +-1.00494779608456845030e-03, +-1.00892653794981169979e-03, +-1.01232529419831556589e-03, +-1.01514265615029741774e-03, +-1.01737754862461565394e-03, +-1.01902923024675272530e-03, +-1.02009729356571554777e-03, +-1.02058166497997625417e-03, +-1.02048260447267446181e-03, +-1.01980070515639048741e-03, +-1.01853689262794660890e-03, +-1.01669242413375375544e-03, +-1.01426888754638775715e-03, +-1.01126820015312980997e-03, +-1.00769260725730729240e-03, +-1.00354468059351414899e-03, +-9.98827316557644555306e-04, +-9.93543734253049580854e-04, +-9.87697473353981499761e-04, +-9.81292391787839295494e-04, +-9.74332663237617449883e-04, +-9.66822774466185295462e-04, +-9.58767522464084383411e-04, +-9.50172011422648630022e-04, +-9.41041649534305781055e-04, +-9.31382145622106083493e-04, +-9.21199505600451087374e-04, +-9.10500028769397197308e-04, +-8.99290303944565551711e-04, +-8.87577205425210550085e-04, +-8.75367888802800289162e-04, +-8.62669786612691802744e-04, +-8.49490603831530729194e-04, +-8.35838313223061083780e-04, +-8.21721150535182709787e-04, +-8.07147609551117617942e-04, +-7.92126436997654084955e-04, +-7.76666627313488014232e-04, +-7.60777417280939101916e-04, +-7.44468280523723365504e-04, +-7.27748921874987655251e-04, +-7.10629271617923522104e-04, +-6.93119479603028368700e-04, +-6.75229909245266381526e-04, +-6.56971131404673501161e-04, +-6.38353918154137712354e-04, +-6.19389236437722294319e-04, +-6.00088241623651132139e-04, +-5.80462270955458170714e-04, +-5.60522836905225714695e-04, +-5.40281620432863491331e-04, +-5.19750464155060228240e-04, +-4.98941365428588355299e-04, +-4.77866469351204028841e-04, +-4.56538061684547645785e-04, +-4.34968561703376289593e-04, +-4.13170514974962768510e-04, +-3.91156586073003096314e-04, +-3.68939551230221718554e-04, +-3.46532290933948842939e-04, +-3.23947782468940600423e-04, +-3.01199092411757270073e-04, +-2.78299369081070745603e-04, +-2.55261834948078349290e-04, +-2.32099779011821834730e-04, +-2.08826549143248190420e-04, +-1.85455544402832308909e-04, +-1.62000207336008043239e-04, +-1.38474016250865456347e-04, +-1.14890477482541928256e-04, +-9.12631176487416705644e-05, +-6.76054759008182519671e-05, +-4.39310961748295172825e-05, +-2.02535194471571128164e-05, + 3.41372400124625000704e-06, + 2.70571223073466086593e-05, + 5.06631897304295544804e-05, + 7.42184743349819369285e-05, + 9.77095656468657952631e-05, + 1.21123102278798669873e-04, + 1.44445779520586308278e-04, + 1.67664356890219484351e-04, + 1.90765665640995252163e-04, + 2.13736616220833977771e-04, + 2.36564205679401197901e-04, + 2.59235525018876972973e-04, + 2.81737766484226406522e-04, + 3.04058230788827618760e-04, + 3.26184334271549601202e-04, + 3.48103615980852423070e-04, + 3.69803744682461728397e-04, + 3.91272525786277706496e-04, + 4.12497908188799451267e-04, + 4.33467991027201371770e-04, + 4.54171030341281908426e-04, + 4.74595445639567638761e-04, + 4.94729826365895158924e-04, + 5.14562938262885013335e-04, + 5.34083729628744225196e-04, + 5.53281337463915729412e-04, + 5.72145093504289737989e-04, + 5.90664530137289503671e-04, + 6.08829386198019386657e-04, + 6.26629612641936822176e-04, + 6.44055378091031721643e-04, + 6.61097074250476457111e-04, + 6.77745321192732130128e-04, + 6.93990972506254143876e-04, + 7.09825120305858456998e-04, + 7.25239100102302775876e-04, + 7.40224495528040305620e-04, + 7.54773142916835191284e-04, + 7.68877135734856572910e-04, + 7.82528828860328353779e-04, + 7.95720842710183188552e-04, + 8.08446067210845170301e-04, + 8.20697665611487049177e-04, + 8.32469078137362318050e-04, + 8.43754025481521134980e-04, + 8.54546512132969143805e-04, + 8.64840829539518206326e-04, + 8.74631559103689298733e-04, + 8.83913575010109465319e-04, + 8.92682046882942626005e-04, + 9.00932442271964615751e-04, + 9.08660528966120082696e-04, + 9.15862377133194608195e-04, + 9.22534361284796920223e-04, + 9.28673162065495115362e-04, + 9.34275767865342418421e-04, + 9.39339476254983990131e-04, + 9.43861895242741424407e-04, + 9.47840944353070817725e-04, + 9.51274855525978185397e-04, + 9.54162173837028583338e-04, + 9.56501758037713121358e-04, + 9.58292780916003973483e-04, + 9.59534729477142054460e-04, + 9.60227404944570409398e-04, + 9.60370922581348226629e-04, + 9.59965711332194985249e-04, + 9.59012513286591154055e-04, + 9.57512382963391348902e-04, + 9.55466686417531189252e-04, + 9.52877100169494421419e-04, + 9.49745609958331992936e-04, + 9.46074509319091115633e-04, + 9.41866397985661216001e-04, + 9.37124180120078799534e-04, + 9.31851062369440700205e-04, + 9.26050551751833660001e-04, + 9.19726453372463970473e-04, + 9.12882867971548752663e-04, + 9.05524189305535872827e-04, + 8.97655101363274135137e-04, + 8.89280575418887665219e-04, + 8.80405866923194158763e-04, + 8.71036512235576058406e-04, + 8.61178325198361390401e-04, + 8.50837393555776847279e-04, + 8.40020075219696923594e-04, + 8.28732994384399467708e-04, + 8.16983037492857960653e-04, + 8.04777349056774379821e-04, + 7.92123327333073561259e-04, + 7.79028619859369530695e-04, + 7.65501118851119729744e-04, + 7.51548956463218408713e-04, + 7.37180499918858086333e-04, + 7.22404346508583494919e-04, + 7.07229318462486390359e-04, + 6.91664457698695713146e-04, + 6.75719020451036778314e-04, + 6.59402471779397571228e-04, + 6.42724479965596788740e-04, + 6.25694910798709228936e-04, + 6.08323821752458095656e-04, + 5.90621456058646517734e-04, + 5.72598236680009584250e-04, + 5.54264760185757283245e-04, + 5.35631790533803520474e-04, + 5.16710252763027825043e-04, + 4.97511226599373773682e-04, + 4.78045939979498718704e-04, + 4.58325762495759227340e-04, + 4.38362198766371338136e-04, + 4.18166881734467700462e-04, + 3.97751565900299880723e-04, + 3.77128120490046988070e-04, + 3.56308522565547207937e-04, + 3.35304850078806907388e-04, + 3.14129274875331928468e-04, + 2.92794055650324276316e-04, + 2.71311530861826331624e-04, + 2.49694111604887615530e-04, + 2.27954274450881122505e-04, + 2.06104554256081410344e-04, + 1.84157536943679384566e-04, + 1.62125852263222448597e-04, + 1.40022166532036894350e-04, + 1.17859175362270858218e-04, + 9.56495963781261012088e-05, + 7.34061619272917469060e-05, + 5.11416117907757448134e-05, + 2.88686858953092775838e-05, + 6.60011703245474962544e-06, +-1.56513764112641267506e-05, +-3.78730977094623622752e-05, +-6.00523790315616779367e-05, +-8.21765886552515715992e-05, +-1.04233138151800156347e-04, +-1.26209489539367793924e-04, +-1.48093162401345972059e-04, +-1.69871740964736657117e-04, +-1.91532881135268300563e-04, +-2.13064317484699505389e-04, +-2.34453870186744113427e-04, +-2.55689451897549299090e-04, +-2.76759074576870677410e-04, +-2.97650856246099086537e-04, +-3.18353027679335392423e-04, +-3.38853939023753682018e-04, +-3.59142066345504676773e-04, +-3.79206018097636495413e-04, +-3.99034541506046805132e-04, +-4.18616528870369446116e-04, +-4.37941023775921783445e-04, +-4.56997227213373118440e-04, +-4.75774503602719464699e-04, +-4.94262386718192386383e-04, +-5.12450585510814218305e-04, +-5.30328989825377310544e-04, +-5.47887676008649280625e-04, +-5.65116912405763628310e-04, +-5.82007164741549449030e-04, +-5.98549101384425463745e-04, +-6.14733598488893004212e-04, +-6.30551745014977364258e-04, +-6.45994847621079656963e-04, +-6.61054435427856318212e-04, +-6.75722264650496957927e-04, +-6.89990323096750768871e-04, +-7.03850834528551736954e-04, +-7.17296262884492574242e-04, +-7.30319316361157646819e-04, +-7.42912951350982778652e-04, +-7.55070376234532832961e-04, +-7.66785055025333219143e-04, +-7.78050710864884066675e-04, +-7.88861329366501596444e-04, +-7.99211161806001623743e-04, +-8.09094728157404166971e-04, +-8.18506819972308029276e-04, +-8.27442503101282920627e-04, +-8.35897120255950105278e-04, +-8.43866293410389599859e-04, +-8.51345926040684010221e-04, +-8.58332205201442922232e-04, +-8.64821603438301273262e-04, +-8.70810880535423945462e-04, +-8.76297085097227715367e-04, +-8.81277555963454932789e-04, +-8.85749923457110387506e-04, +-8.89712110464565414381e-04, +-8.93162333347438598848e-04, +-8.96099102685879683565e-04, +-8.98521223852970446835e-04, +-9.00427797420107569638e-04, +-9.01818219393255059504e-04, +-9.02692181280114911909e-04, +-9.03049669988348823954e-04, +-9.02890967555027251605e-04, +-9.02216650707655248853e-04, +-9.01027590257164317372e-04, +-8.99324950323396755253e-04, +-8.97110187393653770935e-04, +-8.94385049215033777793e-04, +-8.91151573521319268802e-04, +-8.87412086595320399006e-04, +-8.83169201667640974690e-04, +-8.78425817152939884119e-04, +-8.73185114724849367231e-04, +-8.67450557230792511539e-04, +-8.61225886448070839484e-04, +-8.54515120682583636733e-04, +-8.47322552211840669678e-04, +-8.39652744573696728503e-04, +-8.31510529702644309025e-04, +-8.22901004915378340120e-04, +-8.13829529747517842198e-04, +-8.04301722643430768052e-04, +-7.94323457501185689437e-04, +-7.83900860074752763550e-04, +-7.73040304235644501474e-04, +-7.61748408096249419140e-04, +-7.50032029997244466084e-04, +-7.37898264361402087853e-04, +-7.25354437416511968473e-04, +-7.12408102789705661648e-04, +-6.99067036976015396266e-04, +-6.85339234683824977817e-04, +-6.71232904059968502400e-04, +-6.56756461797351536944e-04, +-6.41918528127957059397e-04, +-6.26727921704332315012e-04, +-6.11193654372324123199e-04, +-5.95324925838475161287e-04, +-5.79131118235020063596e-04, +-5.62621790585767769452e-04, +-5.45806673175928220784e-04, +-5.28695661829722569208e-04, +-5.11298812098492927447e-04, +-4.93626333363000229307e-04, +-4.75688582853520537230e-04, +-4.57496059590992946043e-04, +-4.39059398252854521209e-04, +-4.20389362967140572426e-04, +-4.01496841038451060622e-04, +-3.82392836609444868555e-04, +-3.63088464261537163542e-04, +-3.43594942558548969210e-04, +-3.23923587536901721236e-04, +-3.04085806146491737303e-04, +-2.84093089645560742049e-04, +-2.63957006953748822640e-04, +-2.43689197967006995066e-04, +-2.23301366838275436311e-04, +-2.02805275227777953529e-04, +-1.82212735526838365925e-04, +-1.61535604059103902281e-04, +-1.40785774263093080554e-04, +-1.19975169859954066938e-04, +-9.91157380105508263764e-05, +-7.82194424651331946842e-05, +-5.72982567107504074688e-05, +-3.63641571189655019264e-05, +-1.54291160986802106125e-05, + 5.49490474234285622543e-06, + 2.63959614233348352161e-05, + 4.72621343997122955673e-05, + 6.80815353521026694937e-05, + 8.88423139508433642357e-05, + 1.09532664592484337918e-04, + 1.30140833104319903011e-04, + 1.50655123413172910328e-04, + 1.71063904174602321451e-04, + 1.91355615359099600053e-04, + 2.11518774790675712300e-04, + 2.31541984635477411745e-04, + 2.51413937835562545462e-04, + 2.71123424484858896975e-04, + 2.90659338143525736164e-04, + 3.10010682087186043628e-04, + 3.29166575487528168323e-04, + 3.48116259520795355564e-04, + 3.66849103400749643276e-04, + 3.85354610332733758284e-04, + 4.03622423385466462271e-04, + 4.21642331277442610968e-04, + 4.39404274074367811459e-04, + 4.56898348794905137527e-04, + 4.74114814921268088160e-04, + 4.91044099811763397334e-04, + 5.07676804012220281824e-04, + 5.24003706463404693612e-04, + 5.40015769601512427185e-04, + 5.55704144348954519501e-04, + 5.71060174992583653546e-04, + 5.86075403946940813073e-04, + 6.00741576399512768568e-04, + 6.15050644835952228101e-04, + 6.28994773442125574073e-04, + 6.42566342381337704884e-04, + 6.55757951943882421396e-04, + 6.68562426566777384153e-04, + 6.80972818721725897499e-04, + 6.92982412668881352959e-04, + 7.04584728074633746646e-04, + 7.15773523491389403184e-04, + 7.26542799697492522500e-04, + 7.36886802895533226179e-04, + 7.46800027767298055768e-04, + 7.56277220383868350323e-04, + 7.65313380969130045012e-04, + 7.73903766515502376799e-04, + 7.82043893250363385782e-04, + 7.89729538951949232121e-04, + 7.96956745113565389119e-04, + 8.03721818954994393636e-04, + 8.10021335280101820522e-04, + 8.15852138179731594357e-04, + 8.21211342579053417585e-04, + 8.26096335628634381720e-04, + 8.30504777938583372936e-04, + 8.34434604655206872172e-04, + 8.37884026379746372007e-04, + 8.40851529928737925421e-04, + 8.43335878935819161471e-04, + 8.45336114294710332107e-04, + 8.46851554443294471733e-04, + 8.47881795488795693763e-04, + 8.48426711174108750049e-04, + 8.48486452685477828516e-04, + 8.48061448301770160786e-04, + 8.47152402885697889713e-04, + 8.45760297217433587059e-04, + 8.43886387171142548884e-04, + 8.41532202735059621686e-04, + 8.38699546875822229616e-04, + 8.35390494247859852379e-04, + 8.31607389748687583081e-04, + 8.27352846921140154882e-04, + 8.22629746203563960195e-04, + 8.17441233029105799972e-04, + 8.11790715775362542797e-04, + 8.05681863565683954384e-04, + 7.99118603923527101411e-04, + 7.92105120281344542502e-04, + 7.84645849345590325717e-04, + 7.76745478319420114104e-04, + 7.68408941984943219712e-04, + 7.59641419646665534519e-04, + 7.50448331938106580861e-04, + 7.40835337493533463253e-04, + 7.30808329486818254554e-04, + 7.20373432039535070703e-04, + 7.09536996500486488726e-04, + 6.98305597598893957115e-04, + 6.86686029473570981770e-04, + 6.74685301580476909020e-04, + 6.62310634481180966239e-04, + 6.49569455514414613798e-04, + 6.36469394353982704203e-04, + 6.23018278454912912898e-04, + 6.09224128391051378099e-04, + 5.95095153086705442279e-04, + 5.80639744945168250270e-04, + 5.65866474877092448525e-04, + 5.50784087231426526705e-04, + 5.35401494632215197225e-04, + 5.19727772724077859492e-04, + 5.03772154829525923431e-04, + 4.87544026521280851084e-04, + 4.71052920112772989698e-04, + 4.54308509069835603569e-04, + 4.37320602347533553267e-04, + 4.20099138654383497463e-04, + 4.02654180648284807775e-04, + 3.84995909067011564137e-04, + 3.67134616796844961539e-04, + 3.49080702882780392719e-04, + 3.30844666483778653780e-04, + 3.12437100776581622944e-04, + 2.93868686811618183737e-04, + 2.75150187324561020918e-04, + 2.56292440507140670877e-04, + 2.37306353740675621137e-04, + 2.18202897296279266356e-04, + 1.98993098004925772883e-04, + 1.79688032901358264856e-04, + 1.60298822845364506793e-04, + 1.40836626124112224753e-04, + 1.21312632039215933556e-04, + 1.01738054482220324185e-04, + 8.21241255021581603984e-05, + 6.24820888690072755080e-05, + 4.28231936363832337185e-05, + 2.31586877076589681926e-05, + 3.49981140855670628566e-06, +-1.61422089292776860909e-05, +-3.57561673710188603244e-05, +-5.53308847633998468008e-05, +-7.48552150979509803470e-05, +-9.43180518494260796856e-05, +-1.13708334285348401584e-04, +-1.33015053743449631566e-04, +-1.52227259873300292507e-04, +-1.71334066838623079324e-04, +-1.90324659476782091653e-04, +-2.09188299411965425824e-04, +-2.27914331118587613423e-04, +-2.46492187931631313944e-04, +-2.64911398000205382339e-04, +-2.83161590181416034876e-04, +-3.01232499870904074039e-04, +-3.19113974766915017931e-04, +-3.36795980564636679867e-04, +-3.54268606577632174954e-04, +-3.71522071283203947009e-04, +-3.88546727788614181063e-04, +-4.05333069215096399290e-04, +-4.21871733996659933463e-04, +-4.38153511090731847231e-04, +-4.54169345097848065496e-04, +-4.69910341287265624979e-04, +-4.85367770526103374431e-04, +-5.00533074108989832485e-04, +-5.15397868485681603760e-04, +-5.29953949884007929905e-04, +-5.44193298825634374886e-04, +-5.58108084532057653962e-04, +-5.71690669218670195068e-04, +-5.84933612274217158006e-04, +-5.97829674323603708214e-04, +-6.10371821171734304026e-04, +-6.22553227626419856781e-04, +-6.34367281197839366289e-04, +-6.45807585673186250637e-04, +-6.56867964564019149454e-04, +-6.67542464424877488548e-04, +-6.77825358041074066233e-04, +-6.87711147484166077093e-04, +-6.97194567033422758773e-04, +-7.06270585961741746359e-04, +-7.14934411184561628694e-04, +-7.23181489770394637234e-04, +-7.31007511311650994522e-04, +-7.38408410154600355381e-04, +-7.45380367487197487489e-04, +-7.51919813283889650751e-04, +-7.58023428106295344038e-04, +-7.63688144758921860430e-04, +-7.68911149799110884596e-04, +-7.73689884900469453805e-04, +-7.78022048069176852536e-04, +-7.81905594712582730464e-04, +-7.85338738559663196610e-04, +-7.88319952432907605604e-04, +-7.90847968871373333856e-04, +-7.92921780604692572579e-04, +-7.94540640877896479737e-04, +-7.95704063626980471514e-04, +-7.96411823505323844020e-04, +-7.96663955761047642458e-04, +-7.96460755965521980358e-04, +-7.95802779593343299035e-04, +-7.94690841454150087575e-04, +-7.93126014976744679770e-04, +-7.91109631346083286806e-04, +-7.88643278493758549327e-04, +-7.85728799942701674856e-04, +-7.82368293506905928061e-04, +-7.78564109847002514854e-04, +-7.74318850882812310596e-04, +-7.69635368063673682044e-04, +-7.64516760497901438909e-04, +-7.58966372942442794175e-04, +-7.52987793654077996498e-04, +-7.46584852103500504379e-04, +-7.39761616553728774091e-04, +-7.32522391504357027643e-04, +-7.24871715003236934821e-04, +-7.16814355827273216350e-04, +-7.08355310534040027645e-04, +-6.99499800386016380889e-04, +-6.90253268149437163720e-04, +-6.80621374769529714592e-04, +-6.70609995924295360266e-04, +-6.60225218458873998675e-04, +-6.49473336702642350601e-04, +-6.38360848671277059801e-04, +-6.26894452156058273537e-04, +-6.15081040702747340251e-04, +-6.02927699482527735750e-04, +-5.90441701057256335301e-04, +-5.77630501041881037026e-04, +-5.64501733666179588388e-04, +-5.51063207239021373221e-04, +-5.37322899517202385612e-04, +-5.23288952982047124961e-04, +-5.08969670026456150538e-04, +-4.94373508055059602412e-04, +-4.79509074500653401096e-04, +-4.64385121759629336102e-04, +-4.49010542049456493497e-04, +-4.33394362191214064118e-04, +-4.17545738320244637712e-04, +-4.01473950527997305165e-04, +-3.85188397438232619108e-04, +-3.68698590720627130540e-04, +-3.52014149545262831995e-04, +-3.35144794980849110039e-04, +-3.18100344340219566650e-04, +-3.00890705476273645578e-04, +-2.83525871031688149124e-04, +-2.66015912645737500133e-04, +-2.48370975121568597112e-04, +-2.30601270557308229850e-04, +-2.12717072444391431304e-04, +-1.94728709736517952358e-04, +-1.76646560892675731939e-04, +-1.58481047897534086224e-04, +-1.40242630262970099540e-04, +-1.21941799013744982391e-04, +-1.03589070661107662103e-04, +-8.51949811676530225713e-05, +-6.67700799069139572109e-05, +-4.83249236211274086098e-05, +-2.98700703807564870525e-05, +-1.14160735488978414020e-05, + 7.02652424554682768497e-06, + 2.54471971228236679705e-05, + 4.38354419518023738413e-05, + 6.21807843308446069313e-05, + 8.04727845460066358498e-05, + 9.87010435040899136066e-05, + 1.16855208636383958460e-04, + 1.34924979770344443406e-04, + 1.52900114965400754944e-04, + 1.70770436309920342057e-04, + 1.88525835675920134431e-04, + 2.06156280428297997024e-04, + 2.23651819085366783272e-04, + 2.41002586927498689160e-04, + 2.58198811550729352172e-04, + 2.75230818362170949389e-04, + 2.92089036014278136209e-04, + 3.08764001774616207285e-04, + 3.25246366828520531121e-04, + 3.41526901511388200801e-04, + 3.57596500467790591720e-04, + 3.73446187734516289129e-04, + 3.89067121744707245228e-04, + 4.04450600250306482528e-04, + 4.19588065160076859831e-04, + 4.34471107290538996557e-04, + 4.49091471027067759818e-04, + 4.63441058892829452643e-04, + 4.77511936022862045707e-04, + 4.91296334540600198627e-04, + 5.04786657835014449663e-04, + 5.17975484735516645760e-04, + 5.30855573582563605717e-04, + 5.43419866191619145568e-04, + 5.55661491708522902247e-04, + 5.67573770353875343975e-04, + 5.79150217054632036016e-04, + 5.90384544960849454512e-04, + 6.01270668845691608206e-04, + 6.11802708386863214850e-04, + 6.21974991327834889066e-04, + 6.31782056516764687314e-04, + 6.41218656822146407942e-04, + 6.50279761923036299723e-04, + 6.58960560972716405566e-04, + 6.67256465134287500389e-04, + 6.75163109986891556320e-04, + 6.82676357801303567048e-04, + 6.89792299683732634992e-04, + 6.96507257586713749917e-04, + 7.02817786186088130918e-04, + 7.08720674623126924326e-04, + 7.14212948110944231481e-04, + 7.19291869404349885550e-04, + 7.23954940132546750399e-04, + 7.28199901993943090293e-04, + 7.32024737812592227876e-04, + 7.35427672455747746989e-04, + 7.38407173612188813538e-04, + 7.40961952430967151807e-04, + 7.43090964020374881993e-04, + 7.44793407806954867699e-04, + 7.46068727754538611394e-04, + 7.46916612443245453087e-04, + 7.47336995008605268868e-04, + 7.47330052940939869310e-04, + 7.46896207745253873714e-04, + 7.46036124461981245935e-04, + 7.44750711048991790794e-04, + 7.43041117625342466269e-04, + 7.40908735577333176642e-04, + 7.38355196527534156196e-04, + 7.35382371167495095879e-04, + 7.31992367954923252131e-04, + 7.28187531676248857131e-04, + 7.23970441875473923535e-04, + 7.19343911150391139564e-04, + 7.14310983317213688513e-04, + 7.08874931444885593435e-04, + 7.03039255760210023485e-04, + 6.96807681425207193181e-04, + 6.90184156188062745106e-04, + 6.83172847909139504749e-04, + 6.75778141963576887280e-04, + 6.68004638522109246875e-04, + 6.59857149711750939035e-04, + 6.51340696658104286593e-04, + 6.42460506411091959722e-04, + 6.33222008755997788076e-04, + 6.23630832911684193816e-04, + 6.13692804118148903594e-04, + 6.03413940115261806379e-04, + 5.92800447514970491047e-04, + 5.81858718069071527597e-04, + 5.70595324834820847096e-04, + 5.59017018240628819903e-04, + 5.47130722054300845832e-04, + 5.34943529255999883701e-04, + 5.22462697818653785606e-04, + 5.09695646398130772746e-04, + 4.96649949935782969619e-04, + 4.83333335176001986210e-04, + 4.69753676101234622468e-04, + 4.55918989287601634543e-04, + 4.41837429183325480515e-04, + 4.27517283312972833521e-04, + 4.12966967410454712222e-04, + 3.98195020483432121378e-04, + 3.83210099812103391695e-04, + 3.68020975885298450622e-04, + 3.52636527276817995143e-04, + 3.37065735465011645077e-04, + 3.21317679598622223548e-04, + 3.05401531211941905386e-04, + 2.89326548892257452619e-04, + 2.73102072902946376928e-04, + 2.56737519764977252090e-04, + 2.40242376800225943771e-04, + 2.23626196639659541874e-04, + 2.06898591699577582680e-04, + 1.90069228629096543095e-04, + 1.73147822732087712776e-04, + 1.56144132366777384441e-04, + 1.39067953326214697627e-04, + 1.21929113202958933396e-04, + 1.04737465740963099658e-04, + 8.75028851780528622514e-05, + 7.02352605825545112366e-05, + 5.29444901866215451251e-05, + 3.56404757200933205497e-05, + 1.83331167478597644273e-05, + 1.03230501413102183826e-06, +-1.62520812034707693762e-05, +-3.35101827263670735968e-05, +-5.07321650911279374628e-05, +-6.79082241459080256747e-05, +-8.50285916240537564164e-05, +-1.02083540691677796268e-04, +-1.19063391466316483881e-04, +-1.35958516502816118129e-04, +-1.52759346244455719837e-04, +-1.69456374435215186046e-04, +-1.86040163490673691061e-04, +-2.02501349824351403305e-04, +-2.18830649126511295058e-04, +-2.35018861592449355329e-04, +-2.51056877097335180617e-04, +-2.66935680314695194647e-04, +-2.82646355775669996281e-04, +-2.98180092866208153266e-04, +-3.13528190759385430846e-04, +-3.28682063280201183005e-04, +-3.43633243699864576997e-04, +-3.58373389457262059472e-04, +-3.72894286804705877604e-04, +-3.87187855375492433196e-04, +-4.01246152670716468933e-04, +-4.15061378462855390652e-04, +-4.28625879113702864826e-04, +-4.41932151804175915588e-04, +-4.54972848673900734286e-04, +-4.67740780867979507370e-04, +-4.80228922488919207114e-04, +-4.92430414451660788955e-04, +-5.04338568239140645766e-04, +-5.15946869556969272587e-04, +-5.27248981884690759263e-04, +-5.38238749922089398589e-04, +-5.48910202928370723023e-04, +-5.59257557952611700225e-04, +-5.69275222953672071884e-04, +-5.78957799807889249809e-04, +-5.88300087202963859455e-04, +-5.97297083416476414473e-04, +-6.05943988977575135647e-04, +-6.14236209210458085871e-04, +-6.22169356658183671412e-04, +-6.29739253385739618761e-04, +-6.36941933161007476510e-04, +-6.43773643512582892379e-04, +-6.50230847663354235948e-04, +-6.56310226338886878658e-04, +-6.62008679449682451920e-04, +-6.67323327646487897066e-04, +-6.72251513747878452071e-04, +-6.76790804039441285488e-04, +-6.80938989443917279398e-04, +-6.84694086561815564058e-04, +-6.88054338581924984468e-04, +-6.91018216061473023945e-04, +-6.93584417575499262779e-04, +-6.95751870235252118692e-04, +-6.97519730075439408322e-04, +-6.98887382310238512544e-04, +-6.99854441458020392307e-04, +-7.00420751334910186674e-04, +-7.00586384917250637808e-04, +-7.00351644073214348388e-04, +-6.99717059163839283017e-04, +-6.98683388513845408767e-04, +-6.97251617752650001102e-04, +-6.95422959026119487901e-04, +-6.93198850079607088379e-04, +-6.90580953212918528285e-04, +-6.87571154107985264316e-04, +-6.84171560529966103770e-04, +-6.80384500902708982788e-04, +-6.76212522759481789864e-04, +-6.71658391069967749057e-04, +-6.66725086444653041590e-04, +-6.61415803217692819561e-04, +-6.55733947409528573555e-04, +-6.49683134570482436268e-04, +-6.43267187506764773208e-04, +-6.36490133890204668257e-04, +-6.29356203753268024677e-04, +-6.21869826870875635171e-04, +-6.14035630030630393862e-04, +-6.05858434193134814082e-04, +-5.97343251544118505024e-04, +-5.88495282440187417530e-04, +-5.79319912250014150239e-04, +-5.69822708092951237674e-04, +-5.60009415476908612407e-04, +-5.49885954837576801033e-04, +-5.39458417981255439720e-04, +-5.28733064433041348440e-04, +-5.17716317692869828875e-04, +-5.06414761401502129881e-04, +-4.94835135418839880059e-04, +-4.82984331816689843164e-04, +-4.70869390788640387446e-04, +-4.58497496479242630431e-04, +-4.45875972735065601461e-04, +-4.33012278780107377589e-04, +-4.19914004818108983763e-04, +-4.06588867564375744564e-04, +-3.93044705709642795341e-04, +-3.79289475318866453699e-04, +-3.65331245167339706530e-04, +-3.51178192017081926713e-04, +-3.36838595836177763076e-04, +-3.22320834963867378347e-04, +-3.07633381224204521288e-04, +-2.92784794991132475261e-04, +-2.77783720207839526437e-04, +-2.62638879363297228237e-04, +-2.47359068428886473296e-04, +-2.31953151758071922503e-04, +-2.16430056951960250863e-04, +-2.00798769693994654060e-04, +-1.85068328556394910873e-04, +-1.69247819781622929874e-04, +-1.53346372041766269151e-04, +-1.37373151178878973033e-04, +-1.21337354929306262606e-04, +-1.05248207635004573535e-04, +-8.91149549450086627062e-05, +-7.29468585098004703403e-05, +-5.67531906719987081617e-05, +-4.05432291561632574743e-05, +-2.43262517606341878125e-05, +-8.11153105499568761387e-06, + 8.09167091459697115441e-06, + 2.42741079085157292628e-05, + 4.04265547626939556413e-05, + 5.65398126401744739798e-05, + 7.26047142624750100346e-05, + 8.86121291176844783554e-05, + 1.04552968642355261246e-04, + 1.20418191374254643930e-04, + 1.36198808073058146538e-04, + 1.51885886806070295480e-04, + 1.67470557996213817529e-04, + 1.82944019429153478633e-04, + 1.98297541217112740890e-04, + 2.13522470716304618504e-04, + 2.28610237395321440291e-04, + 2.43552357651734171758e-04, + 2.58340439574197757323e-04, + 2.72966187647394017187e-04, + 2.87421407397178490465e-04, + 3.01698009973331443285e-04, + 3.15788016667368121211e-04, + 3.29683563362888126455e-04, + 3.43376904915868638030e-04, + 3.56860419462906380220e-04, + 3.70126612654194222032e-04, + 3.83168121809794538692e-04, + 3.95977719996309473864e-04, + 4.08548320021925631847e-04, + 4.20872978347595460679e-04, + 4.32944898912126369117e-04, + 4.44757436869292204114e-04, + 4.56304102234621905294e-04, + 4.67578563440100960016e-04, + 4.78574650794741016362e-04, + 4.89286359849140845869e-04, + 4.99707854662346487480e-04, + 5.09833470968881633315e-04, + 5.19657719244667921921e-04, + 5.29175287669990585850e-04, + 5.38381044987819995518e-04, + 5.47270043256114818893e-04, + 5.55837520492576445640e-04, + 5.64078903210458873843e-04, + 5.71989808844079565542e-04, + 5.79566048062779125977e-04, + 5.86803626972093816082e-04, + 5.93698749201003678558e-04, + 6.00247817874220647612e-04, + 6.06447437468376929041e-04, + 6.12294415551340506093e-04, + 6.17785764403646210467e-04, + 6.22918702521296861058e-04, + 6.27690655999173577340e-04, + 6.32099259794388049390e-04, + 6.36142358868971454465e-04, + 6.39818009211379277838e-04, + 6.43124478736333145788e-04, + 6.46060248062606972720e-04, + 6.48624011168465121509e-04, + 6.50814675924448241516e-04, + 6.52631364503392400953e-04, + 6.54073413667472913086e-04, + 6.55140374932347883084e-04, + 6.55832014608344012786e-04, + 6.56148313718822465482e-04, + 6.56089467795875169558e-04, + 6.55655886553618491575e-04, + 6.54848193439355763003e-04, + 6.53667225063030848942e-04, + 6.52114030505376840972e-04, + 6.50189870505314443556e-04, + 6.47896216527166549613e-04, + 6.45234749708334539252e-04, + 6.42207359688187111660e-04, + 6.38816143318927205305e-04, + 6.35063403259281166260e-04, + 6.30951646451974345643e-04, + 6.26483582485939526248e-04, + 6.21662121844317769152e-04, + 6.16490374039393236767e-04, + 6.10971645635609837167e-04, + 6.05109438161931267354e-04, + 5.98907445914837149696e-04, + 5.92369553653347702404e-04, + 5.85499834187430895707e-04, + 5.78302545861415578064e-04, + 5.70782129933787834436e-04, + 5.62943207855098252772e-04, + 5.54790578445580164282e-04, + 5.46329214974210436787e-04, + 5.37564262140980504354e-04, + 5.28501032964188142450e-04, + 5.19145005574684313687e-04, + 5.09501819918850898904e-04, + 4.99577274372495932532e-04, + 4.89377322267549059315e-04, + 4.78908068333559408525e-04, + 4.68175765056459951968e-04, + 4.57186808956279780707e-04, + 4.45947736786433599192e-04, + 4.34465221656520647706e-04, + 4.22746069081200064391e-04, + 4.10797212957284853512e-04, + 3.98625711471500149014e-04, + 3.86238742941308148531e-04, + 3.73643601591243563771e-04, + 3.60847693267234983453e-04, + 3.47858531091431943082e-04, + 3.34683731060088070306e-04, + 3.21331007586994784036e-04, + 3.07808168995286370300e-04, + 2.94123112959944975862e-04, + 2.80283821903894213648e-04, + 2.66298358350258257497e-04, + 2.52174860233517097834e-04, + 2.37921536172264099776e-04, + 2.23546660706324561889e-04, + 2.09058569500978578149e-04, + 1.94465654521075659777e-04, + 1.79776359177804124882e-04, + 1.64999173451064800808e-04, + 1.50142628989783814353e-04, + 1.35215294193867887652e-04, + 1.20225769279667712834e-04, + 1.05182681332417253214e-04, + 9.00946793482652321869e-05, + 7.49704292687580406678e-05, + 5.98186090107322883933e-05, + 4.46479034941903122767e-05, + 2.94669996713655661538e-05, + 1.42845815595480592387e-05, +-8.90674719386678467731e-07, +-1.60501058898957495679e-05, +-3.11850664615309880164e-05, +-4.62869336522098696559e-05, +-6.13471122938098376541e-05, +-7.63570397170260420881e-05, +-9.13081906125804212970e-05, +-1.06192081866257116186e-04, +-1.21000277364919335359e-04, +-1.35724392770807756941e-04, +-1.50356100261421840461e-04, +-1.64887133232308251375e-04, +-1.79309290960107407722e-04, +-1.93614443223211164184e-04, +-2.07794534877538741033e-04, +-2.21841590384600493343e-04, +-2.35747718289653712892e-04, +-2.49505115647181735690e-04, +-2.63106072391320949463e-04, +-2.76542975648779115836e-04, +-2.89808313991833633137e-04, +-3.02894681629039077587e-04, +-3.15794782531314804225e-04, +-3.28501434491123775472e-04, +-3.41007573112413263187e-04, +-3.53306255729321028528e-04, +-3.65390665251150495701e-04, +-3.77254113931894290764e-04, +-3.88890047061697880296e-04, +-4.00292046578829127310e-04, +-4.11453834599746401911e-04, +-4.22369276865425247180e-04, +-4.33032386102221345144e-04, +-4.43437325295184645198e-04, +-4.53578410872218030017e-04, +-4.63450115797292723756e-04, +-4.73047072571043994947e-04, +-4.82364076137125729737e-04, +-4.91396086692756878071e-04, +-5.00138232402001195638e-04, +-5.08585812010168398199e-04, +-5.16734297358173813065e-04, +-5.24579335795330296312e-04, +-5.32116752489386786451e-04, +-5.39342552632568559418e-04, +-5.46252923542469171619e-04, +-5.52844236656707828902e-04, +-5.59113049420296060084e-04, +-5.65056107064770439183e-04, +-5.70670344278172711819e-04, +-5.75952886765007470403e-04, +-5.80901052695480778210e-04, +-5.85512354043150645873e-04, +-5.89784497810519033403e-04, +-5.93715387141844816964e-04, +-5.97303122322707935599e-04, +-6.00546001665863931999e-04, +-6.03442522282995321911e-04, +-6.05991380742033013650e-04, +-6.08191473609774341941e-04, +-6.10041897879654818233e-04, +-6.11541951284462828586e-04, +-6.12691132494012132698e-04, +-6.13489141197734759101e-04, +-6.13935878072276153793e-04, +-6.14031444634213687678e-04, +-6.13776142978129783147e-04, +-6.13170475400273522204e-04, +-6.12215143908160716602e-04, +-6.10911049616502535922e-04, +-6.09259292029921744813e-04, +-6.07261168212986615807e-04, +-6.04918171848152540562e-04, +-6.02231992182249067230e-04, +-5.99204512862249404591e-04, +-5.95837810661095862788e-04, +-5.92134154094380829765e-04, +-5.88096001928879556775e-04, +-5.83726001583780864344e-04, +-5.79026987425731846405e-04, +-5.74001978958720709967e-04, +-5.68654178909981699100e-04, +-5.62986971213088379512e-04, +-5.57003918889516810679e-04, +-5.50708761829973685031e-04, +-5.44105414476881875038e-04, +-5.37197963409420707961e-04, +-5.29990664832675931022e-04, +-5.22487941972209408471e-04, +-5.14694382376049554099e-04, +-5.06614735125277882745e-04, +-4.98253907955200866543e-04, +-4.89616964288741747524e-04, +-4.80709120183835873340e-04, +-4.71535741196723874168e-04, +-4.62102339162885156296e-04, +-4.52414568897704873120e-04, +-4.42478224818736978665e-04, +-4.32299237491589249602e-04, +-4.21883670101533790608e-04, +-4.11237714852763253538e-04, +-4.00367689297795705319e-04, +-3.89280032598777342174e-04, +-3.77981301723072956981e-04, +-3.66478167575481482855e-04, +-3.54777411069201974430e-04, +-3.42885919137923399647e-04, +-3.30810680691371770349e-04, +-3.18558782516682129776e-04, +-3.06137405127995278469e-04, +-2.93553818566704544622e-04, +-2.80815378154804305266e-04, +-2.67929520203833435379e-04, +-2.54903757681815789065e-04, +-2.41745675840952941541e-04, +-2.28462927808299829519e-04, +-2.15063230142214405812e-04, +-2.01554358357060797247e-04, +-1.87944142418778622041e-04, +-1.74240462213917245062e-04, +-1.60451242994757493389e-04, +-1.46584450803131455471e-04, +-1.32648087875677540707e-04, +-1.18650188032929176604e-04, +-1.04598812055253963184e-04, +-9.05020430478532816746e-05, +-7.63679817980816182978e-05, +-6.22047421270673621006e-05, +-4.80204462387773454404e-05, +-3.38232200690939612160e-05, +-1.96211886373398563383e-05, +-5.42247140324502025757e-06, + 8.76482236824777340069e-06, + 2.29325982315957407963e-05, + 3.70727811720706265371e-05, + 5.11773202013517019616e-05, + 6.52381929346686494130e-05, + 7.92474101469974555583e-05, + 9.31970203054730103771e-05, + 1.07079114075787359224e-04, + 1.20885828799772198955e-04, + 1.34609352941733671338e-04, + 1.48241930501015857979e-04, + 1.61775865388299365999e-04, + 1.75203525763176128777e-04, + 1.88517348330553255508e-04, + 2.01709842593477496403e-04, + 2.14773595059988993677e-04, + 2.27701273401630213721e-04, + 2.40485630561381157630e-04, + 2.53119508808481513077e-04, + 2.65595843738193170946e-04, + 2.77907668214037251522e-04, + 2.90048116250403941428e-04, + 3.02010426833358551230e-04, + 3.13787947677527593714e-04, + 3.25374138916987524356e-04, + 3.36762576728041407650e-04, + 3.47946956882078583737e-04, + 3.58921098226289516687e-04, + 3.69678946090518610861e-04, + 3.80214575618283698918e-04, + 3.90522195020292855420e-04, + 4.00596148748304063669e-04, + 4.10430920588102858375e-04, + 4.20021136669482232032e-04, + 4.29361568391889935302e-04, + 4.38447135263920031219e-04, + 4.47272907655273392787e-04, + 4.55834109459644649508e-04, + 4.64126120667108176508e-04, + 4.72144479844627002613e-04, + 4.79884886523366084934e-04, + 4.87343203491520887780e-04, + 4.94515458991510439488e-04, + 5.01397848820237619291e-04, + 5.07986738331495536053e-04, + 5.14278664339342934768e-04, + 5.20270336921509223872e-04, + 5.25958641121905003633e-04, + 5.31340638551345634602e-04, + 5.36413568885707545825e-04, + 5.41174851260732862543e-04, + 5.45622085562818821651e-04, + 5.49753053615153054572e-04, + 5.53565720258578693874e-04, + 5.57058234326825011708e-04, + 5.60228929515402870182e-04, + 5.63076325144043553055e-04, + 5.65599126812190268823e-04, + 5.67796226947321581655e-04, + 5.69666705245914757952e-04, + 5.71209829006884771928e-04, + 5.72425053357448988464e-04, + 5.73312021371367866798e-04, + 5.73870564079618605650e-04, + 5.74100700373610150010e-04, + 5.74002636801101105701e-04, + 5.73576767255045208427e-04, + 5.72823672555648950346e-04, + 5.71744119926011510821e-04, + 5.70339062361724402107e-04, + 5.68609637894926635629e-04, + 5.66557168753326501759e-04, + 5.64183160414795923689e-04, + 5.61489300558173053124e-04, + 5.58477457910976646596e-04, + 5.55149680994817618443e-04, + 5.51508196769305851677e-04, + 5.47555409175347492477e-04, + 5.43293897578766660054e-04, + 5.38726415115223450716e-04, + 5.33855886937539434942e-04, + 5.28685408366441232306e-04, + 5.23218242945951541104e-04, + 5.17457820404608101993e-04, + 5.11407734523782039546e-04, + 5.05071740914395756958e-04, + 4.98453754703430222672e-04, + 4.91557848131608235084e-04, + 4.84388248063773933609e-04, + 4.76949333413366201133e-04, + 4.69245632482725018135e-04, + 4.61281820220592905877e-04, + 4.53062715398815335326e-04, + 4.44593277709539084434e-04, + 4.35878604784927761902e-04, + 4.26923929141124992512e-04, + 4.17734615048157432570e-04, + 4.08316155327850989487e-04, + 3.98674168081502775223e-04, + 3.88814393349325734903e-04, + 3.78742689703628627584e-04, + 3.68465030777748246259e-04, + 3.57987501732803619064e-04, + 3.47316295664270213630e-04, + 3.36457709950689946247e-04, + 3.25418142546407844398e-04, + 3.14204088220705103369e-04, + 3.02822134745452705828e-04, + 2.91278959033536570707e-04, + 2.79581323230313654512e-04, + 2.67736070760376913824e-04, + 2.55750122331942382741e-04, + 2.43630471901182189993e-04, + 2.31384182598852114476e-04, + 2.19018382621588081956e-04, + 2.06540261090263434262e-04, + 1.93957063877727543073e-04, + 1.81276089408560325388e-04, + 1.68504684432981764438e-04, + 1.55650239777576011087e-04, + 1.42720186075200863515e-04, + 1.29721989476556069784e-04, + 1.16663147345869003713e-04, + 1.03551183943265592683e-04, + 9.03936460960799980377e-05, + 7.71980988618959664254e-05, + 6.39721211855788279756e-05, + 5.07233015529098420324e-05, + 3.74592336431094660547e-05, + 2.41875119832061500670e-05, + 1.09157276060909018059e-05, +-2.34853628469845146187e-06, +-1.55977086414162786562e-05, +-2.88242348869596923613e-05, +-4.20205812159120831802e-05, +-5.51792388792400324794e-05, +-6.82927284502260999177e-05, +-8.13536040692178018903e-05, +-9.43544576647877523837e-05, +-1.07287923148899612901e-04, +-1.20146680583802623705e-04, +-1.32923460318065689029e-04, +-1.45611047089732014966e-04, +-1.58202284094046845058e-04, +-1.70690077013562770646e-04, +-1.83067398008342023790e-04, +-1.95327289664015750449e-04, +-2.07462868895485753841e-04, +-2.19467330804082712487e-04, +-2.31333952486024421909e-04, +-2.43056096790058889963e-04, +-2.54627216022116969682e-04, +-2.66040855595085605489e-04, +-2.77290657621565787404e-04, +-2.88370364447411301270e-04, +-2.99273822124557198864e-04, +-3.09994983820817795236e-04, +-3.20527913164946520654e-04, +-3.30866787525005792182e-04, +-3.41005901218438382556e-04, +-3.50939668651816677209e-04, +-3.60662627388737895996e-04, +-3.70169441144112937835e-04, +-3.79454902703223032924e-04, +-3.88513936763931614412e-04, +-3.97341602700649319281e-04, +-4.05933097248160023023e-04, +-4.14283757104453339952e-04, +-4.22389061450620915700e-04, +-4.30244634386746675411e-04, +-4.37846247282407585646e-04, +-4.45189821040535387009e-04, +-4.52271428273436375180e-04, +-4.59087295389815042927e-04, +-4.65633804591701605784e-04, +-4.71907495780237373154e-04, +-4.77905068369312367293e-04, +-4.83623383006156549232e-04, +-4.89059463197895642403e-04, +-4.94210496843377989837e-04, +-4.99073837669386272294e-04, +-5.03647006570560255671e-04, +-5.07927692852353862910e-04, +-5.11913755376417790866e-04, +-5.15603223607854132746e-04, +-5.18994298563852079348e-04, +-5.22085353663235022734e-04, +-5.24874935476607245785e-04, +-5.27361764376676599858e-04, +-5.29544735088589781265e-04, +-5.31422917139951151225e-04, +-5.32995555210500379477e-04, +-5.34262069381259826692e-04, +-5.35222055283147762558e-04, +-5.35875284145083223553e-04, +-5.36221702741643767819e-04, +-5.36261433240417940797e-04, +-5.35994772949250210085e-04, +-5.35422193963616460319e-04, +-5.34544342714442298307e-04, +-5.33362039416725316164e-04, +-5.31876277419383609174e-04, +-5.30088222456788840664e-04, +-5.27999211802546121117e-04, +-5.25610753326072018335e-04, +-5.22924524452632929344e-04, +-5.19942371027533258195e-04, +-5.16666306085201390737e-04, +-5.13098508523981305419e-04, +-5.09241321687478316720e-04, +-5.05097251853375752567e-04, +-5.00668966630677097357e-04, +-4.95959293266389714822e-04, +-4.90971216862717439386e-04, +-4.85707878505841088215e-04, +-4.80172573307527546498e-04, +-4.74368748360683557905e-04, +-4.68300000610171580050e-04, +-4.61970074640185440762e-04, +-4.55382860379525326953e-04, +-4.48542390726171106338e-04, +-4.41452839092643458969e-04, +-4.34118516873516094388e-04, +-4.26543870836773282920e-04, +-4.18733480440457346301e-04, +-4.10692055076295619871e-04, +-4.02424431241824444132e-04, +-3.93935569642999588221e-04, +-3.85230552228620710866e-04, +-3.76314579158696684014e-04, +-3.67192965708273077411e-04, +-3.57871139108791979765e-04, +-3.48354635328699147479e-04, +-3.38649095795268096840e-04, +-3.28760264059559039092e-04, +-3.18693982406488616858e-04, +-3.08456188411998706057e-04, +-2.98052911449364968648e-04, +-2.87490269146621982028e-04, +-2.76774463797361711895e-04, +-2.65911778726769776858e-04, +-2.54908574615198501266e-04, +-2.43771285781356852364e-04, +-2.32506416427293309719e-04, +-2.21120536847362134797e-04, +-2.09620279603374160817e-04, +-1.98012335668160057052e-04, +-1.86303450539779524029e-04, +-1.74500420328618278693e-04, +-1.62610087819718690657e-04, +-1.50639338512448478849e-04, +-1.38595096639894068595e-04, +-1.26484321170500490497e-04, +-1.14314001793776732867e-04, +-1.02091154892787922296e-04, +-8.98228195055708475902e-05, +-7.75160532779040826849e-05, +-6.51779284095440432020e-05, +-5.28155275965366106071e-05, +-4.04359399717151504088e-05, +-2.80462570457926562079e-05, +-1.56535686513557642486e-05, +-3.26495889210444343624e-06, + 9.11249790054165639743e-06, + 2.14717412006368892899e-05, + 3.38057283092167403242e-05, + 4.61074383610954739352e-05, + 5.83698763150761234034e-05, + 7.05860769251900996464e-05, + 8.27491086907310743719e-05, + 9.48520777828465352357e-05, + 1.06888131945465347230e-04, + 1.18850464368359115953e-04, + 1.30732317530151336904e-04, + 1.42526987009093485245e-04, + 1.54227825259548495572e-04, + 1.65828245351846937858e-04, + 1.77321724673696056200e-04, + 1.88701808590856294186e-04, + 1.99962114065118143997e-04, + 2.11096333227541019164e-04, + 2.22098236904959408719e-04, + 2.32961678097786452921e-04, + 2.43680595407194330610e-04, + 2.54249016409682922994e-04, + 2.64661060977358164950e-04, + 2.74910944541823074223e-04, + 2.84992981300038268795e-04, + 2.94901587360451048966e-04, + 3.04631283827309126255e-04, + 3.14176699821949083694e-04, + 3.23532575438972966244e-04, + 3.32693764636005074025e-04, + 3.41655238055194434080e-04, + 3.50412085775090025464e-04, + 3.58959519991325229707e-04, + 3.67292877624660627292e-04, + 3.75407622854972045263e-04, + 3.83299349579812611254e-04, + 3.90963783796212480549e-04, + 3.98396785904493201929e-04, + 4.05594352932717237652e-04, + 4.12552620680778098922e-04, + 4.19267865782840679426e-04, + 4.25736507687102228546e-04, + 4.31955110551815945567e-04, + 4.37920385056580596227e-04, + 4.43629190127953329428e-04, + 4.49078534578485372587e-04, + 4.54265578658337963736e-04, + 4.59187635518681089644e-04, + 4.63842172586124870497e-04, + 4.68226812847528570376e-04, + 4.72339336044462119145e-04, + 4.76177679776842175188e-04, + 4.79739940515123866431e-04, + 4.83024374520600813590e-04, + 4.86029398673382302676e-04, + 4.88753591207665154424e-04, + 4.91195692353966193756e-04, + 4.93354604888095117816e-04, + 4.95229394586578497428e-04, + 4.96819290588439285358e-04, + 4.98123685663175381003e-04, + 4.99142136384935733613e-04, + 4.99874363212820149900e-04, + 5.00320250477433235529e-04, + 5.00479846273746572204e-04, + 5.00353362260458648866e-04, + 4.99941173366037620342e-04, + 4.99243817401748952133e-04, + 4.98261994581954289173e-04, + 4.96996566952077824426e-04, + 4.95448557724650537858e-04, + 4.93619150523917594661e-04, + 4.91509688539529211379e-04, + 4.89121673589913252660e-04, + 4.86456765095920123584e-04, + 4.83516778965485997076e-04, + 4.80303686389979968101e-04, + 4.76819612553058206749e-04, + 4.73066835252845254919e-04, + 4.69047783438315086732e-04, + 4.64765035660812749103e-04, + 4.60221318441676426666e-04, + 4.55419504556999951966e-04, + 4.50362611240582178668e-04, + 4.45053798306218380970e-04, + 4.39496366190426988700e-04, + 4.33693753916839246001e-04, + 4.27649536983611762604e-04, + 4.21367425174935209421e-04, + 4.14851260298147500507e-04, + 4.08105013847745185657e-04, + 4.01132784597763502807e-04, + 3.93938796123864838888e-04, + 3.86527394256778707507e-04, + 3.78903044468504332596e-04, + 3.71070329192896123955e-04, + 3.63033945082216335121e-04, + 3.54798700201316714441e-04, + 3.46369511160995113223e-04, + 3.37751400192573319938e-04, + 3.28949492164903488020e-04, + 3.19969011546054665687e-04, + 3.10815279311211242839e-04, + 3.01493709798685276691e-04, + 2.92009807515892561881e-04, + 2.82369163897162314333e-04, + 2.72577454015293597824e-04, + 2.62640433248783711044e-04, + 2.52563933906683622723e-04, + 2.42353861813065601894e-04, + 2.32016192853029426611e-04, + 2.21556969482438587647e-04, + 2.10982297203188133052e-04, + 2.00298341006229532702e-04, + 1.89511321784351343799e-04, + 1.78627512716812605594e-04, + 1.67653235627924536433e-04, + 1.56594857321689550278e-04, + 1.45458785894609618538e-04, + 1.34251467028869596798e-04, + 1.22979380267843285647e-04, + 1.11649035276331349935e-04, + 1.00266968087514806969e-04, + 8.88397373387060364193e-05, + 7.73739204984463118959e-05, + 6.58761100865689746284e-05, + 5.43529098898822812845e-05, + 4.28109311752722368678e-05, + 3.12567889026958147750e-05, + 1.96970979400246795697e-05, + 8.13846928198325526361e-06, +-3.41249372467339250558e-06, +-1.49491991475911624329e-05, +-2.64650702247123145554e-05, +-3.79535491074849259605e-05, +-4.94081005893409459882e-05, +-6.08222158171220890705e-05, +-7.21894159836215413640e-05, +-8.35032559989468706153e-05, +-9.47573281387071252556e-05, +-1.05945265666950816461e-04, +-1.17060746431808460001e-04, +-1.28097496431813168485e-04, +-1.39049293350893167628e-04, +-1.49909970060043025702e-04, +-1.60673418083712545501e-04, +-1.71333591028951604061e-04, +-1.81884507975470710237e-04, +-1.92320256824521286943e-04, +-2.02634997604990462535e-04, +-2.12822965734663506043e-04, +-2.22878475234921188562e-04, +-2.32795921897065518930e-04, +-2.42569786398529724757e-04, +-2.52194637367171917153e-04, +-2.61665134392132306407e-04, +-2.70976030979354039815e-04, +-2.80122177450312201570e-04, +-2.89098523782284854127e-04, +-2.97900122388595328931e-04, +-3.06522130837423188374e-04, +-3.14959814507391293315e-04, +-3.23208549178839786662e-04, +-3.31263823559207256243e-04, +-3.39121241741069823911e-04, +-3.46776525591634588071e-04, +-3.54225517072336341072e-04, +-3.61464180487291921601e-04, +-3.68488604659406027153e-04, +-3.75295005032959282966e-04, +-3.81879725701552677659e-04, +-3.88239241360328717068e-04, +-3.94370159181469716065e-04, +-4.00269220611873847385e-04, +-4.05933303092217750898e-04, +-4.11359421696386878559e-04, +-4.16544730690475114351e-04, +-4.21486525010528862399e-04, +-4.26182241658291949011e-04, +-4.30629461014228067349e-04, +-4.34825908067166936634e-04, +-4.38769453559957806933e-04, +-4.42458115050543214063e-04, +-4.45890057887998378632e-04, +-4.49063596103017892164e-04, +-4.51977193212385814410e-04, +-4.54629462937196024159e-04, +-4.57019169834384534831e-04, +-4.59145229841358777558e-04, +-4.61006710733478388374e-04, +-4.62602832494264496789e-04, +-4.63932967598159218692e-04, +-4.64996641205815024796e-04, +-4.65793531271870616534e-04, +-4.66323468565258629059e-04, +-4.66586436602117857111e-04, +-4.66582571491450407916e-04, +-4.66312161693693675614e-04, +-4.65775647692456124232e-04, +-4.64973621579678497197e-04, +-4.63906826554567289656e-04, +-4.62576156336664179227e-04, +-4.60982654493493390190e-04, +-4.59127513683252981222e-04, +-4.57012074813076816290e-04, +-4.54637826113443851636e-04, +-4.52006402129344277314e-04, +-4.49119582628882253825e-04, +-4.45979291430018782647e-04, +-4.42587595146185029237e-04, +-4.38946701851662950556e-04, +-4.35058959667485500768e-04, +-4.30926855268744430933e-04, +-4.26553012314354973531e-04, +-4.21940189800147375659e-04, +-4.17091280336356255796e-04, +-4.12009308350574096971e-04, +-4.06697428217259312686e-04, +-4.01158922314968034977e-04, +-3.95397199012481159307e-04, +-3.89415790585079821338e-04, +-3.83218351062148158623e-04, +-3.76808654007610018769e-04, +-3.70190590234281159936e-04, +-3.63368165453703019507e-04, +-3.56345497862799480068e-04, +-3.49126815668818354065e-04, +-3.41716454554033186291e-04, +-3.34118855081727756696e-04, +-3.26338560045002091647e-04, +-3.18380211759965842631e-04, +-3.10248549305032668161e-04, +-3.01948405707699765559e-04, +-2.93484705080720911091e-04, +-2.84862459709394287826e-04, +-2.76086767091391477574e-04, +-2.67162806931154044997e-04, +-2.58095838090502502794e-04, +-2.48891195497272449746e-04, +-2.39554287013787821662e-04, +-2.30090590267009276020e-04, +-2.20505649442205787147e-04, +-2.10805072042026829309e-04, +-2.00994525612865481291e-04, +-1.91079734440417233063e-04, +-1.81066476216359793653e-04, +-1.70960578678090068449e-04, +-1.60767916223468677233e-04, +-1.50494406502535882537e-04, +-1.40146006988172149195e-04, +-1.29728711527686151094e-04, +-1.19248546877326160043e-04, +-1.08711569221710101099e-04, +-9.81238606801850763708e-05, +-8.74915258021262919313e-05, +-7.68206880531919903462e-05, +-6.61174862945537560044e-05, +-5.53880712571479811158e-05, +-4.46386020128183616507e-05, +-3.38752424447514053707e-05, +-2.31041577187158825475e-05, +-1.23315107575055638581e-05, +-1.56345872044351334759e-06, + 9.19385051001696058297e-06, + 1.99342818325943639068e-05, + 3.06517164204148291097e-05, + 4.13400552010434981019e-05, + 5.19932223217173526989e-05, + 6.26051685973046974495e-05, + 7.31698749393950269174e-05, + 8.36813557645763278318e-05, + 9.41336623796225205937e-05, + 1.04520886342181746720e-04, + 1.14837162794693847952e-04, + 1.25076673769810187576e-04, + 1.35233651465430277944e-04, + 1.45302381487516881669e-04, + 1.55277206058868723132e-04, + 1.65152527192051468401e-04, + 1.74922809824715685349e-04, + 1.84582584915542787917e-04, + 1.94126452499097224393e-04, + 2.03549084697879242812e-04, + 2.12845228689902707473e-04, + 2.22009709630148407153e-04, + 2.31037433524272298050e-04, + 2.39923390052979132632e-04, + 2.48662655345496428575e-04, + 2.57250394700618317985e-04, + 2.65681865253823213443e-04, + 2.73952418588994082733e-04, + 2.82057503293309968541e-04, + 2.89992667453910593113e-04, + 2.97753561094963236852e-04, + 3.05335938553796587460e-04, + 3.12735660794901402029e-04, + 3.19948697660284706902e-04, + 3.26971130055313046695e-04, + 3.33799152068596993118e-04, + 3.40429073024882096823e-04, + 3.46857319469846304971e-04, + 3.53080437085642826617e-04, + 3.59095092536410422437e-04, + 3.64898075242447582529e-04, + 3.70486299082366027022e-04, + 3.75856804022209637847e-04, + 3.81006757670713364344e-04, + 3.85933456759954328450e-04, + 3.90634328550441736316e-04, + 3.95106932160183021464e-04, + 3.99348959816850238372e-04, + 4.03358238032495769118e-04, + 4.07132728700219297200e-04, + 4.10670530112230828569e-04, + 4.13969877898831897789e-04, + 4.17029145887845879240e-04, + 4.19846846884104163249e-04, + 4.22421633368623200468e-04, + 4.24752298117164013222e-04, + 4.26837774737901984833e-04, + 4.28677138127993610176e-04, + 4.30269604848864133020e-04, + 4.31614533420087809028e-04, + 4.32711424531789182885e-04, + 4.33559921175517891476e-04, + 4.34159808693626808693e-04, + 4.34511014747204218304e-04, + 4.34613609202668001435e-04, + 4.34467803937177638515e-04, + 4.34073952563060591527e-04, + 4.33432550071505902529e-04, + 4.32544232395796221600e-04, + 4.31409775894451988712e-04, + 4.30030096754630268997e-04, + 4.28406250316232413682e-04, + 4.26539430317180844748e-04, + 4.24430968060405871753e-04, + 4.22082331503046044325e-04, + 4.19495124268545250320e-04, + 4.16671084582238100344e-04, + 4.13612084131137220516e-04, + 4.10320126848655590979e-04, + 4.06797347625035990524e-04, + 4.03046010944322816681e-04, + 3.99068509448671923049e-04, + 3.94867362431040608978e-04, + 3.90445214257016648927e-04, + 3.85804832716899566078e-04, + 3.80949107308997192770e-04, + 3.75881047455209468464e-04, + 3.70603780649984598967e-04, + 3.65120550543784417111e-04, + 3.59434714962230262691e-04, + 3.53549743862119564622e-04, + 3.47469217225564457226e-04, + 3.41196822893517369337e-04, + 3.34736354339987610389e-04, + 3.28091708388290057355e-04, + 3.21266882870694259894e-04, + 3.14265974232871717151e-04, + 3.07093175084575183576e-04, + 2.99752771698005490968e-04, + 2.92249141455357803153e-04, + 2.84586750247056946388e-04, + 2.76770149822231086197e-04, + 2.68803975092983104406e-04, + 2.60692941394056651970e-04, + 2.52441841699531203946e-04, + 2.44055543798067387786e-04, + 2.35538987428655314377e-04, + 2.26897181378157982660e-04, + 2.18135200542623168421e-04, + 2.09258182954089169475e-04, + 2.00271326774336208163e-04, + 1.91179887257744631369e-04, + 1.81989173684729625387e-04, + 1.72704546267654705490e-04, + 1.63331413031008576943e-04, + 1.53875226667652081989e-04, + 1.44341481372964688425e-04, + 1.34735709658744315766e-04, + 1.25063479148570258709e-04, + 1.15330389356819486019e-04, + 1.05542068452749301325e-04, + 9.57041700118449787478e-05, + 8.58223697561741577077e-05, + 7.59023622856443207175e-05, + 6.59498578020433471767e-05, + 5.59705788277444033440e-05, + 4.59702569209572621425e-05, + 3.59546293894085665843e-05, + 2.59294360043086512160e-05, + 1.59004157166498285290e-05, + 5.87330337721188446920e-06, +-4.14617353701999446564e-06, +-1.41522981889934754151e-05, +-2.41393676379234885633e-05, +-3.41016960841382575317e-05, +-4.40336181005696522257e-05, +-5.39294918490548975433e-05, +-6.37837022796263207513e-05, +-7.35906643109786139231e-05, +-8.33448259903158111123e-05, +-9.30406716307915674464e-05, +-1.02672724924753142484e-04, +-1.12235552031169472749e-04, +-1.21723764635187306645e-04, +-1.31132022978417295961e-04, +-1.40455038858246640358e-04, +-1.49687578594178148693e-04, +-1.58824465959857513524e-04, +-1.67860585079007983188e-04, +-1.76790883283683004619e-04, +-1.85610373933242124578e-04, +-1.94314139192479492721e-04, +-2.02897332767363176810e-04, +-2.11355182596845939808e-04, +-2.19682993499378809155e-04, +-2.27876149772357342645e-04, +-2.35930117743474312237e-04, +-2.43840448272265441099e-04, +-2.51602779200596157229e-04, +-2.59212837750722130490e-04, +-2.66666442869611193447e-04, +-2.73959507518241514052e-04, +-2.81088040904634635809e-04, +-2.88048150659414798139e-04, +-2.94836044952623201488e-04, +-3.01448034550882504670e-04, +-3.07880534813461108779e-04, +-3.14130067626494494971e-04, +-3.20193263274004568698e-04, +-3.26066862245033475126e-04, +-3.31747716975704792786e-04, +-3.37232793525372445079e-04, +-3.42519173185958092365e-04, +-3.47604054023637506869e-04, +-3.52484752352054538874e-04, +-3.57158704136308719976e-04, +-3.61623466326981902238e-04, +-3.65876718123521590606e-04, +-3.69916262166333537249e-04, +-3.73740025656983437721e-04, +-3.77346061405942046450e-04, +-3.80732548807360233426e-04, +-3.83897794740389560527e-04, +-3.86840234396619738182e-04, +-3.89558432033239830650e-04, +-3.92051081651568350539e-04, +-3.94317007600659507997e-04, +-3.96355165105705619343e-04, +-3.98164640721032441449e-04, +-3.99744652707502629626e-04, +-4.01094551334191251613e-04, +-4.02213819104267004522e-04, +-4.03102070904986001763e-04, +-4.03759054081854400035e-04, +-4.04184648436960245865e-04, +-4.04378866151571740410e-04, +-4.04341851633132352058e-04, +-4.04073881286819201839e-04, +-4.03575363211878201074e-04, +-4.02846836823000703422e-04, +-4.01888972397027575446e-04, +-4.00702570545332346658e-04, +-3.99288561612268872933e-04, +-3.97648005000088408580e-04, +-3.95782088420835174210e-04, +-3.93692127075682019467e-04, +-3.91379562762282434078e-04, +-3.88845962910724810089e-04, +-3.86093019548719798301e-04, +-3.83122548196679628581e-04, +-3.79936486693416947905e-04, +-3.76536893953195608929e-04, +-3.72925948654929972394e-04, +-3.69105947864348422904e-04, +-3.65079305589995940784e-04, +-3.60848551273959680056e-04, +-3.56416328218264332091e-04, +-3.51785391947902702746e-04, +-3.46958608511509539966e-04, +-3.41938952720719716982e-04, +-3.36729506329282559166e-04, +-3.31333456153044218079e-04, +-3.25754092131937047095e-04, +-3.19994805335147892728e-04, +-3.14059085910667681873e-04, +-3.07950520980461819095e-04, +-3.01672792482518580589e-04, +-2.95229674961088311026e-04, +-2.88625033306340523283e-04, +-2.81862820445018204176e-04, +-2.74947074983157644778e-04, +-2.67881918802505628041e-04, +-2.60671554611964777660e-04, +-2.53320263455520278562e-04, +-2.45832402178220821125e-04, +-2.38212400851451575621e-04, +-2.30464760159363048859e-04, +-2.22594048747734558165e-04, +-2.14604900536931233329e-04, +-2.06502012000535557258e-04, +-1.98290139411133950476e-04, +-1.89974096055152907262e-04, +-1.81558749417992085131e-04, +-1.73049018341384308823e-04, +-1.64449870154523194316e-04, +-1.55766317780646929318e-04, +-1.47003416820761271481e-04, +-1.38166262616194393661e-04, +-1.29259987291687318631e-04, +-1.20289756780731966232e-04, +-1.11260767834878675090e-04, +-1.02178245018739763763e-04, +-9.30474376924268498914e-05, +-8.38736169831565017523e-05, +-7.46620727477739890053e-05, +-6.54181105279376081448e-05, +-5.61470484997162090244e-05, +-4.68542144193485576007e-05, +-3.75449425669173780990e-05, +-2.82245706896867571811e-05, +-1.88984369468525752515e-05, +-9.57187685745089512619e-06, +-2.50220253166946479370e-07, + 9.06121176221840221013e-06, + 1.83571098449908816895e-05, + 2.76321794336816537255e-05, + 3.68811437592135666556e-05, + 4.60987468417495339684e-05, + 5.52797564722329147621e-05, + 6.44189671769343854841e-05, + 7.35112031636342259672e-05, + 8.25513212473374231003e-05, + 9.15342137542006137590e-05, + 1.00454811401901069581e-04, + 1.09308086154850524381e-04, + 1.18089054052647829071e-04, + 1.26792778010161884652e-04, + 1.35414370587798690198e-04, + 1.43948996730092746744e-04, + 1.52391876471503188604e-04, + 1.60738287607595838752e-04, + 1.68983568330243670531e-04, + 1.77123119825359898573e-04, + 1.85152408831718565856e-04, + 1.93066970159443514676e-04, + 2.00862409166768096517e-04, + 2.08534404193699878438e-04, + 2.16078708951240975071e-04, + 2.23491154864851335540e-04, + 2.30767653370864866047e-04, + 2.37904198164594560738e-04, + 2.44896867398899378224e-04, + 2.51741825832007637496e-04, + 2.58435326923423880699e-04, + 2.64973714876783311267e-04, + 2.71353426628539464403e-04, + 2.77570993781410069266e-04, + 2.83623044481539374282e-04, + 2.89506305238360116608e-04, + 2.95217602686185913181e-04, + 3.00753865286583336493e-04, + 3.06112124970612023683e-04, + 3.11289518720129045667e-04, + 3.16283290087134808400e-04, + 3.21090790650627329848e-04, + 3.25709481409937177433e-04, + 3.30136934114071980105e-04, + 3.34370832526131541752e-04, + 3.38408973622323120626e-04, + 3.42249268724889273759e-04, + 3.45889744568388601224e-04, + 3.49328544298793523294e-04, + 3.52563928404906736999e-04, + 3.55594275581636054019e-04, + 3.58418083524750480211e-04, + 3.61033969656628290525e-04, + 3.63440671782813055999e-04, + 3.65637048678958849739e-04, + 3.67622080607960151355e-04, + 3.69394869767037141092e-04, + 3.70954640664598411879e-04, + 3.72300740426744327174e-04, + 3.73432639033317674820e-04, + 3.74349929483439925783e-04, + 3.75052327890526104696e-04, + 3.75539673506779519020e-04, + 3.75811928677284036969e-04, + 3.75869178723718091930e-04, + 3.75711631757917824750e-04, + 3.75339618425418329768e-04, + 3.74753591579224973156e-04, + 3.73954125884068270050e-04, + 3.72941917351453974382e-04, + 3.71717782805840797795e-04, + 3.70282659282345936666e-04, + 3.68637603356378044158e-04, + 3.66783790405674587840e-04, + 3.64722513805233164354e-04, + 3.62455184055677408564e-04, + 3.59983327845599923502e-04, + 3.57308587048594551976e-04, + 3.54432717655444305162e-04, + 3.51357588642338164626e-04, + 3.48085180775715128960e-04, + 3.44617585354531092562e-04, + 3.40957002890739319448e-04, + 3.37105741728795874762e-04, + 3.33066216605056779430e-04, + 3.28840947147959132123e-04, + 3.24432556319903108322e-04, + 3.19843768801808070543e-04, + 3.15077409321264686852e-04, + 3.10136400925462669617e-04, + 3.05023763199732222788e-04, + 2.99742610432934862910e-04, + 2.94296149730754368415e-04, + 2.88687679078032178367e-04, + 2.82920585351309613817e-04, + 2.76998342282779573022e-04, + 2.70924508376842870794e-04, + 2.64702724780600893301e-04, + 2.58336713109347953805e-04, + 2.51830273228646013463e-04, + 2.45187280994006067195e-04, + 2.38411685949818300109e-04, + 2.31507508988586837694e-04, + 2.24478839972069534785e-04, + 2.17329835315641735263e-04, + 2.10064715537319865631e-04, + 2.02687762772885523210e-04, + 1.95203318258571319535e-04, + 1.87615779782783292061e-04, + 1.79929599108352478208e-04, + 1.72149279366823641443e-04, + 1.64279372426300712944e-04, + 1.56324476234388271998e-04, + 1.48289232137772291394e-04, + 1.40178322180001724197e-04, + 1.31996466379041452969e-04, + 1.23748419986174359531e-04, + 1.15438970727843310919e-04, + 1.07072936032028641199e-04, + 9.86551602407646912674e-05, + 9.01905118104061922493e-05, + 8.16838805012586526922e-05, + 7.31401745581928999611e-05, + 6.45643178838649969007e-05, + 5.59612472061890399498e-05, + 4.73359092415654616050e-05, + 3.86932578557977460893e-05, + 3.00382512239181022112e-05, + 2.13758489908508619718e-05, + 1.27110094344164514346e-05, + 4.04868663231493498654e-06, +-4.60617236531486804862e-06, +-1.32486303560268950814e-05, +-2.18737627965935988274e-05, +-3.04766606039162663141e-05, +-3.90524329440386771335e-05, +-4.75962100075382721592e-05, +-5.61031457698656416577e-05, +-6.45684207347658160750e-05, +-7.29872446596370569490e-05, +-8.13548592609855323026e-05, +-8.96665408985710283294e-05, +-9.79176032367135154100e-05, +-1.06103399881264301701e-04, +-1.14219326990759500518e-04, +-1.22260825860294306986e-04, +-1.30223385476667787367e-04, +-1.38102545043372279022e-04, +-1.45893896474014590726e-04, +-1.53593086852781251627e-04, +-1.61195820860575358014e-04, +-1.68697863165478154166e-04, +-1.76095040776206332271e-04, +-1.83383245357263575124e-04, +-1.90558435504502971490e-04, +-1.97616638979844499871e-04, +-2.04553954903916496199e-04, +-2.11366555905413412665e-04, +-2.18050690225988521003e-04, +-2.24602683779532712486e-04, +-2.31018942164689760873e-04, +-2.37295952629612913335e-04, +-2.43430285987647672136e-04, +-2.49418598483226250720e-04, +-2.55257633606716517576e-04, +-2.60944223857345624935e-04, +-2.66475292453244793581e-04, +-2.71847854987617462523e-04, +-2.77059021030343338027e-04, +-2.82105995673898740650e-04, +-2.86986081022970918215e-04, +-2.91696677626899613517e-04, +-2.96235285854203533526e-04, +-3.00599507208460371525e-04, +-3.04787045584920001685e-04, +-3.08795708467034170797e-04, +-3.12623408062509989137e-04, +-3.16268162378132073644e-04, +-3.19728096232883450198e-04, +-3.23001442208842737963e-04, +-3.26086541539376013193e-04, +-3.28981844934199483665e-04, +-3.31685913340901627425e-04, +-3.34197418642568527033e-04, +-3.36515144291180958672e-04, +-3.38637985876496302052e-04, +-3.40564951630163302489e-04, +-3.42295162864854200010e-04, +-3.43827854348234302102e-04, +-3.45162374611635318009e-04, +-3.46298186193322516443e-04, +-3.47234865816296292464e-04, +-3.47972104500599249514e-04, +-3.48509707610135627091e-04, +-3.48847594834057013122e-04, +-3.48985800102794084098e-04, +-3.48924471438857429929e-04, +-3.48663870742568846994e-04, +-3.48204373512918418428e-04, +-3.47546468503779780370e-04, +-3.46690757315755763122e-04, +-3.45637953923957387536e-04, +-3.44388884142068690732e-04, +-3.42944485023055438931e-04, +-3.41305804196959756622e-04, +-3.39473999146208769290e-04, +-3.37450336418937347962e-04, +-3.35236190780833392174e-04, +-3.32833044306071442267e-04, +-3.30242485407915102851e-04, +-3.27466207809625300430e-04, +-3.24506009456285323105e-04, +-3.21363791368333459424e-04, +-3.18041556437396186544e-04, +-3.14541408165269157499e-04, +-3.10865549346798478083e-04, +-3.07016280697481171256e-04, +-3.02995999426636253033e-04, +-2.98807197757022834691e-04, +-2.94452461391812403239e-04, +-2.89934467929851976634e-04, +-2.85255985230187464677e-04, +-2.80419869726833046429e-04, +-2.75429064694814387804e-04, +-2.70286598468527671825e-04, +-2.64995582613490349589e-04, +-2.59559210052583209764e-04, +-2.53980753147903693268e-04, +-2.48263561739382960028e-04, +-2.42411061141333119629e-04, +-2.36426750098121530837e-04, +-2.30314198700187072744e-04, +-2.24077046261636817458e-04, +-2.17718999160677065480e-04, +-2.11243828644175747709e-04, +-2.04655368597559766909e-04, +-1.97957513281590559125e-04, +-1.91154215037028974876e-04, +-1.84249481958865466954e-04, +-1.77247375541147338725e-04, +-1.70152008294119155233e-04, +-1.62967541334830558729e-04, +-1.55698181952718529668e-04, +-1.48348181151564014997e-04, +-1.40921831169260738459e-04, +-1.33423462976836989169e-04, +-1.25857443758204442640e-04, +-1.18228174371988047249e-04, +-1.10540086797179302569e-04, +-1.02797641563733886216e-04, +-9.50053251698690202779e-05, +-8.71676474874451848130e-05, +-7.92891391569480421435e-05, +-7.13743489735723545724e-05, +-6.34278412659133373520e-05, +-5.54541932687728470635e-05, +-4.74579924915896622650e-05, +-3.94438340839858202430e-05, +-3.14163182000519927554e-05, +-2.33800473626161515084e-05, +-1.53396238292672757364e-05, +-7.29964696164099043725e-06, + 7.35289400800058785423e-07, + 8.76059956072690135676e-06, + 1.67717085752691440334e-05, + 2.47640548591994233581e-05, + 3.27330927774992179306e-05, + 4.06742952258349121995e-05, + 4.85831561974826067188e-05, + 5.64551933352481954465e-05, + 6.42859504669411802903e-05, + 7.20710001229515570022e-05, + 7.98059460346407204163e-05, + 8.74864256117493171517e-05, + 9.51081123980788522947e-05, + 1.02666718503417308400e-04, + 1.10157997010735983186e-04, + 1.17577744357177826798e-04, + 1.24921802687524364020e-04, + 1.32186062178827283932e-04, + 1.39366463334907178051e-04, + 1.46458999249442900882e-04, + 1.53459717836390693510e-04, + 1.60364724026482917364e-04, + 1.67170181928681389327e-04, + 1.73872316955147449263e-04, + 1.80467417908883949636e-04, + 1.86951839032647022755e-04, + 1.93322002018104301428e-04, + 1.99574397974115166953e-04, + 2.05705589353056221948e-04, + 2.11712211834139661399e-04, + 2.17590976162706123713e-04, + 2.23338669944412427466e-04, + 2.28952159393546036611e-04, + 2.34428391034224761335e-04, + 2.39764393353856245438e-04, + 2.44957278407680664051e-04, + 2.50004243373813900102e-04, + 2.54902572057763023537e-04, + 2.59649636345685814673e-04, + 2.64242897605613895860e-04, + 2.68679908035895302198e-04, + 2.72958311960145715448e-04, + 2.77075847068031439532e-04, + 2.81030345601230668959e-04, + 2.84819735483968607473e-04, + 2.88442041397530505187e-04, + 2.91895385798214199429e-04, + 2.95177989878195508062e-04, + 2.98288174468830185292e-04, + 3.01224360885935828203e-04, + 3.03985071716642170879e-04, + 3.06568931547421675947e-04, + 3.08974667632958628800e-04, + 3.11201110505533425424e-04, + 3.13247194524650732217e-04, + 3.15111958366658898717e-04, + 3.16794545454155058485e-04, + 3.18294204324996645328e-04, + 3.19610288940773337035e-04, + 3.20742258934658165670e-04, + 3.21689679798506877016e-04, + 3.22452223009245763068e-04, + 3.23029666094488715922e-04, + 3.23421892637434677410e-04, + 3.23628892221117367076e-04, + 3.23650760312099662532e-04, + 3.23487698083753741091e-04, + 3.23140012179301756075e-04, + 3.22608114414811391040e-04, + 3.21892521422396742613e-04, + 3.20993854233888264126e-04, + 3.19912837805281418183e-04, + 3.18650300482314343883e-04, + 3.17207173407532596471e-04, + 3.15584489869251980446e-04, + 3.13783384592866167444e-04, + 3.11805092974967040537e-04, + 3.09650950260776226895e-04, + 3.07322390665431383582e-04, + 3.04820946439691672133e-04, + 3.02148246880660359404e-04, + 2.99306017288154683001e-04, + 2.96296077867383965149e-04, + 2.93120342578621461815e-04, + 2.89780817934593706246e-04, + 2.86279601746334145390e-04, + 2.82618881818277357942e-04, + 2.78800934593397952560e-04, + 2.74828123749229578238e-04, + 2.70702898745622138645e-04, + 2.66427793325122298871e-04, + 2.62005423966893218578e-04, + 2.57438488295109720125e-04, + 2.52729763442789332178e-04, + 2.47882104372053313750e-04, + 2.42898442151831685893e-04, + 2.37781782193984719039e-04, + 2.32535202449068816293e-04, + 2.27161851562591142212e-04, + 2.21664946993031298540e-04, + 2.16047773092666164701e-04, + 2.10313679152429068835e-04, + 2.04466077411766494580e-04, + 1.98508441034933119868e-04, + 1.92444302054725852134e-04, + 1.86277249284949120503e-04, + 1.80010926202826978225e-04, + 1.73649028802625680088e-04, + 1.67195303421656588962e-04, + 1.60653544540157914395e-04, + 1.54027592556047951671e-04, + 1.47321331536073504842e-04, + 1.40538686944578018788e-04, + 1.33683623351231527059e-04, + 1.26760142119053490503e-04, + 1.19772279074078399062e-04, + 1.12724102158015825103e-04, + 1.05619709065267838215e-04, + 9.84632248656736166819e-05, + 9.12587996143574470059e-05, + 8.40106059500621168935e-05, + 7.67228366833554533723e-05, + 6.93997023760999396736e-05, + 6.20454289135817277541e-05, + 5.46642550706949160956e-05, + 4.72604300735806080519e-05, + 3.98382111581210927170e-05, + 3.24018611266886229260e-05, + 2.49556459045488985800e-05, + 1.75038320973170900537e-05, + 1.00506845508623119789e-05, + 2.60046391505357440467e-06, +-4.84257578724628453024e-06, +-1.22741895846601957513e-05, +-1.96901439736055691699e-05, +-2.70862193254132534745e-05, +-3.44582122826427863452e-05, +-4.18019381432365520865e-05, +-4.91132332314092313582e-05, +-5.63879572535800466628e-05, +-6.36219956382819091861e-05, +-7.08112618586212363026e-05, +-7.79516997359988795179e-05, +-8.50392857237956806661e-05, +-9.20700311697229486791e-05, +-9.90399845556698052700e-05, +-1.05945233713539423387e-04, +-1.12781908016172197095e-04, +-1.19546180541878292172e-04, +-1.26234270211473149090e-04, +-1.32842443896610563079e-04, +-1.39367018498237036110e-04, +-1.45804362994017441780e-04, +-1.52150900453594729216e-04, +-1.58403110020568740251e-04, +-1.64557528860099149893e-04, +-1.70610754071058763354e-04, +-1.76559444561685330907e-04, +-1.82400322887701021131e-04, +-1.88130177051889265882e-04, +-1.93745862264151107917e-04, +-1.99244302661073536273e-04, +-2.04622492984076230016e-04, +-2.09877500215226739464e-04, +-2.15006465169834002022e-04, +-2.20006604044963781320e-04, +-2.24875209923037860070e-04, +-2.29609654229712996506e-04, +-2.34207388145253733377e-04, +-2.38665943968643126617e-04, +-2.42982936433764040154e-04, +-2.47156063976803242084e-04, +-2.51183109954370624526e-04, +-2.55061943811678553534e-04, +-2.58790522200035065601e-04, +-2.62366890043213652015e-04, +-2.65789181552087544740e-04, +-2.69055621187019552206e-04, +-2.72164524567514133028e-04, +-2.75114299328679378503e-04, +-2.77903445924066144594e-04, +-2.80530558374482365432e-04, +-2.82994324962458426113e-04, +-2.85293528871928667081e-04, +-2.87427048772961131386e-04, +-2.89393859351164052952e-04, +-2.91193031781574363133e-04, +-2.92823734146810019888e-04, +-2.94285231799317132436e-04, +-2.95576887667566815150e-04, +-2.96698162506095247833e-04, +-2.97648615089306386138e-04, +-2.98427902348986473068e-04, +-2.99035779455541356198e-04, +-2.99472099842951298022e-04, +-2.99736815177487569105e-04, +-2.99829975270314748326e-04, +-2.99751727934055112266e-04, +-2.99502318783477473017e-04, +-2.99082090980496079820e-04, +-2.98491484923676638277e-04, +-2.97731037882504939382e-04, +-2.96801383576682481068e-04, +-2.95703251700761983022e-04, +-2.94437467394450386442e-04, +-2.93004950658959568456e-04, +-2.91406715719765864719e-04, +-2.89643870336288734163e-04, +-2.87717615058818976508e-04, +-2.85629242433306474672e-04, +-2.83380136154447051858e-04, +-2.80971770167645455707e-04, +-2.78405707720416845195e-04, +-2.75683600363831927699e-04, +-2.72807186904635450876e-04, +-2.69778292308697948982e-04, +-2.66598826556476689500e-04, +-2.63270783451207898707e-04, +-2.59796239380568065765e-04, +-2.56177352032518543517e-04, +-2.52416359066249054721e-04, +-2.48515576738865041385e-04, +-2.44477398488780056640e-04, +-2.40304293476628925757e-04, +-2.35998805084586303973e-04, +-2.31563549375006809058e-04, +-2.27001213509300385799e-04, +-2.22314554128057417478e-04, +-2.17506395693240964359e-04, +-2.12579628793644199699e-04, +-2.07537208414486720482e-04, +-2.02382152172165928486e-04, +-1.97117538515386705664e-04, +-1.91746504893500153760e-04, +-1.86272245893312135556e-04, +-1.80698011345398386069e-04, +-1.75027104401053194751e-04, +-1.69262879581007170742e-04, +-1.63408740797064619410e-04, +-1.57468139347822794899e-04, +-1.51444571889650255424e-04, +-1.45341578384115073432e-04, +-1.39162740023062326405e-04, +-1.32911677132557424445e-04, +-1.26592047056915218929e-04, +-1.20207542024052590340e-04, +-1.13761886993405384643e-04, +-1.07258837487659783316e-04, +-1.00702177409562164813e-04, +-9.40957168450681270561e-05, +-8.74432898541086471968e-05, +-8.07487522502475194583e-05, +-7.40159793705156095938e-05, +-6.72488638367082234085e-05, +-6.04513133094537063756e-05, +-5.36272482362472248819e-05, +-4.67805995949890251378e-05, +-3.99153066340006816592e-05, +-3.30353146100565781473e-05, +-2.61445725256313035213e-05, +-1.92470308666743191849e-05, +-1.23466393421882220175e-05, +-5.44734462700067394256e-06, + 1.44691189122907742152e-06, + 8.33219635915731991185e-06, + 1.52045846980238205263e-05, + 2.20601648356691710140e-05, + 2.88950389290342959231e-05, + 3.57053255759800123258e-05, + 4.24871620149298346875e-05, + 4.92367063114172048323e-05, + 5.59501395300588034607e-05, + 6.26236678908249482520e-05, + 6.92535249083772849656e-05, + 7.58359735132689484916e-05, + 8.23673081538160148027e-05, + 8.88438568774603065845e-05, + 9.52619833904571407419e-05, + 1.01618089094736445996e-04, + 1.07908615100796547912e-04, + 1.14130044215511548540e-04, + 1.20278902903740668169e-04, + 1.26351763222651335486e-04, + 1.32345244727680633103e-04, + 1.38256016349078191072e-04, + 1.44080798237992946907e-04, + 1.49816363581082602745e-04, + 1.55459540382645440516e-04, + 1.61007213213293658063e-04, + 1.66456324924208517568e-04, + 1.71803878326033914858e-04, + 1.77046937831481864629e-04, + 1.82182631060826721089e-04, + 1.87208150409221387497e-04, + 1.92120754575244299164e-04, + 1.96917770049651416229e-04, + 2.01596592563618655673e-04, + 2.06154688495617809162e-04, + 2.10589596236331749735e-04, + 2.14898927510659952262e-04, + 2.19080368656271521873e-04, + 2.23131681857964108947e-04, + 2.27050706337181441982e-04, + 2.30835359496065032096e-04, + 2.34483638015429345178e-04, + 2.37993618906142247269e-04, + 2.41363460513226320541e-04, + 2.44591403472347386668e-04, + 2.47675771618061590050e-04, + 2.50614972843412405108e-04, + 2.53407499910435565511e-04, + 2.56051931211167507936e-04, + 2.58546931478778998018e-04, + 2.60891252448485638522e-04, + 2.63083733467921166392e-04, + 2.65123302056677822517e-04, + 2.67008974414759331969e-04, + 2.68739855879716155965e-04, + 2.70315141332255878728e-04, + 2.71734115550168267312e-04, + 2.72996153510415167677e-04, + 2.74100720639277955180e-04, + 2.75047373010480411190e-04, + 2.75835757491237044091e-04, + 2.76465611836200725413e-04, + 2.76936764729322759931e-04, + 2.77249135773662686282e-04, + 2.77402735429210095530e-04, + 2.77397664898823418430e-04, + 2.77234115962408846773e-04, + 2.76912370759493020253e-04, + 2.76432801520381165802e-04, + 2.75795870246112379866e-04, + 2.75002128337457571201e-04, + 2.74052216173225097421e-04, + 2.72946862638190302849e-04, + 2.71686884600967171015e-04, + 2.70273186342183185330e-04, + 2.68706758933346897579e-04, + 2.66988679566817544743e-04, + 2.65120110837324977557e-04, + 2.63102299975484803154e-04, + 2.60936578033862389640e-04, + 2.58624359026030797588e-04, + 2.56167139019227189586e-04, + 2.53566495181161690939e-04, + 2.50824084781579728989e-04, + 2.47941644149205875185e-04, + 2.44920987584716133307e-04, + 2.41764006230414186041e-04, + 2.38472666897310341073e-04, + 2.35049010850323818796e-04, + 2.31495152552345612000e-04, + 2.27813278367987374863e-04, + 2.24005645227630785727e-04, + 2.20074579252881860408e-04, + 2.16022474343967573742e-04, + 2.11851790730109416395e-04, + 2.07565053483680750195e-04, + 2.03164850999056984188e-04, + 1.98653833437066455227e-04, + 1.94034711135973993255e-04, + 1.89310252989946878202e-04, + 1.84483284795969022882e-04, + 1.79556687570185045640e-04, + 1.74533395834689777828e-04, + 1.69416395875703968332e-04, + 1.64208723974330704888e-04, + 1.58913464610781706397e-04, + 1.53533748643116163459e-04, + 1.48072751461745600373e-04, + 1.42533691120615488420e-04, + 1.36919826446232244851e-04, + 1.31234455125635378044e-04, + 1.25480911774428335794e-04, + 1.19662565986003067314e-04, + 1.13782820363092171140e-04, + 1.07845108532812357350e-04, + 1.01852893146268084785e-04, + 9.58096638640913071758e-05, + 8.97189353288038125020e-05, + 8.35842451253892703041e-05, + 7.74091517311708171871e-05, + 7.11972324561945549498e-05, + 6.49520813753084395436e-05, + 5.86773072531284785184e-05, + 5.23765314630894333252e-05, + 4.60533859017605735615e-05, + 3.97115108997169615726e-05, + 3.33545531299399012877e-05, + 2.69861635152601212417e-05, + 2.06099951357281601966e-05, + 1.42297011374239464445e-05, + 7.84893264358421670118e-06, + 1.47133666946563786569e-06, +-4.89944595795788563131e-06, +-1.12597826742650033679e-05, +-1.76060512446440944824e-05, +-2.39346418225641322213e-05, +-3.02419589988916038355e-05, +-3.65244238402926538526e-05, +-4.27784759157675114065e-05, +-4.90005753101717809908e-05, +-5.51872046235883968062e-05, +-6.13348709554239443801e-05, +-6.74401078721121943153e-05, +-7.34994773573187349476e-05, +-7.95095717435526355005e-05, +-8.54670156241022589347e-05, +-9.13684677442247916886e-05, +-9.72106228705329827259e-05, +-1.02990213637535249144e-04, +-1.08704012370301582183e-04, +-1.14348832882239030933e-04, +-1.19921532246967561266e-04, +-1.25419012543391523258e-04, +-1.30838222572801670578e-04, +-1.36176159547326554701e-04, +-1.41429870748598893225e-04, +-1.46596455155808636037e-04, +-1.51673065042229072161e-04, +-1.56656907539345593332e-04, +-1.61545246167741111346e-04, +-1.66335402333829893021e-04, +-1.71024756791804714243e-04, +-1.75610751069764359483e-04, +-1.80090888859417295109e-04, +-1.84462737368601463689e-04, +-1.88723928635743296543e-04, +-1.92872160805764557030e-04, +-1.96905199366593993164e-04, +-2.00820878345682555252e-04, +-2.04617101465884017146e-04, +-2.08291843260079455108e-04, +-2.11843150143963964045e-04, +-2.15269141446432097026e-04, +-2.18568010397017243587e-04, +-2.21738025069880467571e-04, +-2.24777529283855221449e-04, +-2.27684943458087584887e-04, +-2.30458765422837560640e-04, +-2.33097571185028482272e-04, +-2.35600015648165144258e-04, +-2.37964833286258476731e-04, +-2.40190838771433997885e-04, +-2.42276927554912959329e-04, +-2.44222076401095133848e-04, +-2.46025343874493635128e-04, +-2.47685870779298261159e-04, +-2.49202880551373695713e-04, +-2.50575679602528446788e-04, +-2.51803657616905742379e-04, +-2.52886287799411761581e-04, +-2.53823127076041447393e-04, +-2.54613816246114423730e-04, +-2.55258080086343225150e-04, +-2.55755727406747662873e-04, +-2.56106651058446010017e-04, +-2.56310827893362850466e-04, +-2.56368318675959138472e-04, +-2.56279267947061176278e-04, +-2.56043903839951736412e-04, +-2.55662537848869153827e-04, +-2.55135564550115290575e-04, +-2.54463461275976690883e-04, +-2.53646787741720056760e-04, +-2.52686185625914012682e-04, +-2.51582378104383988602e-04, +-2.50336169338122934043e-04, +-2.48948443915500688007e-04, +-2.47420166249151312829e-04, +-2.45752379927938354159e-04, +-2.43946207024417992780e-04, +-2.42002847358256754223e-04, +-2.39923577716073371238e-04, +-2.37709751028206703414e-04, +-2.35362795502931025464e-04, +-2.32884213718665853896e-04, +-2.30275581674753719499e-04, +-2.27538547801391219296e-04, +-2.24674831929338742875e-04, +-2.21686224220039661921e-04, +-2.18574584056813192318e-04, +-2.15341838897799910417e-04, +-2.11989983091363462259e-04, +-2.08521076654672306251e-04, +-2.04937244016203435910e-04, +-2.01240672722932391033e-04, +-1.97433612112999371446e-04, +-1.93518371954601639930e-04, +-1.89497321052062165161e-04, +-1.85372885819735596941e-04, +-1.81147548824731936421e-04, +-1.76823847299330738289e-04, +-1.72404371623836980172e-04, +-1.67891763780981287087e-04, +-1.63288715782630906338e-04, +-1.58597968069809712021e-04, +-1.53822307886959517469e-04, +-1.48964567631409072149e-04, +-1.44027623179032189917e-04, +-1.39014392187015984161e-04, +-1.33927832374908250841e-04, +-1.28770939784726684953e-04, +-1.23546747021317972074e-04, +-1.18258321473934703560e-04, +-1.12908763520077224328e-04, +-1.07501204712651167732e-04, +-1.02038805951497883089e-04, +-9.65247556403633775101e-05, +-9.09622678303766927241e-05, +-8.53545803511158610944e-05, +-7.97049529303493834971e-05, +-7.40166653035361572950e-05, +-6.82930153141845771095e-05, +-6.25373170061634808944e-05, +-5.67528987090696620090e-05, +-5.09431011177533815009e-05, +-4.51112753671087087165e-05, +-3.92607811032360062451e-05, +-3.33949845520835634973e-05, +-2.75172565866769451451e-05, +-2.16309707940438413821e-05, +-1.57395015429393948119e-05, +-9.84622205347808669251e-06, +-3.95450246978667291299e-06, + 1.93229206330573338499e-06, + 7.81080331823583281971e-06, + 1.36776818965353001598e-05, + 1.95295891331412940274e-05, + 2.53631989924010254722e-05, + 3.11751999544031924995e-05, + 3.69622968907776241966e-05, + 4.27212129288199275452e-05, + 4.84486913029018664584e-05, + 5.41414971921248957621e-05, + 5.97964195431813658947e-05, + 6.54102728773860912868e-05, + 7.09798990809431715968e-05, + 7.65021691772440931741e-05, + 8.19739850804731076412e-05, + 8.73922813293384121618e-05, + 9.27540268000407564604e-05, + 9.80562263975138116018e-05, + 1.03295922723993288585e-04, + 1.08470197723987624161e-04, + 1.13576174304741347185e-04, + 1.18611017931288513657e-04, + 1.23571938195231626964e-04, + 1.28456190356295279348e-04, + 1.33261076856053907241e-04, + 1.37983948802590338087e-04, + 1.42622207425680382412e-04, + 1.47173305501465306920e-04, + 1.51634748745910018621e-04, + 1.56004097176282787189e-04, + 1.60278966439910032374e-04, + 1.64457029109492771420e-04, + 1.68536015944279398771e-04, + 1.72513717116415843562e-04, + 1.76387983401819222569e-04, + 1.80156727334917880767e-04, + 1.83817924326707803767e-04, + 1.87369613745391966429e-04, + 1.90809899959169668648e-04, + 1.94136953340610880553e-04, + 1.97349011231975375721e-04, + 2.00444378871088047271e-04, + 2.03421430277243321921e-04, + 2.06278609096683117384e-04, + 2.09014429407214987486e-04, + 2.11627476481567565469e-04, + 2.14116407509085294883e-04, + 2.16479952275410651545e-04, + 2.18716913799805800578e-04, + 2.20826168929834235413e-04, + 2.22806668893034610273e-04, + 2.24657439805431047601e-04, + 2.26377583136560162113e-04, + 2.27966276130837073623e-04, + 2.29422772185062839910e-04, + 2.30746401181916479780e-04, + 2.31936569779289853983e-04, + 2.32992761655362052436e-04, + 2.33914537709302807530e-04, + 2.34701536217598021733e-04, + 2.35353472945890507175e-04, + 2.35870141216392695174e-04, + 2.36251411930833043378e-04, + 2.36497233549024313271e-04, + 2.36607632023086867507e-04, + 2.36582710687435922303e-04, + 2.36422650104641229310e-04, + 2.36127707867309972372e-04, + 2.35698218356151145605e-04, + 2.35134592454421556497e-04, + 2.34437317218964954776e-04, + 2.33606955508089235429e-04, + 2.32644145566544174094e-04, + 2.31549600567894977307e-04, + 2.30324108114598991807e-04, + 2.28968529696129264976e-04, + 2.27483800105504667616e-04, + 2.25870926814611687646e-04, + 2.24130989308722247937e-04, + 2.22265138380645918331e-04, + 2.20274595384963348642e-04, + 2.18160651452820167134e-04, + 2.15924666667776987477e-04, + 2.13568069203236673070e-04, + 2.11092354421993914264e-04, + 2.08499083938437130724e-04, + 2.05789884644064712763e-04, + 2.02966447696813575728e-04, + 2.00030527474900313590e-04, + 1.96983940495784002342e-04, + 1.93828564300923292208e-04, + 1.90566336307002704526e-04, + 1.87199252624317116680e-04, + 1.83729366843086441233e-04, + 1.80158788788307001969e-04, + 1.76489683244053914514e-04, + 1.72724268647881387890e-04, + 1.68864815756162396296e-04, + 1.64913646281104273863e-04, + 1.60873131500388584026e-04, + 1.56745690840089552413e-04, + 1.52533790431842698147e-04, + 1.48239941645072722306e-04, + 1.43866699595155821557e-04, + 1.39416661628403223006e-04, + 1.34892465784759241557e-04, + 1.30296789239119602255e-04, + 1.25632346722192602372e-04, + 1.20901888921826961877e-04, + 1.16108200865747232967e-04, + 1.11254100286645201583e-04, + 1.06342435970584441723e-04, + 1.01376086089681932472e-04, + 9.63579565200426416864e-05, + 9.12909791459249860338e-05, + 8.61781101511258242455e-05, + 8.10223282985787361839e-05, + 7.58266331991632841188e-05, + 7.05940435707285904570e-05, + 6.53275954883418709775e-05, + 6.00303406267707601431e-05, + 5.47053444962296712734e-05, + 4.93556846723300390086e-05, + 4.39844490214451387493e-05, + 3.85947339222574980089e-05, + 3.31896424847004075168e-05, + 2.77722827672396915886e-05, + 2.23457659935181742969e-05, + 1.69132047694604267319e-05, + 1.14777113016647637858e-05, + 6.04239561835710224983e-06, + 6.10363793728645020518e-07, +-4.81528382325380808311e-06, +-1.02314543745700456363e-05, +-1.56350642523847494154e-05, +-2.10230408508807413534e-05, +-2.63923243095009231191e-05, +-3.17398692468697033722e-05, +-3.70626464842205185883e-05, +-4.23576447574330595914e-05, +-4.76218724167029767991e-05, +-5.28523591128858801825e-05, +-5.80461574695681123935e-05, +-6.32003447399251964056e-05, +-6.83120244474383017403e-05, +-7.33783280095512028618e-05, +-7.83964163433584703636e-05, +-8.33634814524302451963e-05, +-8.82767479938875655916e-05, +-9.31334748248567243206e-05, +-9.79309565274441714503e-05, +-1.02666524911384672157e-04, +-1.07337550493532478228e-04, +-1.11941443953376520482e-04, +-1.16475657563775984358e-04, +-1.20937686596131455368e-04, +-1.25325070699215711592e-04, +-1.29635395250910385187e-04, +-1.33866292682098157263e-04, +-1.38015443772047713324e-04, +-1.42080578914434722728e-04, +-1.46059479353512834980e-04, +-1.49949978389612786304e-04, +-1.53749962553389324382e-04, +-1.57457372748113794830e-04, +-1.61070205359542604606e-04, +-1.64586513332575895248e-04, +-1.68004407214276350055e-04, +-1.71322056162632199933e-04, +-1.74537688920543577207e-04, +-1.77649594754509306677e-04, +-1.80656124357563160031e-04, +-1.83555690715879498342e-04, +-1.86346769938744346575e-04, +-1.89027902051352861886e-04, +-1.91597691750067656950e-04, +-1.94054809119746906601e-04, +-1.96397990312779409513e-04, +-1.98626038189485975725e-04, +-2.00737822919565348781e-04, +-2.02732282544295099209e-04, +-2.04608423499208415697e-04, +-2.06365321097002875567e-04, +-2.08002119970448036889e-04, +-2.09518034475094608749e-04, +-2.10912349051600370295e-04, +-2.12184418547517878980e-04, +-2.13333668498409933503e-04, +-2.14359595368183043079e-04, +-2.15261766748550323726e-04, +-2.16039821517564244657e-04, +-2.16693469957175179064e-04, +-2.17222493829804320963e-04, +-2.17626746413933055187e-04, +-2.17906152498744288149e-04, +-2.18060708337866669768e-04, +-2.18090481562302831997e-04, +-2.17995611052633665597e-04, +-2.17776306770636030692e-04, +-2.17432849550450564774e-04, +-2.16965590849471163170e-04, +-2.16374952459152508069e-04, +-2.15661426175948502115e-04, +-2.14825573432618965528e-04, +-2.13868024890168464437e-04, +-2.12789479990694880424e-04, +-2.11590706471458399373e-04, +-2.10272539840493795068e-04, +-2.08835882814101080193e-04, +-2.07281704716627822619e-04, +-2.05611040842872101015e-04, +-2.03824991783563389154e-04, +-2.01924722714337458607e-04, +-1.99911462648656409243e-04, +-1.97786503655151527006e-04, +-1.95551200039875640226e-04, +-1.93206967493983087581e-04, +-1.90755282207361699176e-04, +-1.88197679948765912066e-04, +-1.85535755113050746619e-04, +-1.82771159736013454056e-04, +-1.79905602477525801202e-04, +-1.76940847573584393148e-04, +-1.73878713757827938272e-04, +-1.70721073153264649115e-04, +-1.67469850134842302650e-04, +-1.64127020163558210364e-04, +-1.60694608592805399886e-04, +-1.57174689447680583382e-04, +-1.53569384177978999996e-04, +-1.49880860385627755508e-04, +-1.46111330527314676282e-04, +-1.42263050593096474329e-04, +-1.38338318761709250845e-04, +-1.34339474033567067698e-04, +-1.30268894841948973309e-04, +-1.26128997643502378410e-04, +-1.21922235488716284571e-04, +-1.17651096573263047097e-04, +-1.13318102771055339347e-04, +-1.08925808149881126548e-04, +-1.04476797470485840437e-04, +-9.99736846699831026861e-05, +-9.54191113304803323683e-05, +-9.08157451338251561638e-05, +-8.61662783033089883962e-05, +-8.14734260333982814777e-05, +-7.67399249081906023075e-05, +-7.19685313096766739269e-05, +-6.71620198166663929249e-05, +-6.23231815953190427171e-05, +-5.74548227822070198159e-05, +-5.25597628608498169912e-05, +-4.76408330326411294346e-05, +-4.27008745831808004092e-05, +-3.77427372447754268139e-05, +-3.27692775562946159791e-05, +-2.77833572210794834225e-05, +-2.27878414640919380344e-05, +-1.77855973889981053694e-05, +-1.27794923363028358154e-05, +-7.77239224340285758588e-06, +-2.76716000750597664943e-06, + 2.23334614765047225155e-06, + 7.22627430035223622482e-06, + 1.22087804538059595082e-05, + 1.71780301524608407758e-05, + 2.21312000908374962855e-05, + 2.70654797139531880809e-05, + 3.19780728084379127691e-05, + 3.68661990834432147361e-05, + 4.17270957404514982554e-05, + 4.65580190311022323554e-05, + 5.13562458021581016814e-05, + 5.61190750267443480906e-05, + 6.08438293210010258259e-05, + 6.55278564453003783789e-05, + 7.01685307891888973997e-05, + 7.47632548392249471477e-05, + 7.93094606288941272312e-05, + 8.38046111697948801871e-05, + 8.82462018632895745093e-05, + 9.26317618918994384889e-05, + 9.69588555895161487196e-05, + 1.01225083789883730243e-04, + 1.05428085152447302661e-04, + 1.09565537464902931428e-04, + 1.13635158921721518338e-04, + 1.17634709377956067329e-04, + 1.21561991577586462265e-04, + 1.25414852355879225454e-04, + 1.29191183814908515468e-04, + 1.32888924471751327088e-04, + 1.36506060378661892669e-04, + 1.40040626214685270945e-04, + 1.43490706347988396978e-04, + 1.46854435868515841024e-04, + 1.50130001590280805039e-04, + 1.53315643022813413417e-04, + 1.56409653311238074644e-04, + 1.59410380144482617453e-04, + 1.62316226631138655961e-04, + 1.65125652142516246785e-04, + 1.67837173122445686060e-04, + 1.70449363863413175593e-04, + 1.72960857248622345769e-04, + 1.75370345459602272869e-04, + 1.77676580649003228304e-04, + 1.79878375578234217958e-04, + 1.81974604219625616178e-04, + 1.83964202322818494873e-04, + 1.85846167945095638082e-04, + 1.87619561945405119441e-04, + 1.89283508441830545512e-04, + 1.90837195232300557094e-04, + 1.92279874178338393460e-04, + 1.93610861551680866121e-04, + 1.94829538343613950903e-04, + 1.95935350536894948301e-04, + 1.96927809340166344414e-04, + 1.97806491384736336846e-04, + 1.98571038883713909618e-04, + 1.99221159753417060602e-04, + 1.99756627697045236825e-04, + 2.00177282250609553729e-04, + 2.00483028791162594395e-04, + 2.00673838507340500988e-04, + 2.00749748332303471193e-04, + 2.00710860839155866373e-04, + 2.00557344098951099076e-04, + 2.00289431501410645185e-04, + 1.99907421538506638011e-04, + 1.99411677551082736374e-04, + 1.98802627438700833676e-04, + 1.98080763332926219986e-04, + 1.97246641234288935590e-04, + 1.96300880613169869337e-04, + 1.95244163974890567017e-04, + 1.94077236389296096204e-04, + 1.92800904985150346445e-04, + 1.91416038409673633282e-04, + 1.89923566253578820747e-04, + 1.88324478441976569726e-04, + 1.86619824591544307586e-04, + 1.84810713334366470651e-04, + 1.82898311608877559096e-04, + 1.80883843918355590027e-04, + 1.78768591557429662019e-04, + 1.76553891807085754475e-04, + 1.74241137098672801628e-04, + 1.71831774147425040116e-04, + 1.69327303056034789413e-04, + 1.66729276388829827970e-04, + 1.64039298217118011776e-04, + 1.61259023136285878450e-04, + 1.58390155255254730902e-04, + 1.55434447158867309821e-04, + 1.52393698843932419136e-04, + 1.49269756629439789971e-04, + 1.46064512041690788922e-04, + 1.42779900675020699667e-04, + 1.39417901028690864249e-04, + 1.35980533320795114868e-04, + 1.32469858279776427946e-04, + 1.28887975914319409792e-04, + 1.25237024262341641208e-04, + 1.21519178119826532425e-04, + 1.17736647750260424580e-04, + 1.13891677575382762027e-04, + 1.09986544848155620062e-04, + 1.06023558308557749072e-04, + 1.02005056823126766924e-04, + 9.79334080089949563690e-05, + 9.38110068432369283674e-05, + 8.96402742583390368340e-05, + 8.54236557246172082802e-05, + 8.11636198204074375134e-05, + 7.68626567908638934834e-05, + 7.25232770962033334184e-05, + 6.81480099502408253210e-05, + 6.37394018500648417607e-05, + 5.93000150977037791236e-05, + 5.48324263146410183461e-05, + 5.03392249500377099197e-05, + 4.58230117835234620669e-05, + 4.12863974234202202882e-05, + 3.67320008012637997784e-05, + 3.21624476634885960824e-05, + 2.75803690611435845046e-05, + 2.29883998385047982199e-05, + 1.83891771214516705382e-05, + 1.37853388064824855514e-05, + 9.17952205116795011679e-06, + 4.57436176706797238011e-06, +-2.75108842579818438910e-08, +-4.62346999106136241029e-06, +-9.21089638641225220430e-06, +-1.37871791373255400920e-05, +-1.83497170273250301319e-05, +-2.28959200315399970119e-05, +-2.74232107835103849100e-05, +-3.19290260328724777978e-05, +-3.64108180931019818124e-05, +-4.08660562784996536732e-05, +-4.52922283295994015603e-05, +-4.96868418262625327142e-05, +-5.40474255875064181487e-05, +-5.83715310574944550438e-05, +-6.26567336767544860471e-05, +-6.69006342379224212954e-05, +-7.11008602252454944507e-05, +-7.52550671370984356097e-05, +-7.93609397907785223342e-05, +-8.34161936088556751033e-05, +-8.74185758863736857033e-05, +-9.13658670381457783342e-05, +-9.52558818255899069152e-05, +-9.90864705622930764172e-05, +-1.02855520297645628824e-04, +-1.06560955978024466816e-04, +-1.10200741584761408303e-04, +-1.13772881248329986426e-04, +-1.17275420338133038616e-04, +-1.20706446527301793710e-04, +-1.24064090831927222123e-04, +-1.27346528624161774851e-04, +-1.30551980618646957209e-04, +-1.33678713831734421146e-04, +-1.36725042512981202628e-04, +-1.39689329048471762296e-04, +-1.42569984835333479116e-04, +-1.45365471127236698399e-04, +-1.48074299850179806918e-04, +-1.50695034388278933371e-04, +-1.53226290339108047649e-04, +-1.55666736238194213047e-04, +-1.58015094252302533938e-04, +-1.60270140841145748061e-04, +-1.62430707387187727537e-04, +-1.64495680793215953231e-04, +-1.66464004047380415832e-04, +-1.68334676755447923760e-04, +-1.70106755639931378401e-04, +-1.71779355005955645377e-04, +-1.73351647173555225515e-04, +-1.74822862876237544423e-04, +-1.76192291625613234839e-04, +-1.77459282041936094012e-04, +-1.78623242150403258857e-04, +-1.79683639643093680336e-04, +-1.80640002106423656165e-04, +-1.81491917214075620078e-04, +-1.82239032885274609931e-04, +-1.82881057408414176473e-04, +-1.83417759529990343371e-04, +-1.83848968508822530749e-04, +-1.84174574135603265346e-04, +-1.84394526717789769034e-04, +-1.84508837029895376297e-04, +-1.84517576229257786137e-04, +-1.84420875737372863242e-04, +-1.84218927086907938075e-04, +-1.83911981734526851434e-04, +-1.83500350839676173650e-04, +-1.82984405009505745514e-04, +-1.82364574010110863959e-04, +-1.81641346444305146679e-04, +-1.80815269396154251801e-04, +-1.79886948042512636280e-04, +-1.78857045231831964091e-04, +-1.77726281030521376285e-04, +-1.76495432237164907125e-04, +-1.75165331864910952826e-04, +-1.73736868592374774480e-04, +-1.72210986183407241141e-04, +-1.70588682876102914121e-04, +-1.68871010741435372948e-04, +-1.67059075011932430324e-04, +-1.65154033380787864348e-04, +-1.63157095271909268353e-04, +-1.61069521081280296517e-04, +-1.58892621390163224591e-04, +-1.56627756150609387950e-04, +-1.54276333843780973348e-04, +-1.51839810611594959108e-04, +-1.49319689362255997572e-04, +-1.46717518850139323847e-04, +-1.44034892730693565204e-04, +-1.41273448590855218087e-04, +-1.38434866955593221692e-04, +-1.35520870271185604229e-04, +-1.32533221865797814620e-04, +-1.29473724888089073738e-04, +-1.26344221224348324251e-04, +-1.23146590394907499066e-04, +-1.19882748430450496667e-04, +-1.16554646728892494570e-04, +-1.13164270893511021972e-04, +-1.09713639553016026698e-04, +-1.06204803164258788938e-04, +-1.02639842798286093709e-04, +-9.90208689104574309690e-05, +-9.53500200953488063907e-05, +-9.16294618271747146219e-05, +-8.78613851864693950078e-05, +-8.40480055737724741525e-05, +-8.01915614110729224086e-05, +-7.62943128317693849017e-05, +-7.23585403599120898779e-05, +-6.83865435794958062077e-05, +-6.43806397945781601344e-05, +-6.03431626810021750013e-05, +-5.62764609305052045107e-05, +-5.21828968880001095782e-05, +-4.80648451828273766406e-05, +-4.39246913547101223052e-05, +-3.97648304753519063080e-05, +-3.55876657662771198705e-05, +-3.13956072138546100360e-05, +-2.71910701822341436737e-05, +-2.29764740250598643260e-05, +-1.87542406966089186175e-05, +-1.45267933633486321363e-05, +-1.02965550165577958658e-05, +-6.06594708686369126855e-06, +-1.83738806147565725218e-06, + 2.38670789508730654728e-06, + 6.60393231605029799332e-06, + 1.08118838022856526365e-05, + 1.50081693864890804819e-05, + 1.91904058907051211296e-05, + 2.33562212764937420536e-05, + 2.75032559869653701879e-05, + 3.16291642799266015692e-05, + 3.57316155513857358346e-05, + 3.98082956486727347189e-05, + 4.38569081724363369137e-05, + 4.78751757667874686011e-05, + 5.18608413968659121744e-05, + 5.58116696131162758521e-05, + 5.97254478015662288413e-05, + 6.35999874194105038012e-05, + 6.74331252152119678313e-05, + 7.12227244330430300963e-05, + 7.49666759998972407220e-05, + 7.86628996957159043685e-05, + 8.23093453053795327638e-05, + 8.59039937520326019873e-05, + 8.94448582111133600001e-05, + 9.29299852044797151680e-05, + 9.63574556740282402905e-05, + 9.97253860342133961791e-05, + 1.03031929202938195831e-04, + 1.06275275610134644190e-04, + 1.09453654183648506066e-04, + 1.12565333311777745389e-04, + 1.15608621781949924361e-04, + 1.18581869695136337068e-04, + 1.21483469355360853659e-04, + 1.24311856133939833708e-04, + 1.27065509307947152248e-04, + 1.29742952872464735155e-04, + 1.32342756326188934566e-04, + 1.34863535429971070998e-04, + 1.37303952937931089294e-04, + 1.39662719300668973499e-04, + 1.41938593340331764125e-04, + 1.44130382897093850406e-04, + 1.46236945446754414840e-04, + 1.48257188689131702477e-04, + 1.50190071106954631209e-04, + 1.52034602494970392606e-04, + 1.53789844459004473734e-04, + 1.55454910884727745025e-04, + 1.57028968375900465160e-04, + 1.58511236661886526942e-04, + 1.59900988974221943979e-04, + 1.61197552392132844234e-04, + 1.62400308156727989691e-04, + 1.63508691953843704383e-04, + 1.64522194165353128834e-04, + 1.65440360088857943638e-04, + 1.66262790125675229700e-04, + 1.66989139937054223255e-04, + 1.67619120568575667371e-04, + 1.68152498542703266729e-04, + 1.68589095919475644722e-04, + 1.68928790325348127024e-04, + 1.69171514950206333802e-04, + 1.69317258512600938907e-04, + 1.69366065193253035638e-04, + 1.69318034536926169398e-04, + 1.69173321322751827635e-04, + 1.68932135403124315375e-04, + 1.68594741511303550284e-04, + 1.68161459037872361389e-04, + 1.67632661776220571190e-04, + 1.67008777637239416583e-04, + 1.66290288333431385444e-04, + 1.65477729032657161099e-04, + 1.64571687981757684184e-04, + 1.63572806100295385775e-04, + 1.62481776544717680536e-04, + 1.61299344243187993495e-04, + 1.60026305401423106544e-04, + 1.58663506979840374144e-04, + 1.57211846142359855600e-04, + 1.55672269677209203047e-04, + 1.54045773390101885464e-04, + 1.52333401470171580496e-04, + 1.50536245829059009979e-04, + 1.48655445413586417922e-04, + 1.46692185492392439651e-04, + 1.44647696917026745639e-04, + 1.42523255357962074646e-04, + 1.40320180515933701443e-04, + 1.38039835309150310440e-04, + 1.35683625036847225554e-04, + 1.33252996519696450227e-04, + 1.30749437217595669385e-04, + 1.28174474325369749201e-04, + 1.25529673846935238340e-04, + 1.22816639648479919303e-04, + 1.20037012491233243219e-04, + 1.17192469044403129027e-04, + 1.14284720878873418933e-04, + 1.11315513442261188005e-04, + 1.08286625015946468605e-04, + 1.05199865654693577497e-04, + 1.02057076109495512093e-04, + 9.88601267342783304043e-05, + 9.56109163771139760083e-05, + 9.23113712565947120868e-05, + 8.89634438240340108539e-05, + 8.55691116121616991534e-05, + 8.21303760709912982884e-05, + 7.86492613915423208508e-05, + 7.51278133181146123365e-05, + 7.15680979497604612561e-05, + 6.79722005317787153359e-05, + 6.43422242377698607113e-05, + 6.06802889430856936094e-05, + 5.69885299903377532185e-05, + 5.32690969476886882583e-05, + 4.95241523606481209006e-05, + 4.57558704980855863662e-05, + 4.19664360932403064002e-05, + 3.81580430803206248217e-05, + 3.43328933276007924294e-05, + 3.04931953676192458200e-05, + 2.66411631252087834044e-05, + 2.27790146442161646153e-05, + 1.89089708134602095535e-05, + 1.50332540927946444229e-05, + 1.11540872399499682495e-05, + 7.27369203889113503421e-06, + 3.39428803041684083773e-06, +-4.81908754276311450070e-07, +-4.35268705634372629675e-06, +-8.21584164763919663841e-06, +-1.20691745839433958802e-05, +-1.59104964523640528653e-05, +-1.97376276122016780436e-05, +-2.35483994285795049709e-05, +-2.73406554981410021381e-05, +-3.11122528661240456025e-05, +-3.48610632341272955897e-05, +-3.85849741578888450833e-05, +-4.22818902344056668941e-05, +-4.59497342777289552842e-05, +-4.95864484827761740015e-05, +-5.31899955765110986849e-05, +-5.67583599558492673393e-05, +-6.02895488116546415976e-05, +-6.37815932381954160072e-05, +-6.72325493274930760176e-05, +-7.06404992478322041284e-05, +-7.40035523060039669620e-05, +-7.73198459925695190907e-05, +-8.05875470096189763401e-05, +-8.38048522804609266092e-05, +-8.69699899406400548209e-05, +-9.00812203098600702616e-05, +-9.31368368441220313616e-05, +-9.61351670676795016460e-05, +-9.90745734842556015267e-05, +-1.01953454467028386448e-04, +-1.04770245126946709891e-04, +-1.07523418158803123158e-04, +-1.10211484664747875421e-04, +-1.12832994954700652560e-04, +-1.15386539323270961746e-04, +-1.17870748802769852344e-04, +-1.20284295891912211356e-04, +-1.22625895259826191760e-04, +-1.24894304424997594233e-04, +-1.27088324408796619729e-04, +-1.29206800363245279464e-04, +-1.31248622172700554062e-04, +-1.33212725029144128013e-04, +-1.35098089980784487676e-04, +-1.36903744453693149413e-04, +-1.38628762746211502523e-04, +-1.40272266495882424152e-04, +-1.41833425118677113443e-04, +-1.43311456220300168993e-04, +-1.44705625979375639015e-04, +-1.46015249502334635862e-04, +-1.47239691149835216733e-04, +-1.48378364834568840904e-04, +-1.49430734290319368980e-04, +-1.50396313312156941142e-04, +-1.51274665967682871333e-04, +-1.52065406779206268055e-04, +-1.52768200876835928996e-04, +-1.53382764122401261215e-04, +-1.53908863204188484618e-04, +-1.54346315702462519998e-04, +-1.54694990125800718034e-04, +-1.54954805918226855375e-04, +-1.55125733437199472397e-04, +-1.55207793902502094903e-04, +-1.55201059316101394776e-04, +-1.55105652353058453673e-04, +-1.54921746223595071862e-04, +-1.54649564506431944988e-04, +-1.54289380953534071422e-04, +-1.53841519266410082720e-04, +-1.53306352844135500117e-04, +-1.52684304503277075687e-04, +-1.51975846169923051046e-04, +-1.51181498544025521777e-04, +-1.50301830736287767064e-04, +-1.49337459877842251886e-04, +-1.48289050702975444508e-04, +-1.47157315105178143448e-04, +-1.45943011666808031192e-04, +-1.44646945162670226758e-04, +-1.43269966037836245969e-04, +-1.41812969860030777154e-04, +-1.40276896746939125880e-04, +-1.38662730768791489120e-04, +-1.36971499326602120161e-04, +-1.35204272506452450198e-04, +-1.33362162410215011723e-04, +-1.31446322463141056745e-04, +-1.29457946698729233501e-04, +-1.27398269021328599442e-04, +-1.25268562446894228622e-04, +-1.23070138322430765393e-04, +-1.20804345524507650679e-04, +-1.18472569637393813956e-04, +-1.16076232111318126267e-04, +-1.13616789401283968986e-04, +-1.11095732087066782702e-04, +-1.08514583974842290402e-04, +-1.05874901181016539101e-04, +-1.03178271198800118515e-04, +-1.00426311948084758256e-04, +-9.76206708091875252457e-05, +-9.47630236410444991074e-05, +-9.18550737843973141112e-05, +-8.88985510506610496001e-05, +-8.58952106969416680562e-05, +-8.28468323879038561972e-05, +-7.97552191450655496591e-05, +-7.66221962841397250411e-05, +-7.34496103410512394703e-05, +-7.02393279872563352237e-05, +-6.69932349350013444994e-05, +-6.37132348331598941495e-05, +-6.04012481542852742197e-05, +-5.70592110735821189476e-05, +-5.36890743402856300114e-05, +-5.02928021423770289528e-05, +-4.68723709650220007926e-05, +-4.34297684435565900540e-05, +-3.99669922116305890969e-05, +-3.64860487451815660126e-05, +-3.29889522029066755543e-05, +-2.94777232639011821304e-05, +-2.59543879631318446101e-05, +-2.24209765254152845900e-05, +-1.88795221985704670439e-05, +-1.53320600864227232015e-05, +-1.17806259822765688943e-05, +-8.22725520364250435790e-06, +-4.67398142876525914271e-06, +-1.12283553561652046528e-06, + 2.42415555586849744280e-06, + 5.96497003777039182297e-06, + 9.49759236367494958416e-06, + 1.30200143930290886731e-05, + 1.65302365297154976124e-05, + 2.00262688542018995176e-05, + 2.35061322486258601641e-05, + 2.69678595141725338990e-05, + 3.04094964801652475677e-05, + 3.38291031041225136330e-05, + 3.72247545623280811614e-05, + 4.05945423301795488562e-05, + 4.39365752517605946421e-05, + 4.72489805980300616090e-05, + 5.05299051130391751476e-05, + 5.37775160475925401854e-05, + 5.69900021797799109010e-05, + 6.01655748218186950589e-05, + 6.33024688126045798455e-05, + 6.63989434955355209119e-05, + 6.94532836809095877094e-05, + 7.24638005925247566689e-05, + 7.54288327978053365708e-05, + 7.83467471210983574734e-05, + 8.12159395395303644084e-05, + 8.40348360609798490086e-05, + 8.68018935836787020261e-05, + 8.95156007369763171777e-05, + 9.21744787028109000904e-05, + 9.47770820174428766953e-05, + 9.73219993530192951838e-05, + 9.98078542785484291089e-05, + 1.02233305999877626346e-04, + 1.04597050078279252879e-04, + 1.06897819127260571481e-04, + 1.09134383487232477302e-04, + 1.11305551877675454743e-04, + 1.13410172026465080842e-04, + 1.15447131276023696555e-04, + 1.17415357165986388734e-04, + 1.19313817992076323833e-04, + 1.21141523340904152650e-04, + 1.22897524600417128735e-04, + 1.24580915445738179192e-04, + 1.26190832300148298968e-04, + 1.27726454771003749460e-04, + 1.29187006060312931576e-04, + 1.30571753349855405749e-04, + 1.31880008160592337128e-04, + 1.33111126686225034448e-04, + 1.34264510100741093525e-04, + 1.35339604839805301758e-04, + 1.36335902855876962966e-04, + 1.37252941846921911991e-04, + 1.38090305458667854995e-04, + 1.38847623460269244903e-04, + 1.39524571893355508502e-04, + 1.40120873194398874121e-04, + 1.40636296290376592178e-04, + 1.41070656667688923902e-04, + 1.41423816414358241448e-04, + 1.41695684235501812628e-04, + 1.41886215442108465281e-04, + 1.41995411913169058797e-04, + 1.42023322031210527672e-04, + 1.41970040591311803596e-04, + 1.41835708683687403576e-04, + 1.41620513549942957229e-04, + 1.41324688413120390503e-04, + 1.40948512281664279549e-04, + 1.40492309727460512516e-04, + 1.39956450638105661232e-04, + 1.39341349943586742142e-04, + 1.38647467317560966387e-04, + 1.37875306853443076616e-04, + 1.37025416715516460461e-04, + 1.36098388765306077238e-04, + 1.35094858163456845238e-04, + 1.34015502947381628333e-04, + 1.32861043584951986655e-04, + 1.31632242504520034906e-04, + 1.30329903601576123319e-04, + 1.28954871722338328469e-04, + 1.27508032124644551074e-04, + 1.25990309916430414392e-04, + 1.24402669472184333093e-04, + 1.22746113827731657530e-04, + 1.21021684053717931608e-04, + 1.19230458608205958028e-04, + 1.17373552668725822899e-04, + 1.15452117444264388342e-04, + 1.13467339467561269067e-04, + 1.11420439868162524316e-04, + 1.09312673626677319912e-04, + 1.07145328810660439892e-04, + 1.04919725792656324940e-04, + 1.02637216450778944853e-04, + 1.00299183352382616555e-04, + 9.79070389212828459625e-05, + 9.54622245890343021661e-05, + 9.29662099307709859563e-05, + 9.04204917861251337118e-05, + 8.78265933657491361646e-05, + 8.51860633439697795440e-05, + 8.25004749381152567740e-05, + 7.97714249750583101993e-05, + 7.70005329455285302594e-05, + 7.41894400467507647698e-05, + 7.13398082139749418204e-05, + 6.84533191414649809991e-05, + 6.55316732935233309948e-05, + 6.25765889061299349127e-05, + 5.95898009797798930746e-05, + 5.65730602641084840982e-05, + 5.35281322348962640303e-05, + 5.04567960640498228923e-05, + 4.73608435831570034977e-05, + 4.42420782412198123029e-05, + 4.11023140571756856096e-05, + 3.79433745677702796120e-05, + 3.47670917715006306549e-05, + 3.15753050690913554294e-05, + 2.83698602012252819608e-05, + 2.51526081840889388815e-05, + 2.19254042433976171740e-05, + 1.86901067473987712679e-05, + 1.54485761396172072233e-05, + 1.22026738718400676369e-05, + 8.95426133799693216720e-06, + 5.70519880953679468414e-06, + 2.45734437291689684403e-06, +-7.87447130237725029692e-07, +-4.02732515958524032887e-06, +-7.26044452868275316679e-06, +-1.04849664530539972413e-05, +-1.36990595931614081774e-05, +-1.69009010916851591059e-05, +-2.00886776045228981175e-05, +-2.32605863249292218813e-05, +-2.64148360002174825494e-05, +-2.95496479404527710906e-05, +-3.26632570185692985083e-05, +-3.57539126613519710695e-05, +-3.88198798307268989525e-05, +-4.18594399948131874701e-05, +-4.48708920881937505377e-05, +-4.78525534608703297839e-05, +-5.08027608153759224091e-05, +-5.37198711315230623370e-05, +-5.66022625782771395811e-05, +-5.94483354122496957970e-05, +-6.22565128623159649065e-05, +-6.50252419998696961625e-05, +-6.77529945942363268996e-05, +-7.04382679527763058127e-05, +-7.30795857452109842494e-05, +-7.56754988117607863083e-05, +-7.82245859545587472750e-05, +-8.07254547120429588646e-05, +-8.31767421157772956445e-05, +-8.55771154294189502010e-05, +-8.79252728693081722763e-05, +-9.02199443063830727177e-05, +-9.24598919490082272500e-05, +-9.46439110063570436353e-05, +-9.67708303319964480843e-05, +-9.88395130473318793462e-05, +-1.00848857144579225412e-04, +-1.02797796068976429913e-04, +-1.04685299279854606281e-04, +-1.06510372790377650341e-04, +-1.08272059685596318680e-04, +-1.09969440618577611341e-04, +-1.11601634284353844629e-04, +-1.13167797871448837341e-04, +-1.14667127490753893888e-04, +-1.16098858581540945157e-04, +-1.17462266294409572748e-04, +-1.18756665850985608014e-04, +-1.19981412880174577386e-04, +-1.21135903730876983027e-04, +-1.22219575760907419324e-04, +-1.23231907602096356184e-04, +-1.24172419401388892416e-04, +-1.25040673037858960726e-04, +-1.25836272315542666532e-04, +-1.26558863132016492748e-04, +-1.27208133622654898272e-04, +-1.27783814280521123164e-04, +-1.28285678051853307665e-04, +-1.28713540407127574909e-04, +-1.29067259387689078475e-04, +-1.29346735627960067851e-04, +-1.29551912353247712954e-04, +-1.29682775353174970954e-04, +-1.29739352930806405104e-04, +-1.29721715827507011074e-04, +-1.29629977123626777182e-04, +-1.29464292115094922872e-04, +-1.29224858166029714888e-04, +-1.28911914537480141833e-04, +-1.28525742192432532911e-04, +-1.28066663577224341096e-04, +-1.27535042379524224485e-04, +-1.26931283263051979506e-04, +-1.26255831579210470172e-04, +-1.25509173055851516688e-04, +-1.24691833463355639632e-04, +-1.23804378258269496800e-04, +-1.22847412204727150179e-04, +-1.21821578973907172273e-04, +-1.20727560721779606824e-04, +-1.19566077645420637825e-04, +-1.18337887518172143108e-04, +-1.17043785203959168793e-04, +-1.15684602151032309364e-04, +-1.14261205865508758540e-04, +-1.12774499364983135674e-04, +-1.11225420612612888125e-04, +-1.09614941931962398339e-04, +-1.07944069403014051949e-04, +-1.06213842239701207601e-04, +-1.04425332149347485926e-04, +-1.02579642674402744655e-04, +-1.00677908516879591628e-04, +-9.87212948458993696643e-05, +-9.67109965887680804323e-05, +-9.46482377060114694195e-05, +-9.25342704508053923206e-05, +-9.03703746132478017740e-05, +-8.81578567499270010759e-05, +-8.58980493992450127834e-05, +-8.35923102829684219880e-05, +-8.12420214944795825900e-05, +-7.88485886742140853296e-05, +-7.64134401727725140778e-05, +-7.39380262022039087908e-05, +-7.14238179759623244237e-05, +-6.88723068380450985934e-05, +-6.62850033818259808810e-05, +-6.36634365591029851607e-05, +-6.10091527798890391780e-05, +-5.83237150034378014633e-05, +-5.56087018211295729380e-05, +-5.28657065316302825957e-05, +-5.00963362089557252181e-05, +-4.73022107639477868909e-05, +-4.44849619997154997839e-05, +-4.16462326615831018211e-05, +-3.87876754821360727392e-05, +-3.59109522218197118487e-05, +-3.30177327057781363410e-05, +-3.01096938573906879706e-05, +-2.71885187291101264469e-05, +-2.42558955311136346803e-05, +-2.13135166584285751863e-05, +-1.83630777169545625609e-05, +-1.54062765490442216251e-05, +-1.24448122591593738538e-05, +-9.48038424016769929749e-06, +-6.51469120083589183379e-06, +-3.54943019507466532529e-06, +-5.86295653488527638405e-07, + 2.37302158221821148760e-06, + 5.32683522143069861928e-06, + 8.27346448286191381023e-06, + 1.12112350482972268184e-05, + 1.41384800113054187414e-05, + 1.70535408203802065375e-05, + 1.99547682159801403000e-05, + 2.28405231609389523773e-05, + 2.57091777637233010942e-05, + 2.85591161940189065772e-05, + 3.13887355901324983888e-05, + 3.41964469577007317870e-05, + 3.69806760592044563105e-05, + 3.97398642937916670619e-05, + 4.24724695669193537460e-05, + 4.51769671493239000906e-05, + 4.78518505248824157702e-05, + 5.04956322267979359933e-05, + 5.31068446617757945380e-05, + 5.56840409216389250861e-05, + 5.82257955819805972353e-05, + 6.07307054873712566403e-05, + 6.31973905227825399032e-05, + 6.56244943706810369847e-05, + 6.80106852534736013504e-05, + 7.03546566608603151554e-05, + 7.26551280617074665301e-05, + 7.49108456000490471188e-05, + 7.71205827748727728481e-05, + 7.92831411032435707121e-05, + 8.13973507665162628304e-05, + 8.34620712392105025155e-05, + 8.54761919002437216665e-05, + 8.74386326261934136023e-05, + 8.93483443662723540333e-05, + 9.12043096987145523709e-05, + 9.30055433682796324664e-05, + 9.47510928045935062712e-05, + 9.64400386210567564342e-05, + 9.80714950940618610149e-05, + 9.96446106222721028753e-05, + 1.01158568165728382656e-04, + 1.02612585664560169562e-04, + 1.04005916437090132763e-04, + 1.05337849557132784027e-04, + 1.06607710210300974068e-04, + 1.07814860029146553436e-04, + 1.08958697406971076818e-04, + 1.10038657790159221262e-04, + 1.11054213948895991334e-04, + 1.12004876226144938888e-04, + 1.12890192764771252285e-04, + 1.13709749712725811358e-04, + 1.14463171406168479332e-04, + 1.15150120530503418228e-04, + 1.15770298259229445850e-04, + 1.16323444370574466855e-04, + 1.16809337341866760875e-04, + 1.17227794421640891544e-04, + 1.17578671679441387104e-04, + 1.17861864033347977262e-04, + 1.18077305255228525620e-04, + 1.18224967953752292129e-04, + 1.18304863535199995448e-04, + 1.18317042142129913288e-04, + 1.18261592569961779611e-04, + 1.18138642161559509242e-04, + 1.17948356679904758004e-04, + 1.17690940158963789036e-04, + 1.17366634732863803995e-04, + 1.16975720443508680781e-04, + 1.16518515026772340008e-04, + 1.15995373677425865329e-04, + 1.15406688792958039944e-04, + 1.14752889696471350382e-04, + 1.14034442338837080757e-04, + 1.13251848980312161972e-04, + 1.12405647851827392831e-04, + 1.11496412796171015655e-04, + 1.10524752889300383963e-04, + 1.09491312042027578609e-04, + 1.08396768582333136470e-04, + 1.07241834818576963558e-04, + 1.06027256583881440439e-04, + 1.04753812761974128402e-04, + 1.03422314794789343279e-04, + 1.02033606172135439690e-04, + 1.00588561903744460506e-04, + 9.90880879740364323887e-05, + 9.75331207799133901139e-05, + 9.59246265519796495209e-05, + 9.42636007594733522788e-05, + 9.25510674993434647893e-05, + 9.07880788697715116788e-05, + 8.89757143285934223474e-05, + 8.71150800369563193095e-05, + 8.52073081886286283915e-05, + 8.32535563253643403313e-05, + 8.12550066387327429764e-05, + 7.92128652588326546708e-05, + 7.71283615303221291911e-05, + 7.50027472761658441352e-05, + 7.28372960496142743273e-05, + 7.06333023747593316630e-05, + 6.83920809761930819422e-05, + 6.61149659981945323883e-05, + 6.38033102139136647918e-05, + 6.14584842250172271472e-05, + 5.90818756522692805321e-05, + 5.66748883175234417645e-05, + 5.42389414176053005876e-05, + 5.17754686905652722838e-05, + 4.92859175748246270223e-05, + 4.67717483616246192265e-05, + 4.42344333413538523341e-05, + 4.16754559442534589821e-05, + 3.90963098759170062319e-05, + 3.64984982481686095644e-05, + 3.38835327057898264913e-05, + 3.12529325496060770987e-05, + 2.86082238564397440281e-05, + 2.59509385964386121227e-05, + 2.32826137482886975970e-05, + 2.06047904128203539622e-05, + 1.79190129255183850797e-05, + 1.52268279684512867372e-05, + 1.25297836820848089342e-05, + 9.82942877762201860177e-06, + 7.12731165015420239825e-06, + 4.42497949335259697511e-06, + 1.72397741607120027234e-06, +-9.74152438591300545820e-07, +-3.66787177127622279055e-06, +-6.35564700089772787053e-06, +-9.03595013522811150888e-06, +-1.17072596370426850940e-05, +-1.43680612853348429033e-05, +-1.70168490311088741731e-05, +-1.96521258473063757481e-05, +-2.22724045722929874815e-05, +-2.48762087465587318491e-05, +-2.74620734420669071810e-05, +-3.00285460838262985587e-05, +-3.25741872632199556503e-05, +-3.50975715426378017596e-05, +-3.75972882509638620259e-05, +-4.00719422694826037015e-05, +-4.25201548077314798470e-05, +-4.49405641689601653135e-05, +-4.73318265046533437649e-05, +-4.96926165577844057412e-05, +-5.20216283943892467806e-05, +-5.43175761229789356922e-05, +-5.65791946015099025133e-05, +-5.88052401314395777510e-05, +-6.09944911385232351646e-05, +-6.31457488399748983641e-05, +-6.52578378976302012505e-05, +-6.73296070567570273304e-05, +-6.93599297701697614779e-05, +-7.13477048073084426077e-05, +-7.32918568479592438987e-05, +-7.51913370602950043584e-05, +-7.70451236629288198831e-05, +-7.88522224706823078241e-05, +-8.06116674237784532151e-05, +-8.23225211001796784195e-05, +-8.39838752108034195757e-05, +-8.55948510773545134279e-05, +-8.71546000925265052688e-05, +-8.86623041623341395616e-05, +-9.01171761303480768493e-05, +-9.15184601836167176863e-05, +-9.28654322400672107207e-05, +-9.41574003171887131567e-05, +-9.53937048818311668537e-05, +-9.65737191809003779359e-05, +-9.76968495528504664652e-05, +-9.87625357197741252134e-05, +-9.97702510599723062104e-05, +-1.00719502860870411881e-04, +-1.01609832552167786510e-04, +-1.02440815919101530407e-04, +-1.03212063295764626164e-04, +-1.03923219738351186561e-04, +-1.04573965178293452004e-04, +-1.05164014555214358751e-04, +-1.05693117929663829482e-04, +-1.06161060575574886056e-04, +-1.06567663052451822372e-04, +-1.06912781257252219227e-04, +-1.07196306455972030416e-04, +-1.07418165294943403058e-04, +-1.07578319791868081681e-04, +-1.07676767306620711079e-04, +-1.07713540491867520218e-04, +-1.07688707223558459772e-04, +-1.07602370511359431062e-04, +-1.07454668389108225495e-04, +-1.07245773785382550523e-04, +-1.06975894374283873184e-04, +-1.06645272406552399651e-04, +-1.06254184521135326192e-04, +-1.05802941537346746376e-04, +-1.05291888227765690245e-04, +-1.04721403072029775822e-04, +-1.04091897991691806000e-04, +-1.03403818066321226388e-04, +-1.02657641231036926891e-04, +-1.01853877955673766901e-04, +-1.00993070905791316192e-04, +-1.00075794585747357554e-04, +-9.91026549640561086902e-05, +-9.80742890812979042133e-05, +-9.69913646407931124161e-05, +-9.58545795823286168359e-05, +-9.46646616391909589408e-05, +-9.34223678787874924024e-05, +-9.21284842271553308570e-05, +-9.07838249776128224534e-05, +-8.93892322839143330148e-05, +-8.79455756381782092872e-05, +-8.64537513339248380991e-05, +-8.49146819145573397919e-05, +-8.33293156075965769404e-05, +-8.16986257450709826454e-05, +-8.00236101703410545325e-05, +-7.83052906317712431187e-05, +-7.65447121635933332108e-05, +-7.47429424543394473968e-05, +-7.29010712032219468804e-05, +-7.10202094648487806125e-05, +-6.91014889826641889262e-05, +-6.71460615115136803116e-05, +-6.51550981297363063834e-05, +-6.31297885411947681941e-05, +-6.10713403676550390092e-05, +-5.89809784319366008933e-05, +-5.68599440322564117804e-05, +-5.47094942081945308492e-05, +-5.25309009987145816302e-05, +-5.03254506926742041614e-05, +-4.80944430722666716100e-05, +-4.58391906498364391982e-05, +-4.35610178985148694948e-05, +-4.12612604771267081670e-05, +-3.89412644498179452723e-05, +-3.66023855008608539076e-05, +-3.42459881450970870078e-05, +-3.18734449344449372976e-05, +-2.94861356610133087193e-05, +-2.70854465571730438690e-05, +-2.46727694931252419688e-05, +-2.22495011724306296223e-05, +-1.98170423258837072170e-05, +-1.73767969043094321503e-05, +-1.49301712706606661907e-05, +-1.24785733919144050828e-05, +-1.00234120312237155384e-05, +-7.56609594078786384176e-06, +-5.10803305590721484829e-06, +-2.65062969064796876903e-06, +-1.95289735662093879841e-07, + 2.25658614149781538763e-06, + 4.70360129302714707189e-06, + 7.14436388406460956736e-06, + 9.57748768197934699769e-06, + 1.20015928413035928855e-05, + 1.44153066838678001481e-05, + 1.68172644736985684973e-05, + 1.92061101862432256275e-05, + 2.15804972714890652230e-05, + 2.39390894105489946330e-05, + 2.62805612652901807722e-05, + 2.86035992205861757688e-05, + 3.09069021187789754650e-05, + 3.31891819859409621185e-05, + 3.54491647495335673412e-05, + 3.76855909470640991661e-05, + 3.98972164253476286417e-05, + 4.20828130299881090571e-05, + 4.42411692846974037292e-05, + 4.63710910600786401664e-05, + 4.84714022315057565344e-05, + 5.05409453257393869504e-05, + 5.25785821559190830470e-05, + 5.45831944446160030582e-05, + 5.65536844345369244078e-05, + 5.84889754866179482624e-05, + 6.03880126651817544857e-05, + 6.22497633097759614507e-05, + 6.40732175934516200036e-05, + 6.58573890671531589130e-05, + 6.76013151899331594073e-05, + 6.93040578447094631495e-05, + 7.09647038392890094557e-05, + 7.25823653923957063478e-05, + 7.41561806044386303671e-05, + 7.56853139127996218504e-05, + 7.71689565313425266486e-05, + 7.86063268739927838722e-05, + 7.99966709621114031078e-05, + 8.13392628154750729503e-05, + 8.26334048266602784602e-05, + 8.38784281186408519097e-05, + 8.50736928854174478216e-05, + 8.62185887155113381969e-05, + 8.73125348981630282396e-05, + 8.83549807120687932067e-05, + 8.93454056965571380595e-05, + 9.02833199050315720431e-05, + 9.11682641405671851135e-05, + 9.19998101735852404819e-05, + 9.27775609414710033911e-05, + 9.35011507300643465376e-05, + 9.41702453369411529019e-05, + 9.47845422164207620109e-05, + 9.53437706062401266714e-05, + 9.58476916358535753569e-05, + 9.62960984163175226676e-05, + 9.66888161117409645909e-05, + 9.70257019922829883106e-05, + 9.73066454687029886274e-05, + 9.75315681084497403076e-05, + 9.77004236333403651774e-05, + 9.78131978988259413559e-05, + 9.78699088548996316969e-05, + 9.78706064886931931908e-05, + 9.78153727488194655671e-05, + 9.77043214515344428731e-05, + 9.75375981687954049385e-05, + 9.73153800983090819503e-05, + 9.70378759156690566361e-05, + 9.67053256086932366224e-05, + 9.63180002940841964183e-05, + 9.58762020165379531865e-05, + 9.53802635304530459226e-05, + 9.48305480643773406665e-05, + 9.42274490683603826915e-05, + 9.35713899443812172551e-05, + 9.28628237600275093996e-05, + 9.21022329456168908045e-05, + 9.12901289749561102105e-05, + 9.04270520299548278501e-05, + 8.95135706492842500494e-05, + 8.85502813613394572714e-05, + 8.75378083017155033231e-05, + 8.64768028154355933648e-05, + 8.53679430442136669664e-05, + 8.42119334989644183860e-05, + 8.30095046178623384566e-05, + 8.17614123102081163550e-05, + 8.04684374863896741690e-05, + 7.91313855742244295563e-05, + 7.77510860219827716839e-05, + 7.63283917883946329882e-05, + 7.48641788199511630389e-05, + 7.33593455158201108654e-05, + 7.18148121806984416748e-05, + 7.02315204659344010599e-05, + 6.86104327992547092423e-05, + 6.69525318034425696596e-05, + 6.52588197043136263292e-05, + 6.35303177283451494866e-05, + 6.17680654903193261922e-05, + 5.99731203713451578997e-05, + 5.81465568876299857470e-05, + 5.62894660503753302872e-05, + 5.44029547171763266846e-05, + 5.24881449353098910931e-05, + 5.05461732772982176055e-05, + 4.85781901691450268576e-05, + 4.65853592116120024023e-05, + 4.45688564950032751967e-05, + 4.25298699077687427554e-05, + 4.04695984393985014349e-05, + 3.83892514779906950887e-05, + 3.62900481029001826128e-05, + 3.41732163729119983926e-05, + 3.20399926102781816627e-05, + 2.98916206811338720545e-05, + 2.77293512726352792174e-05, + 2.55544411672685861127e-05, + 2.33681525147488944956e-05, + 2.11717521018997930282e-05, + 1.89665106210108342917e-05, + 1.67537019369919437987e-05, + 1.45346023538229485151e-05, + 1.23104898806885715561e-05, + 1.00826434982246897416e-05, + 7.85234242529587054475e-06, + 5.62086538672328424332e-06, + 3.38948988238076994443e-06, + 1.15949145807567223944e-06, +-1.06785702137072707871e-06, +-3.29128609643022805093e-06, +-5.50953043415126442282e-06, +-7.72132954601048490098e-06, +-9.92542850192639466761e-06, +-1.21205786400318798465e-05, +-1.43055382718054505098e-05, +-1.64790733821644087950e-05, +-1.86399583241264707630e-05, +-2.07869765076501085866e-05, +-2.29189210822677048591e-05, +-2.50345956131302830444e-05, +-2.71328147500858357817e-05, +-2.92124048894140672726e-05, +-3.12722048278788822620e-05, +-3.33110664086613662642e-05, +-3.53278551589146714283e-05, +-3.73214509185134290983e-05, +-3.92907484596808479252e-05, +-4.12346580971520483842e-05, +-4.31521062885095992652e-05, +-4.50420362244331414815e-05, +-4.69034084084459727392e-05, +-4.87352012259119438489e-05, +-5.05364115019466182167e-05, +-5.23060550479419978189e-05, +-5.40431671964060976313e-05, +-5.57468033238534737064e-05, +-5.74160393614016982132e-05, +-5.90499722928839986262e-05, +-6.06477206401485110371e-05, +-6.22084249353098108415e-05, +-6.37312481796986922324e-05, +-6.52153762892660273948e-05, +-6.66600185262068023343e-05, +-6.80644079165767824100e-05, +-6.94278016536845402323e-05, +-7.07494814870478466295e-05, +-7.20287540967148501693e-05, +-7.32649514527553767347e-05, +-7.44574311597405420022e-05, +-7.56055767860350496235e-05, +-7.67087981777354925789e-05, +-7.77665317570998471846e-05, +-7.87782408053171710489e-05, +-7.97434157294830232507e-05, +-8.06615743136474125027e-05, +-8.15322619538178135472e-05, +-8.23550518768057822480e-05, +-8.31295453428154712148e-05, +-8.38553718316820378541e-05, +-8.45321892126865308053e-05, +-8.51596838978487685485e-05, +-8.57375709786715794677e-05, +-8.62655943462551288645e-05, +-8.67435267947428979536e-05, +-8.71711701080811815620e-05, +-8.75483551300409708427e-05, +-8.78749418175082112241e-05, +-8.81508192770273922871e-05, +-8.83759057846058285928e-05, +-8.85501487887902459777e-05, +-8.86735248970403253620e-05, +-8.87460398454319876341e-05, +-8.87677284517321478442e-05, +-8.87386545518955844984e-05, +-8.86589109200488812183e-05, +-8.85286191720270214433e-05, +-8.83479296525471903935e-05, +-8.81170213061050432417e-05, +-8.78361015316937552991e-05, +-8.75054060214538136477e-05, +-8.71251985833677709175e-05, +-8.66957709481281274576e-05, +-8.62174425603089747113e-05, +-8.56905603539940554595e-05, +-8.51154985129900034952e-05, +-8.44926582158212472655e-05, +-8.38224673656400427703e-05, +-8.31053803052506274724e-05, +-8.23418775174244912257e-05, +-8.15324653107033707304e-05, +-8.06776754908900028181e-05, +-7.97780650184373106007e-05, +-7.88342156519530526523e-05, +-7.78467335780445683635e-05, +-7.68162490277368720107e-05, +-7.57434158797055202611e-05, +-7.46289112505573565791e-05, +-7.34734350724463647960e-05, +-7.22777096582538457334e-05, +-7.10424792545960120905e-05, +-6.97685095829731762810e-05, +-6.84565873693016984378e-05, +-6.71075198621341007877e-05, +-6.57221343398554209113e-05, +-6.43012776071557890780e-05, +-6.28458154810835923102e-05, +-6.13566322669881414808e-05, +-5.98346302246723383829e-05, +-5.82807290250536745514e-05, +-5.66958651977116231350e-05, +-5.50809915695821473340e-05, +-5.34370766951852471703e-05, +-5.17651042787056485015e-05, +-5.00660725882709159050e-05, +-4.83409938627764752253e-05, +-4.65908937116066385552e-05, +-4.48168105076074261466e-05, +-4.30197947736637000340e-05, +-4.12009085632678118496e-05, +-3.93612248353795128467e-05, +-3.75018268240328908462e-05, +-3.56238074029696449125e-05, +-3.37282684457607440684e-05, +-3.18163201816986404395e-05, +-2.98890805479001212680e-05, +-2.79476745379709999822e-05, +-2.59932335476144176260e-05, +-2.40268947175631300377e-05, +-2.20498002742151532848e-05, +-2.00630968683545589837e-05, +-1.80679349123383810435e-05, +-1.60654679161321810180e-05, +-1.40568518225757011658e-05, +-1.20432443422608051199e-05, +-1.00258042884029404491e-05, +-8.00569091208727099719e-06, +-5.98406323826935972361e-06, +-3.96207940290984570201e-06, +-1.94089599162064887166e-06, + 7.83326198005747898907e-08, + 2.09445492257301924948e-06, + 4.10632292949940006763e-06, + 6.11279282652582891513e-06, + 8.11272562092629197044e-06, + 1.01049877857409114437e-05, + 1.20884519001330790116e-05, + 1.40619972852336154977e-05, + 1.60245106352098204275e-05, + 1.79748866431337342073e-05, + 1.99120286213276946629e-05, + 2.18348491158356895975e-05, + 2.37422705146771266798e-05, + 2.56332256495490372664e-05, + 2.75066583906145059298e-05, + 2.93615242341154332678e-05, + 3.11967908823933051383e-05, + 3.30114388160605143471e-05, + 3.48044618580061525877e-05, + 3.65748677288642252687e-05, + 3.83216785937263849210e-05, + 4.00439315997342949434e-05, + 4.17406794042833988461e-05, + 4.34109906935455636926e-05, + 4.50539506910283595867e-05, + 4.66686616558951677231e-05, + 4.82542433707754188257e-05, + 4.98098336188025105076e-05, + 5.13345886496223527710e-05, + 5.28276836341212981227e-05, + 5.42883131076322484254e-05, + 5.57156914013806444015e-05, + 5.71090530619421132309e-05, + 5.84676532584898041777e-05, + 5.97907681776162523235e-05, + 6.10776954055230943694e-05, + 6.23277542973780997616e-05, + 6.35402863336491786732e-05, + 6.47146554632286333470e-05, + 6.58502484331734486145e-05, + 6.69464751048926757886e-05, + 6.80027687566194964435e-05, + 6.90185863720170044832e-05, + 6.99934089147837939756e-05, + 7.09267415890902172158e-05, + 7.18181140857647161381e-05, + 7.26670808140748066949e-05, + 7.34732211190075503587e-05, + 7.42361394839436268501e-05, + 7.49554657186243128170e-05, + 7.56308551323502581193e-05, + 7.62619886923002242643e-05, + 7.68485731669290054405e-05, + 7.73903412543740319013e-05, + 7.78870516958209856877e-05, + 7.83384893737935715909e-05, + 7.87444653953147782324e-05, + 7.91048171599420551657e-05, + 7.94194084126392720741e-05, + 7.96881292814878859675e-05, + 7.99108963002358391528e-05, + 8.00876524156968731425e-05, + 8.02183669800153831232e-05, + 8.03030357278285665534e-05, + 8.03416807383593541874e-05, + 8.03343503824849146247e-05, + 8.02811192548356472283e-05, + 8.01820880909844978159e-05, + 8.00373836697980867074e-05, + 7.98471587010282266798e-05, + 7.96115916982296047740e-05, + 7.93308868371003252356e-05, + 7.90052737993477842459e-05, + 7.86350076021916034787e-05, + 7.82203684136235352425e-05, + 7.77616613535522615110e-05, + 7.72592162809664708160e-05, + 7.67133875672632579209e-05, + 7.61245538558890809302e-05, + 7.54931178084552014299e-05, + 7.48195058374859282803e-05, + 7.41041678259918263445e-05, + 7.33475768340236086891e-05, + 7.25502287924132663235e-05, + 7.17126421838883761507e-05, + 7.08353577117746115253e-05, + 6.99189379564657824580e-05, + 6.89639670199154882456e-05, + 6.79710501583437364317e-05, + 6.69408134033987737470e-05, + 6.58739031720058094803e-05, + 6.47709858651478100500e-05, + 6.36327474558071720916e-05, + 6.24598930663620521917e-05, + 6.12531465356429315541e-05, + 6.00132499759513726788e-05, + 5.87409633202952744489e-05, + 5.74370638601181475024e-05, + 5.61023457738005077431e-05, + 5.47376196462178894200e-05, + 5.33437119796454611961e-05, + 5.19214646963013157221e-05, + 5.04717346328268796885e-05, + 4.89953930270064014403e-05, + 4.74933249970308410371e-05, + 4.59664290136169696407e-05, + 4.44156163652937726011e-05, + 4.28418106171734954413e-05, + 4.12459470635278838894e-05, + 3.96289721744912600845e-05, + 3.79918430372181689441e-05, + 3.63355267918223325723e-05, + 3.46610000624296407993e-05, + 3.29692483836776077948e-05, + 3.12612656229971128227e-05, + 2.95380533990134290555e-05, + 2.78006204964105713487e-05, + 2.60499822775738051233e-05, + 2.42871600914147949164e-05, + 2.25131806796356132906e-05, + 2.07290755808621738894e-05, + 1.89358805329046950760e-05, + 1.71346348735776756247e-05, + 1.53263809403626031776e-05, + 1.35121634692837809516e-05, + 1.16930289933384643446e-05, + 9.87002524082706459254e-06, + 8.04420053392769432833e-06, + 6.21660318786371497718e-06, + 4.38828091098144307670e-06, + 2.56028020614524101076e-06, + 7.33645773704159215729e-07, +-1.09058008356538882663e-06, +-2.91135805322907028961e-06, +-4.72765240333595687151e-06, +-6.53843156959771685090e-06, +-8.34266873927393720254e-06, +-1.01393424314343474083e-05, +-1.19274370732709349764e-05, +-1.37059435721405858846e-05, +-1.54738598829871196378e-05, +-1.72301915709141233841e-05, +-1.89739523684456172069e-05, +-2.07041647273114594839e-05, +-2.24198603643615891102e-05, +-2.41200808013344202745e-05, +-2.58038778981763044563e-05, +-2.74703143796157200874e-05, +-2.91184643547017321143e-05, +-3.07474138290197399233e-05, +-3.23562612093023567895e-05, +-3.39441178001584614038e-05, +-3.55101082926439871944e-05, +-3.70533712444301888567e-05, +-3.85730595512544287501e-05, +-4.00683409094500665032e-05, +-4.15383982693033816007e-05, +-4.29824302789406134098e-05, +-4.43996517185575042359e-05, +-4.57892939247349858053e-05, +-4.71506052046175686584e-05, +-4.84828512397324982693e-05, +-4.97853154792346060619e-05, +-5.10572995223683090350e-05, +-5.22981234899434565362e-05, +-5.35071263846277400461e-05, +-5.46836664398836234187e-05, +-5.58271214573224499331e-05, +-5.69368891323614851295e-05, +-5.80123873679696164230e-05, +-5.90530545763586015842e-05, +-6.00583499684634902521e-05, +-6.10277538310640554767e-05, +-6.19607677914099007560e-05, +-6.28569150692159534649e-05, +-6.37157407158944321529e-05, +-6.45368118409359687801e-05, +-6.53197178252850279385e-05, +-6.60640705216541051321e-05, +-6.67695044416362863812e-05, +-6.74356769295752540719e-05, +-6.80622683230799142623e-05, +-6.86489821001279852154e-05, +-6.91955450126904592642e-05, +-6.97017072068230802637e-05, +-7.01672423291767658176e-05, +-7.05919476198861947256e-05, +-7.09756439918057140982e-05, +-7.13181760960681986961e-05, +-7.16194123739501793333e-05, +-7.18792450950348377767e-05, +-7.20975903816736135316e-05, +-7.22743882197516537879e-05, +-7.24096024557741556067e-05, +-7.25032207802958942548e-05, +-7.25552546977243766621e-05, +-7.25657394825357868065e-05, +-7.25347341219498558274e-05, +-7.24623212451169996162e-05, +-7.23486070388806753713e-05, +-7.21937211501822589683e-05, +-7.19978165751875085875e-05, +-7.17610695352167158104e-05, +-7.14836793395702676862e-05, +-7.11658682353526731877e-05, +-7.08078812443949090743e-05, +-7.04099859873934258306e-05, +-6.99724724953850081566e-05, +-6.94956530086853716552e-05, +-6.89798617634244460098e-05, +-6.84254547658288183589e-05, +-6.78328095543798148277e-05, +-6.72023249500277669805e-05, +-6.65344207946062419579e-05, +-6.58295376776219041525e-05, +-6.50881366515859591205e-05, +-6.43106989360903185575e-05, +-6.34977256107851671055e-05, +-6.26497372974739176162e-05, +-6.17672738315155477485e-05, +-6.08508939227416309091e-05, +-5.99011748060970076221e-05, +-5.89187118822223946605e-05, +-5.79041183481987132707e-05, +-5.68580248186811984187e-05, +-5.57810789376551931251e-05, +-5.46739449810503702100e-05, +-5.35373034504554770174e-05, +-5.23718506581807131213e-05, +-5.11782983039181917171e-05, +-4.99573730432570882465e-05, +-4.87098160483125057073e-05, +-4.74363825607329001348e-05, +-4.61378414373535389293e-05, +-4.48149746887680454615e-05, +-4.34685770110934173059e-05, +-4.20994553112074291123e-05, +-4.07084282257405295205e-05, +-3.92963256341110296946e-05, +-3.78639881658720183844e-05, +-3.64122667027106395048e-05, +-3.49420218753273198247e-05, +-3.34541235555410240970e-05, +-3.19494503438986083817e-05, +-3.04288890530928917170e-05, +-2.88933341874874255505e-05, +-2.73436874190750308462e-05, +-2.57808570601205806739e-05, +-2.42057575328682884756e-05, +-2.26193088365677101494e-05, +-2.10224360121490399698e-05, +-1.94160686048590696543e-05, +-1.78011401251455341182e-05, +-1.61785875081583371295e-05, +-1.45493505721038791060e-05, +-1.29143714758213699049e-05, +-1.12745941758700444585e-05, +-9.63096388344320252515e-06, +-7.98442652142029617504e-06, +-6.33592818186786765829e-06, +-4.68641458429933138496e-06, +-3.03683053500296397801e-06, +-1.38811938774586377356e-06, + 2.58777493839178202322e-07, + 1.90292127187864929960e-06, + 3.54337616759140759028e-06, + 5.17920999202801067562e-06, + 6.80949467391633912354e-06, + 8.43330678431570807498e-06, + 1.00497280577839181130e-05, + 1.16578459097642718917e-05, + 1.32567539499020862689e-05, + 1.48455524910031115056e-05, + 1.64233490533491062295e-05, + 1.79892588640891236808e-05, + 1.95424053514245014756e-05, + 2.10819206333345681716e-05, + 2.26069460005168742459e-05, + 2.41166323933478058403e-05, + 2.56101408725446344061e-05, + 2.70866430832949805965e-05, + 2.85453217125733007859e-05, + 2.99853709394462142215e-05, + 3.14059968780488809876e-05, + 3.28064180130436779592e-05, + 3.41858656273021432946e-05, + 3.55435842215810670545e-05, + 3.68788319259649065773e-05, + 3.81908809028492260114e-05, + 3.94790177412656769699e-05, + 4.07425438422898093392e-05, + 4.19807757953880351259e-05, + 4.31930457454549954818e-05, + 4.43787017503647075972e-05, + 4.55371081288425238044e-05, + 4.66676457984745168698e-05, + 4.77697126036755268658e-05, + 4.88427236334443488387e-05, + 4.98861115287400902485e-05, + 5.08993267793200968442e-05, + 5.18818380098863440766e-05, + 5.28331322553930322872e-05, + 5.37527152253746494555e-05, + 5.46401115571613411491e-05, + 5.54948650578534959663e-05, + 5.63165389349345359561e-05, + 5.71047160154089449252e-05, + 5.78589989533570669814e-05, + 5.85790104258065492428e-05, + 5.92643933168274041653e-05, + 5.99148108897627355894e-05, + 6.05299469475165509511e-05, + 6.11095059808236870788e-05, + 6.16532133044444885040e-05, + 6.21608151812043867963e-05, + 6.26320789338565816822e-05, + 6.30667930446937390586e-05, + 6.34647672428986905826e-05, + 6.38258325795768347542e-05, + 6.41498414904665125455e-05, + 6.44366678463023396118e-05, + 6.46862069908247323737e-05, + 6.48983757664325786518e-05, + 6.50731125274843654437e-05, + 6.52103771412599882238e-05, + 6.53101509766035163464e-05, + 6.53724368802683817540e-05, + 6.53972591410049980528e-05, + 6.53846634414262362599e-05, + 6.53347167976985163280e-05, + 6.52475074871135241571e-05, + 6.51231449636010796761e-05, + 6.49617597612497395644e-05, + 6.47635033859116657304e-05, + 6.45285481949697814485e-05, + 6.42570872653582068207e-05, + 6.39493342499302042841e-05, + 6.36055232222692201391e-05, + 6.32259085100558739911e-05, + 6.28107645171077595475e-05, + 6.23603855342008971162e-05, + 6.18750855388094879363e-05, + 6.13551979838913776489e-05, + 6.08010755758598702586e-05, + 6.02130900418846006969e-05, + 5.95916318866736676439e-05, + 5.89371101388912814706e-05, + 5.82499520873748857785e-05, + 5.75306030073172492193e-05, + 5.67795258765894393974e-05, + 5.59972010823701890950e-05, + 5.51841261183018495025e-05, + 5.43408152723015371618e-05, + 5.34677993052802834643e-05, + 5.25656251209348160261e-05, + 5.16348554268246720794e-05, + 5.06760683869446402865e-05, + 4.96898572660009552938e-05, + 4.86768300656121986501e-05, + 4.76376091526542401900e-05, + 4.65728308799746458426e-05, + 4.54831451997094723732e-05, + 4.43692152694205702067e-05, + 4.32317170513272638010e-05, + 4.20713389048248215750e-05, + 4.08887811725691820543e-05, + 3.96847557603624830438e-05, + 3.84599857110910642592e-05, + 3.72152047729705208619e-05, + 3.59511569623536525052e-05, + 3.46685961213579385467e-05, + 3.33682854705920874040e-05, + 3.20509971572010551400e-05, + 3.07175117985585750834e-05, + 2.93686180218123159854e-05, + 2.80051119996170835922e-05, + 2.66277969822622470077e-05, + 2.52374828265144898710e-05, + 2.38349855214322459531e-05, + 2.24211267114313739257e-05, + 2.09967332168798777813e-05, + 1.95626365525002586521e-05, + 1.81196724438590493929e-05, + 1.66686803422232323734e-05, + 1.52105029380648706125e-05, + 1.37459856734939339152e-05, + 1.22759762539012447631e-05, + 1.08013241590919135580e-05, + 9.32288015419072379738e-06, + 7.84149580059962841079e-06, + 6.35802296728773956217e-06, + 4.87331334269314813773e-06, + 3.38821794751525819401e-06, + 1.90358664867536025810e-06, + 4.20267674722007678397e-07, +-1.06089286704349063181e-06, +-2.53905147144755971960e-06, +-4.01336771405853671665e-06, +-5.48300472726051319248e-06, +-6.94712967353908428204e-06, +-8.40491421565995491089e-06, +-9.85553498354600196257e-06, +-1.12981740375379932287e-05, +-1.27320193278005813889e-05, +-1.41562651496129757108e-05, +-1.55701125942935366840e-05, +-1.69727699954863943171e-05, +-1.83634533706132413357e-05, +-1.97413868571768872317e-05, +-2.11058031437259111299e-05, +-2.24559438952188090413e-05, +-2.37910601725753876787e-05, +-2.51104128461361075818e-05, +-2.64132730028669993332e-05, +-2.76989223470385161768e-05, +-2.89666535941785825052e-05, +-3.02157708580817170672e-05, +-3.14455900306639634365e-05, +-3.26554391544575276863e-05, +-3.38446587875432448227e-05, +-3.50126023607246299988e-05, +-3.61586365267507298072e-05, +-3.72821415014014433467e-05, +-3.83825113962520523994e-05, +-3.94591545429407643156e-05, +-4.05114938087662831479e-05, +-4.15389669034495396562e-05, +-4.25410266768976613630e-05, +-4.35171414078138610380e-05, +-4.44667950830035220650e-05, +-4.53894876672311637202e-05, +-4.62847353634881464551e-05, +-4.71520708635396170122e-05, +-4.79910435886203451676e-05, +-4.88012199201597561809e-05, +-4.95821834204167205301e-05, +-5.03335350429265633945e-05, +-5.10548933326265304408e-05, +-5.17458946156012646414e-05, +-5.24061931783268363742e-05, +-5.30354614363393909939e-05, +-5.36333900922485962647e-05, +-5.41996882830139510762e-05, +-5.47340837164388594079e-05, +-5.52363227967925824054e-05, +-5.57061707395272917836e-05, +-5.61434116750343203787e-05, +-5.65478487413978341881e-05, +-5.69193041661166998697e-05, +-5.72576193367504884379e-05, +-5.75626548604881785863e-05, +-5.78342906126072504132e-05, +-5.80724257738199440486e-05, +-5.82769788565022921634e-05, +-5.84478877198096668589e-05, +-5.85851095736871960683e-05, +-5.86886209717912786239e-05, +-5.87584177933450407718e-05, +-5.87945152139549069526e-05, +-5.87969476654236840492e-05, +-5.87657687846015756232e-05, +-5.87010513513210692091e-05, +-5.86028872154704082165e-05, +-5.84713872132640056231e-05, +-5.83066810727762474998e-05, +-5.81089173088098371331e-05, +-5.78782631071765932274e-05, +-5.76149041984740298956e-05, +-5.73190447214473209757e-05, +-5.69909070760322414208e-05, +-5.66307317661793541358e-05, +-5.62387772325672526141e-05, +-5.58153196753171827195e-05, +-5.53606528668218819548e-05, +-5.48750879548260181830e-05, +-5.43589532558681387997e-05, +-5.38125940392313040217e-05, +-5.32363723015430049873e-05, +-5.26306665321520585781e-05, +-5.19958714694554905247e-05, +-5.13323978483126871185e-05, +-5.06406721387124545189e-05, +-4.99211362758563274877e-05, +-4.91742473818266735545e-05, +-4.84004774790149961978e-05, +-4.76003131954764758258e-05, +-4.67742554624208601633e-05, +-4.59228192039893781543e-05, +-4.50465330195347888644e-05, +-4.41459388585886764659e-05, +-4.32215916887159588432e-05, +-4.22740591564579529368e-05, +-4.13039212415705373426e-05, +-4.03117699047655450996e-05, +-3.92982087291690829157e-05, +-3.82638525557110084044e-05, +-3.72093271126660717248e-05, +-3.61352686395672686765e-05, +-3.50423235057168379857e-05, +-3.39311478235224090556e-05, +-3.28024070568877919004e-05, +-3.16567756248915059525e-05, +-3.04949365009877199171e-05, +-2.93175808079664161425e-05, +-2.81254074089120697057e-05, +-2.69191224944017248270e-05, +-2.56994391661852553642e-05, +-2.44670770175918836234e-05, +-2.32227617109122020126e-05, +-2.19672245519847623529e-05, +-2.07012020622797709220e-05, +-1.94254355486677272565e-05, +-1.81406706711849960521e-05, +-1.68476570089850853130e-05, +-1.55471476247899104671e-05, +-1.42398986280482303988e-05, +-1.29266687370718316063e-05, +-1.16082188403988693324e-05, +-1.02853115576371897586e-05, +-8.95871080003975092416e-06, +-7.62918133106494951846e-06, +-6.29748832717637000583e-06, +-4.96439693911456911849e-06, +-3.63067185393867396159e-06, +-2.29707685802459498842e-06, +-9.64374401315848450426e-07, + 3.66674836944231519952e-07, + 1.69531238074935703441e-06, + 3.02078238789119312040e-06, + 4.34233207830084875904e-06, + 5.65921215992918806928e-06, + 6.97067725192901449440e-06, + 8.27598630488246552004e-06, + 9.57440301788133736832e-06, + 1.08651962521827093731e-05, + 1.21476404412087555200e-05, + 1.34210159967052598768e-05, + 1.46846097107889237831e-05, + 1.59377151536783862637e-05, + 1.71796330668853545218e-05, + 1.84096717516477081152e-05, + 1.96271474523901250152e-05, + 2.08313847350004374291e-05, + 2.20217168597138741371e-05, + 2.31974861483999769760e-05, + 2.43580443460485478093e-05, + 2.55027529762765186715e-05, + 2.66309836906033699266e-05, + 2.77421186114023531077e-05, + 2.88355506682450058473e-05, + 2.99106839275143976181e-05, + 3.09669339150908589178e-05, + 3.20037279319387916966e-05, + 3.30205053624261607144e-05, + 3.40167179752114232517e-05, + 3.49918302165381128787e-05, + 3.59453194957816331854e-05, + 3.68766764630972321086e-05, + 3.77854052790209193153e-05, + 3.86710238758958244651e-05, + 3.95330642109541764121e-05, + 4.03710725109682755916e-05, + 4.11846095083103026020e-05, + 4.19732506683146705116e-05, + 4.27365864078233130617e-05, + 4.34742223048040452049e-05, + 4.41857792989385563150e-05, + 4.48708938830692915926e-05, + 4.55292182854370863364e-05, + 4.61604206425851002231e-05, + 4.67641851628709925696e-05, + 4.73402122805066265026e-05, + 4.78882188000329483382e-05, + 4.84079380311931386409e-05, + 4.88991199141192096943e-05, + 4.93615311347864993397e-05, + 4.97949552306842973051e-05, + 5.01991926866579958816e-05, + 5.05740610208843503087e-05, + 5.09193948609473228035e-05, + 5.12350460099867614349e-05, + 5.15208835028994156444e-05, + 5.17767936525754493993e-05, + 5.20026800861617919140e-05, + 5.21984637713472843972e-05, + 5.23640830326715540628e-05, + 5.24994935578649676486e-05, + 5.26046683942319904669e-05, + 5.26795979350977647813e-05, + 5.27242898963412381865e-05, + 5.27387692830453080699e-05, + 5.27230783462991780706e-05, + 5.26772765301947225270e-05, + 5.26014404090633305310e-05, + 5.24956636150047901762e-05, + 5.23600567557668073533e-05, + 5.21947473230388830738e-05, + 5.19998795912271193358e-05, + 5.17756145067857189357e-05, + 5.15221295681833840827e-05, + 5.12396186965899134232e-05, + 5.09282920973702621955e-05, + 5.05883761124873977634e-05, + 5.02201130639010932745e-05, + 4.98237610880825857601e-05, + 4.93995939617437136368e-05, + 4.89479009189001211121e-05, + 4.84689864593871208814e-05, + 4.79631701489468674927e-05, + 4.74307864110306472431e-05, + 4.68721843104290958456e-05, + 4.62877273288830334104e-05, + 4.56777931328110654310e-05, + 4.50427733333015571236e-05, + 4.43830732385187975314e-05, + 4.36991115986785094998e-05, + 4.29913203437512904219e-05, + 4.22601443140560245420e-05, + 4.15060409839102542823e-05, + 4.07294801785067884332e-05, + 3.99309437841909614544e-05, + 3.91109254523149503578e-05, + 3.82699302968499331071e-05, + 3.74084745859401725113e-05, + 3.65270854275851831246e-05, + 3.56263004496409294844e-05, + 3.47066674743320204575e-05, + 3.37687441874715604177e-05, + 3.28130978025864834921e-05, + 3.18403047201496259048e-05, + 3.08509501821220885999e-05, + 2.98456279220141111716e-05, + 2.88249398106583463292e-05, + 2.77894954979411405727e-05, + 2.67399120506568739174e-05, + 2.56768135867345998077e-05, + 2.46008309060387078085e-05, + 2.35126011179608967452e-05, + 2.24127672660373206972e-05, + 2.13019779497730199318e-05, + 2.01808869439458528371e-05, + 1.90501528155745074983e-05, + 1.79104385387887921337e-05, + 1.67624111078244624493e-05, + 1.56067411483699600464e-05, + 1.44441025274743162915e-05, + 1.32751719622829946729e-05, + 1.21006286277736464400e-05, + 1.09211537637588811984e-05, + 9.73743028136644528262e-06, + 8.55014236922561691437e-06, + 7.35997509958635033394e-06, + 6.16761403459692181825e-06, + 4.97374483296533837542e-06, + 3.77905285722950647743e-06, + 2.58422278186008839003e-06, + 1.38993820241930683239e-06, + 1.96881245997903772338e-07, +-9.94267816848598569217e-07, +-2.18283095844447963890e-06, +-3.36813277840069707876e-06, +-4.54950088586700000424e-06, +-5.72626627941386950107e-06, +-6.89776372433048807836e-06, +-8.06333212712694707145e-06, +-9.22231490703067589279e-06, +-1.03740603642693244191e-05, +-1.15179220449344173161e-05, +-1.26532591022196861730e-05, +-1.37794366538495711072e-05, +-1.48958261354584999990e-05, +-1.60018056497799296184e-05, +-1.70967603114136951952e-05, +-1.81800825869820380861e-05, +-1.92511726305242952264e-05, +-2.03094386138927829864e-05, +-2.13542970520092069756e-05, +-2.23851731227873900821e-05, +-2.34015009815511875976e-05, +-2.44027240697762211102e-05, +-2.53882954179860686225e-05, +-2.63576779426533689202e-05, +-2.73103447369098503218e-05, +-2.82457793549575378290e-05, +-2.91634760899918437553e-05, +-3.00629402455041167019e-05, +-3.09436883998153130820e-05, +-3.18052486637019455554e-05, +-3.26471609309779970515e-05, +-3.34689771219005548241e-05, +-3.42702614192727262341e-05, +-3.50505904971203557973e-05, +-3.58095537418260222574e-05, +-3.65467534655933827146e-05, +-3.72618051121717498101e-05, +-3.79543374546707974228e-05, +-3.86239927854306394216e-05, +-3.92704270978131317837e-05, +-3.98933102598363287456e-05, +-4.04923261795653974715e-05, +-4.10671729621785269976e-05, +-4.16175630586323642046e-05, +-4.21432234058559141441e-05, +-4.26438955584067616068e-05, +-4.31193358115292238756e-05, +-4.35693153155569312869e-05, +-4.39936201816156069303e-05, +-4.43920515785651946397e-05, +-4.47644258211561343495e-05, +-4.51105744493632472049e-05, +-4.54303442988531914885e-05, +-4.57235975625737596506e-05, +-4.59902118434391446694e-05, +-4.62300801980975147932e-05, +-4.64431111717703053654e-05, +-4.66292288241590738816e-05, +-4.67883727464197082162e-05, +-4.69204980692097139592e-05, +-4.70255754618213880035e-05, +-4.71035911224101212042e-05, +-4.71545467593474220552e-05, +-4.71784595637180143891e-05, +-4.71753621729942670049e-05, +-4.71453026259235373810e-05, +-4.70883443086696765927e-05, +-4.70045658922535814004e-05, +-4.68940612613444625227e-05, +-4.67569394344568726790e-05, +-4.65933244756150703129e-05, +-4.64033553975471216042e-05, +-4.61871860564808808737e-05, +-4.59449850386188616159e-05, +-4.56769355383655138421e-05, +-4.53832352283949652812e-05, +-4.50640961216473178623e-05, +-4.47197444253447825278e-05, +-4.43504203871267281252e-05, +-4.39563781334040550529e-05, +-4.35378855000395927045e-05, +-4.30952238554646824297e-05, +-4.26286879163457669119e-05, +-4.21385855559199974771e-05, +-4.16252376051221437895e-05, +-4.10889776466288376587e-05, +-4.05301518019508379771e-05, +-3.99491185117068837215e-05, +-3.93462483092169100062e-05, +-3.87219235875561562329e-05, +-3.80765383602142771309e-05, +-3.74104980155082837679e-05, +-3.67242190649002693526e-05, +-3.60181288853753334362e-05, +-3.52926654560366292231e-05, +-3.45482770890794257056e-05, +-3.37854221553090375610e-05, +-3.30045688043594255523e-05, +-3.22061946798075831645e-05, +-3.13907866293216945321e-05, +-3.05588404100427330412e-05, +-2.97108603893675688823e-05, +-2.88473592413132615716e-05, +-2.79688576386454084658e-05, +-2.70758839409515568225e-05, +-2.61689738788582883049e-05, +-2.52486702345479146949e-05, +-2.43155225188067227653e-05, +-2.33700866447662229544e-05, +-2.24129245985293835562e-05, +-2.14446041069073238181e-05, +-2.04656983024178883341e-05, +-1.94767853857754148804e-05, +-1.84784482860567825561e-05, +-1.74712743187444023349e-05, +-1.64558548418461311194e-05, +-1.54327849102923173909e-05, +-1.44026629288111792759e-05, +-1.33660903034842037365e-05, +-1.23236710921832843933e-05, +-1.12760116540923691986e-05, +-1.02237202985157386555e-05, +-9.16740693317562989567e-06, +-8.10768271220163393815e-06, +-7.04515968401436206049e-06, +-5.98045043930514029506e-06, +-4.91416775931360371891e-06, +-3.84692426460422025455e-06, +-2.77933206454218416435e-06, +-1.71200240766848139346e-06, +-6.45545333172962557628e-07, + 4.19430676336646794336e-07, + 1.48231904057302648397e-06, + 2.54251542561663930372e-06, + 3.59941808609308168670e-06, + 4.65242820524958869112e-06, + 5.70095023278988534811e-06, + 6.74439222023971488674e-06, + 7.78216615367016922942e-06, + 8.81368828359270617260e-06, + 9.83837945182666922020e-06, + 1.08556654151943217460e-05, + 1.18649771658138885200e-05, + 1.28657512478499302136e-05, + 1.38574300705307268156e-05, + 1.48394622172600090695e-05, + 1.58113027506664198453e-05, + 1.67724135133877546580e-05, + 1.77222634244721200859e-05, + 1.86603287711980042802e-05, + 1.95860934961685117974e-05, + 2.04990494795206747223e-05, + 2.13986968160965711628e-05, + 2.22845440874262652991e-05, + 2.31561086283755511721e-05, + 2.40129167883148332595e-05, + 2.48545041866689361690e-05, + 2.56804159627113593367e-05, + 2.64902070194693860814e-05, + 2.72834422616106000525e-05, + 2.80596968271851059942e-05, + 2.88185563131008925446e-05, + 2.95596169942142674564e-05, + 3.02824860359208226652e-05, + 3.09867817001359949951e-05, + 3.16721335445593264431e-05, + 3.23381826151192079948e-05, + 3.29845816314999765108e-05, + 3.36109951656569510029e-05, + 3.42170998132293449818e-05, + 3.48025843577636647915e-05, + 3.53671499276745119299e-05, + 3.59105101458437678133e-05, + 3.64323912718148200060e-05, + 3.69325323364901809465e-05, + 3.74106852692794952407e-05, + 3.78666150176288244058e-05, + 3.83000996588942581029e-05, + 3.87109305044850893402e-05, + 3.90989121962477274223e-05, + 3.94638627950426708552e-05, + 3.98056138614771284553e-05, + 4.01240105287611420687e-05, + 4.04189115676629857573e-05, + 4.06901894435291198787e-05, + 4.09377303653654542282e-05, + 4.11614343269538722871e-05, + 4.13612151399990495742e-05, + 4.15370004592994877942e-05, + 4.16887317999427647820e-05, + 4.18163645465287068582e-05, + 4.19198679544291165572e-05, + 4.19992251430971813499e-05, + 4.20544330814450761122e-05, + 4.20855025653108131916e-05, + 4.20924581870419940027e-05, + 4.20753382972270773108e-05, + 4.20341949586107831312e-05, + 4.19690938922323789214e-05, + 4.18801144158325268558e-05, + 4.17673493745770476031e-05, + 4.16309050641507942731e-05, + 4.14709011462787672121e-05, + 4.12874705567371297560e-05, + 4.10807594059191025335e-05, + 4.08509268720259451839e-05, + 4.05981450869582284656e-05, + 4.03225990149817188125e-05, + 4.00244863242588127953e-05, + 3.97040172513205211744e-05, + 3.93614144585763300172e-05, + 3.89969128849576671548e-05, + 3.86107595897814662080e-05, + 3.82032135899500682069e-05, + 3.77745456905820574433e-05, + 3.73250383091862464823e-05, + 3.68549852934909236125e-05, + 3.63646917330434846769e-05, + 3.58544737646997589589e-05, + 3.53246583721261741586e-05, + 3.47755831794332366546e-05, + 3.42075962390870128276e-05, + 3.36210558142060423280e-05, + 3.30163301553966777682e-05, + 3.23937972722568060207e-05, + 3.17538446996900900290e-05, + 3.10968692591733985816e-05, + 3.04232768151230764501e-05, + 2.97334820265093258108e-05, + 2.90279080938678783936e-05, + 2.83069865018621188567e-05, + 2.75711567575615524813e-05, + 2.68208661245598943643e-05, + 2.60565693531506030998e-05, + 2.52787284066631597003e-05, + 2.44878121841591343355e-05, + 2.36842962396411912224e-05, + 2.28686624979444416434e-05, + 2.20413989674784742564e-05, + 2.12029994499905229957e-05, + 2.03539632475213441687e-05, + 1.94947948667270345394e-05, + 1.86260037207404863615e-05, + 1.77481038287503190129e-05, + 1.68616135134610017573e-05, + 1.59670550966399525954e-05, + 1.50649545929016600080e-05, + 1.41558414019059438765e-05, + 1.32402479991802029098e-05, + 1.23187096257152244321e-05, + 1.13917639765278494500e-05, + 1.04599508883682767454e-05, + 9.52381202675309655368e-06, + 8.58389057250431938178e-06, + 7.64073090797513138387e-06, + 6.69487830314289765184e-06, + 5.74687860175188295145e-06, + 4.79727790767192774363e-06, + 3.84662227168647334824e-06, + 2.89545737884364760088e-06, + 1.94432823658253304009e-06, + 9.93778863798429985474e-07, + 4.43519810261418219453e-08, +-9.03411298083134494987e-07, +-1.84897177381668332505e-06, +-2.79179246581568572222e-06, +-3.73133891666547724968e-06, +-4.66707949352351104895e-06, +-5.59848568756837193684e-06, +-6.52503241114909488603e-06, +-7.44619829242155147390e-06, +-8.36146596735429801020e-06, +-9.27032236890755496482e-06, +-1.01722590132379665735e-05, +-1.10667722827682534897e-05, +-1.19533637059645449316e-05, +-1.28315402336673929602e-05, +-1.37008145118236726118e-05, +-1.45607051504696124636e-05, +-1.54107369888173211751e-05, +-1.62504413562997488372e-05, +-1.70793563294315240981e-05, +-1.78970269843458541098e-05, +-1.87030056448704560027e-05, +-1.94968521260079873374e-05, +-2.02781339726898497515e-05, +-2.10464266936743830125e-05, +-2.18013139904647730040e-05, +-2.25423879811231864039e-05, +-2.32692494188629845134e-05, +-2.39815079053020545374e-05, +-2.46787820982652636209e-05, +-2.53606999140241696946e-05, +-2.60268987238786572637e-05, +-2.66770255449520642306e-05, +-2.73107372251350898203e-05, +-2.79277006220566396152e-05, +-2.85275927760007770367e-05, +-2.91101010766786506953e-05, +-2.96749234237720292370e-05, +-3.02217683811674436194e-05, +-3.07503553247967688486e-05, +-3.12604145840304585829e-05, +-3.17516875765274536082e-05, +-3.22239269364954619744e-05, +-3.26768966362916865294e-05, +-3.31103721013135404044e-05, +-3.35241403181086740208e-05, +-3.39179999356772221173e-05, +-3.42917613599035768068e-05, +-3.46452468410814200988e-05, +-3.49782905544949971623e-05, +-3.52907386740210617191e-05, +-3.55824494387227893157e-05, +-3.58532932124095292024e-05, +-3.61031525361412189944e-05, +-3.63319221736595660043e-05, +-3.65395091497331203439e-05, +-3.67258327814061905970e-05, +-3.68908247021470958485e-05, +-3.70344288788946495372e-05, +-3.71566016220048470271e-05, +-3.72573115881061459097e-05, +-3.73365397758733679086e-05, +-3.73942795147359094356e-05, +-3.74305364465390174970e-05, +-3.74453285001817191228e-05, +-3.74386858592581299020e-05, +-3.74106509227334344111e-05, +-3.73612782586900054964e-05, +-3.72906345511812774523e-05, +-3.71987985402384284698e-05, +-3.70858609550741078051e-05, +-3.69519244405358592356e-05, +-3.67971034768620346741e-05, +-3.66215242927991649845e-05, +-3.64253247721413610217e-05, +-3.62086543537608289011e-05, +-3.59716739251909398806e-05, +-3.57145557098436036985e-05, +-3.54374831479307815388e-05, +-3.51406507711717790501e-05, +-3.48242640713705212661e-05, +-3.44885393629439755150e-05, +-3.41337036395026344345e-05, +-3.37599944245618602615e-05, +-3.33676596164906268116e-05, +-3.29569573277930418366e-05, +-3.25281557188254321234e-05, +-3.20815328260544299979e-05, +-3.16173763849646847373e-05, +-3.11359836477270585640e-05, +-3.06376611957413178553e-05, +-3.01227247471705252121e-05, +-2.95914989595860117668e-05, +-2.90443172278450244467e-05, +-2.84815214773259415084e-05, +-2.79034619526477284249e-05, +-2.73104970020026914545e-05, +-2.67029928572347473455e-05, +-2.60813234097965965382e-05, +-2.54458699827217350983e-05, +-2.47970210987495716533e-05, +-2.41351722447432573014e-05, +-2.34607256325420285845e-05, +-2.27740899563922217575e-05, +-2.20756801471030884767e-05, +-2.13659171230650388217e-05, +-2.06452275383031910749e-05, +-1.99140435276834237366e-05, +-1.91728024494465332597e-05, +-1.84219466252117046706e-05, +-1.76619230776150628139e-05, +-1.68931832657115450086e-05, +-1.61161828183312975558e-05, +-1.53313812655206427630e-05, +-1.45392417682358304494e-05, +-1.37402308464459345215e-05, +-1.29348181058055242533e-05, +-1.21234759630454037166e-05, +-1.13066793702690812049e-05, +-1.04849055382779459772e-05, +-9.65863365911334948940e-06, +-8.82834462796514155621e-06, +-7.99452076460905629502e-06, +-7.15764553453369098759e-06, +-6.31820326991743474922e-06, +-5.47667889061570897704e-06, +-4.63355762531863929758e-06, +-3.78932473303858924915e-06, +-2.94446522508681059839e-06, +-2.09946358769777104725e-06, +-1.25480350545903780141e-06, +-4.10967585703884757521e-07, + 4.31562915977009008788e-07, + 1.27230836894944277571e-06, + 2.11079103932071460005e-06, + 2.94653536014252898618e-06, + 3.77906819987967961097e-06, + 4.60791912899369108820e-06, + 5.43262068449194016279e-06, + 6.25270863229422647450e-06, + 7.06772222727031654239e-06, + 7.87720447080152108251e-06, + 8.68070236573491179038e-06, + 9.47776716855934883059e-06, + 1.02679546387046329188e-05, + 1.10508252847855289948e-05, + 1.18259446076950094435e-05, + 1.25928833403731488022e-05, + 1.33512176841488130493e-05, + 1.41005295415132480126e-05, + 1.48404067452006041290e-05, + 1.55704432834508311935e-05, + 1.62902395213322402135e-05, + 1.69994024180030318645e-05, + 1.76975457398040286305e-05, + 1.83842902690431043002e-05, + 1.90592640083929755197e-05, + 1.97221023807678906147e-05, + 2.03724484245830909945e-05, + 2.10099529842914574005e-05, + 2.16342748960969371002e-05, + 2.22450811687472009364e-05, + 2.28420471593103576108e-05, + 2.34248567438443574510e-05, + 2.39932024828722749476e-05, + 2.45467857815675249479e-05, + 2.50853170445967065243e-05, + 2.56085158254919929746e-05, + 2.61161109705264067420e-05, + 2.66078407569898643540e-05, + 2.70834530258070006151e-05, + 2.75427053084297310910e-05, + 2.79853649479419435960e-05, + 2.84112092143175989727e-05, + 2.88200254137772721131e-05, + 2.92116109921902309310e-05, + 2.95857736324748295058e-05, + 2.99423313459514552895e-05, + 3.02811125576063902359e-05, + 3.06019561852344731414e-05, + 3.09047117124088772445e-05, + 3.11892392552770306917e-05, + 3.14554096231257185974e-05, + 3.17031043727105386106e-05, + 3.19322158563235434462e-05, + 3.21426472635838068469e-05, + 3.23343126569389799764e-05, + 3.25071370008686157485e-05, + 3.26610561847839823827e-05, + 3.27960170396232209987e-05, + 3.29119773481435616428e-05, + 3.30089058489176179569e-05, + 3.30867822340391137381e-05, + 3.31455971405566354542e-05, + 3.31853521356474453628e-05, + 3.32060596955532425618e-05, + 3.32077431783010264656e-05, + 3.31904367902360999997e-05, + 3.31541855463981258254e-05, + 3.30990452247738323123e-05, + 3.30250823144645263966e-05, + 3.29323739578086778848e-05, + 3.28210078865044069620e-05, + 3.26910823517787598727e-05, + 3.25427060486570274289e-05, + 3.23759980343831654933e-05, + 3.21910876410516532862e-05, + 3.19881143825098785360e-05, + 3.17672278555962777865e-05, + 3.15285876357804020743e-05, + 3.12723631672755098660e-05, + 3.09987336476968641276e-05, + 3.07078879073422307631e-05, + 3.04000242831731254834e-05, + 3.00753504875796523151e-05, + 2.97340834720133863225e-05, + 2.93764492855759244065e-05, + 2.90026829286541534467e-05, + 2.86130282016945522135e-05, + 2.82077375492130921937e-05, + 2.77870718991382409868e-05, + 2.73513004975885902525e-05, + 2.69007007391876059731e-05, + 2.64355579930219527422e-05, + 2.59561654243505824063e-05, + 2.54628238121749757804e-05, + 2.49558413627831115046e-05, + 2.44355335193822060570e-05, + 2.39022227679302646662e-05, + 2.33562384393019751726e-05, + 2.27979165078862079359e-05, + 2.22275993867542926926e-05, + 2.16456357195166269815e-05, + 2.10523801689935258924e-05, + 2.04481932028270123260e-05, + 1.98334408761695914203e-05, + 1.92084946115600319473e-05, + 1.85737309761447836221e-05, + 1.79295314563576179442e-05, + 1.72762822302007563351e-05, + 1.66143739372523043473e-05, + 1.59442014465590105223e-05, + 1.52661636225209913461e-05, + 1.45806630889290942863e-05, + 1.38881059912848947536e-05, + 1.31889017575441241904e-05, + 1.24834628574239182218e-05, + 1.17722045604144076358e-05, + 1.10555446926362083376e-05, + 1.03339033926850970682e-05, + 9.60770286660610835401e-06, + 8.87736714213917295769e-06, + 8.14332182237846214528e-06, + 7.40599383898811708220e-06, + 6.66581120511662847053e-06, + 5.92320276815220692627e-06, + 5.17859796246125674333e-06, + 4.43242656225190390784e-06, + 3.68511843470406844027e-06, + 2.93710329350725519965e-06, + 2.18881045294667824256e-06, + 1.44066858267776568184e-06, + 6.93105463328498643878e-07, +-5.34522569318000109946e-08, +-7.98579304717572919173e-07, +-1.54185202251970832288e-06, +-2.28284860840320051088e-06, +-3.02114935421031389665e-06, +-3.75633688210878496775e-06, +-4.48799637936313885382e-06, +-5.21571583119760455970e-06, +-5.93908625161027179838e-06, +-6.65770191203593872154e-06, +-7.37116056769570928293e-06, +-8.07906368153382318078e-06, +-8.78101664560747212731e-06, +-9.47662899980729766419e-06, +-1.01655146477980716876e-05, +-1.08472920700360401147e-05, +-1.15215845337792326716e-05, +-1.21880202999511892778e-05, +-1.28462328267551614196e-05, +-1.34958609699263177819e-05, +-1.41365491795134746316e-05, +-1.47679476930840737262e-05, +-1.53897127252478330606e-05, +-1.60015066533978296873e-05, +-1.66029981995690071228e-05, +-1.71938626083174473280e-05, +-1.77737818205255124692e-05, +-1.83424446430409821820e-05, +-1.88995469140607142496e-05, +-1.94447916641716418988e-05, +-1.99778892729651633619e-05, +-2.04985576211432968317e-05, +-2.10065222380378098066e-05, +-2.15015164444660525898e-05, +-2.19832814908509086081e-05, +-2.24515666905336362430e-05, +-2.29061295482131846272e-05, +-2.33467358834453286897e-05, +-2.37731599491474201167e-05, +-2.41851845450333852378e-05, +-2.45826011259452240434e-05, +-2.49652099050124548756e-05, +-2.53328199515970210081e-05, +-2.56852492839710685329e-05, +-2.60223249566979663422e-05, +-2.63438831426579298076e-05, +-2.66497692096954663589e-05, +-2.69398377918485816931e-05, +-2.72139528551308018016e-05, +-2.74719877578380960005e-05, +-2.77138253053556592794e-05, +-2.79393577994475523249e-05, +-2.81484870820020636713e-05, +-2.83411245732301139656e-05, +-2.85171913042964311541e-05, +-2.86766179443786176822e-05, +-2.88193448221488309965e-05, +-2.89453219416760952935e-05, +-2.90545089927504981216e-05, +-2.91468753556345132793e-05, +-2.92224001002483448552e-05, +-2.92810719798009543599e-05, +-2.93228894188808181459e-05, +-2.93478604960236810328e-05, +-2.93560029207774113129e-05, +-2.93473440052880433669e-05, +-2.93219206304335843936e-05, +-2.92797792065350247323e-05, +-2.92209756286776301080e-05, +-2.91455752266783351279e-05, +-2.90536527097378728982e-05, +-2.89452921058199178666e-05, +-2.88205866958015281636e-05, +-2.86796389424427922371e-05, +-2.85225604142267152093e-05, +-2.83494717041206751521e-05, +-2.81605023433202391432e-05, +-2.79557907100283667510e-05, +-2.77354839333381227289e-05, +-2.74997377922758771290e-05, +-2.72487166100799959093e-05, +-2.69825931437795252883e-05, +-2.67015484691465684885e-05, +-2.64057718610977712947e-05, +-2.60954606696212069907e-05, +-2.57708201913090847589e-05, +-2.54320635365780473264e-05, +-2.50794114926622185510e-05, +-2.47130923824611631432e-05, +-2.43333419193429083098e-05, +-2.39404030579782670638e-05, +-2.35345258413101434184e-05, +-2.31159672437494752078e-05, +-2.26849910106949353332e-05, +-2.22418674944758635930e-05, +-2.17868734868193039472e-05, +-2.13202920479438652059e-05, +-2.08424123323838041491e-05, +-2.03535294116561999106e-05, +-1.98539440938636343103e-05, +-1.93439627403565497755e-05, +-1.88238970795673100412e-05, +-1.82940640181116715769e-05, +-1.77547854492869263538e-05, +-1.72063880590754648210e-05, +-1.66492031297704090782e-05, +-1.60835663413408166554e-05, +-1.55098175706546329380e-05, +-1.49283006886787883053e-05, +-1.43393633557766034665e-05, +-1.37433568152237134072e-05, +-1.31406356850657396885e-05, +-1.25315577484303698698e-05, +-1.19164837424470248790e-05, +-1.12957771458482026110e-05, +-1.06698039654265613285e-05, +-1.00389325214426427445e-05, +-9.40353323211844157182e-06, +-8.76397839734067131087e-06, +-8.12064198169950727862e-06, +-7.47389939698852350989e-06, +-6.82412728429159437049e-06, +-6.17170329578283326645e-06, +-5.51700587636662085001e-06, +-4.86041404527424057491e-06, +-4.20230717776569626185e-06, +-3.54306478703081491720e-06, +-2.88306630643768218789e-06, +-2.22269087224340068095e-06, +-1.56231710689249263685e-06, +-9.02322903026265212716e-07, +-2.43085208325657879777e-07, + 4.15020188692070241853e-07, + 1.07161887179235378480e-06, + 1.72633800896124487047e-06, + 2.37880656301163715107e-06, + 3.02865550076134820403e-06, + 3.67551800066570465779e-06, + 4.31902965876675653769e-06, + 4.95882869287509108695e-06, + 5.59455614484735050385e-06, + 6.22585608085616216224e-06, + 6.85237578953995891761e-06, + 7.47376597792307623553e-06, + 8.08968096499781815715e-06, + 8.69977887286206749402e-06, + 9.30372181530736666231e-06, + 9.90117608375414723029e-06, + 1.04918123304324667667e-05, + 1.10753057487085165546e-05, + 1.16513362504588705059e-05, + 1.22195886403962862164e-05, + 1.27797527872529815987e-05, + 1.33315237917292095805e-05, + 1.38746021511168710365e-05, + 1.44086939205101016335e-05, + 1.49335108705172178858e-05, + 1.54487706413894936150e-05, + 1.59541968934863105428e-05, + 1.64495194539962877323e-05, + 1.69344744598370269687e-05, + 1.74088044966656047203e-05, + 1.78722587339096677364e-05, + 1.83245930557734450217e-05, + 1.87655701881329496747e-05, + 1.91949598212630230727e-05, + 1.96125387283323720589e-05, + 2.00180908796079946171e-05, + 2.04114075523055411008e-05, + 2.07922874360462036562e-05, + 2.11605367338478548244e-05, + 2.15159692586163032817e-05, + 2.18584065250839677179e-05, + 2.21876778371520620508e-05, + 2.25036203706003066312e-05, + 2.28060792511126929382e-05, + 2.30949076276010261842e-05, + 2.33699667407799707231e-05, + 2.36311259869688547377e-05, + 2.38782629770920889936e-05, + 2.41112635908534832393e-05, + 2.43300220260626135784e-05, + 2.45344408430947687194e-05, + 2.47244310044678461521e-05, + 2.48999119095234487111e-05, + 2.50608114242014547006e-05, + 2.52070659059005263759e-05, + 2.53386202234201725390e-05, + 2.54554277719819088525e-05, + 2.55574504833309083937e-05, + 2.56446588309218829473e-05, + 2.57170318301951886415e-05, + 2.57745570339536455825e-05, + 2.58172305228509982138e-05, + 2.58450568910080320990e-05, + 2.58580492267732674574e-05, + 2.58562290886494391582e-05, + 2.58396264764083687885e-05, + 2.58082797974207070447e-05, + 2.57622358282285832381e-05, + 2.57015496713930713401e-05, + 2.56262847076503301675e-05, + 2.55365125434126198959e-05, + 2.54323129536535378888e-05, + 2.53137738202205607126e-05, + 2.51809910656159463322e-05, + 2.50340685822968625073e-05, + 2.48731181575412977117e-05, + 2.46982593939325721589e-05, + 2.45096196255167505238e-05, + 2.43073338296873121584e-05, + 2.40915445348619378086e-05, + 2.38624017240045997246e-05, + 2.36200627340624288075e-05, + 2.33646921513807236321e-05, + 2.30964617031644264128e-05, + 2.28155501450558444859e-05, + 2.25221431449012520778e-05, + 2.22164331627798575491e-05, + 2.18986193273720365431e-05, + 2.15689073087443379398e-05, + 2.12275091876318188378e-05, + 2.08746433212990305033e-05, + 2.05105342060640502609e-05, + 2.01354123365703269947e-05, + 1.97495140618939641253e-05, + 1.93530814385750261550e-05, + 1.89463620806633047968e-05, + 1.85296090068704985814e-05, + 1.81030804849221997979e-05, + 1.76670398732044751401e-05, + 1.72217554598013985296e-05, + 1.67675002990209279609e-05, + 1.63045520455078192621e-05, + 1.58331927860449225669e-05, + 1.53537088691371193265e-05, + 1.48663907324963997689e-05, + 1.43715327285100159978e-05, + 1.38694329478100649496e-05, + 1.33603930410508834665e-05, + 1.28447180389832295180e-05, + 1.23227161709552708244e-05, + 1.17946986819301291035e-05, + 1.12609796481351171312e-05, + 1.07218757914499571946e-05, + 1.01777062926427738516e-05, + 9.62879260356504592831e-06, + 9.07545825840731586903e-06, + 8.51802868414534395823e-06, + 7.95683101026131923061e-06, + 7.39219387787010935662e-06, + 6.82444724835357750922e-06, + 6.25392221161505916386e-06, + 5.68095079406488222078e-06, + 5.10586576644759276318e-06, + 4.52900045162168937197e-06, + 3.95068853240210902949e-06, + 3.37126385957580590002e-06, + 2.79106026020026960787e-06, + 2.21041134629440781136e-06, + 1.62965032403097053739e-06, + 1.04910980353893797621e-06, + 4.69121609423969816268e-07, +-1.09983407885784446779e-07, +-6.87875559861819363080e-07, +-1.26422650655941540912e-06, +-1.83870944215866707785e-06, +-2.41099927925814251037e-06, +-2.98077283181781552669e-06, +-3.54770899664894408157e-06, +-4.11148893334953399492e-06, +-4.67179624258384839990e-06, +-5.22831714261491216074e-06, +-5.78074064397335153019e-06, +-6.32875872218480591626e-06, +-6.87206648846043886310e-06, +-7.41036235823793521568e-06, +-7.94334821749933495355e-06, +-8.47072958676628828367e-06, +-8.99221578268483114820e-06, +-9.50752007711151433478e-06, +-1.00163598536144939110e-05, +-1.05184567613050262248e-05, +-1.10135368659148606880e-05, +-1.15013307980458232298e-05, +-1.19815738984936175071e-05, +-1.24540063605928145280e-05, +-1.29183733694884611521e-05, +-1.33744252382685912655e-05, +-1.38219175408834683421e-05, +-1.42606112417824770782e-05, +-1.46902728222004355977e-05, +-1.51106744030272206920e-05, +-1.55215938641985491263e-05, +-1.59228149605396966692e-05, +-1.63141274340170367916e-05, +-1.66953271223259263928e-05, +-1.70662160637601778752e-05, +-1.74266025983238355662e-05, +-1.77763014650210005691e-05, +-1.81151338952815387428e-05, +-1.84429277024754141470e-05, +-1.87595173674722256573e-05, +-1.90647441202047199617e-05, +-1.93584560171974732774e-05, +-1.96405080150238890778e-05, +-1.99107620396580777466e-05, +-2.01690870516893970240e-05, +-2.04153591073708575137e-05, +-2.06494614154744169461e-05, +-2.08712843899290058163e-05, +-2.10807256982194106203e-05, +-2.12776903055268819069e-05, +-2.14620905145943367527e-05, +-2.16338460013017256061e-05, +-2.17928838459405791773e-05, +-2.19391385601769272338e-05, +-2.20725521096971615139e-05, +-2.21930739325313472097e-05, +-2.23006609530529530257e-05, +-2.23952775916547660337e-05, +-2.24768957701059413827e-05, +-2.25454949125917081373e-05, +-2.26010619424491719610e-05, +-2.26435912746056351556e-05, +-2.26730848037337861828e-05, +-2.26895518881395304210e-05, +-2.26930093293992605151e-05, +-2.26834813477678370105e-05, +-2.26609995533789395977e-05, +-2.26256029132635929800e-05, +-2.25773377142134946906e-05, +-2.25162575215193229503e-05, +-2.24424231336153037980e-05, +-2.23559025326656501465e-05, +-2.22567708311276078921e-05, +-2.21451102143313804113e-05, +-2.20210098791169147888e-05, +-2.18845659685713447666e-05, +-2.17358815029120373732e-05, +-2.15750663065627956596e-05, +-2.14022369314727249265e-05, +-2.12175165767294450026e-05, +-2.10210350045200421447e-05, +-2.08129284524956139116e-05, +-2.05933395425968121279e-05, +-2.03624171863999439073e-05, +-2.01203164870448847703e-05, +-1.98671986378080534994e-05, +-1.96032308173856533286e-05, +-1.93285860819534852074e-05, +-1.90434432540722883950e-05, +-1.87479868085084750535e-05, +-1.84424067550420635135e-05, +-1.81268985183354106028e-05, +-1.78016628149372209476e-05, +-1.74669055274989030828e-05, +-1.71228375762811146975e-05, +-1.67696747880257406472e-05, +-1.64076377622852373006e-05, +-1.60369517352758793533e-05, +-1.56578464413495735093e-05, +-1.52705559721640566414e-05, +-1.48753186336378656238e-05, +-1.44723768007754817841e-05, +-1.40619767704562352530e-05, +-1.36443686122615369144e-05, +-1.32198060174485617084e-05, +-1.27885461461470160532e-05, +-1.23508494728771689751e-05, +-1.19069796304737485969e-05, +-1.14572032525241123438e-05, +-1.10017898143939981797e-05, +-1.05410114729497751473e-05, +-1.00751429050663908628e-05, +-9.60446114501671036024e-06, +-9.12924542083821511740e-06, +-8.64977698977298705156e-06, +-8.16633897287741896158e-06, +-7.67921618889827246499e-06, +-7.18869498751202211574e-06, +-6.69506308202449553879e-06, +-6.19860938162804727016e-06, +-5.69962382331348281457e-06, +-5.19839720353396213883e-06, +-4.69522100971802372742e-06, +-4.19038725172889743185e-06, +-3.68418829336696433132e-06, +-3.17691668401197745318e-06, +-2.66886499050160637978e-06, +-2.16032562934221739981e-06, +-1.65159069934772865291e-06, +-1.14295181480165719692e-06, +-6.34699939237223993940e-07, +-1.27125219930865964068e-07, + 3.79483176804446976763e-07, + 8.84837229415048084051e-07, + 1.38865022392344135295e-06, + 1.89063691565660948537e-06, + 2.39051368980350543056e-06, + 2.88799872070356053645e-06, + 3.38281212979515968504e-06, + 3.87467614211226955731e-06, + 4.36331524126018218350e-06, + 4.84845632277730857507e-06, + 5.32982884579943108584e-06, + 5.80716498294156890627e-06, + 6.28019976832197123205e-06, + 6.74867124362975824505e-06, + 7.21232060217923931738e-06, + 7.67089233085512087109e-06, + 8.12413434987819258522e-06, + 8.57179815031460507597e-06, + 9.01363892925431026452e-06, + 9.44941572258580350576e-06, + 9.87889153529582866875e-06, + 1.03018334692242354077e-05, + 1.07180128482058532928e-05, + 1.11272053405328737749e-05, + 1.15291910786727369798e-05, + 1.19237547761785921742e-05, + 1.23106858417307881825e-05, + 1.26897784902497355293e-05, + 1.30608318510224895531e-05, + 1.34236500727868487704e-05, + 1.37780424257190294344e-05, + 1.41238234002725815088e-05, + 1.44608128028181916441e-05, + 1.47888358480361837552e-05, + 1.51077232480150609343e-05, + 1.54173112980111264947e-05, + 1.57174419588311981054e-05, + 1.60079629357866409767e-05, + 1.62887277541956994331e-05, + 1.65595958313870623361e-05, + 1.68204325451708860712e-05, + 1.70711092987549151222e-05, + 1.73115035820617087312e-05, + 1.75414990294297246641e-05, + 1.77609854736682751155e-05, + 1.79698589964435695681e-05, + 1.81680219749743536840e-05, + 1.83553831250179843454e-05, + 1.85318575401295563383e-05, + 1.86973667271814836071e-05, + 1.88518386381246428555e-05, + 1.89952076979892261869e-05, + 1.91274148291101984921e-05, + 1.92484074715740798728e-05, + 1.93581395998826688587e-05, + 1.94565717358317040323e-05, + 1.95436709576050705363e-05, + 1.96194109050871230563e-05, + 1.96837717813977941246e-05, + 1.97367403506575926565e-05, + 1.97783099319904582180e-05, + 1.98084803897790467670e-05, + 1.98272581201802304074e-05, + 1.98346560339216278375e-05, + 1.98306935353937785049e-05, + 1.98153964980584857704e-05, + 1.97887972361948640476e-05, + 1.97509344730071558156e-05, + 1.97018533051198989033e-05, + 1.96416051634883520843e-05, + 1.95702477707543367439e-05, + 1.94878450950789703635e-05, + 1.93944673004863832040e-05, + 1.92901906937534684103e-05, + 1.91750976678850051373e-05, + 1.90492766422124609142e-05, + 1.89128219991563888266e-05, + 1.87658340176993620855e-05, + 1.86084188036114926950e-05, + 1.84406882164763881947e-05, + 1.82627597935659933724e-05, + 1.80747566706147357355e-05, + 1.78768074995447826664e-05, + 1.76690463631958512617e-05, + 1.74516126871156478269e-05, + 1.72246511484645271060e-05, + 1.69883115820999146554e-05, + 1.67427488838910094079e-05, + 1.64881229113318102759e-05, + 1.62245983815127213317e-05, + 1.59523447665149745417e-05, + 1.56715361862937387256e-05, + 1.53823512991161662699e-05, + 1.50849731896229228884e-05, + 1.47795892545813357618e-05, + 1.44663910864051258596e-05, + 1.41455743545015973133e-05, + 1.38173386845338111450e-05, + 1.34818875356564122405e-05, + 1.31394280758153236577e-05, + 1.27901710551714238936e-05, + 1.24343306777357970924e-05, + 1.20721244712898652016e-05, + 1.17037731556691947766e-05, + 1.13295005094903200078e-05, + 1.09495332354001166718e-05, + 1.05641008239284915968e-05, + 1.01734354160254741075e-05, + 9.77777166436417707733e-06, + 9.37734659349238440105e-06, + 8.97239945891504566951e-06, + 8.56317160519109046130e-06, + 8.14990632312829315351e-06, + 7.73284870615977176810e-06, + 7.31224550598672419900e-06, + 6.88834498757161637657e-06, + 6.46139678356662984916e-06, + 6.03165174826215254474e-06, + 5.59936181114026503485e-06, + 5.16477983011814751843e-06, + 4.72815944456637594131e-06, + 4.28975492818819883339e-06, + 3.84982104183822503198e-06, + 3.40861288638080421604e-06, + 2.96638575565200338164e-06, + 2.52339498962473315831e-06, + 2.07989582785497810255e-06, + 1.63614326329362652845e-06, + 1.19239189654723987055e-06, + 7.48895790669445095407e-07, + 3.05908326571625776241e-07, +-1.36317940881114572753e-07, +-5.77531425986414698518e-07, +-1.01748165446873717438e-06, +-1.45591940480376818372e-06, +-1.89259684853121109570e-06, +-2.32726768946181945073e-06, +-2.75968730172187791391e-06, +-3.18961286654260444098e-06, +-3.61680350772475395115e-06, +-4.04102042570235190153e-06, +-4.46202703013145677961e-06, +-4.87958907093086315863e-06, +-5.29347476770270431638e-06, +-5.70345493746202430210e-06, +-6.10930312060542652779e-06, +-6.51079570505022606116e-06, +-6.90771204847647766264e-06, +-7.29983459860577372710e-06, +-7.68694901145177016447e-06, +-8.06884426747877637565e-06, +-8.44531278560606176982e-06, +-8.81615053499690261524e-06, +-9.18115714457292360416e-06, +-9.54013601019537525608e-06, +-9.89289439945689410725e-06, +-1.02392435540285157503e-05, +-1.05789987895082151180e-05, +-1.09119795927181496489e-05, +-1.12380097164049367058e-05, +-1.15569172712818179387e-05, +-1.18685348153817650919e-05, +-1.21726994406635834228e-05, +-1.24692528568320288901e-05, +-1.27580414723287455134e-05, +-1.30389164724542902805e-05, +-1.33117338945781214641e-05, +-1.35763547004100975057e-05, +-1.38326448452840637915e-05, +-1.40804753444306167702e-05, +-1.43197223362026314689e-05, +-1.45502671422277009592e-05, +-1.47719963244507672032e-05, +-1.49848017390525759050e-05, +-1.51885805872105738001e-05, +-1.53832354626835289546e-05, +-1.55686743961984593867e-05, +-1.57448108966214301034e-05, +-1.59115639888950593595e-05, +-1.60688582487281346781e-05, +-1.62166238340240249699e-05, +-1.63547965130369332254e-05, +-1.64833176892467266300e-05, +-1.66021344229449986304e-05, +-1.67111994495269690472e-05, +-1.68104711944856884120e-05, +-1.68999137851070388113e-05, +-1.69794970588658022861e-05, +-1.70491965685248872658e-05, +-1.71089935839418872147e-05, +-1.71588750905891277256e-05, +-1.71988337847946457871e-05, +-1.72288680657142012447e-05, +-1.72489820240458028352e-05, +-1.72591854275000641512e-05, +-1.72594937030417242213e-05, +-1.72499279159197036566e-05, +-1.72305147455039143491e-05, +-1.72012864579503712398e-05, +-1.71622808757165273689e-05, +-1.71135413439511928759e-05, +-1.70551166937853976150e-05, +-1.69870612025510246137e-05, +-1.69094345509577617692e-05, +-1.68223017772587667151e-05, +-1.67257332284380452606e-05, +-1.66198045084538685654e-05, +-1.65045964235747666643e-05, +-1.63801949248439752678e-05, +-1.62466910477154159362e-05, +-1.61041808488969476394e-05, +-1.59527653404471681951e-05, +-1.57925504211673684571e-05, +-1.56236468053350227754e-05, +-1.54461699488246402123e-05, +-1.52602399726646910730e-05, +-1.50659815840795875837e-05, +-1.48635239950677219589e-05, +-1.46530008385678102385e-05, +-1.44345500822663306819e-05, +-1.42083139401014696147e-05, +-1.39744387815186386459e-05, +-1.37330750385350818741e-05, +-1.34843771106714372927e-05, +-1.32285032678095108182e-05, +-1.29656155510367461763e-05, +-1.26958796715383549959e-05, +-1.24194649075998671690e-05, +-1.21365439997829936740e-05, +-1.18472930443392576808e-05, +-1.15518913849262173693e-05, +-1.12505215026924608397e-05, +-1.09433689047985292748e-05, +-1.06306220114370569618e-05, +-1.03124720414310326811e-05, +-9.98911289646390806746e-06, +-9.66074104402634771841e-06, +-9.32755539913410898457e-06, +-8.98975720490331666607e-06, +-8.64754991204318386249e-06, +-8.30113905734212395051e-06, +-7.95073214121866026069e-06, +-7.59653850440942178638e-06, +-7.23876920386707314615e-06, +-6.87763688794204854321e-06, +-6.51335567091628095621e-06, +-6.14614100697516552689e-06, +-5.77620956367455239778e-06, +-5.40377909498920278296e-06, +-5.02906831401159492038e-06, +-4.65229676537581108160e-06, +-4.27368469748049481391e-06, +-3.89345293458471427688e-06, +-3.51182274885061115744e-06, +-3.12901573240642411555e-06, +-2.74525366950255710500e-06, +-2.36075840884032086628e-06, +-1.97575173612730443720e-06, +-1.59045524696390774673e-06, +-1.20509022010166682739e-06, +-8.19877491164466545524e-07, +-4.35037326897878480005e-07, +-5.07893000186937941852e-08, + 3.32647835264701963937e-07, + 7.15056266991011401958e-07, + 1.09621924837422310365e-06, + 1.47592121985241872538e-06, + 1.85394793018892599705e-06, + 2.23008655655825313813e-06, + 2.60412582354907889203e-06, + 2.97585612102449336496e-06, + 3.34506962075543128396e-06, + 3.71156039179419859137e-06, + 4.07512451449323400283e-06, + 4.43556019312523663384e-06, + 4.79266786703672172316e-06, + 5.14625032027519291555e-06, + 5.49611278963019283487e-06, + 5.84206307102959016220e-06, + 6.18391162423353208402e-06, + 6.52147167576954129561e-06, + 6.85455932005260181654e-06, + 7.18299361864097611125e-06, + 7.50659669756249047314e-06, + 7.82519384267587422464e-06, + 8.13861359300433846395e-06, + 8.44668783199705641891e-06, + 8.74925187666988167100e-06, + 9.04614456457850991435e-06, + 9.33720833857896873390e-06, + 9.62228932933213677251e-06, + 9.90123743550565465295e-06, + 1.01739064016425803086e-05, + 1.04401538936425447330e-05, + 1.06998415718315421479e-05, + 1.09528351615697443715e-05, + 1.11990045213757959499e-05, + 1.14382237085241558977e-05, + 1.16703710420870291280e-05, + 1.18953291633899048006e-05, + 1.21129850938512417829e-05, + 1.23232302901790470909e-05, + 1.25259606968983349296e-05, + 1.27210767961849803022e-05, + 1.29084836549834598316e-05, + 1.30880909693871328668e-05, + 1.32598131062616946208e-05, + 1.34235691420937951136e-05, + 1.35792828990487302932e-05, + 1.37268829782224906786e-05, + 1.38663027900751689578e-05, + 1.39974805820346134686e-05, + 1.41203594632604494623e-05, + 1.42348874265606466504e-05, + 1.43410173674542311574e-05, + 1.44387071003753392044e-05, + 1.45279193720158173131e-05, + 1.46086218718049036649e-05, + 1.46807872395258838879e-05, + 1.47443930700731856367e-05, + 1.47994219153501084768e-05, + 1.48458612833167961215e-05, + 1.48837036341919119975e-05, + 1.49129463738179148723e-05, + 1.49335918441997313264e-05, + 1.49456473112284446691e-05, + 1.49491249496032089275e-05, + 1.49440418249668886146e-05, + 1.49304198732706183515e-05, + 1.49082858773864185118e-05, + 1.48776714409868946381e-05, + 1.48386129597128356167e-05, + 1.47911515896521751179e-05, + 1.47353332131532132959e-05, + 1.46712084019985736114e-05, + 1.45988323779665271851e-05, + 1.45182649708080687578e-05, + 1.44295705736699748613e-05, + 1.43328180959947710691e-05, + 1.42280809139304630388e-05, + 1.41154368182840922366e-05, + 1.39949679600544020416e-05, + 1.38667607935803263323e-05, + 1.37309060173433526632e-05, + 1.35874985124628946476e-05, + 1.34366372789253006354e-05, + 1.32784253695879846650e-05, + 1.31129698220019766261e-05, + 1.29403815880963342583e-05, + 1.27607754617702922906e-05, + 1.25742700044388885011e-05, + 1.23809874685797173814e-05, + 1.21810537193292244224e-05, + 1.19745981541777892090e-05, + 1.17617536208142295677e-05, + 1.15426563331714449024e-05, + 1.13174457857225807409e-05, + 1.10862646660882621001e-05, + 1.08492587659991565309e-05, + 1.06065768906759967075e-05, + 1.03583707666798818434e-05, + 1.01047949482890619580e-05, + 9.84600672246289829138e-06, + 9.58216601244215827264e-06, + 9.31343528005553203603e-06, + 9.03997942678299933766e-06, + 8.76196569363900174996e-06, + 8.47956355993590845071e-06, + 8.19294464098436757177e-06, + 7.90228258480172436834e-06, + 7.60775296787702002085e-06, + 7.30953319006439522813e-06, + 7.00780236866348362574e-06, + 6.70274123175005229701e-06, + 6.39453201082003652993e-06, + 6.08335833281021253502e-06, + 5.76940511155902288967e-06, + 5.45285843877125582177e-06, + 5.13390547455034551393e-06, + 4.81273433756231556671e-06, + 4.48953399489534794848e-06, + 4.16449415167896653590e-06, + 3.83780514052692429906e-06, + 3.50965781086775528301e-06, + 3.18024341822695296120e-06, + 2.84975351352448496748e-06, + 2.51837983245139741199e-06, + 2.18631418498888039782e-06, + 1.85374834513309478132e-06, + 1.52087394088868180660e-06, + 1.18788234459368242750e-06, + 8.54964563638969000998e-07, + 5.22311131639455979077e-07, + 1.90112000130503982774e-07, +-1.41443569165127144841e-07, +-4.72167111427258322109e-07, +-8.01871065130554529929e-07, +-1.13036887767394417904e-06, +-1.45747511019990077643e-06, +-1.78300554152943349745e-06, +-2.10677727116673305869e-06, +-2.42860882131162050769e-06, +-2.74832023782412414206e-06, +-3.06573319008543263771e-06, +-3.38067106969957008626e-06, +-3.69295908798608184869e-06, +-4.00242437219907550613e-06, +-4.30889606043524369669e-06, +-4.61220539516788939752e-06, +-4.91218581536073784053e-06, +-5.20867304711107137976e-06, +-5.50150519277325040547e-06, +-5.79052281851486924603e-06, +-6.07556904025867903059e-06, +-6.35648960796446912367e-06, +-6.63313298820617108662e-06, +-6.90535044500056127508e-06, +-7.17299611884493175119e-06, +-7.43592710392244173663e-06, +-7.69400352343472750019e-06, +-7.94708860302274787185e-06, +-8.19504874223798014101e-06, +-8.43775358402712548757e-06, +-8.67507608219503231826e-06, +-8.90689256681143526513e-06, +-9.13308280752864666172e-06, +-9.35353007477842320907e-06, +-9.56812119881768913406e-06, +-9.77674662659346799308e-06, +-9.97930047640225587741e-06, +-1.01756805903098395061e-05, +-1.03657885843171664226e-05, +-1.05495298962378540402e-05, +-1.07268138312754163948e-05, +-1.08975536052689632541e-05, +-1.10616663855950794401e-05, +-1.12190733297047288709e-05, +-1.13696996212789541697e-05, +-1.15134745039878948566e-05, +-1.16503313128391599354e-05, +-1.17802075031027646805e-05, +-1.19030446768033701643e-05, +-1.20187886067651972661e-05, +-1.21273892582080803395e-05, +-1.22288008078826377517e-05, +-1.23229816607413100770e-05, +-1.24098944641409426887e-05, +-1.24895061195742445941e-05, +-1.25617877919291833080e-05, +-1.26267149162764970278e-05, +-1.26842672021870910226e-05, +-1.27344286355826809563e-05, +-1.27771874781232745640e-05, +-1.28125362641396452218e-05, +-1.28404717951158474197e-05, +-1.28609951317310474550e-05, +-1.28741115834723465414e-05, +-1.28798306958283372134e-05, +-1.28781662350772487912e-05, +-1.28691361706835918807e-05, +-1.28527626553190634970e-05, +-1.28290720025245128650e-05, +-1.27980946620313942489e-05, +-1.27598651927620886218e-05, +-1.27144222335301226119e-05, +-1.26618084714623414664e-05, +-1.26020706081659076143e-05, +-1.25352593236666657602e-05, +-1.24614292381415428035e-05, +-1.23806388714751623682e-05, +-1.22929506006672047076e-05, +-1.21984306151204884824e-05, +-1.20971488698402506546e-05, +-1.19891790365764339750e-05, +-1.18745984529418113659e-05, +-1.17534880695398776456e-05, +-1.16259323951374368445e-05, +-1.14920194399183685165e-05, +-1.13518406568538079223e-05, +-1.12054908812311493295e-05, +-1.10530682683752438347e-05, +-1.08946742296059593923e-05, +-1.07304133664714714479e-05, +-1.05603934032992665185e-05, +-1.03847251181075779763e-05, +-1.02035222719208779302e-05, +-1.00169015365332405226e-05, +-9.82498242076738657132e-06, +-9.62788719526892533595e-06, +-9.42574081589087935042e-06, +-9.21867084571004267567e-06, +-9.00680737572287916197e-06, +-8.79028294427637022824e-06, +-8.56923245527351259271e-06, +-8.34379309521075756921e-06, +-8.11410424909460554577e-06, +-7.88030741528924488369e-06, +-7.64254611934633504094e-06, +-7.40096582686917382960e-06, +-7.15571385546351836380e-06, +-6.90693928582781290984e-06, +-6.65479287203611895166e-06, +-6.39942695106712918212e-06, +-6.14099535163319854876e-06, +-5.87965330236342373891e-06, +-5.61555733939511250274e-06, +-5.34886521342830269742e-06, +-5.07973579629795705422e-06, +-4.80832898711880610677e-06, +-4.53480561805786592893e-06, +-4.25932735978965902460e-06, +-3.98205662668941065763e-06, +-3.70315648181929639785e-06, +-3.42279054176300851270e-06, +-3.14112288136435437299e-06, +-2.85831793842106375632e-06, +-2.57454041839861196264e-06, +-2.28995519920570692832e-06, +-2.00472723609599568439e-06, +-1.71902146674648263972e-06, +-1.43300271656756140053e-06, +-1.14683560429862268911e-06, +-8.60684447942252036623e-07, +-5.74713171094427766504e-07, +-2.89085209713597664617e-07, +-3.96341939478251296110e-09, + 2.80490016808534609067e-07, + 5.64113679962953421250e-07, + 8.46747006173344896037e-07, + 1.12823037680340410583e-06, + 1.40840520793811109215e-06, + 1.68711403904242672689e-06, + 1.96420062076637285675e-06, + 2.23951000184795544334e-06, + 2.51288861506598641053e-06, + 2.78418436219555765417e-06, + 3.05324669791958273155e-06, + 3.31992671265051673821e-06, + 3.58407721421717316118e-06, + 3.84555280837218626654e-06, + 4.10420997807660228022e-06, + 4.35990716151877168199e-06, + 4.61250482882560770565e-06, + 4.86186555742507531383e-06, + 5.10785410601973079235e-06, + 5.35033748713194356707e-06, + 5.58918503818238221671e-06, + 5.82426849106429956731e-06, + 6.05546204017706400874e-06, + 6.28264240888338113098e-06, + 6.50568891435568739365e-06, + 6.72448353077756515444e-06, + 6.93891095087089373919e-06, + 7.14885864570919282062e-06, + 7.35421692279753319929e-06, + 7.55487898238148465092e-06, + 7.75074097196019129528e-06, + 7.94170203897623056888e-06, + 8.12766438165342534124e-06, + 8.30853329796486298722e-06, + 8.48421723269773222391e-06, + 8.65462782259947107971e-06, + 8.81967993958106861606e-06, + 8.97929173195711876623e-06, + 9.13338466370594821242e-06, + 9.28188355172597093559e-06, + 9.42471660107943996656e-06, + 9.56181543820204782021e-06, + 9.69311514206661032516e-06, + 9.81855427328706617540e-06, + 9.93807490115107773816e-06, + 1.00516226285705943843e-05, + 1.01591466149406832020e-05, + 1.02605995968987750983e-05, + 1.03559379069769316912e-05, + 1.04451214901417424743e-05, + 1.05281139182170699055e-05, + 1.06048824021864677416e-05, + 1.06753978023731855288e-05, + 1.07396346364968783339e-05, + 1.07975710856074994448e-05, + 1.08491889978979006982e-05, + 1.08944738903980051003e-05, + 1.09334149485546700144e-05, + 1.09660050237023010909e-05, + 1.09922406284309627094e-05, + 1.10121219298593066863e-05, + 1.10256527408215773174e-05, + 1.10328405089781558080e-05, + 1.10336963038616736523e-05, + 1.10282348018699333952e-05, + 1.10164742692203395746e-05, + 1.09984365428796701980e-05, + 1.09741470094854162102e-05, + 1.09436345822753026573e-05, + 1.09069316760433128688e-05, + 1.08640741801411637853e-05, + 1.08151014295454121441e-05, + 1.07600561740116316219e-05, + 1.06989845453377939037e-05, + 1.06319360227604537122e-05, + 1.05589633965072819227e-05, + 1.04801227295333686110e-05, + 1.03954733174649689091e-05, + 1.03050776467800735478e-05, + 1.02090013512532056038e-05, + 1.01073131666939828753e-05, + 1.00000848840093901980e-05, + 9.88739130062094606394e-06, + 9.76931017026862892453e-06, + 9.64592215123430269373e-06, + 9.51731075301832287069e-06, + 9.38356228150362642153e-06, + 9.24476578264260636546e-06, + 9.10101298470273608427e-06, + 8.95239823910756736568e-06, + 8.79901845991063759865e-06, + 8.64097306194044156673e-06, + 8.47836389765517216299e-06, + 8.31129519274676613631e-06, + 8.13987348053439576051e-06, + 7.96420753518800302127e-06, + 7.78440830382320983472e-06, + 7.60058883750940706770e-06, + 7.41286422123340111201e-06, + 7.22135150286187937354e-06, + 7.02616962114339291517e-06, + 6.82743933279976089379e-06, + 6.62528313874512338812e-06, + 6.41982520947684842004e-06, + 6.21119130968985121773e-06, + 5.99950872215320453294e-06, + 5.78490617089735561883e-06, + 5.56751374375751685266e-06, + 5.34746281431924760940e-06, + 5.12488596331278031701e-06, + 4.89991689950258687289e-06, + 4.67269038011961418454e-06, + 4.44334213087987709952e-06, + 4.21200876564441589159e-06, + 3.97882770575729567648e-06, + 3.74393709911667144121e-06, + 3.50747573902317319374e-06, + 3.26958298285330172902e-06, + 3.03039867060520659957e-06, + 2.79006304336402052000e-06, + 2.54871666173396763366e-06, + 2.30650032428370582201e-06, + 2.06355498605534895103e-06, + 1.82002167717590069487e-06, + 1.57604142162576490206e-06, + 1.33175515621080687286e-06, + 1.08730364977607694810e-06, + 8.42827422715224723608e-07, + 5.98466666817798730862e-07, + 3.54361165500383015065e-07, + 1.10650214466601145526e-07, +-1.32527457159341769654e-07, +-3.75033765181279387019e-07, +-6.16731348117982223764e-07, +-8.57483644384870604974e-07, +-1.09715496882697242401e-06, +-1.33561058856459451812e-06, +-1.57271679809768592289e-06, +-1.80834099364739390638e-06, +-2.04235174667385346287e-06, +-2.27461887654183985059e-06, +-2.50501352229047160599e-06, +-2.73340821346838846000e-06, +-2.95967693999581947631e-06, +-3.18369522101568454449e-06, +-3.40534017269651038867e-06, +-3.62449057495060442016e-06, +-3.84102693703176620771e-06, +-4.05483156197683158547e-06, +-4.26578860985994465493e-06, +-4.47378415981817885059e-06, +-4.67870627082610431870e-06, +-4.88044504117963632650e-06, +-5.07889266666103897304e-06, +-5.27394349735436316360e-06, +-5.46549409308178958515e-06, +-5.65344327743282125745e-06, +-5.83769219035584263823e-06, +-6.01814433929215356056e-06, +-6.19470564881734900520e-06, +-6.36728450877158616566e-06, +-6.53579182085452806356e-06, +-6.70014104365581900433e-06, +-6.86024823610766216613e-06, +-7.01603209933177423939e-06, +-7.16741401686316151218e-06, +-7.31431809323110943569e-06, +-7.45667119087909145226e-06, +-7.59440296540647431485e-06, +-7.72744589911581192265e-06, +-7.85573533285050310242e-06, +-7.97920949610866873263e-06, +-8.09780953542020220872e-06, +-8.21147954097478835185e-06, +-8.32016657148992507269e-06, +-8.42382067730890197923e-06, +-8.52239492171977940256e-06, +-8.61584540048746502295e-06, +-8.70413125959197291938e-06, +-8.78721471116717128705e-06, +-8.86506104763514668932e-06, +-8.93763865403249516855e-06, +-9.00491901852594998912e-06, +-9.06687674111571462719e-06, +-9.12348954052592163661e-06, +-9.17473825928260702616e-06, +-9.22060686698159047512e-06, +-9.26108246174664932824e-06, +-9.29615526988461694400e-06, +-9.32581864373973304274e-06, +-9.35006905775386307602e-06, +-9.36890610273917822759e-06, +-9.38233247837104300938e-06, +-9.39035398390946727946e-06, +-9.39297950715976480397e-06, +-9.39022101168187463889e-06, +-9.38209352226113891724e-06, +-9.36861510865258015606e-06, +-9.34980686761262702199e-06, +-9.32569290323271860845e-06, +-9.29630030559048952147e-06, +-9.26165912773481235900e-06, +-9.22180236102228707016e-06, +-9.17676590882337654416e-06, +-9.12658855861738727770e-06, +-9.07131195249644772880e-06, +-9.01098055609939421230e-06, +-8.94564162599733138977e-06, +-8.87534517555361527068e-06, +-8.80014393928162666969e-06, +-8.72009333572471611652e-06, +-8.63525142888329921994e-06, +-8.54567888821502508222e-06, +-8.45143894723457394103e-06, +-8.35259736074052112995e-06, +-8.24922236069722452712e-06, +-8.14138461080064133836e-06, +-8.02915715975743407074e-06, +-7.91261539330765898304e-06, +-7.79183698502164539547e-06, +-7.66690184590263985908e-06, +-7.53789207282747358732e-06, +-7.40489189585616646447e-06, +-7.26798762444797763775e-06, +-7.12726759261192169612e-06, +-6.98282210303029636403e-06, +-6.83474337018834747465e-06, +-6.68312546254524426573e-06, +-6.52806424378415029071e-06, +-6.36965731317252602944e-06, +-6.20800394507595081702e-06, +-6.04320502765754885186e-06, +-5.87536300080224453186e-06, +-5.70458179330339185380e-06, +-5.53096675935019674964e-06, +-5.35462461435186519118e-06, +-5.17566337014321141424e-06, +-4.99419226960263364762e-06, +-4.81032172072758387396e-06, +-4.62416323020455543279e-06, +-4.43582933651357265599e-06, +-4.24543354260686772332e-06, +-4.05309024820171368161e-06, +-3.85891468172737918331e-06, +-3.66302283196632931856e-06, +-3.46553137942988627687e-06, +-3.26655762750855510455e-06, +-3.06621943343732231445e-06, +-2.86463513911618343607e-06, +-2.66192350182618693409e-06, +-2.45820362488117562057e-06, +-2.25359488825541727446e-06, +-2.04821687922720013799e-06, +-1.84218932307831247064e-06, +-1.63563201388926604866e-06, +-1.42866474546994879804e-06, +-1.22140724246515182631e-06, +-1.01397909167432569799e-06, +-8.06499673625078029042e-07, +-5.99088094436327444290e-07, +-3.91863118017023242330e-07, +-1.84943098628889751524e-07, + 2.15540861419684426667e-08, + 2.27511101966967466315e-07, + 4.32811223880043209387e-07, + 6.37338401859019189379e-07, + 8.40977325854192905002e-07, + 1.04361349022508806704e-06, + 1.24513325755019998089e-06, + 1.44542392177450216890e-06, + 1.64437377065950114052e-06, + 1.84187214750444789869e-06, + 2.03780951209777257423e-06, + 2.23207750087511452161e-06, + 2.42456898624406490649e-06, + 2.61517813504639618351e-06, + 2.80380046612576570131e-06, + 2.99033290696995661509e-06, + 3.17467384939732300976e-06, + 3.35672320425774437633e-06, + 3.53638245511906924553e-06, + 3.71355471091059317744e-06, + 3.88814475749635763264e-06, + 4.06005910814819412596e-06, + 4.22920605290116388692e-06, + 4.39549570675089384069e-06, + 4.55884005668278723919e-06, + 4.71915300750006533998e-06, + 4.87635042643024103849e-06, + 5.03035018648692755928e-06, + 5.18107220856522701196e-06, + 5.32843850224952383525e-06, + 5.47237320531358473132e-06, + 5.61280262189333594894e-06, + 5.74965525931381193962e-06, + 5.88286186355211838841e-06, + 6.01235545332134090329e-06, + 6.13807135275468517243e-06, + 6.25994722267931996977e-06, + 6.37792309046513804878e-06, + 6.49194137843068450202e-06, + 6.60194693079779326846e-06, + 6.70788703918137587323e-06, + 6.80971146660357458814e-06, + 6.90737247002230281208e-06, + 7.00082482136491290685e-06, + 7.09002582705877526905e-06, + 7.17493534605098864026e-06, + 7.25551580631220637360e-06, + 7.33173221981546288786e-06, + 7.40355219598984530240e-06, + 7.47094595364170035832e-06, + 7.53388633134188754210e-06, + 7.59234879627670417821e-06, + 7.64631145156141268828e-06, + 7.69575504201604814413e-06, + 7.74066295840411851953e-06, + 7.78102124013589340075e-06, + 7.81681857643788967132e-06, + 7.84804630599365161535e-06, + 7.87469841505748138885e-06, + 7.89677153404848565748e-06, + 7.91426493262873480251e-06, + 7.92718051327426929855e-06, + 7.93552280334505359466e-06, + 7.93929894566308982874e-06, + 7.93851868760764620798e-06, + 7.93319436873791183408e-06, + 7.92334090695392168925e-06, + 7.90897578320756958670e-06, + 7.89011902477623500857e-06, + 7.86679318711244252764e-06, + 7.83902333428366876954e-06, + 7.80683701801724535304e-06, + 7.77026425536612447970e-06, + 7.72933750501182780370e-06, + 7.68409164222195630977e-06, + 7.63456393248006921998e-06, + 7.58079400380666152174e-06, + 7.52282381779056517397e-06, + 7.46069763935092151688e-06, + 7.39446200525034590259e-06, + 7.32416569138081104189e-06, + 7.24985967884426853560e-06, + 7.17159711885090219710e-06, + 7.08943329645732147265e-06, + 7.00342559317115033967e-06, + 6.91363344844324002262e-06, + 6.82011832007511287137e-06, + 6.72294364356627759040e-06, + 6.62217479042785679954e-06, + 6.51787902548926013278e-06, + 6.41012546322492830867e-06, + 6.29898502313035979733e-06, + 6.18453038417209923617e-06, + 6.06683593834504205765e-06, + 5.94597774336311937993e-06, + 5.82203347451249516448e-06, + 5.69508237570125013232e-06, + 5.56520520973042217313e-06, + 5.43248420782122392469e-06, + 5.29700301842786852943e-06, + 5.15884665536775968036e-06, + 5.01810144530070211867e-06, + 4.87485497458916059279e-06, + 4.72919603557198831207e-06, + 4.58121457228396545999e-06, + 4.43100162565413800605e-06, + 4.27864927821586065842e-06, + 4.12425059836174341351e-06, + 3.96789958417691884638e-06, + 3.80969110688415655311e-06, + 3.64972085393445999985e-06, + 3.48808527177698559195e-06, + 3.32488150834214283460e-06, + 3.16020735527182339492e-06, + 2.99416118993082249565e-06, + 2.82684191723347329501e-06, + 2.65834891131958394095e-06, + 2.48878195711375767025e-06, + 2.31824119180212634826e-06, + 2.14682704626095390252e-06, + 1.97464018646858031233e-06, + 1.80178145494066620423e-06, + 1.62835181221444846777e-06, + 1.45445227842166370380e-06, + 1.28018387498127474226e-06, + 1.10564756644572971662e-06, + 9.30944202533528893967e-07, + 7.56174460383558706575e-07, + 5.81438787057772137935e-07, + 4.06837342332995493781e-07, + 2.32469941807973572217e-07, + 5.84360003605464838908e-08, +-1.15165524016196481795e-07, +-2.88236185961157478515e-07, +-4.60678108053030918551e-07, +-6.32394035641693353382e-07, +-8.03287391175248576365e-07, +-9.73262327992278866677e-07, +-1.14222378354964966348e-06, +-1.31007753205661820651e-06, +-1.47673023648642007660e-06, +-1.64208949993695062100e-06, +-1.80606391631259277593e-06, +-1.96856312029973079598e-06, +-2.12949783660893906853e-06, +-2.28877992845738131554e-06, +-2.44632244526540991875e-06, +-2.60203966954189995785e-06, +-2.75584716293343213363e-06, +-2.90766181141288047594e-06, +-3.05740186958367351418e-06, +-3.20498700407640839933e-06, +-3.35033833601523650274e-06, +-3.49337848253191377853e-06, +-3.63403159730610840275e-06, +-3.77222341011111343188e-06, +-3.90788126534447433042e-06, +-4.04093415952591392912e-06, +-4.17131277773873497690e-06, +-4.29894952900307645335e-06, +-4.42377858055843327302e-06, +-4.54573589104088312044e-06, +-4.66475924253666648223e-06, +-4.78078827150107880212e-06, +-4.89376449852186315914e-06, +-5.00363135691748540988e-06, +-5.11033422015512990528e-06, +-5.21382042807596778544e-06, +-5.31403931191554123584e-06, +-5.41094221810950165016e-06, +-5.50448253087047069913e-06, +-5.59461569353127499173e-06, +-5.68129922864175650784e-06, +-5.76449275681243674909e-06, +-5.84415801429719277657e-06, +-5.92025886930820698860e-06, +-5.99276133705720719759e-06, +-6.06163359351762427620e-06, +-6.12684598790327211872e-06, +-6.18837105385967135374e-06, +-6.24618351936512419082e-06, +-6.30026031533919750782e-06, +-6.35058058295712848316e-06, +-6.39712567966953613306e-06, +-6.43987918392721429004e-06, +-6.47882689861198942782e-06, +-6.51395685317499943250e-06, +-6.54525930448471249620e-06, +-6.57272673638766514792e-06, +-6.59635385798559469776e-06, +-6.61613760063350534395e-06, +-6.63207711366379757420e-06, +-6.64417375884241211495e-06, +-6.65243110356349872368e-06, +-6.65685491279031274194e-06, +-6.65745313974966963219e-06, +-6.65423591538958656902e-06, +-6.64721553660889651050e-06, +-6.63640645326926765439e-06, +-6.62182525400028480084e-06, +-6.60349065080916732668e-06, +-6.58142346250719060277e-06, +-6.55564659696565526196e-06, +-6.52618503221475609801e-06, +-6.49306579639951552747e-06, +-6.45631794660739462695e-06, +-6.41597254658263945040e-06, +-6.37206264334415081952e-06, +-6.32462324272206488792e-06, +-6.27369128383118030161e-06, +-6.21930561249836743221e-06, +-6.16150695366234792122e-06, +-6.10033788276449535378e-06, +-6.03584279615001515287e-06, +-5.96806788049923278545e-06, +-5.89706108130940631553e-06, +-5.82287207044756658384e-06, +-5.74555221279694319542e-06, +-5.66515453201526036843e-06, +-5.58173367543274885226e-06, +-5.49534587810695348729e-06, +-5.40604892606070708310e-06, +-5.31390211872570004752e-06, +-5.21896623061564390400e-06, +-5.12130347225329365013e-06, +-5.02097745037598523939e-06, +-4.91805312744465109411e-06, +-4.81259678048159588907e-06, +-4.70467595926274513780e-06, +-4.59435944389046620792e-06, +-4.48171720177175865495e-06, +-4.36682034403174463086e-06, +-4.24974108138584086476e-06, +-4.13055267949739200956e-06, +-4.00932941385171509125e-06, +-3.88614652417032873467e-06, +-3.76108016839454787432e-06, +-3.63420737626596489757e-06, +-3.50560600253174686132e-06, +-3.37535467980288975763e-06, +-3.24353277109359282678e-06, +-3.11022032207008786392e-06, +-2.97549801303766165317e-06, +-2.83944711069247344591e-06, +-2.70214941967136185736e-06, +-2.56368723392205452038e-06, +-2.42414328792700028154e-06, +-2.28360070780758763959e-06, +-2.14214296233768618929e-06, +-1.99985381389505311643e-06, +-1.85681726937918172971e-06, +-1.71311753112369806511e-06, +-1.56883894783374962087e-06, +-1.42406596557164193617e-06, +-1.27888307882598605392e-06, +-1.13337478168536349648e-06, +-9.87625519151570836163e-07, +-8.41719638613064665786e-07, +-6.95741341511352204364e-07, +-5.49774635225687810111e-07, +-4.03903285203652358387e-07, +-2.58210767364619000791e-07, +-1.12780220802875344963e-07, + 3.23055991830684097878e-08, + 1.76964367708724778855e-07, + 3.21114236543438189078e-07, + 4.64673879946063572873e-07, + 6.07562540071123210426e-07, + 7.49700071920371749061e-07, + 8.91006987815025860095e-07, + 1.03140450136427425456e-06, + 1.17081457090602433941e-06, + 1.30915994239623084851e-06, + 1.44636419172353368897e-06, + 1.58235176642631552541e-06, + 1.71704802678972351765e-06, + 1.85037928630060069746e-06, + 1.98227285143870244472e-06, + 2.11265706078306988520e-06, + 2.24146132341246485419e-06, + 2.36861615658157347906e-06, + 2.49405322264845444755e-06, + 2.61770536524023275885e-06, + 2.73950664463357572141e-06, + 2.85939237233350266468e-06, + 2.97729914483249884479e-06, + 3.09316487653266211920e-06, + 3.20692883181446816197e-06, + 3.31853165623432036477e-06, + 3.42791540683944990220e-06, + 3.53502358157950725138e-06, + 3.63980114780429875857e-06, + 3.74219456983363037592e-06, + 3.84215183558227767505e-06, + 3.93962248223251686305e-06, + 4.03455762093816806731e-06, + 4.12690996055009787897e-06, + 4.21663383035196559137e-06, + 4.30368520179581453395e-06, + 4.38802170922777651609e-06, + 4.46960266959470585012e-06, + 4.54838910112321163730e-06, + 4.62434374096319227585e-06, + 4.69743106178853688561e-06, + 4.76761728734836138144e-06, + 4.83487040696272629773e-06, + 4.89916018895741111830e-06, + 4.96045819303296106926e-06, + 5.01873778156387963061e-06, + 5.07397412982442447456e-06, + 5.12614423513811590729e-06, + 5.17522692494871317675e-06, + 5.22120286381103742548e-06, + 5.26405455930064433061e-06, + 5.30376636684197204255e-06, + 5.34032449345513637005e-06, + 5.37371700042290210606e-06, + 5.40393380487774409700e-06, + 5.43096668031327048978e-06, + 5.45480925602115842708e-06, + 5.47545701545760188074e-06, + 5.49290729354319507956e-06, + 5.50715927290080433390e-06, + 5.51821397903640711657e-06, + 5.52607427446940615412e-06, + 5.53074485181774806004e-06, + 5.53223222584567817618e-06, + 5.53054472448127380454e-06, + 5.52569247881201016526e-06, + 5.51768741206704879188e-06, + 5.50654322759543274221e-06, + 5.49227539585013617960e-06, + 5.47490114038823605808e-06, + 5.45443942289814534188e-06, + 5.43091092726536726806e-06, + 5.40433804268870449940e-06, + 5.37474484585942960917e-06, + 5.34215708221641970028e-06, + 5.30660214629070434828e-06, + 5.26810906115345203946e-06, + 5.22670845698185819179e-06, + 5.18243254875779933987e-06, + 5.13531511311474995156e-06, + 5.08539146434873193589e-06, + 5.03269842960957088606e-06, + 4.97727432328926165021e-06, + 4.91915892062447536855e-06, + 4.85839343053077035771e-06, + 4.79502046768650205761e-06, + 4.72908402388465426040e-06, + 4.66062943867137881228e-06, + 4.58970336929019699759e-06, + 4.51635375995152054556e-06, + 4.44062981044616933641e-06, + 4.36258194412544737627e-06, + 4.28226177526485068410e-06, + 4.19972207583456497138e-06, + 4.11501674169647542961e-06, + 4.02820075825028238263e-06, + 3.93933016554731602391e-06, + 3.84846202289762216335e-06, + 3.75565437298938188386e-06, + 3.66096620554404999308e-06, + 3.56445742052937107578e-06, + 3.46618879095310788465e-06, + 3.36622192525887642755e-06, + 3.26461922935039320666e-06, + 3.16144386826273460570e-06, + 3.05675972750716587302e-06, + 2.95063137411155366322e-06, + 2.84312401738004221383e-06, + 2.73430346939548900412e-06, + 2.62423610528835733665e-06, + 2.51298882329570483720e-06, + 2.40062900463402164141e-06, + 2.28722447320975292833e-06, + 2.17284345519123839340e-06, + 2.05755453846596430753e-06, + 1.94142663200690945903e-06, + 1.82452892517181498007e-06, + 1.70693084695912356741e-06, + 1.58870202524435859482e-06, + 1.46991224602059460634e-06, + 1.35063141266662197534e-06, + 1.23092950526634752769e-06, + 1.11087654000282617921e-06, + 9.90542528650260827215e-07, + 8.69997438187136635693e-07, + 7.49311150553558232788e-07, + 6.28553422575956171735e-07, + 5.07793846080199777306e-07, + 3.87101808219950752071e-07, + 2.66546452036637359768e-07, + 1.46196637279211919523e-07, + 2.61209014996513097622e-08, +-9.36125785480710641559e-08, +-2.12936025188332329408e-07, +-3.31782097760571907408e-07, +-4.50083930191668236211e-07, +-5.67775168183275709294e-07, +-6.84790005993688176635e-07, +-8.01063222793833814618e-07, +-9.16530218579230311038e-07, +-1.03112704961422672079e-06, +-1.14479046339492176093e-06, +-1.25745793310772014899e-06, +-1.36906769156673085052e-06, +-1.47955876461155409369e-06, +-1.58887100394770566988e-06, +-1.69694511941227368702e-06, +-1.80372271064780189541e-06, +-1.90914629816775581196e-06, +-2.01315935379763895325e-06, +-2.11570633047440601331e-06, +-2.21673269139235624129e-06, +-2.31618493847693730396e-06, +-2.41401064017204397923e-06, +-2.51015845853012064279e-06, +-2.60457817558802397410e-06, +-2.69722071901685094830e-06, +-2.78803818703287373008e-06, +-2.87698387255719700099e-06, +-2.96401228661247619401e-06, +-3.04907918094525491427e-06, +-3.13214156986324088414e-06, +-3.21315775127703456810e-06, +-3.29208732693637732224e-06, +-3.36889122185290401895e-06, +-3.44353170289642487268e-06, +-3.51597239656325077098e-06, +-3.58617830590191733468e-06, +-3.65411582659302460743e-06, +-3.71975276217506551713e-06, +-3.78305833841012117849e-06, +-3.84400321678365093078e-06, +-3.90255950713312254181e-06, +-3.95870077940074512301e-06, +-4.01240207450610770714e-06, +-4.06363991433488812364e-06, +-4.11239231084125285599e-06, +-4.15863877425935865654e-06, +-4.20236032042448446743e-06, +-4.24353947720017342875e-06, +-4.28216029001119185047e-06, +-4.31820832648155806497e-06, +-4.35167068017766995946e-06, +-4.38253597345699451516e-06, +-4.41079435942349164690e-06, +-4.43643752299069560910e-06, +-4.45945868105587513408e-06, +-4.47985258178600159821e-06, +-4.49761550302029909350e-06, +-4.51274524979143300062e-06, +-4.52524115097084023650e-06, +-4.53510405504175193850e-06, +-4.54233632500539397060e-06, +-4.54694183242584894293e-06, +-4.54892595061959283142e-06, +-4.54829554699628510261e-06, +-4.54505897455774022598e-06, +-4.53922606256257512138e-06, +-4.53080810636444806448e-06, +-4.51981785643228738179e-06, +-4.50626950656128519675e-06, +-4.49017868128402610519e-06, +-4.47156242249136545128e-06, +-4.45043917527324955132e-06, +-4.42682877299008102390e-06, +-4.40075242158549665903e-06, +-4.37223268315208425070e-06, +-4.34129345876175116439e-06, +-4.30795997057291989114e-06, +-4.27225874322715952063e-06, +-4.23421758454818478526e-06, +-4.19386556555651685739e-06, +-4.15123299981356679695e-06, +-4.10635142210863573125e-06, +-4.05925356650451797034e-06, +-4.00997334375461245165e-06, +-3.95854581810788347368e-06, +-3.90500718351647261954e-06, +-3.84939473926163028560e-06, +-3.79174686501394100978e-06, +-3.73210299534384178129e-06, +-3.67050359369971365087e-06, +-3.60699012586834896589e-06, +-3.54160503293725947090e-06, +-3.47439170377438781006e-06, +-3.40539444704242567051e-06, +-3.33465846276757226665e-06, +-3.26222981347759901722e-06, +-3.18815539492950643052e-06, +-3.11248290644416109035e-06, +-3.03526082086643820009e-06, +-2.95653835416947222251e-06, +-2.87636543472176765438e-06, +-2.79479267223601303066e-06, +-2.71187132641859964837e-06, +-2.62765327533899515464e-06, +-2.54219098353815390706e-06, +-2.45553746989530186833e-06, +-2.36774627527249690158e-06, +-2.27887142995641191922e-06, +-2.18896742091688744107e-06, +-2.09808915890182256402e-06, +-2.00629194538800892082e-06, +-1.91363143940754862785e-06, +-1.82016362426948875164e-06, +-1.72594477419635162234e-06, +-1.63103142089514905451e-06, +-1.53548032008255493308e-06, +-1.43934841798375985031e-06, +-1.34269281782482158857e-06, +-1.24557074633660619018e-06, +-1.14803952029313359972e-06, +-1.05015651309915032019e-06, +-9.51979121449571438300e-07, +-8.53564732078559276071e-07, +-7.54970688617303580583e-07, +-6.56254258580785667422e-07, +-5.57472600498841932364e-07, +-4.58682731214803567250e-07, +-3.59941493366721268602e-07, +-2.61305523070885236846e-07, +-1.62831217825798099669e-07, +-6.45747046531622918148e-08, + 3.34081915028460607542e-08, + 1.31061979105115269233e-07, + 2.28331531061093047517e-07, + 3.25162115452506418290e-07, + 4.21499425940175324931e-07, + 5.17289611827256223732e-07, + 6.12479307764515172907e-07, + 7.07015663081470306902e-07, + 8.00846370727535963142e-07, + 8.93919695807548723643e-07, + 9.86184503696360592316e-07, + 1.07759028771747680805e-06, + 1.16808719637099324993e-06, + 1.25762606009643313325e-06, + 1.34615841755636422783e-06, + 1.43363654142701431353e-06, + 1.52001346368244521319e-06, + 1.60524300035914707475e-06, + 1.68927977578831839769e-06, + 1.77207924628335479643e-06, + 1.85359772327053896192e-06, + 1.93379239585117203927e-06, + 2.01262135278386203690e-06, + 2.09004360387575857427e-06, + 2.16601910077334100819e-06, + 2.24050875713967010219e-06, + 2.31347446821209968128e-06, + 2.38487912972836386475e-06, + 2.45468665621208123303e-06, + 2.52286199861151334042e-06, + 2.58937116127982583862e-06, + 2.65418121829169547439e-06, + 2.71726032908779813765e-06, + 2.77857775344037205028e-06, + 2.83810386573328862561e-06, + 2.89581016855032907358e-06, + 2.95166930556685687487e-06, + 3.00565507373729543829e-06, + 3.05774243477661226693e-06, + 3.10790752592901346437e-06, + 3.15612767002082679062e-06, + 3.20238138479374552623e-06, + 3.24664839151536307337e-06, + 3.28890962286420223838e-06, + 3.32914723008697677049e-06, + 3.36734458942622126102e-06, + 3.40348630781685071737e-06, + 3.43755822785064014868e-06, + 3.46954743200808672055e-06, + 3.49944224615744907365e-06, + 3.52723224232133607687e-06, + 3.55290824071145572597e-06, + 3.57646231103275916171e-06, + 3.59788777305844983311e-06, + 3.61717919647792329573e-06, + 3.63433240001992844556e-06, + 3.64934444985388431064e-06, + 3.66221365727246736405e-06, + 3.67293957565916496310e-06, + 3.68152299674478401627e-06, + 3.68796594615754264255e-06, + 3.69227167827109476069e-06, + 3.69444467035641090999e-06, + 3.69449061604251067923e-06, + 3.69241641809255407447e-06, + 3.68823018050121809172e-06, + 3.68194119992049474706e-06, + 3.67355995642082701168e-06, + 3.66309810359520425440e-06, + 3.65056845801397982505e-06, + 3.63598498803867909083e-06, + 3.61936280200335549955e-06, + 3.60071813577239656246e-06, + 3.58006833968386969076e-06, + 3.55743186488838466342e-06, + 3.53282824909282608752e-06, + 3.50627810171953317514e-06, + 3.47780308849131654283e-06, + 3.44742591545312398587e-06, + 3.41517031244148100487e-06, + 3.38106101601311265410e-06, + 3.34512375184437054455e-06, + 3.30738521661340731931e-06, + 3.26787305937770838069e-06, + 3.22661586245842979003e-06, + 3.18364312184520498148e-06, + 3.13898522713461071050e-06, + 3.09267344101413714559e-06, + 3.04473987830630518563e-06, + 2.99521748458606001315e-06, + 2.94414001438530427212e-06, + 2.89154200899865406331e-06, + 2.83745877390457421898e-06, + 2.78192635581631105178e-06, + 2.72498151937718603862e-06, + 2.66666172351495323772e-06, + 2.60700509747023960325e-06, + 2.54605041651313995614e-06, + 2.48383707736592921508e-06, + 2.42040507334248784649e-06, + 2.35579496922448726218e-06, + 2.29004787588705505843e-06, + 2.22320542469039954603e-06, + 2.15530974165298533032e-06, + 2.08640342142196774357e-06, + 2.01652950105673072815e-06, + 1.94573143364140580303e-06, + 1.87405306174228235695e-06, + 1.80153859072609659169e-06, + 1.72823256195534356335e-06, + 1.65417982587563572154e-06, + 1.57942551501363361584e-06, + 1.50401501689824875799e-06, + 1.42799394692362609795e-06, + 1.35140812116891807883e-06, + 1.27430352919099175392e-06, + 1.19672630680600165567e-06, + 1.11872270887555548908e-06, + 1.04033908211438514454e-06, + 9.61621837932593595614e-07, + 8.82617425331797973857e-07, + 8.03372303868260350135e-07, + 7.23932916698523442543e-07, + 6.44345663725568065214e-07, + 5.64656874857124303848e-07, + 4.84912783394116915736e-07, + 4.05159499563223062539e-07, + 3.25442984208674460614e-07, + 2.45809022658112731786e-07, + 1.66303198777160306628e-07, + 8.69708692272027903669e-08, + 7.85713794072117322522e-09, +-7.09931691716676215865e-08, +-1.49535529268482347680e-07, +-2.27725747365171486868e-07, +-3.05519980848837318375e-07, +-3.82874763706501346521e-07, +-4.59747030453731194650e-07, +-5.36094139750675601478e-07, +-6.11873897692766847291e-07, +-6.87044580763594041777e-07, +-7.61564958437679165913e-07, +-8.35394315421141605512e-07, +-9.08492473518483241836e-07, +-9.80819813113976304058e-07, +-1.05233729425625164956e-06, +-1.12300647733612530584e-06, +-1.19278954334437999738e-06, +-1.26164931370253481165e-06, +-1.32954926965386881663e-06, +-1.39645357120588546386e-06, +-1.46232707561449405058e-06, +-1.52713535540064995902e-06, +-1.59084471589067184708e-06, +-1.65342221227063001310e-06, +-1.71483566614886781052e-06, +-1.77505368161545113680e-06, +-1.83404566079325564072e-06, +-1.89178181887221348355e-06, +-1.94823319862069280282e-06, +-2.00337168436514229084e-06, +-2.05717001543450264187e-06, +-2.10960179906117775394e-06, +-2.16064152273371070425e-06, +-2.21026456599565581941e-06, +-2.25844721168562965249e-06, +-2.30516665661384152826e-06, +-2.35040102167078548251e-06, +-2.39412936136406383631e-06, +-2.43633167277975945574e-06, +-2.47698890396499016471e-06, +-2.51608296172876497540e-06, +-2.55359671885850362846e-06, +-2.58951402074998920553e-06, +-2.62381969144887382413e-06, +-2.65649953910217082780e-06, +-2.68754036081854804860e-06, +-2.71692994693660306132e-06, +-2.74465708470059315127e-06, +-2.77071156134348277634e-06, +-2.79508416657755373943e-06, +-2.81776669449305452715e-06, +-2.83875194486578497579e-06, +-2.85803372387518624004e-06, +-2.87560684423360267943e-06, +-2.89146712472987382482e-06, +-2.90561138918856466730e-06, +-2.91803746484780862573e-06, +-2.92874418015865453993e-06, +-2.93773136200894074995e-06, +-2.94499983237584587605e-06, +-2.95055140441023676853e-06, +-2.95438887795761926909e-06, +-2.95651603451999344031e-06, +-2.95693763166347438543e-06, +-2.95565939687693110985e-06, +-2.95268802088687215850e-06, +-2.94803115043462330338e-06, +-2.94169738052167357241e-06, +-2.93369624612953431959e-06, +-2.92403821342084482528e-06, +-2.91273467042851974806e-06, +-2.89979791724021359437e-06, +-2.88524115568552475564e-06, +-2.86907847853367548813e-06, +-2.85132485820962740443e-06, +-2.83199613503694229294e-06, +-2.81110900501579379722e-06, +-2.78868100714493697984e-06, +-2.76473051029656053377e-06, +-2.73927669965326065288e-06, +-2.71233956271653185119e-06, +-2.68393987489646478775e-06, +-2.65409918469246439721e-06, +-2.62283979847510613493e-06, +-2.59018476487935021233e-06, +-2.55615785881960940799e-06, +-2.52078356513729817673e-06, +-2.48408706189168983184e-06, +-2.44609420330517115589e-06, +-2.40683150237354884389e-06, +-2.36632611315396292482e-06, +-2.32460581274025857810e-06, +-2.28169898293852692147e-06, +-2.23763459165468254892e-06, +-2.19244217400458949748e-06, +-2.14615181316064773556e-06, +-2.09879412094551363500e-06, +-2.05040021818578316432e-06, +-2.00100171483782110160e-06, +-1.95063068989816435785e-06, +-1.89931967111113481318e-06, +-1.84710161448549238660e-06, +-1.79400988363453340540e-06, +-1.74007822895002694472e-06, +-1.68534076662445773069e-06, +-1.62983195753369262521e-06, +-1.57358658599301992021e-06, +-1.51663973839943020132e-06, +-1.45902678177302702247e-06, +-1.40078334221047426768e-06, +-1.34194528326338093541e-06, +-1.28254868425455118572e-06, +-1.22262981854484770803e-06, +-1.16222513176453179750e-06, +-1.10137122001903489497e-06, +-1.04010480808683832089e-06, +-9.78462727617415689625e-07, +-9.16481895344879420621e-07, +-8.54199291329082445989e-07, +-7.91651937236919995967e-07, +-7.28876874676428218509e-07, +-6.65911143596146899220e-07, +-6.02791760762178925358e-07, +-5.39555698325257482511e-07, +-4.76239862490052774988e-07, +-4.12881072298987595103e-07, +-3.49516038541690854304e-07, +-2.86181342804064272744e-07, +-2.22913416666661733927e-07, +-1.59748521064022687018e-07, +-9.67227258185584328684e-08, +-3.38718893582766938970e-08, + 2.87683613695412570172e-08, + 9.11626507777930940099e-08, + 1.53275874301229528026e-07, + 2.15073217829609376242e-07, + 2.76520176901766833620e-07, + 3.37582575650052953442e-07, + 3.98226585485819280378e-07, + 4.58418743513730979390e-07, + 5.18125970668006750755e-07, + 5.77315589558766536398e-07, + 6.35955342019936643428e-07, + 6.94013406349350241498e-07, + 7.51458414232049067549e-07, + 8.08259467337988365555e-07, + 8.64386153585596963575e-07, + 9.19808563062980821321e-07, + 9.74497303597860849836e-07, + 1.02842351597027310336e-06, + 1.08155888875847427063e-06, + 1.13387567281072351305e-06, + 1.18534669533762647095e-06, + 1.23594537361629275206e-06, + 1.28564572830046089292e-06, + 1.33442239633006842733e-06, + 1.38225064343414957853e-06, + 1.42910637622117390762e-06, + 1.47496615385122660710e-06, + 1.51980719928470874307e-06, + 1.56360741010246000211e-06, + 1.60634536889251227715e-06, + 1.64800035319896004223e-06, + 1.68855234502865835288e-06, + 1.72798203991181336901e-06, + 1.76627085551270775016e-06, + 1.80340093978719079100e-06, + 1.83935517868373362992e-06, + 1.87411720338522404077e-06, + 1.90767139708889131071e-06, + 1.94000290132205409853e-06, + 1.97109762179168084047e-06, + 2.00094223376600235736e-06, + 2.02952418698673586018e-06, + 2.05683171011063731075e-06, + 2.08285381467995650348e-06, + 2.10758029862004405122e-06, + 2.13100174926526816907e-06, + 2.15310954591206726866e-06, + 2.17389586189977999014e-06, + 2.19335366621972616361e-06, + 2.21147672465324978376e-06, + 2.22825960043981455305e-06, + 2.24369765447650766928e-06, + 2.25778704505024781826e-06, + 2.27052472710528124541e-06, + 2.28190845104710389511e-06, + 2.29193676108612702237e-06, + 2.30060899312292095007e-06, + 2.30792527217872156528e-06, + 2.31388650937382493307e-06, + 2.31849439845752497517e-06, + 2.32175141189321189097e-06, + 2.32366079650259840000e-06, + 2.32422656867321367902e-06, + 2.32345350913359285878e-06, + 2.32134715730082542021e-06, + 2.31791380520532445909e-06, + 2.31316049099797609704e-06, + 2.30709499204498586449e-06, + 2.29972581761599807363e-06, + 2.29106220117129925082e-06, + 2.28111409225408822216e-06, + 2.26989214799404362660e-06, + 2.25740772422860767231e-06, + 2.24367286624860951035e-06, + 2.22870029917506208745e-06, + 2.21250341797413235839e-06, + 2.19509627711749353150e-06, + 2.17649357989546114511e-06, + 2.15671066739044013289e-06, + 2.13576350711850353347e-06, + 2.11366868134673037600e-06, + 2.09044337509497678252e-06, + 2.06610536382953460056e-06, + 2.04067300085759004675e-06, + 2.01416520443082648289e-06, + 1.98660144456682630719e-06, + 1.95800172959701842290e-06, + 1.92838659245047678824e-06, + 1.89777707668168250577e-06, + 1.86619472225263513379e-06, + 1.83366155107768614062e-06, + 1.80020005234090271963e-06, + 1.76583316759495554916e-06, + 1.73058427565218490126e-06, + 1.69447717727606724807e-06, + 1.65753607968390744685e-06, + 1.61978558087014416989e-06, + 1.58125065376022968674e-06, + 1.54195663020503578884e-06, + 1.50192918482580689152e-06, + 1.46119431871970167741e-06, + 1.41977834303604934816e-06, + 1.37770786243346328062e-06, + 1.33500975842797161234e-06, + 1.29171117264239797330e-06, + 1.24783948996719974604e-06, + 1.20342232164300215316e-06, + 1.15848748827509167059e-06, + 1.11306300279010028919e-06, + 1.06717705334514073476e-06, + 1.02085798619962035772e-06, + 9.74134288559960768089e-07, + 9.27034571407410057516e-07, + 8.79587552319131062115e-07, + 8.31822038292692897728e-07, + 7.83766908584062082816e-07, + 7.35451097569259232492e-07, + 6.86903577639007368221e-07, + 6.38153342137989641187e-07, + 5.89229388356360835835e-07, + 5.40160700585000643775e-07, + 4.90976233243457187642e-07, + 4.41704894091038422500e-07, + 3.92375527528903780770e-07, + 3.43016898004928283419e-07, + 2.93657673529008577219e-07, + 2.44326409308779522962e-07, + 1.95051531514807551777e-07, + 1.45861321184445247206e-07, + 9.67838982725986303713e-08, + 4.78472058599844523217e-08, +-9.21005474744702503668e-10, +-4.94931931086882342167e-08, +-9.78420376464564573501e-08, +-1.45940458001584575920e-07, +-1.93761626279445676683e-07, +-2.41278982453654766505e-07, +-2.88466248828108414775e-07, +-3.35297444276962340684e-07, +-3.81746898255006320598e-07, +-4.27789264571066302430e-07, +-4.73399534917222114972e-07, +-5.18553052146814792709e-07, +-5.63225523294378261140e-07, +-6.07393032330819015965e-07, +-6.51032052647343771201e-07, +-6.94119459261828810033e-07, +-7.36632540741495661135e-07, +-7.78549010835974351873e-07, +-8.19847019815002990540e-07, +-8.60505165505228740834e-07, +-9.00502504020766893004e-07, +-9.39818560182277438796e-07, +-9.78433337620207624330e-07, +-1.01632732855600549368e-06, +-1.05348152325874204263e-06, +-1.08987741917143933322e-06, +-1.12549702970306422209e-06, +-1.16032289268355194760e-06, +-1.19433807847637408471e-06, +-1.22752619774656060195e-06, +-1.25987140888039317136e-06, +-1.29135842505383920910e-06, +-1.32197252094692572073e-06, +-1.35169953910148305289e-06, +-1.38052589591981443812e-06, +-1.40843858730261145449e-06, +-1.43542519392307942238e-06, +-1.46147388613708025001e-06, +-1.48657342852669403075e-06, +-1.51071318407641715728e-06, +-1.53388311798088013959e-06, +-1.55607380108330755062e-06, +-1.57727641294412167073e-06, +-1.59748274453934551225e-06, +-1.61668520058867329841e-06, +-1.63487680151331660552e-06, +-1.65205118502362447400e-06, +-1.66820260733800235944e-06, +-1.68332594403215350657e-06, +-1.69741669052133461662e-06, +-1.71047096217573973425e-06, +-1.72248549407075639464e-06, +-1.73345764037363372509e-06, +-1.74338537336835821088e-06, +-1.75226728212076132235e-06, +-1.76010257078606954751e-06, +-1.76689105656130685063e-06, +-1.77263316728519251133e-06, +-1.77732993868832065915e-06, +-1.78098301129675234904e-06, +-1.78359462699196298197e-06, +-1.78516762523086079262e-06, +-1.78570543892935940332e-06, +-1.78521209001314350987e-06, +-1.78369218463975973750e-06, +-1.78115090809610287207e-06, +-1.77759401937562411090e-06, +-1.77302784543973451412e-06, +-1.76745927516809092517e-06, +-1.76089575300256703723e-06, +-1.75334527228990434716e-06, +-1.74481636832821328595e-06, +-1.73531811112254267233e-06, +-1.72486009785515407010e-06, +-1.71345244507588775535e-06, +-1.70110578061850780769e-06, +-1.68783123524888313502e-06, +-1.67364043405101201273e-06, +-1.65854548755706267844e-06, +-1.64255898262770882562e-06, +-1.62569397308913031908e-06, +-1.60796397013341495032e-06, +-1.58938293248850158598e-06, +-1.56996525636511224694e-06, +-1.54972576518680987152e-06, +-1.52867969911091771475e-06, +-1.50684270434656038082e-06, +-1.48423082227753830000e-06, +-1.46086047839705183582e-06, +-1.43674847106163933866e-06, +-1.41191196007170637922e-06, +-1.38636845508614875617e-06, +-1.36013580387858669546e-06, +-1.33323218044282189100e-06, +-1.30567607295518684662e-06, +-1.27748627160150214245e-06, +-1.24868185627640912946e-06, +-1.21928218416289764874e-06, +-1.18930687719987378282e-06, +-1.15877580944566389195e-06, +-1.12770909434537172875e-06, +-1.09612707191003274157e-06, +-1.06405029581553169958e-06, +-1.03149952042926247822e-06, +-9.98495687772529807701e-07, +-9.65059914426676481838e-07, +-9.31213478390952664649e-07, +-8.96977805900184483883e-07, +-8.62374458209779445916e-07, +-8.27425118357190793336e-07, +-7.92151577906262162004e-07, +-7.56575723683538659993e-07, +-7.20719524513991164460e-07, +-6.84605017964106205270e-07, +-6.48254297100182736997e-07, +-6.11689497269627655389e-07, +-5.74932782912928941364e-07, +-5.38006334414506664360e-07, +-5.00932334998829214645e-07, +-4.63732957681074963406e-07, +-4.26430352278680451037e-07, +-3.89046632491231587593e-07, +-3.51603863057291967577e-07, +-3.14124046993758822385e-07, +-2.76629112926271202933e-07, +-2.39140902517306048575e-07, +-2.01681157999109538668e-07, +-1.64271509818435231461e-07, +-1.26933464399964462611e-07, +-8.96883920351864315859e-08, +-5.25575149034115698627e-08, +-1.55618952314867990895e-08, + 2.12775764013299585065e-08, + 5.79401926069906488081e-08, + 9.44054405745448819568e-08, + 1.30653013292186337421e-07, + 1.66662820599558795692e-07, + 2.02415000063943526019e-07, + 2.37889927675723810546e-07, + 2.73068228356823773127e-07, + 3.07930786275391611075e-07, + 3.42458754964303537689e-07, + 3.76633567235821728614e-07, + 4.10436944888391124100e-07, + 4.43850908200505621429e-07, + 4.76857785206895217304e-07, + 5.09440220752432540740e-07, + 5.41581185319310635908e-07, + 5.73263983623200237778e-07, + 6.04472262974243596559e-07, + 6.35190021398912689916e-07, + 6.65401615518975020092e-07, + 6.95091768183470321082e-07, + 7.24245575851318119156e-07, + 7.52848515719723294374e-07, + 7.80886452596346764020e-07, + 8.08345645511779781934e-07, + 8.35212754069576196438e-07, + 8.61474844531168266227e-07, + 8.87119395633187721666e-07, + 9.12134304134851931249e-07, + 9.36507890093278214952e-07, + 9.60228901864740647514e-07, + 9.83286520829949339681e-07, + 1.00567036584242141413e-06, + 1.02737049739676264377e-06, + 1.04837742151761943520e-06, + 1.06868209336723852610e-06, + 1.08827592057027628516e-06, + 1.10715076625582966250e-06, + 1.12529895181575091329e-06, + 1.14271325937887085896e-06, + 1.15938693400089711674e-06, + 1.17531368556989454737e-06, + 1.19048769042744956491e-06, + 1.20490359270577919489e-06, + 1.21855650538120670311e-06, + 1.23144201104462276445e-06, + 1.24355616238968221938e-06, + 1.25489548241968085992e-06, + 1.26545696437420174112e-06, + 1.27523807137680262633e-06, + 1.28423673580516101703e-06, + 1.29245135838526580120e-06, + 1.29988080701139087871e-06, + 1.30652441529377014066e-06, + 1.31238198083599927004e-06, + 1.31745376324439163689e-06, + 1.32174048187173134272e-06, + 1.32524331329766233412e-06, + 1.32796388854876269223e-06, + 1.32990429006080199844e-06, + 1.33106704838625078829e-06, + 1.33145513865011407038e-06, + 1.33107197675730615317e-06, + 1.32992141535492971224e-06, + 1.32800773955295289713e-06, + 1.32533566240690744947e-06, + 1.32191032016635722368e-06, + 1.31773726729301165080e-06, + 1.31282247125248552902e-06, + 1.30717230708382066220e-06, + 1.30079355175099455860e-06, + 1.29369337828076866856e-06, + 1.28587934969133494247e-06, + 1.27735941271630673508e-06, + 1.26814189132872078392e-06, + 1.25823548006989592576e-06, + 1.24764923718779050332e-06, + 1.23639257759010710187e-06, + 1.22447526561697376243e-06, + 1.21190740763842257076e-06, + 1.19869944448191002670e-06, + 1.18486214369488304102e-06, + 1.17040659164850020835e-06, + 1.15534418548697581979e-06, + 1.13968662492878543633e-06, + 1.12344590392501977927e-06, + 1.10663430218058598693e-06, + 1.08926437654394660522e-06, + 1.07134895227114512445e-06, + 1.05290111416989715657e-06, + 1.03393419762981751439e-06, + 1.01446177954410255975e-06, + 9.94497669129371662775e-07, + 9.74055898649058925340e-07, + 9.53150714046586472362e-07, + 9.31796565494312280840e-07, + 9.10008097864302267693e-07, + 8.87800141127001133190e-07, + 8.65187700683895514984e-07, + 8.42185947640272748656e-07, + 8.18810209024182236434e-07, + 7.95075957957726542799e-07, + 7.70998803786799171281e-07, + 7.46594482175384812077e-07, + 7.21878845170593542560e-07, + 6.96867851244202251346e-07, + 6.71577555317616239466e-07, + 6.46024098775229858276e-07, + 6.20223699473059009471e-07, + 5.94192641748351015229e-07, + 5.67947266436226132378e-07, + 5.41503960899324198661e-07, + 5.14879149076390935720e-07, + 4.88089281555710163631e-07, + 4.61150825679230424805e-07, + 4.34080255683209686411e-07, + 4.06894042881135298369e-07, + 3.79608645894640438035e-07, + 3.52240500938070933540e-07, + 3.24806012162310247429e-07, + 2.97321542063398880870e-07, + 2.69803401961428131034e-07, + 2.42267842555118836346e-07, + 2.14731044557422131870e-07, + 1.87209109417413194962e-07, + 1.59718050133666455064e-07, + 1.32273782164225461408e-07, + 1.04892114438199221113e-07, + 7.75887404739308462697e-08, + 5.03792296086632588358e-08, + 2.32790183440865896232e-08, +-3.69659818658931578941e-09, +-3.05324746267394544896e-08, +-5.72136236741530471848e-08, +-8.37252242245850243792e-08, +-1.10052629376678321428e-07, +-1.36181374294073481367e-07, +-1.62097183920627326452e-07, +-1.87785980544769814165e-07, +-2.13233891209139598521e-07, +-2.38427254961746979659e-07, +-2.63352629945029146904e-07, +-2.87996800319276546365e-07, +-3.12346783017024135980e-07, +-3.36389834325182185351e-07, +-3.60113456291384048568e-07, +-3.83505402952390790727e-07, +-4.06553686380447893525e-07, +-4.29246582545680592520e-07, +-4.51572636991498591533e-07, +-4.73520670320518712649e-07, +-4.95079783488583814637e-07, +-5.16239362904583738092e-07, +-5.36989085333807117288e-07, +-5.57318922603415019422e-07, +-5.77219146106557435187e-07, +-5.96680331105458410703e-07, +-6.15693360830245960493e-07, +-6.34249430372643094367e-07, +-6.52340050373084766760e-07, +-6.69957050499727724785e-07, +-6.87092582718938420602e-07, +-7.03739124355339611445e-07, +-7.19889480941261699077e-07, +-7.35536788854606509566e-07, +-7.50674517744575483077e-07, +-7.65296472744807734602e-07, +-7.79396796473609713033e-07, +-7.92969970821073911788e-07, +-8.06010818523039620686e-07, +-8.18514504521946435161e-07, +-8.30476537114796092696e-07, +-8.41892768888536356313e-07, +-8.52759397443332283837e-07, +-8.63072965904298430121e-07, +-8.72830363222411219091e-07, +-8.82028824265426919197e-07, +-8.90665929699767875244e-07, +-8.98739605664438117104e-07, +-9.06248123238310469019e-07, +-9.13190097701748130089e-07, +-9.19564487594497149126e-07, +-9.25370593571038710503e-07, +-9.30608057055225739965e-07, +-9.35276858695977623270e-07, +-9.39377316625935791305e-07, +-9.42910084525095898317e-07, +-9.45876149491550481034e-07, +-9.48276829721570430580e-07, +-9.50113772001370499672e-07, +-9.51388949013003911569e-07, +-9.52104656456936804630e-07, +-9.52263509993941125969e-07, +-9.51868442009069101583e-07, +-9.50922698200532126112e-07, +-9.49429833996434605628e-07, +-9.47393710802382531800e-07, +-9.44818492083089586131e-07, +-9.41708639281177158997e-07, +-9.38068907576461653450e-07, +-9.33904341489098676729e-07, +-9.29220270330045943147e-07, +-9.24022303502344510841e-07, +-9.18316325656801089995e-07, +-9.12108491705894399878e-07, +-9.05405221699414408662e-07, +-8.98213195565829804566e-07, +-8.90539347723179252958e-07, +-8.82390861563444624379e-07, +-8.73775163814392542299e-07, +-8.64699918782943232475e-07, +-8.55173022484167478071e-07, +-8.45202596660064471297e-07, +-8.34796982692334232859e-07, +-8.23964735413379340429e-07, +-8.12714616819815811869e-07, +-8.01055589692947371830e-07, +-7.88996811130245460602e-07, +-7.76547625992668790471e-07, +-7.63717560271924312522e-07, +-7.50516314382267606353e-07, +-7.36953756381291203872e-07, +-7.23039915124214685738e-07, +-7.08784973356202141615e-07, +-6.94199260747239361661e-07, +-6.79293246874135843310e-07, +-6.64077534154205262483e-07, +-6.48562850735273878957e-07, +-6.32760043346189360169e-07, +-6.16680070113397994562e-07, +-6.00333993346826913225e-07, +-5.83732972300828602773e-07, +-5.66888255913847209443e-07, +-5.49811175532121660261e-07, +-5.32513137621453772346e-07, +-5.15005616471779758539e-07, +-4.97300146899023921939e-07, +-4.79408316948729425562e-07, +-4.61341760605933600647e-07, +-4.43112150515734081304e-07, +-4.24731190718963677602e-07, +-4.06210609407354576801e-07, +-3.87562151702548692569e-07, +-3.68797572463265930466e-07, +-3.49928629124907727258e-07, +-3.30967074575835952180e-07, +-3.11924650074512148172e-07, +-2.92813078211650909737e-07, +-2.73644055921480525304e-07, +-2.54429247546160283934e-07, +-2.35180277957349847825e-07, +-2.15908725738868123295e-07, +-1.96626116434371227810e-07, +-1.77343915863602168094e-07, +-1.58073523511642661593e-07, +-1.38826265993976471359e-07, +-1.19613390601659479034e-07, +-1.00446058929897965640e-07, +-8.13353405935726935918e-08, +-6.22922070331324441674e-08, +-4.33275254142092293362e-08, +-2.44520526242285169324e-08, + 0 /* Need a final zero coefficient */ + diff --git a/libk3b/plugin/libsamplerate/mid_qual_coeffs.h b/libk3b/plugin/libsamplerate/mid_qual_coeffs.h new file mode 100644 index 0000000..7bf47df --- /dev/null +++ b/libk3b/plugin/libsamplerate/mid_qual_coeffs.h @@ -0,0 +1,5315 @@ +/* +** Copyright (C) 2002,2003 Erik de Castro Lopo +** +** 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 2 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, write to the Free Software +** Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +/* +** f = make_filter (19, 128, 100.2) ; +** Pass band width : 0.0039063 (should be 0.0039062) +** Stop band atten. : 100.35 dB +** -3dB band width : 0.665 +** half length : 5285 +** increment : 128 +*/ + + 9.20381425342432724079e-01, + 9.20302993473144703707e-01, + 9.20067721990720843728e-01, + 9.19675683262634269255e-01, + 9.19126997871811179941e-01, + 9.18421834572361261984e-01, + 9.17560410227629907887e-01, + 9.16542989730570578644e-01, + 9.15369885906517022356e-01, + 9.14041459398341027409e-01, + 9.12558118534084750095e-01, + 9.10920319177104365060e-01, + 9.09128564558774221460e-01, + 9.07183405093831884969e-01, + 9.05085438178449441793e-01, + 9.02835307971073142141e-01, + 9.00433705156164609917e-01, + 8.97881366690907456451e-01, + 8.95179075534992096941e-01, + 8.92327660363587904513e-01, + 8.89327995263616055688e-01, + 8.86180999413433867495e-01, + 8.82887636746086057471e-01, + 8.79448915596223401714e-01, + 8.75865888330860098421e-01, + 8.72139650964099621966e-01, + 8.68271342755988384532e-01, + 8.64262145795659297853e-01, + 8.60113284568922442652e-01, + 8.55826025510500576488e-01, + 8.51401676541053253899e-01, + 8.46841586589208494829e-01, + 8.42147145098761318316e-01, + 8.37319781521271289115e-01, + 8.32360964794223279206e-01, + 8.27272202804994805092e-01, + 8.22055041840814237908e-01, + 8.16711066024966680921e-01, + 8.11241896739414047879e-01, + 8.05649192034131989004e-01, + 7.99934646023336304310e-01, + 7.94099988268876399999e-01, + 7.88146983151028934778e-01, + 7.82077429226948894758e-01, + 7.75893158577014574462e-01, + 7.69596036139359007677e-01, + 7.63187959032822549332e-01, + 7.56670855868614267159e-01, + 7.50046686050942712498e-01, + 7.43317439066910390366e-01, + 7.36485133765944488538e-01, + 7.29551817629036647439e-01, + 7.22519566028118842560e-01, + 7.15390481475825179558e-01, + 7.08166692865972891013e-01, + 7.00850354705043199210e-01, + 6.93443646334978125445e-01, + 6.85948771147587565977e-01, + 6.78367955790895149626e-01, + 6.70703449367723969488e-01, + 6.62957522626846706970e-01, + 6.55132467147013564102e-01, + 6.47230594514182855370e-01, + 6.39254235492288658271e-01, + 6.31205739187853498429e-01, + 6.23087472208794013184e-01, + 6.14901817817740559136e-01, + 6.06651175080214377644e-01, + 5.98337958007979286990e-01, + 5.89964594697926170141e-01, + 5.81533526466822769940e-01, + 5.73047206982255086238e-01, + 5.64508101390120198282e-01, + 5.55918685439004245374e-01, + 5.47281444601789957005e-01, + 5.38598873194839455891e-01, + 5.29873473495091729113e-01, + 5.21107754855426819063e-01, + 5.12304232818644900149e-01, + 5.03465428230393974296e-01, + 4.94593866351407229764e-01, + 4.85692075969380243627e-01, + 4.76762588510854068424e-01, + 4.67807937153435049460e-01, + 4.58830655938690934459e-01, + 4.49833278886094922733e-01, + 4.40818339108329071419e-01, + 4.31788367928309491095e-01, + 4.22745893998278443604e-01, + 4.13693442421281976085e-01, + 4.04633533875401296687e-01, + 3.95568683741051418945e-01, + 3.86501401231698737959e-01, + 3.77434188528326886036e-01, + 3.68369539917981492216e-01, + 3.59309940936731631034e-01, + 3.50257867517365428789e-01, + 3.41215785142159444554e-01, + 3.32186148001037462318e-01, + 3.23171398155436717659e-01, + 3.14173964708215069930e-01, + 3.05196262979898602641e-01, + 2.96240693691587786418e-01, + 2.87309642154843669637e-01, + 2.78405477468841422439e-01, + 2.69530551725107592187e-01, + 2.60687199220140719547e-01, + 2.51877735676207303861e-01, + 2.43104457470603635416e-01, + 2.34369640873684476068e-01, + 2.25675541295929371621e-01, + 2.17024392544335781308e-01, + 2.08418406088417329514e-01, + 1.99859770336071163044e-01, + 1.91350649919593329695e-01, + 1.82893184992099055997e-01, + 1.74489490534610131034e-01, + 1.66141655674062554970e-01, + 1.57851743012483253237e-01, + 1.49621787967589486845e-01, + 1.41453798125033586297e-01, + 1.33349752602548832225e-01, + 1.25311601426208646393e-01, + 1.17341264919035181968e-01, + 1.09440633102170670199e-01, + 1.01611565108827309190e-01, + 9.38558886112234730392e-02, + 8.61753992607110774760e-02, + 7.85718601412871003875e-02, + 7.10470012366834768880e-02, + 6.36025189112217892440e-02, + 5.62400754046094436545e-02, + 4.89612983408535609731e-02, + 4.17677802514581156257e-02, + 3.46610781130688300200e-02, + 2.76427128997189970605e-02, + 2.07141691498255002546e-02, + 1.38768945480800508230e-02, + 7.13229952237052523822e-03, + 4.81756855863834190269e-04, +-6.07339868562557089193e-03, +-1.25318707108654243260e-02, +-1.88924015449200635719e-02, +-2.51537725552469157431e-02, +-3.13148044620756293988e-02, +-3.73743576329800403224e-02, +-4.33313323615558548818e-02, +-4.91846691301275826258e-02, +-5.49333488564130167919e-02, +-6.05763931240776432041e-02, +-6.61128643971268664670e-02, +-7.15418662180770936754e-02, +-7.68625433898662002719e-02, +-8.20740821414635834952e-02, +-8.71757102771481412473e-02, +-9.21666973094307923065e-02, +-9.70463545756019146937e-02, +-1.01814035337895597566e-01, +-1.06469134867262671396e-01, +-1.11011090510758053673e-01, +-1.15439381742549487808e-01, +-1.19753530198565633080e-01, +-1.23953099694804141917e-01, +-1.28037696229327896402e-01, +-1.32006967967990523904e-01, +-1.35860605213926149970e-01, +-1.39598340360859801690e-01, +-1.43219947830287880342e-01, +-1.46725243992595816289e-01, +-1.50114087072177021520e-01, +-1.53386377036633686499e-01, +-1.56542055470133889550e-01, +-1.59581105431021136321e-01, +-1.62503551293762121821e-01, +-1.65309458575341239328e-01, +-1.67998933746201201123e-01, +-1.70572124025848675943e-01, +-1.73029217163238657751e-01, +-1.75370441202067656183e-01, +-1.77596064231102662712e-01, +-1.79706394119684198518e-01, +-1.81701778238549410682e-01, +-1.83582603166114660675e-01, +-1.85349294380384888026e-01, +-1.87002315936635632454e-01, +-1.88542170131047126524e-01, +-1.89969397150449442746e-01, +-1.91284574708360660678e-01, +-1.92488317667500768993e-01, +-1.93581277648966099125e-01, +-1.94564142628253139433e-01, +-1.95437636518337454206e-01, +-1.96202518740000220188e-01, +-1.96859583779614849552e-01, +-1.97409660734602421250e-01, +-1.97853612846778603718e-01, +-1.98192337023800152496e-01, +-1.98426763348949375398e-01, +-1.98557854579480330681e-01, +-1.98586605633759266665e-01, +-1.98514043067442053081e-01, +-1.98341224538922389353e-01, +-1.98069238264312830200e-01, +-1.97699202462185225082e-01, +-1.97232264788348182760e-01, +-1.96669601760900314424e-01, +-1.96012418175829317146e-01, +-1.95261946513421102978e-01, +-1.94419446335739987131e-01, +-1.93486203675455742390e-01, +-1.92463530416288858271e-01, +-1.91352763665352892941e-01, +-1.90155265117664590280e-01, +-1.88872420413116609561e-01, +-1.87505638486184761371e-01, +-1.86056350908662238020e-01, +-1.84526011225710412367e-01, +-1.82916094285511643402e-01, +-1.81228095562823987574e-01, +-1.79463530476726945695e-01, +-1.77623933702856395822e-01, +-1.75710858480429804596e-01, +-1.73725875914355953888e-01, +-1.71670574272733023058e-01, +-1.69546558280039033617e-01, +-1.67355448406313112031e-01, +-1.65098880152636018348e-01, +-1.62778503333212087867e-01, +-1.60395981354360589455e-01, +-1.57952990490720118766e-01, +-1.55451219158974890400e-01, +-1.52892367189410044448e-01, +-1.50278145095599335868e-01, +-1.47610273342536069130e-01, +-1.44890481613516919346e-01, +-1.42120508076075402482e-01, +-1.39302098647282379673e-01, +-1.36437006258713466877e-01, +-1.33526990121390659594e-01, +-1.30573814991000874963e-01, +-1.27579250433698415668e-01, +-1.24545070092789769700e-01, +-1.21473050956605960193e-01, +-1.18364972627860873255e-01, +-1.15222616594794866063e-01, +-1.12047765504399418623e-01, +-1.08842202438021534716e-01, +-1.05607710189640782716e-01, +-1.02346070547107481641e-01, +-9.90590635766376431670e-02, +-9.57484669108492753020e-02, +-9.24160550406251946054e-02, +-8.90635986110882432731e-02, +-8.56928637219669248060e-02, +-8.23056112326309707861e-02, +-7.89035960720733398066e-02, +-7.54885665541076555929e-02, +-7.20622636980560449249e-02, +-6.86264205551892075841e-02, +-6.51827615411845612270e-02, +-6.17330017748623643969e-02, +-5.82788464234569522637e-02, +-5.48219900546751473525e-02, +-5.13641159957934842484e-02, +-4.79068957000384210154e-02, +-4.44519881204940292552e-02, +-4.10010390917734252048e-02, +-3.75556807196898087553e-02, +-3.41175307791583073969e-02, +-3.06881921205520574736e-02, +-2.72692520847377800619e-02, +-2.38622819270072061837e-02, +-2.04688362501167613050e-02, +-1.70904524466470482402e-02, +-1.37286501508831742385e-02, +-1.03849307004176948793e-02, +-7.06077660767133897385e-03, +-3.75765104151932821316e-03, +-4.76997319211794638602e-04, + 2.77976159123423990222e-03, + 6.01122355799481745270e-03, + 9.21600776157955291212e-03, + 1.23927551599897541740e-02, + 1.55401289427332476439e-02, + 1.86568149735395066857e-02, + 2.17415222216296409596e-02, + 2.47929831813923952366e-02, + 2.78099542803314468686e-02, + 3.07912162751492260448e-02, + 3.37355746358383862260e-02, + 3.66418599176616260893e-02, + 3.95089281209001219608e-02, + 4.23356610382612519317e-02, + 4.51209665898422082608e-02, + 4.78637791455433780907e-02, + 5.05630598348475110426e-02, + 5.32177968438652948535e-02, + 5.58270056995735716732e-02, + 5.83897295411673830645e-02, + 6.09050393784494881189e-02, + 6.33720343372027039575e-02, + 6.57898418914746596631e-02, + 6.81576180827297012366e-02, + 7.04745477258180152980e-02, + 7.27398446017178401668e-02, + 7.49527516370186164263e-02, + 7.71125410701128527480e-02, + 7.92185146040738086270e-02, + 8.12700035461998010478e-02, + 8.32663689342140606042e-02, + 8.52070016491116299928e-02, + 8.70913225146551783773e-02, + 8.89187823835221463620e-02, + 9.06888622101164748601e-02, + 9.24010731100602389354e-02, + 9.40549564063880572107e-02, + 9.56500836624715466971e-02, + 9.71860567017110571486e-02, + 9.86625076140278250980e-02, + 1.00079098749209560726e-01, + 1.01435522697153571170e-01, + 1.02731502255068357643e-01, + 1.03966790381692222867e-01, + 1.05141170138599651662e-01, + 1.06254454618664812005e-01, + 1.07306486861763028529e-01, + 1.08297139757793273174e-01, + 1.09226315937109075271e-01, + 1.10093947648453857613e-01, + 1.10899996624498939357e-01, + 1.11644453935089996155e-01, + 1.12327339828307448677e-01, + 1.12948703559463028978e-01, + 1.13508623208143408223e-01, + 1.14007205483430296145e-01, + 1.14444585517425839738e-01, + 1.14820926647215854066e-01, + 1.15136420185409663053e-01, + 1.15391285179401628658e-01, + 1.15585768159497587204e-01, + 1.15720142876065593129e-01, + 1.15794710025859670655e-01, + 1.15809796967682440694e-01, + 1.15765757427549992320e-01, + 1.15662971193527863711e-01, + 1.15501843800413089847e-01, + 1.15282806204434651320e-01, + 1.15006314448161270358e-01, + 1.14672849315791761104e-01, + 1.14282915979024457531e-01, + 1.13837043633692902578e-01, + 1.13335785127364224723e-01, + 1.12779716578100402957e-01, + 1.12169436984582482353e-01, + 1.11505567827804186187e-01, + 1.10788752664543674320e-01, + 1.10019656712822919142e-01, + 1.09198966429570901160e-01, + 1.08327389080707270352e-01, + 1.07405652303864840302e-01, + 1.06434503663973611953e-01, + 1.05414710201933409239e-01, + 1.04347057976597171192e-01, + 1.03232351600300586991e-01, + 1.02071413768162977398e-01, + 1.00865084781397620906e-01, + 9.96142220648654208581e-02, + 9.83196996791074473432e-02, + 9.69824078270985767691e-02, + 9.56032523559593450102e-02, + 9.41831542538692501054e-02, + 9.27230491424269054335e-02, + 9.12238867646961854030e-02, + 8.96866304691910365410e-02, + 8.81122566900391923639e-02, + 8.65017544235756330462e-02, + 8.48561247016157149670e-02, + 8.31763800616522747111e-02, + 8.14635440142294359189e-02, + 7.97186505077449730772e-02, + 7.79427433909263833733e-02, + 7.61368758732360317865e-02, + 7.43021099834537401829e-02, + 7.24395160266886328770e-02, + 7.05501720400689841250e-02, + 6.86351632473627820685e-02, + 6.66955815127786150187e-02, + 6.47325247941935855156e-02, + 6.27470965960619936341e-02, + 6.07404054222478104186e-02, + 5.87135642290347939398e-02, + 5.66676898785539728820e-02, + 5.46039025928778953833e-02, + 5.25233254090291187821e-02, + 5.04270836351378148876e-02, + 4.83163043079990264794e-02, + 4.61921156522659484556e-02, + 4.40556465415169601352e-02, + 4.19080259614387148903e-02, + 3.97503824753536946779e-02, + 3.75838436923350352470e-02, + 3.54095357381316658274e-02, + 3.32285827291374860626e-02, + 3.10421062496353539206e-02, + 2.88512248325339532018e-02, + 2.66570534438272561950e-02, + 2.44607029709929951755e-02, + 2.22632797155504665032e-02, + 2.00658848899928875242e-02, + 1.78696141193047525197e-02, + 1.56755569472778119589e-02, + 1.34847963478305701845e-02, + 1.12984082415343196903e-02, + 9.11746101754993230892e-03, + 6.94301506117043099736e-03, + 4.77612228716621078223e-03, + 2.61782567912160601259e-03, + 4.69158834953931199938e-04, +-1.66885448120184334310e-03, +-3.79520078056328966087e-03, +-5.90887728454510350456e-03, +-8.00889235270581950621e-03, +-1.00942659036281096735e-02, +-1.21640298285631744818e-02, +-1.42172283976795769261e-02, +-1.62529186587560860178e-02, +-1.82701708281667977996e-02, +-2.02680686740044913030e-02, +-2.22457098911984715861e-02, +-2.42022064684845883420e-02, +-2.61366850470883434199e-02, +-2.80482872709881952966e-02, +-2.99361701286294627777e-02, +-3.17995062859638480401e-02, +-3.36374844106955839251e-02, +-3.54493094876133021942e-02, +-3.72342031249025678941e-02, +-3.89914038513265101549e-02, +-4.07201674041748756805e-02, +-4.24197670078825320172e-02, +-4.40894936432238218615e-02, +-4.57286563069958726380e-02, +-4.73365822621031329120e-02, +-4.89126172779674045499e-02, +-5.04561258611889093539e-02, +-5.19664914763842064604e-02, +-5.34431167571409876382e-02, +-5.48854237070259126652e-02, +-5.62928538905927214331e-02, +-5.76648686143374361590e-02, +-5.90009490975559047765e-02, +-6.03005966330638770723e-02, +-6.15633327377404851455e-02, +-6.27886992928659848356e-02, +-6.39762586742271682771e-02, +-6.51255938719669663639e-02, +-6.62363086001636625078e-02, +-6.73080273961252362191e-02, +-6.83403957093936531564e-02, +-6.93330799804545011567e-02, +-7.02857677091563298744e-02, +-7.11981675128459667867e-02, +-7.20700091742300513742e-02, +-7.29010436789823551562e-02, +-7.36910432431144429843e-02, +-7.44398013301399846808e-02, +-7.51471326580581411303e-02, +-7.58128731961966451092e-02, +-7.64368801519491603003e-02, +-7.70190319474562123947e-02, +-7.75592281862732546571e-02, +-7.80573896100858338754e-02, +-7.85134580455219832640e-02, +-7.89273963411314394278e-02, +-7.92991882945930925963e-02, +-7.96288385702248469045e-02, +-7.99163726068679303172e-02, +-8.01618365162299895132e-02, +-8.03652969717648935077e-02, +-8.05268410881816582014e-02, +-8.06465762916719064446e-02, +-8.07246301809524391402e-02, +-8.07611503792237672705e-02, +-8.07563043771459543319e-02, +-8.07102793669422780010e-02, +-8.06232820677405676024e-02, +-8.04955385422673613816e-02, +-8.03272940050135386691e-02, +-8.01188126219958829388e-02, +-7.98703773022373386681e-02, +-7.95822894810978148650e-02, +-7.92548688955872077111e-02, +-7.88884533517974217975e-02, +-7.84833984845913629202e-02, +-7.80400775096937587838e-02, +-7.75588809683271651618e-02, +-7.70402164645424963885e-02, +-7.64845083953963472689e-02, +-7.58921976741284420864e-02, +-7.52637414464975562645e-02, +-7.45996128004335623540e-02, +-7.39003004691712872543e-02, +-7.31663085280282593503e-02, +-7.23981560849959182580e-02, +-7.15963769653113479841e-02, +-7.07615193901859063086e-02, +-6.98941456498595042879e-02, +-6.89948317711622932658e-02, +-6.80641671797573843961e-02, +-6.71027543572484258538e-02, +-6.61112084933319216207e-02, +-6.50901571331780198770e-02, +-6.40402398202278705375e-02, +-6.29621077345897672828e-02, +-6.18564233272276414732e-02, +-6.07238599501278633608e-02, +-5.95651014826367106170e-02, +-5.83808419541620299276e-02, +-5.71717851634284957019e-02, +-5.59386442944868889082e-02, +-5.46821415296654678162e-02, +-5.34030076596649916354e-02, +-5.21019816909916097525e-02, +-5.07798104509243897198e-02, +-4.94372481902171159729e-02, +-4.80750561837304871138e-02, +-4.66940023291949543593e-02, +-4.52948607443019804486e-02, +-4.38784113623226362799e-02, +-4.24454395264523623443e-02, +-4.09967355830820473495e-02, +-3.95330944741913298257e-02, +-3.80553153290659820773e-02, +-3.65642010555344981748e-02, +-3.50605579309238787888e-02, +-3.35451951929296859900e-02, +-3.20189246305989869135e-02, +-3.04825601756209853266e-02, +-2.89369174941192380812e-02, +-2.73828135791425071599e-02, +-2.58210663440446019923e-02, +-2.42524942169475357656e-02, +-2.26779157364765740490e-02, +-2.10981491489598167732e-02, +-1.95140120072784944982e-02, +-1.79263207715556205368e-02, +-1.63358904118689959861e-02, +-1.47435340131725541729e-02, +-1.31500623826066934119e-02, +-1.15562836593809201841e-02, +-9.96300292740478522779e-03, +-8.37102183084635804999e-03, +-6.78113819279113280714e-03, +-5.19414563717416049443e-03, +-3.61083321415951816885e-03, +-2.03198502912982836496e-03, +-4.58379875457016528785e-04, + 1.10920912878408159559e-03, + 2.67001489999788748156e-03, + 4.22327674398739229267e-03, + 5.76824070645192907292e-03, + 7.30415991891262585123e-03, + 8.83029493991307340428e-03, + 1.03459140913472139728e-02, + 1.18502937897689078484e-02, + 1.33427188725394711699e-02, + 1.48224829186761088151e-02, + 1.62888885642629918649e-02, + 1.77412478122899279487e-02, + 1.91788823367922064977e-02, + 2.06011237811589489888e-02, + 2.20073140504912223570e-02, + 2.33968055978847275234e-02, + 2.47689617045220474012e-02, + 2.61231567534600458980e-02, + 2.74587764969989392427e-02, + 2.87752183175302503337e-02, + 3.00718914817559267172e-02, + 3.13482173881795972425e-02, + 3.26036298077741898416e-02, + 3.38375751177299316508e-02, + 3.50495125281968383790e-02, + 3.62389143019323234363e-02, + 3.74052659667742509741e-02, + 3.85480665208594169835e-02, + 3.96668286305130596281e-02, + 4.07610788207384555637e-02, + 4.18303576582400582495e-02, + 4.28742199269152648999e-02, + 4.38922347957571498678e-02, + 4.48839859791098777508e-02, + 4.58490718892284668251e-02, + 4.67871057810912635566e-02, + 4.76977158894239181008e-02, + 4.85805455578927625204e-02, + 4.94352533604324947958e-02, + 5.02615132146747092823e-02, + 5.10590144874505449946e-02, + 5.18274620923405288098e-02, + 5.25665765792536696099e-02, + 5.32760942160161940495e-02, + 5.39557670619600152073e-02, + 5.46053630334999498541e-02, + 5.52246659616954863048e-02, + 5.58134756417962285546e-02, + 5.63716078747732926568e-02, + 5.68988945008435942352e-02, + 5.73951834249974424118e-02, + 5.78603386345437897820e-02, + 5.82942402086913807890e-02, + 5.86967843201876629533e-02, + 5.90678832290408364902e-02, + 5.94074652683551154841e-02, + 5.97154748223121395467e-02, + 5.99918722963358186373e-02, + 6.02366340794795798730e-02, + 6.04497524990822918123e-02, + 6.06312357677402588574e-02, + 6.07811079226447462109e-02, + 6.08994087573431347460e-02, + 6.09861937459786132565e-02, + 6.10415339600735781800e-02, + 6.10655159779199541159e-02, + 6.10582417866455048894e-02, + 6.10198286770287368075e-02, + 6.09504091311373757955e-02, + 6.08501307028684462752e-02, + 6.07191558914731074892e-02, + 6.05576620081493127712e-02, + 6.03658410357920463540e-02, + 6.01438994819913433365e-02, + 5.98920582253712890930e-02, + 5.96105523553696475814e-02, + 5.92996310055547357076e-02, + 5.89595571805846263569e-02, + 5.85906075769135961662e-02, + 5.81930723973530239501e-02, + 5.77672551595985947492e-02, + 5.73134724988377947108e-02, + 5.68320539645518138516e-02, + 5.63233418116318024227e-02, + 5.57876907859301829351e-02, + 5.52254679043691909524e-02, + 5.46370522297332239514e-02, + 5.40228346402717510277e-02, + 5.33832175942438452720e-02, + 5.27186148895339920517e-02, + 5.20294514184751963337e-02, + 5.13161629180133513350e-02, + 5.05791957153526455793e-02, + 4.98190064692186004858e-02, + 4.90360619068817560340e-02, + 4.82308385570846126500e-02, + 4.74038224790149093080e-02, + 4.65555089874726130139e-02, + 4.56864023743756911267e-02, + 4.47970156267560870589e-02, + 4.38878701413918104191e-02, + 4.29594954362301426065e-02, + 4.20124288587509150950e-02, + 4.10472152914242438548e-02, + 4.00644068544164441703e-02, + 3.90645626056996611575e-02, + 3.80482482387188569728e-02, + 3.70160357777762072384e-02, + 3.59685032712854929615e-02, + 3.49062344830574772248e-02, + 3.38298185817733007563e-02, + 3.27398498288028888537e-02, + 3.16369272645302956892e-02, + 3.05216543933420694779e-02, + 2.93946388674391281826e-02, + 2.82564921696314662325e-02, + 2.71078292952747976208e-02, + 2.59492684335090040282e-02, + 2.47814306479556094309e-02, + 2.36049395570361274233e-02, + 2.24204210140672086093e-02, + 2.12285027872915685321e-02, + 2.00298142400041241651e-02, + 1.88249860109280658937e-02, + 1.76146496949991550329e-02, + 1.63994375247131611573e-02, + 1.51799820521929199751e-02, + 1.39569158321288973312e-02, + 1.27308711057459132687e-02, + 1.15024794859493635635e-02, + 1.02723716438034538834e-02, + 9.04117699648874194318e-03, + 7.80952339689281599400e-03, + 6.57803682497710377058e-03, + 5.34734108107065390925e-03, + 4.11805748123311807923e-03, + 2.89080455483250748500e-03, + 1.66619774448026097997e-03, + 4.44849108462394484276e-04, +-7.72632974192619353775e-04, +-1.98564409587129479459e-03, +-3.19358410962515939027e-03, +-4.39585741537518604610e-03, +-5.59187324294384193596e-03, +-6.78104593178024354222e-03, +-7.96279520725374188872e-03, +-9.13654645338901789942e-03, +-1.03017309819179135599e-02, +-1.14577862975281108415e-02, +-1.26041563591888523127e-02, +-1.37402918374362748022e-02, +-1.48656503675044012608e-02, +-1.59796967981878784704e-02, +-1.70819034363291870349e-02, +-1.81717502868205364741e-02, +-1.92487252880175659098e-02, +-2.03123245424604338683e-02, +-2.13620525428040268501e-02, +-2.23974223928605567502e-02, +-2.34179560236593246880e-02, +-2.44231844044319607034e-02, +-2.54126477484353970049e-02, +-2.63858957135253285875e-02, +-2.73424875973971651111e-02, +-2.82819925274152735029e-02, +-2.92039896449517132060e-02, +-3.01080682841611060874e-02, +-3.09938281451182656712e-02, +-3.18608794612527251866e-02, +-3.27088431610126698090e-02, +-3.35373510236956218211e-02, +-3.43460458293886189418e-02, +-3.51345815029584646050e-02, +-3.59026232520415142235e-02, +-3.66498476989806504234e-02, +-3.73759430066653228208e-02, +-3.80806089982259413085e-02, +-3.87635572705481989964e-02, +-3.94245113015637763110e-02, +-4.00632065512871449187e-02, +-4.06793905565660182666e-02, +-4.12728230195161804872e-02, +-4.18432758896181006270e-02, +-4.23905334394521562946e-02, +-4.29143923340550431655e-02, +-4.34146616938810431252e-02, +-4.38911631513571320884e-02, +-4.43437309010235244933e-02, +-4.47722117432520008706e-02, +-4.51764651215424140052e-02, +-4.55563631533957985598e-02, +-4.59117906547691981278e-02, +-4.62426451581186420681e-02, +-4.65488369240420196693e-02, +-4.68302889465325583584e-02, +-4.70869369518625499604e-02, +-4.73187293911136036551e-02, +-4.75256274263797934276e-02, +-4.77076049106652452791e-02, +-4.78646483615089088359e-02, +-4.79967569283660938639e-02, +-4.81039423537813551346e-02, +-4.81862289283918193705e-02, +-4.82436534398009986280e-02, +-4.82762651153660765635e-02, +-4.82841255589469900422e-02, +-4.82673086816636301433e-02, +-4.82259006267171733140e-02, +-4.81599996883273831494e-02, +-4.80697162248445095112e-02, +-4.79551725660972635867e-02, +-4.78165029150386111656e-02, +-4.76538532437557615928e-02, +-4.74673811839129988766e-02, +-4.72572559116971463444e-02, +-4.70236580273407853148e-02, +-4.67667794292976057857e-02, +-4.64868231831488537553e-02, +-4.61840033853220879867e-02, +-4.58585450217043055776e-02, +-4.55106838212354786188e-02, +-4.51406661045703067048e-02, +-4.47487486278967949715e-02, +-4.43351984220053674246e-02, +-4.39002926267011706063e-02, +-4.34443183206557337339e-02, +-4.29675723467968784242e-02, +-4.24703611333365343983e-02, +-4.19530005105376649355e-02, +-4.14158155233245728333e-02, +-4.08591402398425090903e-02, +-4.02833175560728118381e-02, +-3.96886989966125647289e-02, +-3.90756445117304562764e-02, +-3.84445222708086342678e-02, +-3.77957084522856853748e-02, +-3.71295870302152039577e-02, +-3.64465495575560030628e-02, +-3.57469949463106728693e-02, +-3.50313292446328208851e-02, +-3.42999654110217877534e-02, +-3.35533230857262762536e-02, +-3.27918283594781714840e-02, +-3.20159135396808763874e-02, +-3.12260169141751545152e-02, +-3.04225825127068701115e-02, +-2.96060598662241068746e-02, +-2.87769037641279583351e-02, +-2.79355740096046620269e-02, +-2.70825351731674365818e-02, +-2.62182563445339765484e-02, +-2.53432108829716763732e-02, +-2.44578761662360491536e-02, +-2.35627333382326387134e-02, +-2.26582670555346976649e-02, +-2.17449652328813719526e-02, +-2.08233187877915476571e-02, +-1.98938213844193738378e-02, +-1.89569691767836438767e-02, +-1.80132605515005567165e-02, +-1.70631958701489179486e-02, +-1.61072772113989640119e-02, +-1.51460081130329674015e-02, +-1.41798933139869222375e-02, +-1.32094384965426719925e-02, +-1.22351500287977872639e-02, +-1.12575347075429474386e-02, +-1.02770995016708190789e-02, +-9.29435129624720662855e-03, +-8.30979663736668323903e-03, +-7.32394147791955510418e-03, +-6.33729092439597792991e-03, +-5.35034898484767259402e-03, +-4.36361831813259892082e-03, +-3.37759998456233596562e-03, +-2.39279319807447028376e-03, +-1.40969508004874419758e-03, +-4.28800414884481764701e-04, + 5.49398592542026499921e-04, + 1.52441255742493384819e-03, + 2.49575515346705124192e-03, + 3.46294334909421361660e-03, + 4.42549764133481383921e-03, + 5.38294228725484918269e-03, + 6.33480553283812409388e-03, + 7.28061983920614500670e-03, + 8.21992210606954480656e-03, + 9.15225389230991427658e-03, + 1.00771616335884814375e-02, + 1.09941968568804098599e-02, + 1.19029163918370119862e-02, + 1.28028825788794285712e-02, + 1.36936634739278067369e-02, + 1.45748330496734655737e-02, + 1.54459713933036285605e-02, + 1.63066649005877105372e-02, + 1.71565064662418664820e-02, + 1.79950956704824222010e-02, + 1.88220389616893905849e-02, + 1.96369498350979915235e-02, + 2.04394490074384753420e-02, + 2.12291645874509368741e-02, + 2.20057322421993752093e-02, + 2.27687953591133446229e-02, + 2.35180052036899414625e-02, + 2.42530210727860510989e-02, + 2.49735104434401083973e-02, + 2.56791491171582640651e-02, + 2.63696213596067048635e-02, + 2.70446200356534542653e-02, + 2.77038467397033236206e-02, + 2.83470119212748915272e-02, + 2.89738350057704117935e-02, + 2.95840445103900430424e-02, + 3.01773781551470283990e-02, + 3.07535829689405612597e-02, + 3.13124153906489052779e-02, + 3.18536413652031544230e-02, + 3.23770364346098321606e-02, + 3.28823858238901367557e-02, + 3.33694845219050725826e-02, + 3.38381373570426913222e-02, + 3.42881590677418662816e-02, + 3.47193743678329280744e-02, + 3.51316180066747196786e-02, + 3.55247348240743179848e-02, + 3.58985797999757036414e-02, + 3.62530180989057912444e-02, + 3.65879251091717136446e-02, + 3.69031864768026920953e-02, + 3.71986981342348130286e-02, + 3.74743663237384755371e-02, + 3.77301076155911810361e-02, + 3.79658489210015839821e-02, + 3.81815274997910139576e-02, + 3.83770909628457501661e-02, + 3.85524972693506232102e-02, + 3.87077147188212219997e-02, + 3.88427219379517477127e-02, + 3.89575078623010107037e-02, + 3.90520717128378727634e-02, + 3.91264229673738417326e-02, + 3.91805813269093319851e-02, + 3.92145766769267448137e-02, + 3.92284490436606639308e-02, + 3.92222485453833716318e-02, + 3.91960353387427393179e-02, + 3.91498795601925853038e-02, + 3.90838612625587153437e-02, + 3.89980703467861372635e-02, + 3.88926064889137598768e-02, + 3.87675790623278684888e-02, + 3.86231070553441427351e-02, + 3.84593189841744911850e-02, + 3.82763528013330134314e-02, + 3.80743557995419576456e-02, + 3.78534845111941978257e-02, + 3.76139046034402041441e-02, + 3.73557907689583551525e-02, + 3.70793266124797640804e-02, + 3.67847045331337260676e-02, + 3.64721256026843687614e-02, + 3.61417994397318920186e-02, + 3.57939440799517269443e-02, + 3.54287858424472551500e-02, + 3.50465591922946295700e-02, + 3.46475065993586336943e-02, + 3.42318783934602438590e-02, + 3.37999326159794388769e-02, + 3.33519348679760310739e-02, + 3.28881581549163512501e-02, + 3.24088827280907126882e-02, + 3.19143959228117141125e-02, + 3.14049919934835039537e-02, + 3.08809719456320137809e-02, + 3.03426433649902835277e-02, + 2.97903202437320435703e-02, + 2.92243228039485228309e-02, + 2.86449773184645310742e-02, + 2.80526159290918272737e-02, + 2.74475764624171579553e-02, + 2.68302022432251076334e-02, + 2.62008419056547099679e-02, + 2.55598492021924458828e-02, + 2.49075828106016076979e-02, + 2.42444061388931500489e-02, + 2.35706871284384854304e-02, + 2.28867980553310382263e-02, + 2.21931153300989475463e-02, + 2.14900192958749729211e-02, + 2.07778940251304410081e-02, + 2.00571271150767407865e-02, + 1.93281094818433703264e-02, + 1.85912351535375483524e-02, + 1.78469010622939669442e-02, + 1.70955068354214992365e-02, + 1.63374545857532041393e-02, + 1.55731487013095522970e-02, + 1.48029956343801779445e-02, + 1.40274036901342491479e-02, + 1.32467828148644800601e-02, + 1.24615443839752523814e-02, + 1.16721009898197274068e-02, + 1.08788662294939664221e-02, + 1.00822544926967554851e-02, + 9.28268074975848594965e-03, + 8.48056033994836096224e-03, + 7.67630876016376067356e-03, + 6.87034145410842303492e-03, + 6.06307360206417237519e-03, + 5.25491991135924960826e-03, + 4.44629440763854959229e-03, + 3.63761022703795386390e-03, + 2.82927940936458007654e-03, + 2.02171269238637712692e-03, + 1.21531930732854268409e-03, + 4.10506775680379075531e-04, +-3.92319292591773477897e-04, +-1.19275539932616717227e-03, +-1.99040035684389668771e-03, +-2.78485548493010359392e-03, +-3.57572480602225085608e-03, +-4.36261523851058825862e-03, +-5.14513678806150041162e-03, +-5.92290273686880194143e-03, +-6.69552983074627079685e-03, +-7.46263846397084845696e-03, +-8.22385286178995214557e-03, +-8.97880126050735853649e-03, +-9.72711608506233310623e-03, +-1.04684341240196421979e-02, +-1.12023967018896625919e-02, +-1.19286498486973670946e-02, +-1.26468444667234853479e-02, +-1.33566364943390990250e-02, +-1.40576870668614704873e-02, +-1.47496626743549175825e-02, +-1.54322353163073335003e-02, +-1.61050826531120676310e-02, +-1.67678881542855998110e-02, +-1.74203412433571909468e-02, +-1.80621374393645714451e-02, +-1.86929784948938332301e-02, +-1.93125725306022809347e-02, +-1.99206341661660978060e-02, +-2.05168846475965727105e-02, +-2.11010519708690891250e-02, +-2.16728710018125117487e-02, +-2.22320835922093923420e-02, +-2.27784386920556920775e-02, +-2.33116924579366280312e-02, +-2.38316083574713066806e-02, +-2.43379572697852361585e-02, +-2.48305175819705514773e-02, +-2.53090752814938702020e-02, +-2.57734240445178890144e-02, +-2.62233653201022591517e-02, +-2.66587084102499136118e-02, +-2.70792705457725754736e-02, +-2.74848769579453880429e-02, +-2.78753609459266790682e-02, +-2.82505639399193153594e-02, +-2.86103355600531468472e-02, +-2.89545336709700236455e-02, +-2.92830244320940215330e-02, +-2.95956823435738237971e-02, +-2.98923902878850261677e-02, +-3.01730395670819218079e-02, +-3.04375299356923270655e-02, +-3.06857696292481205158e-02, +-3.09176753884519220361e-02, +-3.11331724789744579418e-02, +-3.13321947068878961518e-02, +-3.15146844297364905896e-02, +-3.16805925632501414468e-02, +-3.18298785837100445262e-02, +-3.19625105259753808373e-02, +-3.20784649771835711496e-02, +-3.21777270661380843109e-02, +-3.22602904484012090180e-02, +-3.23261572871092819903e-02, +-3.23753382295313973938e-02, +-3.24078523793953007792e-02, +-3.24237272650036850719e-02, +-3.24229988031694352224e-02, +-3.24057112589975146455e-02, +-3.23719172015455164404e-02, +-3.23216774553950619842e-02, +-3.22550610481695601561e-02, +-3.21721451540349229203e-02, +-3.20730150332222269105e-02, +-3.19577639676131355917e-02, +-3.18264931924307492572e-02, +-3.16793118240798893259e-02, +-3.15163367841841124406e-02, +-3.13376927198667984409e-02, +-3.11435119203261716325e-02, +-3.09339342297566856355e-02, +-3.07091069566692957682e-02, +-3.04691847796660503223e-02, +-3.02143296497258302680e-02, +-2.99447106890591077666e-02, +-2.96605040865920502324e-02, +-2.93618929901409558836e-02, +-2.90490673953408620744e-02, +-2.87222240313914564669e-02, +-2.83815662436870431995e-02, +-2.80273038733983362314e-02, +-2.76596531340728875314e-02, +-2.72788364853265505316e-02, +-2.68850825036951179836e-02, +-2.64786257507202589523e-02, +-2.60597066383420963853e-02, +-2.56285712916748155410e-02, +-2.51854714092403474124e-02, +-2.47306641207374125480e-02, +-2.42644118424243347698e-02, +-2.37869821301946587910e-02, +-2.32986475304263404573e-02, +-2.27996854286841091342e-02, +-2.22903778963591883699e-02, +-2.17710115353269804961e-02, +-2.12418773207074841614e-02, +-2.07032704418132450230e-02, +-2.01554901413684046940e-02, +-1.95988395530860316784e-02, +-1.90336255376889230961e-02, +-1.84601585174617617569e-02, +-1.78787523094215382302e-02, +-1.72897239571940322667e-02, +-1.66933935616846752803e-02, +-1.60900841106333160335e-02, +-1.54801213071404045879e-02, +-1.48638333972560768986e-02, +-1.42415509967192804169e-02, +-1.36136069169392123768e-02, +-1.29803359903072849241e-02, +-1.23420748949298001579e-02, +-1.16991619788734471652e-02, +-1.10519370840110493781e-02, +-1.04007413695592701441e-02, +-9.74591713539885336204e-03, +-9.08780764526554395155e-03, +-8.42675694990374125892e-03, +-7.76310971027038485004e-03, +-7.09721102088000169172e-03, +-6.42940623337920000302e-03, +-5.76004078043931225933e-03, +-5.08946000005612835676e-03, +-4.41800896034429992076e-03, +-3.74603228491338785533e-03, +-3.07387397891339432532e-03, +-2.40187725583507205585e-03, +-1.73038436515272897598e-03, +-1.05973642089167863906e-03, +-3.90273231208217510901e-04, + 2.77666870936983212030e-04, + 9.43747195927376416637e-04, + 1.60763286437934816049e-03, + 2.26899097268967123858e-03, + 2.92749075716241266912e-03, + 3.58280375663248612170e-03, + 4.23460397351204959754e-03, + 4.88256803317746110316e-03, + 5.52637534162357668688e-03, + 6.16570824130805751617e-03, + 6.80025216511182754170e-03, + 7.42969578834302112058e-03, + 8.05373117871052007777e-03, + 8.67205394419879975476e-03, + 9.28436337877218062498e-03, + 9.89036260584076794278e-03, + 1.04897587194219873291e-02, + 1.10822629229305347903e-02, + 1.16675906655330941658e-02, + 1.22454617760050857300e-02, + 1.28156005940266576326e-02, + 1.33777360988594062191e-02, + 1.39316020353439252305e-02, + 1.44769370371622355803e-02, + 1.50134847473070466572e-02, + 1.55409939357074259464e-02, + 1.60592186139547725421e-02, + 1.65679181470810912846e-02, + 1.70668573623377166359e-02, + 1.75558066549289203129e-02, + 1.80345420906532633021e-02, + 1.85028455054086320153e-02, + 1.89605046015185567387e-02, + 1.94073130408384669776e-02, + 1.98430705346031681369e-02, + 2.02675829299774241943e-02, + 2.06806622932754168021e-02, + 2.10821269898129222409e-02, + 2.14718017603625459244e-02, + 2.18495177941796202281e-02, + 2.22151127985720682478e-02, + 2.25684310649855168762e-02, + 2.29093235315810418717e-02, + 2.32376478422810298086e-02, + 2.35532684022618996056e-02, + 2.38560564298757396551e-02, + 2.41458900049817716538e-02, + 2.44226541136732810955e-02, + 2.46862406893853837675e-02, + 2.49365486503724774481e-02, + 2.51734839335446165809e-02, + 2.53969595246556420487e-02, + 2.56068954848354853049e-02, + 2.58032189734641453915e-02, + 2.59858642673822630431e-02, + 2.61547727764399259853e-02, + 2.63098930553838268598e-02, + 2.64511808120856638238e-02, + 2.65785989121172516736e-02, + 2.66921173796784670651e-02, + 2.67917133948867500215e-02, + 2.68773712874392570193e-02, + 2.69490825266583827746e-02, + 2.70068457079358954787e-02, + 2.70506665355911626869e-02, + 2.70805578021602322281e-02, + 2.70965393641366091015e-02, + 2.70986381141830531827e-02, + 2.70868879498386908034e-02, + 2.70613297387449595888e-02, + 2.70220112804171637422e-02, + 2.69689872645891524916e-02, + 2.69023192261612989484e-02, + 2.68220754967820745884e-02, + 2.67283311530973760606e-02, + 2.66211679617003732501e-02, + 2.65006743208199592454e-02, + 2.63669451987833119988e-02, + 2.62200820692939373657e-02, + 2.60601928435633990733e-02, + 2.58873917993413214800e-02, + 2.57017995068857182939e-02, + 2.55035427519193710899e-02, + 2.52927544556184984159e-02, + 2.50695735916821975386e-02, + 2.48341451005307974065e-02, + 2.45866198006852616775e-02, + 2.43271542973778100161e-02, + 2.40559108884488212499e-02, + 2.37730574675824729569e-02, + 2.34787674249385819314e-02, + 2.31732195452361150467e-02, + 2.28565979033475072391e-02, + 2.25290917574611608554e-02, + 2.21908954398750551951e-02, + 2.18422082454798119344e-02, + 2.14832343179954671220e-02, + 2.11141825340238932507e-02, + 2.07352663849828984521e-02, + 2.03467038569848726604e-02, + 1.99487173087274823058e-02, + 1.95415333474632871291e-02, + 1.91253827031149341298e-02, + 1.87005001006056471857e-02, + 1.82671241304729649324e-02, + 1.78254971178373536334e-02, + 1.73758649897937239581e-02, + 1.69184771412996537432e-02, + 1.64535862996303787475e-02, + 1.59814483874737844893e-02, + 1.55023223847373312068e-02, + 1.50164701891417791402e-02, + 1.45241564756737676078e-02, + 1.40256485549719173145e-02, + 1.35212162307227472952e-02, + 1.30111316561379447565e-02, + 1.24956691895912394563e-02, + 1.19751052494878589688e-02, + 1.14497181684445926975e-02, + 1.09197880468538122134e-02, + 1.03855966059087159725e-02, + 9.84742704016562143965e-03, + 9.30556386971926295659e-03, + 8.76029279206604755137e-03, + 8.21190053373426452621e-03, + 7.66067470175298657897e-03, + 7.10690363503945106427e-03, + 6.55087625577790554771e-03, + 5.99288192086684483317e-03, + 5.43321027350959859931e-03, + 4.87215109502278989617e-03, + 4.30999415693893248719e-03, + 3.74702907347534584434e-03, + 3.18354515444554302464e-03, + 2.61983125868587608809e-03, + 2.05617564807023672779e-03, + 1.49286584218635853295e-03, + 9.30188473745678081825e-04, + 3.68429144797911432754e-04, +-1.92127716177123029819e-04, +-7.51198996231790326432e-04, +-1.30850303889562991251e-03, +-1.86375978403549190029e-03, +-2.41669090655965632108e-03, +-2.96701995390177180115e-03, +-3.51447248221491799144e-03, +-4.05877619121137057229e-03, +-4.59966105758124674252e-03, +-5.13685946692752325171e-03, +-5.67010634415242211620e-03, +-6.19913928223347811958e-03, +-6.72369866932763082107e-03, +-7.24352781414225668777e-03, +-7.75837306951438713393e-03, +-8.26798395413882135363e-03, +-8.77211327238880053669e-03, +-9.27051723217174085401e-03, +-9.76295556076584719607e-03, +-1.02491916185828580571e-02, +-1.07289925108050229752e-02, +-1.12021291968433227976e-02, +-1.16683765975679858140e-02, +-1.21275137002619763649e-02, +-1.25793236612475982372e-02, +-1.30235939061431136438e-02, +-1.34601162277011333901e-02, +-1.38886868811863382206e-02, +-1.43091066772499612286e-02, +-1.47211810722588463257e-02, +-1.51247202560407922184e-02, +-1.55195392370066180543e-02, +-1.59054579246123636849e-02, +-1.62823012091269786472e-02, +-1.66498990386690776111e-02, +-1.70080864934834194435e-02, +-1.73567038574233001302e-02, +-1.76955966866107171354e-02, +-1.80246158752456059338e-02, +-1.83436177185377254084e-02, +-1.86524639727363474029e-02, +-1.89510219122339153286e-02, +-1.92391643837212557300e-02, +-1.95167698573757708580e-02, +-1.97837224750605396306e-02, +-2.00399120955206018480e-02, +-2.02852343365580237156e-02, +-2.05195906141726648608e-02, +-2.07428881786561915279e-02, +-2.09550401476275363621e-02, +-2.11559655360012838221e-02, +-2.13455892828807378137e-02, +-2.15238422753686667321e-02, +-2.16906613692930197446e-02, +-2.18459894068418723767e-02, +-2.19897752311081634558e-02, +-2.21219736975437064608e-02, +-2.22425456823232385595e-02, +-2.23514580876230314899e-02, +-2.24486838438175441424e-02, +-2.25342019086016941143e-02, +-2.26079972630452222249e-02, +-2.26700609045897422122e-02, +-2.27203898369985682337e-02, +-2.27589870572722542674e-02, +-2.27858615395436989171e-02, +-2.28010282159679666947e-02, +-2.28045079546240481161e-02, +-2.27963275344472623973e-02, +-2.27765196172116414497e-02, +-2.27451227165837051303e-02, +-2.27021811642711575374e-02, +-2.26477450732895796426e-02, +-2.25818702983737081003e-02, +-2.25046183935598033410e-02, +-2.24160565669674592681e-02, +-2.23162576328110422164e-02, +-2.22052999606712764269e-02, +-2.20832674220598039472e-02, +-2.19502493343100429923e-02, +-2.18063404018299551723e-02, +-2.16516406547519850434e-02, +-2.14862553850184781479e-02, +-2.13102950799411924865e-02, +-2.11238753532740700103e-02, +-2.09271168738412970123e-02, +-2.07201452917621688210e-02, +-2.05030911623162483137e-02, +-2.02760898674933312535e-02, +-2.00392815352738624946e-02, +-1.97928109566855824075e-02, +-1.95368275006852568088e-02, +-1.92714850269127511984e-02, +-1.89969417963674683247e-02, +-1.87133603800582019872e-02, +-1.84209075656767175266e-02, +-1.81197542623479680712e-02, +-1.78100754035098000905e-02, +-1.74920498479764381650e-02, +-1.71658602792400527548e-02, +-1.68316931030659776292e-02, +-1.64897383434381879230e-02, +-1.61401895369109177336e-02, +-1.57832436254263346054e-02, +-1.54191008476533275573e-02, +-1.50479646289087866384e-02, +-1.46700414697199573583e-02, +-1.42855408330877838713e-02, +-1.38946750305117498053e-02, +-1.34976591068377456406e-02, +-1.30947107239892130554e-02, +-1.26860500436455827383e-02, +-1.22718996089274719891e-02, +-1.18524842251538416876e-02, +-1.14280308397327317466e-02, +-1.09987684212486756113e-02, +-1.05649278378112127658e-02, +-1.01267417347274506223e-02, +-9.68444441156269923698e-03, +-9.23827169865409740523e-03, +-8.78846083313997161746e-03, +-8.33525033457069991494e-03, +-7.87887988016375100109e-03, +-7.41959017977004194749e-03, +-6.95762285061261864794e-03, +-6.49322029186454475341e-03, +-6.02662555912889408988e-03, +-5.55808223888622741915e-03, +-5.08783432297227420499e-03, +-4.61612608315053844776e-03, +-4.14320194584339666216e-03, +-3.66930636708468534829e-03, +-3.19468370775774284862e-03, +-2.71957810918098006822e-03, +-2.24423336910424412252e-03, +-1.76889281817741881794e-03, +-1.29379919695378617014e-03, +-8.19194533489142270866e-04, +-3.45320021597831196877e-04, + 1.27584100174339069422e-04, + 5.99278668799195350127e-04, + 1.06952571617924155171e-03, + 1.53808858766556200148e-03, + 2.00473205962055367468e-03, + 2.46922245597071959855e-03, + 2.93132776369034713654e-03, + 3.39081774716058033034e-03, + 3.84746406134854872921e-03, + 4.30104036375060765768e-03, + 4.75132242504706578390e-03, + 5.19808823841395525878e-03, + 5.64111812743960539668e-03, + 6.08019485259521982184e-03, + 6.51510371620631252576e-03, + 6.94563266587837867261e-03, + 7.37157239632470640683e-03, + 7.79271644955021464130e-03, + 8.20886131334327799614e-03, + 8.61980651802961989061e-03, + 9.02535473144288127867e-03, + 9.42531185206835209200e-03, + 9.81948710031542437715e-03, + 1.02076931078787062901e-02, + 1.05897460051441894696e-02, + 1.09654655066032842570e-02, + 1.13346749942337312461e-02, + 1.16972015988115480428e-02, + 1.20528762791150233225e-02, + 1.24015338989890838706e-02, + 1.27430133022312791491e-02, + 1.30771573852710050467e-02, + 1.34038131676064240644e-02, + 1.37228318599705717551e-02, + 1.40340689301969769737e-02, + 1.43373841667557219703e-02, + 1.46326417399349796578e-02, + 1.49197102606399897157e-02, + 1.51984628367875466287e-02, + 1.54687771272712503573e-02, + 1.57305353934761547874e-02, + 1.59836245483238222065e-02, + 1.62279362028255533246e-02, + 1.64633667101300000535e-02, + 1.66898172070444779369e-02, + 1.69071936530182861946e-02, + 1.71154068665722303155e-02, + 1.73143725591620549487e-02, + 1.75040113664655661019e-02, + 1.76842488770822502120e-02, + 1.78550156586383436397e-02, + 1.80162472812886650941e-02, + 1.81678843386109678537e-02, + 1.83098724658869831117e-02, + 1.84421623557678958372e-02, + 1.85647097713225045501e-02, + 1.86774755564665419227e-02, + 1.87804256437758242126e-02, + 1.88735310596836944330e-02, + 1.89567679270675991388e-02, + 1.90301174652290280842e-02, + 1.90935659872729333875e-02, + 1.91471048948949201796e-02, + 1.91907306705839213190e-02, + 1.92244448672513647269e-02, + 1.92482540952976406701e-02, + 1.92621700071291257483e-02, + 1.92662092791390723856e-02, + 1.92603935911679381709e-02, + 1.92447496034597632930e-02, + 1.92193089311317975854e-02, + 1.91841081161766568997e-02, + 1.91391885970173640519e-02, + 1.90845966756356746896e-02, + 1.90203834822977521646e-02, + 1.89466049378990836205e-02, + 1.88633217139549183572e-02, + 1.87705991902617184974e-02, + 1.86685074102564685372e-02, + 1.85571210341025014112e-02, + 1.84365192895308768750e-02, + 1.83067859204682249763e-02, + 1.81680091334814851345e-02, + 1.80202815420731528306e-02, + 1.78637001088602434540e-02, + 1.76983660856705124487e-02, + 1.75243849515933046435e-02, + 1.73418663490196370280e-02, + 1.71509240177099529789e-02, + 1.69516757269280171627e-02, + 1.67442432056789658468e-02, + 1.65287520710933055756e-02, + 1.63053317549959643495e-02, + 1.60741154287042248283e-02, + 1.58352399260948337179e-02, + 1.55888456649855098451e-02, + 1.53350765668743439091e-02, + 1.50740799750810755553e-02, + 1.48060065713376716456e-02, + 1.45310102908721653497e-02, + 1.42492482360351419013e-02, + 1.39608805885138576031e-02, + 1.36660705201842418155e-02, + 1.33649841026482960049e-02, + 1.30577902155067059053e-02, + 1.27446604534163440703e-02, + 1.24257690319823609071e-02, + 1.21012926925372719250e-02, + 1.17714106058561026463e-02, + 1.14363042748611334204e-02, + 1.10961574363676110377e-02, + 1.07511559619219848605e-02, + 1.04014877577871447251e-02, + 1.00473426641261246589e-02, + 9.68891235343915212253e-03, + 9.32639022830554151322e-03, + 8.95997131848667513476e-03, + 8.58985217744295814768e-03, + 8.21623077831776238433e-03, + 7.83930640944576623275e-03, + 7.45927956943647635368e-03, + 7.07635186189118064320e-03, + 6.69072588980388575225e-03, + 6.30260514970595094736e-03, + 5.91219392560345287368e-03, + 5.51969718276637197341e-03, + 5.12532046142244023662e-03, + 4.72926977040892190796e-03, + 4.33175148083997027526e-03, + 3.93297221983980160170e-03, + 3.53313876439927251547e-03, + 3.13245793540825817960e-03, + 2.73113649191582047102e-03, + 2.32938102567640907548e-03, + 1.92739785602901348045e-03, + 1.52539292516795199454e-03, + 1.12357169385324685146e-03, + 7.22139037616026076630e-04, + 3.21299143509566089132e-04, +-7.87445925439102364842e-05, +-4.77789667756481134173e-04, +-8.75634573781077039240e-04, +-1.27207889726797546831e-03, +-1.66692341962379432171e-03, +-2.05997021592245954311e-03, +-2.45102275292159678052e-03, +-2.83988598613405971924e-03, +-3.22636645590845556192e-03, +-3.61027238247302534671e-03, +-3.99141375989387706819e-03, +-4.36960244890573310667e-03, +-4.74465226856734742511e-03, +-5.11637908669945132983e-03, +-5.48460090906132020916e-03, +-5.84913796722293360258e-03, +-6.20981280509260748224e-03, +-6.56645036405622325310e-03, +-6.91887806669126605857e-03, +-7.26692589901343100750e-03, +-7.61042649121839841903e-03, +-7.94921519688219710420e-03, +-8.28313017058056322295e-03, +-8.61201244389523008771e-03, +-8.93570599976736823500e-03, +-9.25405784516927093497e-03, +-9.56691808205707705515e-03, +-9.87413997657404438058e-03, +-1.01755800264738422573e-02, +-1.04710980267316584175e-02, +-1.07605571333162300385e-02, +-1.10438239250919990192e-02, +-1.13207684638271209587e-02, +-1.15912643522783440769e-02, +-1.18551887903295075782e-02, +-1.21124226291589674048e-02, +-1.23628504234125462247e-02, +-1.26063604813613176076e-02, +-1.28428449130213884893e-02, +-1.30721996762182875867e-02, +-1.32943246205750771616e-02, +-1.35091235294078314266e-02, +-1.37165041595128135710e-02, +-1.39163782788270101731e-02, +-1.41086617019519286464e-02, +-1.42932743235239592683e-02, +-1.44701401494216879556e-02, +-1.46391873257979802936e-02, +-1.48003481659278162547e-02, +-1.49535591748633858722e-02, +-1.50987610718883325661e-02, +-1.52358988107658115813e-02, +-1.53649215977745036421e-02, +-1.54857829075290397841e-02, +-1.55984404965814546506e-02, +-1.57028564148030853886e-02, +-1.57989970145448431482e-02, +-1.58868329575775346640e-02, +-1.59663392198137396583e-02, +-1.60374950938135772682e-02, +-1.61002841890790400481e-02, +-1.61546944301414231726e-02, +-1.62007180524483263007e-02, +-1.62383515960572676062e-02, +-1.62675958971449409474e-02, +-1.62884560773407099932e-02, +-1.63009415308956705226e-02, +-1.63050659096987474173e-02, +-1.63008471061523926848e-02, +-1.62883072339218455682e-02, +-1.62674726065730329561e-02, +-1.62383737141145109706e-02, +-1.62010451974609233361e-02, +-1.61555258208356707084e-02, +-1.61018584421316855726e-02, +-1.60400899812505326469e-02, +-1.59702713864408145372e-02, +-1.58924575986573272945e-02, +-1.58067075139647107707e-02, +-1.57130839440085059988e-02, +-1.56116535745792449352e-02, +-1.55024869222944727820e-02, +-1.53856582894260490724e-02, +-1.52612457168996174667e-02, +-1.51293309354949591372e-02, +-1.49899993152762481957e-02, +-1.48433398132821487564e-02, +-1.46894449195070758013e-02, +-1.45284106012046419082e-02, +-1.43603362455460986657e-02, +-1.41853246006673119201e-02, +-1.40034817151370259009e-02, +-1.38149168758828280734e-02, +-1.36197425446084856987e-02, +-1.34180742927401692316e-02, +-1.32100307349369578552e-02, +-1.29957334612042334221e-02, +-1.27753069676474068084e-02, +-1.25488785859041301896e-02, +-1.23165784112953900081e-02, +-1.20785392297338319001e-02, +-1.18348964434312736022e-02, +-1.15857879954438421077e-02, +-1.13313542930994892027e-02, +-1.10717381303457890890e-02, +-1.08070846090634192782e-02, +-1.05375410593865573988e-02, +-1.02632569590727744380e-02, +-9.98438385196800254340e-03, +-9.70107526560752726763e-03, +-9.41348662799971515336e-03, +-9.12177518363594015682e-03, +-8.82609990877025046840e-03, +-8.52662142601712247370e-03, +-8.22350191830830204442e-03, +-7.91690504225831676033e-03, +-7.60699584098104789748e-03, +-7.29394065640553979080e-03, +-6.97790704113636535422e-03, +-6.65906366990342071799e-03, +-6.33758025065010895116e-03, +-6.01362743530314651508e-03, +-5.68737673027295675271e-03, +-5.35900040672940281006e-03, +-5.02867141070039921913e-03, +-4.69656327303835750137e-03, +-4.36285001930248206997e-03, +-4.02770607960259777180e-03, +-3.69130619844926536818e-03, +-3.35382534465939949331e-03, +-3.01543862135967731183e-03, +-2.67632117613655082580e-03, +-2.33664811137678819775e-03, +-1.99659439484433081508e-03, +-1.65633477053923894307e-03, +-1.31604366988200688349e-03, +-9.75895123270567642695e-04, +-6.36062672051197525343e-04, +-2.96719280950014205507e-04, + 4.19627489923029214371e-05, + 3.79811866940293777015e-04, + 7.16657358192283769176e-04, + 1.05232942947910620979e-03, + 1.38665929358586822832e-03, + 1.71947925326047606175e-03, + 2.05062278436349190031e-03, + 2.37992461822022008389e-03, + 2.70722082313579063065e-03, + 3.03234888503091078518e-03, + 3.35514778716229861502e-03, + 3.67545808888595972735e-03, + 3.99312200342836869094e-03, + 4.30798347462560838467e-03, + 4.61988825259515914490e-03, + 4.92868396830371639783e-03, + 5.23422020699498662111e-03, + 5.53634858044424124635e-03, + 5.83492279800282634405e-03, + 6.12979873640210736613e-03, + 6.42083450828168002950e-03, + 6.70789052941064140034e-03, + 6.99082958457222531506e-03, + 7.26951689207744420479e-03, + 7.54382016688265842619e-03, + 7.81360968227803008579e-03, + 8.07875833012169572434e-03, + 8.33914167959036965738e-03, + 8.59463803442023742407e-03, + 8.84512848861381158205e-03, + 9.09049698058539933088e-03, + 9.33063034572383098730e-03, + 9.56541836734724204572e-03, + 9.79475382602876601390e-03, + 1.00185325472712388750e-02, + 1.02366534475112885144e-02, + 1.04490185784319629392e-02, + 1.06555331695659429025e-02, + 1.08561056691723126222e-02, + 1.10506477833681605177e-02, + 1.12390745135014444300e-02, + 1.14213041917481192972e-02, + 1.15972585149209383992e-02, + 1.17668625764762845715e-02, + 1.19300448967066957673e-02, + 1.20867374511089888806e-02, + 1.22368756969161197878e-02, + 1.23803985977854972417e-02, + 1.25172486466337395256e-02, + 1.26473718866117884607e-02, + 1.27707179302137523863e-02, + 1.28872399765134221933e-02, + 1.29968948265256969976e-02, + 1.30996428966874464001e-02, + 1.31954482304573617740e-02, + 1.32842785080317399987e-02, + 1.33661050541768675060e-02, + 1.34409028441777739227e-02, + 1.35086505079049911532e-02, + 1.35693303320018558017e-02, + 1.36229282601955156012e-02, + 1.36694338917359037994e-02, + 1.37088404779683696588e-02, + 1.37411449170452750618e-02, + 1.37663477467847624597e-02, + 1.37844531356839973546e-02, + 1.37954688720959822018e-02, + 1.37994063515802581343e-02, + 1.37962805624378334612e-02, + 1.37861100694423310831e-02, + 1.37689169957797372806e-02, + 1.37447270032107649734e-02, + 1.37135692704694871907e-02, + 1.36754764699141325573e-02, + 1.36304847424457160204e-02, + 1.35786336707117930717e-02, + 1.35199662506130090928e-02, + 1.34545288611307815863e-02, + 1.33823712324960784892e-02, + 1.33035464127193650552e-02, + 1.32181107325021699600e-02, + 1.31261237685532539815e-02, + 1.30276483053305639631e-02, + 1.29227502952338896280e-02, + 1.28114988172704970942e-02, + 1.26939660342200184157e-02, + 1.25702271483237072724e-02, + 1.24403603555233947114e-02, + 1.23044467982784695020e-02, + 1.21625705169872422307e-02, + 1.20148184000413785211e-02, + 1.18612801325425308574e-02, + 1.17020481437095178606e-02, + 1.15372175530077808459e-02, + 1.13668861150298707019e-02, + 1.11911541631600167795e-02, + 1.10101245520525005406e-02, + 1.08239025989581676146e-02, + 1.06325960239305756377e-02, + 1.04363148889449076223e-02, + 1.02351715359647547215e-02, + 1.00292805239893083324e-02, + 9.81875856511689806827e-03, + 9.60372445965929077971e-03, + 9.38429903034274093265e-03, + 9.16060505563077998037e-03, + 8.93276720220602567235e-03, + 8.70091195664717161062e-03, + 8.46516755633743532561e-03, + 8.22566391964303297857e-03, + 7.98253257539762242634e-03, + 7.73590659173173638558e-03, + 7.48592050428459592631e-03, + 7.23271024383650030370e-03, + 6.97641306340083741655e-03, + 6.71716746481300884530e-03, + 6.45511312485713174836e-03, + 6.19039082096706390346e-03, + 5.92314235654277116555e-03, + 5.65351048592053172237e-03, + 5.38163883903518876911e-03, + 5.10767184581618297751e-03, + 4.83175466035329001513e-03, + 4.55403308487579983055e-03, + 4.27465349357983477596e-03, + 3.99376275634679561710e-03, + 3.71150816239089074641e-03, + 3.42803734387406560530e-03, + 3.14349819952992014238e-03, + 2.85803881833283880340e-03, + 2.57180740325433027441e-03, + 2.28495219514192630592e-03, + 1.99762139676367333693e-03, + 1.70996309705198873234e-03, + 1.42212519558894585903e-03, + 1.13425532736955879051e-03, + 8.46500787880119249379e-04, + 5.59008458531536360676e-04, + 2.71924732482213711831e-04, +-1.46045591101362367902e-05, +-3.00434220371862336588e-04, +-5.85419763496916080447e-04, +-8.69417480990889736912e-04, +-1.15228451734444565895e-03, +-1.43387894009652252202e-03, +-1.71405981025574941264e-03, +-1.99268725204318009406e-03, +-2.26962252192313383714e-03, +-2.54472807688939806764e-03, +-2.81786764197139655633e-03, +-3.08890627693018818625e-03, +-3.35771044210986593925e-03, +-3.62414806341412312415e-03, +-3.88808859637569193338e-03, +-4.14940308928948755479e-03, +-4.40796424537761438733e-03, +-4.66364648395760274940e-03, +-4.91632600058568031837e-03, +-5.16588082614466512915e-03, +-5.41219088485122776233e-03, +-5.65513805115323408418e-03, +-5.89460620549208617197e-03, +-6.13048128890366673949e-03, +-6.36265135643233371854e-03, +-6.59100662933489230694e-03, +-6.81543954604840913902e-03, +-7.03584481190112302068e-03, +-7.25211944754226237736e-03, +-7.46416283606952078722e-03, +-7.67187676883409296058e-03, +-7.87516548990104849060e-03, +-8.07393573914804915659e-03, +-8.26809679398036317943e-03, +-8.45756050964779383661e-03, +-8.64224135814309693537e-03, +-8.82205646566693382771e-03, +-8.99692564864382551826e-03, +-9.16677144827266789096e-03, +-9.33151916359954529401e-03, +-9.49109688309758385560e-03, +-9.64543551474287760850e-03, +-9.79446881457346311961e-03, +-9.93813341372091867132e-03, +-1.00763688439045248635e-02, +-1.02091175613780275888e-02, +-1.03363249693213758024e-02, +-1.04579394386685748525e-02, +-1.05739123273658041507e-02, +-1.06841979980529435540e-02, +-1.07887538341634794947e-02, +-1.08875402544387003823e-02, +-1.09805207258518982422e-02, +-1.10676617749403266577e-02, +-1.11489329975425002783e-02, +-1.12243070669403085388e-02, +-1.12937597404047310179e-02, +-1.13572698641464103764e-02, +-1.14148193766721185033e-02, +-1.14663933105489043718e-02, +-1.15119797925795526450e-02, +-1.15515700423923072665e-02, +-1.15851583694501700239e-02, +-1.16127421684842080385e-02, +-1.16343219133579756086e-02, +-1.16499011493693144931e-02, +-1.16594864839973874626e-02, +-1.16630875761035632254e-02, +-1.16607171235953484961e-02, +-1.16523908495632707444e-02, +-1.16381274869015692575e-02, +-1.16179487614245235960e-02, +-1.15918793734899987224e-02, +-1.15599469781440481603e-02, +-1.15221821637996792859e-02, +-1.14786184294645918214e-02, +-1.14292921605328150897e-02, +-1.13742426031563578781e-02, +-1.13135118372134652748e-02, +-1.12471447478901080685e-02, +-1.11751889958936409530e-02, +-1.10976949863161849369e-02, +-1.10147158361676694022e-02, +-1.09263073405979870001e-02, +-1.08325279378290572491e-02, +-1.07334386728172945930e-02, +-1.06291031596689976302e-02, +-1.05195875428303799864e-02, +-1.04049604570749746474e-02, +-1.02852929863124966520e-02, +-1.01606586212423712773e-02, +-1.00311332158768314049e-02, +-9.89679494295862653697e-03, +-9.75772424829860450524e-03, +-9.61400380405963254915e-03, +-9.46571846101251432315e-03, +-9.31295519979207127303e-03, +-9.15580308117954107250e-03, +-8.99435319544003054892e-03, +-8.82869861074311521043e-03, +-8.65893432069447625821e-03, +-8.48515719100898131722e-03, +-8.30746590535331487504e-03, +-8.12596091038898099557e-03, +-7.94074436004471931327e-03, +-7.75192005904976402797e-03, +-7.55959340575841978738e-03, +-7.36387133429604930773e-03, +-7.16486225605968488073e-03, +-6.96267600060247564275e-03, +-6.75742375593618195551e-03, +-6.54921800828115602267e-03, +-6.33817248129906873205e-03, +-6.12440207483747056649e-03, +-5.90802280322155672770e-03, +-5.68915173312445864029e-03, +-5.46790692104878739421e-03, +-5.24440735045367430189e-03, +-5.01877286855873742250e-03, +-4.79112412285956183744e-03, +-4.56158249738753112518e-03, +-4.33027004874617267582e-03, +-4.09730944195998200014e-03, +-3.86282388616571940171e-03, +-3.62693707018273397286e-03, +-3.38977309799298612628e-03, +-3.15145642416600349836e-03, +-2.91211178926129628936e-03, +-2.67186415524058896998e-03, +-2.43083864092491410552e-03, +-2.18916045752724818321e-03, +-1.94695484429555434880e-03, +-1.70434700429766003774e-03, +-1.46146204038146722802e-03, +-1.21842489134170429109e-03, +-9.75360268326885652967e-04, +-7.32392591517812274748e-04, +-4.89645927108687487733e-04, +-2.47243924624317883750e-04, +-5.30975460243512911756e-06, + 2.36033953325794955153e-04, + 4.76665171927515821017e-04, + 7.16462537401301477295e-04, + 9.55305409921098193718e-04, + 1.19307393366231218393e-03, + 1.42964909627860559810e-03, + 1.66491278780242935725e-03, + 1.89874785893865663695e-03, + 2.13103817872366176761e-03, + 2.36166869152246855501e-03, + 2.59052547333455795292e-03, + 2.81749578738373649203e-03, + 3.04246813896196085722e-03, + 3.26533232950441303435e-03, + 3.48597950986718595895e-03, + 3.70430223278326144556e-03, + 3.92019450447253243325e-03, + 4.13355183537975935659e-03, + 4.34427129001856843216e-03, + 4.55225153589615232075e-03, + 4.75739289149763357190e-03, + 4.95959737330627960239e-03, + 5.15876874183868530666e-03, + 5.35481254667346043274e-03, + 5.54763617045254779636e-03, + 5.73714887183583450297e-03, + 5.92326182738835572278e-03, + 6.10588817238264490450e-03, + 6.28494304049680499458e-03, + 6.46034360239086408867e-03, + 6.63200910314530080181e-03, + 6.79986089854376415248e-03, + 6.96382249018552904052e-03, + 7.12381955941148153205e-03, + 7.27978000003043010380e-03, + 7.43163394983032809388e-03, + 7.57931382086227036637e-03, + 7.72275432848473775138e-03, + 7.86189251915526618464e-03, + 7.99666779695973849174e-03, + 8.12702194886731447976e-03, + 8.25289916870263103033e-03, + 8.37424607982448221399e-03, + 8.49101175650416456486e-03, + 8.60314774399449817832e-03, + 8.71060807728277902706e-03, + 8.81334929852170718967e-03, + 8.91133047313173894122e-03, + 9.00451320457064906255e-03, + 9.09286164776551726618e-03, + 9.17634252120343510417e-03, + 9.25492511767886209817e-03, + 9.32858131369380602638e-03, + 9.39728557751129400799e-03, + 9.46101497585938137902e-03, + 9.51974917928707746462e-03, + 9.57347046617182048656e-03, + 9.62216372537993622216e-03, + 9.66581645758253331369e-03, + 9.70441877522852311411e-03, + 9.73796340117899505984e-03, + 9.76644566600631813813e-03, + 9.78986350396279965402e-03, + 9.80821744762437608411e-03, + 9.82151062121512652414e-03, + 9.82974873261935853941e-03, + 9.83294006408857654278e-03, + 9.83109546165142171581e-03, + 9.82422832323481126648e-03, + 9.81235458550605912920e-03, + 9.79549270944552429030e-03, + 9.77366366466025406068e-03, + 9.74689091245018769671e-03, + 9.71520038763806249860e-03, + 9.67862047917591658552e-03, + 9.63718200954081366527e-03, + 9.59091821293355135947e-03, + 9.53986471229417709594e-03, + 9.48405949514947999024e-03, + 9.42354288830722815196e-03, + 9.35835753141333638594e-03, + 9.28854834938808680833e-03, + 9.21416252375845123979e-03, + 9.13524946290390424397e-03, + 9.05186077123359793262e-03, + 8.96405021731353467140e-03, + 8.87187370096227494176e-03, + 8.77538921933519559804e-03, + 8.67465683201655221590e-03, + 8.56973862514041548333e-03, + 8.46069867456020023588e-03, + 8.34760300808964732233e-03, + 8.23051956683512782320e-03, + 8.10951816564266063370e-03, + 7.98467045268167613381e-03, + 7.85604986818807735083e-03, + 7.72373160239066269828e-03, + 7.58779255264339144021e-03, + 7.44831127978854735938e-03, + 7.30536796377457674917e-03, + 7.15904435855267175237e-03, + 7.00942374627864812214e-03, + 6.85659089084312764473e-03, + 6.70063199075772355368e-03, + 6.54163463142106230142e-03, + 6.37968773679228450674e-03, + 6.21488152049734249999e-03, + 6.04730743639451170240e-03, + 5.87705812862679335268e-03, + 5.70422738118673677138e-03, + 5.52891006702203955531e-03, + 5.35120209670836722432e-03, + 5.17120036671731789918e-03, + 4.98900270730638639716e-03, + 4.80470783005945180355e-03, + 4.61841527510534633622e-03, + 4.43022535804147177957e-03, + 4.24023911659228945614e-03, + 4.04855825702851463560e-03, + 3.85528510037712974709e-03, + 3.66052252844891639130e-03, + 3.46437392971235937414e-03, + 3.26694314504209770700e-03, + 3.06833441336932816884e-03, + 2.86865231726372458751e-03, + 2.66800172847322068781e-03, + 2.46648775345124351629e-03, + 2.26421567889880867575e-03, + 2.06129091734864790947e-03, + 1.85781895282100093132e-03, + 1.65390528657631021014e-03, + 1.44965538299551312262e-03, + 1.24517461561208316219e-03, + 1.04056821332572727035e-03, + 8.35941206823879187984e-04, + 6.31398375237409098873e-04, + 4.27044193058938911355e-04, + 2.22982777348387794809e-04, + 1.93178352541883997372e-05, +-1.83847388125652280721e-04, +-3.86410161515063485180e-04, +-5.88268318839344113436e-04, +-7.89320310186791547317e-04, +-9.89465252327087745748e-04, +-1.18860297876262669368e-03, +-1.38663408928657127910e-03, +-1.58345999902536368857e-03, +-1.77898298694016492559e-03, +-1.97310624376432260790e-03, +-2.16573391935423681734e-03, +-2.35677116942951958567e-03, +-2.54612420168103805937e-03, +-2.73370032122395708804e-03, +-2.91940797537506343401e-03, +-3.10315679773186291548e-03, +-3.28485765153320842871e-03, +-3.46442267228143797181e-03, +-3.64176530960461748362e-03, +-3.81680036834099439130e-03, +-3.98944404882473329516e-03, +-4.15961398635617159159e-03, +-4.32722928983605027026e-03, +-4.49221057954843436960e-03, +-4.65448002407309498196e-03, +-4.81396137631140419444e-03, +-4.97058000860978871360e-03, +-5.12426294696375662918e-03, +-5.27493890428890055411e-03, +-5.42253831274242328875e-03, +-5.56699335508204027484e-03, +-5.70823799504863171883e-03, +-5.84620800675817245406e-03, +-5.98084100309233864662e-03, +-6.11207646307366722627e-03, +-6.23985575821544256880e-03, +-6.36412217783412659938e-03, +-6.48482095331432296242e-03, +-6.60189928131710984660e-03, +-6.71530634592089337165e-03, +-6.82499333968801785016e-03, +-6.93091348364723199016e-03, +-7.03302204618568189975e-03, +-7.13127636084264718980e-03, +-7.22563584299942916062e-03, +-7.31606200545875488828e-03, +-7.40251847290886687281e-03, +-7.48497099526800394043e-03, +-7.56338745990427392674e-03, +-7.63773790272863697948e-03, +-7.70799451815705905650e-03, +-7.77413166794023880596e-03, +-7.83612588885893024404e-03, +-7.89395589928373019040e-03, +-7.94760260459900953756e-03, +-7.99704910149071600267e-03, +-8.04228068109907878735e-03, +-8.08328483103710852820e-03, +-8.12005123627678772336e-03, +-8.15257177890556759825e-03, +-8.18084053675576655662e-03, +-8.20485378091061375028e-03, +-8.22460997209095365235e-03, +-8.24010975592739773610e-03, +-8.25135595712299906024e-03, +-8.25835357251225588016e-03, +-8.26110976302289051754e-03, +-8.25963384454711686822e-03, +-8.25393727773001892323e-03, +-8.24403365668276502665e-03, +-8.22993869662941301968e-03, +-8.21167022049609611478e-03, +-8.18924814445231435966e-03, +-8.16269446241428900390e-03, +-8.13203322952094770359e-03, +-8.09729054459370524433e-03, +-8.05849453159142650738e-03, +-8.01567532007289515472e-03, +-7.96886502467894497492e-03, +-7.91809772364769626218e-03, +-7.86340943637591806292e-03, +-7.80483810004095092394e-03, +-7.74242354529683460967e-03, +-7.67620747106049876318e-03, +-7.60623341840202440295e-03, +-7.53254674355573021483e-03, +-7.45519459006761028158e-03, +-7.37422586009548602926e-03, +-7.28969118487934625988e-03, +-7.20164289439836468459e-03, +-7.11013498623295006618e-03, +-7.01522309364934187198e-03, +-6.91696445292533119292e-03, +-6.81541786993564071423e-03, +-6.71064368601629723105e-03, +-6.60270374312706912617e-03, +-6.49166134833155817480e-03, +-6.37758123761547179170e-03, +-6.26052953906250375660e-03, +-6.14057373540916311833e-03, +-6.01778262599883193018e-03, +-5.89222628815630304622e-03, +-5.76397603800424263021e-03, +-5.63310439074257793962e-03, +-5.49968502041355174204e-03, +-5.36379271917321667762e-03, +-5.22550335609255588165e-03, +-5.08489383551021401769e-03, +-4.94204205495888618943e-03, +-4.79702686268924927138e-03, +-4.64992801481256979451e-03, +-4.50082613208717050024e-03, +-4.34980265636943953800e-03, +-4.19693980675457916502e-03, +-4.04232053542952999431e-03, +-3.88602848326117904232e-03, +-3.72814793514442046479e-03, +-3.56876377513224178270e-03, +-3.40796144137293617951e-03, +-3.24582688087653560907e-03, +-3.08244650413554361137e-03, +-2.91790713962266495818e-03, +-2.75229598818970896956e-03, +-2.58570057739144132034e-03, +-2.41820871575722370558e-03, +-2.24990844703554021197e-03, +-2.08088800443330694187e-03, +-1.91123576487488202463e-03, +-1.74104020330362123901e-03, +-1.57038984704899425675e-03, +-1.39937323028345179249e-03, +-1.22807884859140337835e-03, +-1.05659511367403743075e-03, +-8.85010308212021861753e-04, +-7.13412540909905373669e-04, +-5.41889701744388552207e-04, +-3.70529417438410636591e-04, +-1.99419007184688332895e-04, +-2.86454386391723757354e-05, + 1.41704715791932274720e-04, + 3.11545322351527997646e-04, + 4.80790728994517078173e-04, + 6.49355808093498481151e-04, + 8.17155998766742235409e-04, + 9.84107348806230984584e-04, + 1.15012655618750773805e-03, + 1.31513101013778751017e-03, + 1.47903883174614527579e-03, + 1.64176891409281364154e-03, + 1.80324096188044400921e-03, + 1.96337553054683720821e-03, + 2.12209406484084378217e-03, + 2.27931893684354004020e-03, + 2.43497348341521844400e-03, + 2.58898204305202080458e-03, + 2.74126999213337996242e-03, + 2.89176378054382390501e-03, + 3.04039096665289229962e-03, + 3.18708025163550725742e-03, + 3.33176151311842744587e-03, + 3.47436583813595005824e-03, + 3.61482555538014498075e-03, + 3.75307426673132269943e-03, + 3.88904687805323055413e-03, + 4.02267962924054024026e-03, + 4.15391012350339004777e-03, + 4.28267735587738347658e-03, + 4.40892174094537157153e-03, + 4.53258513975950821928e-03, + 4.65361088595093140563e-03, + 4.77194381101678308937e-03, + 4.88753026877269871470e-03, + 5.00031815896078389583e-03, + 5.11025695000340892532e-03, + 5.21729770089245179637e-03, + 5.32139308220599526605e-03, + 5.42249739624305147206e-03, + 5.52056659626851391892e-03, + 5.61555830486112211863e-03, + 5.70743183135652247528e-03, + 5.79614818837954730302e-03, + 5.88167010745905063929e-03, + 5.96396205371965346109e-03, + 6.04299023964566684591e-03, + 6.11872263791200451943e-03, + 6.19112899327779828834e-03, + 6.26018083353982283945e-03, + 6.32585147954144774024e-03, + 6.38811605423505318724e-03, + 6.44695149079576538403e-03, + 6.50233653978409681384e-03, + 6.55425177535713839039e-03, + 6.60267960052677606309e-03, + 6.64760425146517907463e-03, + 6.68901180085764834188e-03, + 6.72689016030344512365e-03, + 6.76122908176596693758e-03, + 6.79202015807388054941e-03, + 6.81925682247539518416e-03, + 6.84293434724847406819e-03, + 6.86304984136987261678e-03, + 6.87960224724697578386e-03, + 6.89259233651607575860e-03, + 6.90202270491214152359e-03, + 6.90789776621477530361e-03, + 6.91022374527592089799e-03, + 6.90900867013538935724e-03, + 6.90426236323048170274e-03, + 6.89599643170657299052e-03, + 6.88422425683606498820e-03, + 6.86896098255334458527e-03, + 6.85022350311395231137e-03, + 6.82803044988653656810e-03, + 6.80240217728674077119e-03, + 6.77336074786231978617e-03, + 6.74092991653942995994e-03, + 6.70513511404041261804e-03, + 6.66600342948348283806e-03, + 6.62356359217582818522e-03, + 6.57784595261113724102e-03, + 6.52888246268356915031e-03, + 6.47670665513047465189e-03, + 6.42135362221612788353e-03, + 6.36285999366974046321e-03, + 6.30126391389077868121e-03, + 6.23660501843537051769e-03, + 6.16892440979760654785e-03, + 6.09826463250009130623e-03, + 6.02466964750847117777e-03, + 5.94818480598439686818e-03, + 5.86885682239295450313e-03, + 5.78673374697901473501e-03, + 5.70186493762921998985e-03, + 5.61430103113523277375e-03, + 5.52409391387439444726e-03, + 5.43129669192503241465e-03, + 5.33596366063239947036e-03, + 5.23815027364322050724e-03, + 5.13791311142524926431e-03, + 5.03530984929013124274e-03, + 4.93039922493699201561e-03, + 4.82324100553432541516e-03, + 4.71389595435920891187e-03, + 4.60242579701116046043e-03, + 4.48889318721965805553e-03, + 4.37336167226419578885e-03, + 4.25589565802507278913e-03, + 4.13656037368400047310e-03, + 4.01542183609403160321e-03, + 3.89254681383765111652e-03, + 3.76800279099204432978e-03, + 3.64185793062176202395e-03, + 3.51418103801726458557e-03, + 3.38504152369975422690e-03, + 3.25450936621163181353e-03, + 3.12265507471182202082e-03, + 2.98954965139678783756e-03, + 2.85526455376563029209e-03, + 2.71987165675057146821e-03, + 2.58344321473122102290e-03, + 2.44605182345362590079e-03, + 2.30777038187338556438e-03, + 2.16867205394239955310e-03, + 2.02883023036007446166e-03, + 1.88831849030696359050e-03, + 1.74721056318321156346e-03, + 1.60558029036844077814e-03, + 1.46350158702526116430e-03, + 1.32104840396417614300e-03, + 1.17829468959044993299e-03, + 1.03531435195189738287e-03, + 8.92181220906407453086e-04, + 7.48969010429437957559e-04, + 6.05751281079198837520e-04, + 4.62601402639519420582e-04, + 3.19592516958703328628e-04, + 1.76797501002548605557e-04, + 3.42889301410700559898e-05, +-1.07860958314116714895e-04, +-2.49580301302545907224e-04, +-3.90797645920318444633e-04, +-5.31441985020897648614e-04, +-6.71442792492634734323e-04, +-8.10730058197295030964e-04, +-9.49234322550691531593e-04, +-1.08688671073021991820e-03, +-1.22361896649146595362e-03, +-1.35936348557852870918e-03, +-1.49405334871076226656e-03, +-1.62762235413136985458e-03, +-1.76000504970118200505e-03, +-1.89113676452272319942e-03, +-2.02095364007995759864e-03, +-2.14939266087792180127e-03, +-2.27639168456901649570e-03, +-2.40188947155079574047e-03, +-2.52582571402181800535e-03, +-2.64814106448245725756e-03, +-2.76877716366639818613e-03, +-2.88767666789123715262e-03, +-3.00478327581455654377e-03, +-3.12004175458374362687e-03, +-3.23339796536792432186e-03, +-3.34479888826014811615e-03, +-3.45419264653828387429e-03, +-3.56152853027508903283e-03, +-3.66675701928568381627e-03, +-3.76982980540296712391e-03, +-3.87069981407154629915e-03, +-3.96932122525004045521e-03, +-4.06564949361390860078e-03, +-4.15964136804923296370e-03, +-4.25125491042980478001e-03, +-4.34044951367000032827e-03, +-4.42718591904522635466e-03, +-4.51142623277396223602e-03, +-4.59313394185401763226e-03, +-4.67227392914710930316e-03, +-4.74881248770633347667e-03, +-4.82271733434034600985e-03, +-4.89395762241020149813e-03, +-4.96250395385362200878e-03, +-5.02832839043272725871e-03, +-5.09140446420189209803e-03, +-5.15170718719160612709e-03, +-5.20921306030622689037e-03, +-5.26390008143260215712e-03, +-5.31574775275780748302e-03, +-5.36473708729396422251e-03, +-5.41085061460937211120e-03, +-5.45407238576448103601e-03, +-5.49438797745297521219e-03, +-5.53178449534730623527e-03, +-5.56625057664943048014e-03, +-5.59777639184752800333e-03, +-5.62635364567968653676e-03, +-5.65197557730641106377e-03, +-5.67463695969378130457e-03, +-5.69433409820978980731e-03, +-5.71106482843655206827e-03, +-5.72482851320176878984e-03, +-5.73562603883285941631e-03, +-5.74345981063785135379e-03, +-5.74833374761739290815e-03, +-5.75025327641265435880e-03, +-5.74922532449426235829e-03, +-5.74525831259774157761e-03, +-5.73836214641150563903e-03, +-5.72854820752343851104e-03, +-5.71582934363289423690e-03, +-5.70021985803501312490e-03, +-5.68173549838472177059e-03, +-5.66039344474815377811e-03, +-5.63621229694941539706e-03, +-5.60921206122125953764e-03, +-5.57941413616825417771e-03, +-5.54684129805165914567e-03, +-5.51151768540501883070e-03, +-5.47346878299080803754e-03, +-5.43272140510751410519e-03, +-5.38930367825777700136e-03, +-5.34324502318837303572e-03, +-5.29457613631248175806e-03, +-5.24332897052591333231e-03, +-5.18953671542863627375e-03, +-5.13323377696330972880e-03, +-5.07445575648276473585e-03, +-5.01323942925907713175e-03, +-4.94962272244652261993e-03, +-4.88364469251110090015e-03, +-4.81534550214015970304e-03, +-4.74476639664476486369e-03, +-4.67194967986881478511e-03, +-4.59693868961848651350e-03, +-4.51977777262569171968e-03, +-4.44051225906016977518e-03, +-4.35918843660393785094e-03, +-4.27585352410331936968e-03, +-4.19055564481250319292e-03, +-4.10334379924411681712e-03, +-4.01426783764161857621e-03, +-3.92337843208837196152e-03, +-3.83072704826951850737e-03, +-3.73636591690094466492e-03, +-3.64034800484260446379e-03, +-3.54272698590992135906e-03, +-3.44355721140094522825e-03, +-3.34289368035381060859e-03, +-3.24079200955149126021e-03, +-3.13730840328953165461e-03, +-3.03249962292274259992e-03, +-2.92642295620787733917e-03, +-2.81913618645769506812e-03, +-2.71069756152355744588e-03, +-2.60116576262271661374e-03, +-2.49059987302636997100e-03, +-2.37905934662592955658e-03, +-2.26660397639284923177e-03, +-2.15329386274948570215e-03, +-2.03918938186720523700e-03, +-1.92435115390780829905e-03, +-1.80884001122574964056e-03, +-1.69271696654636218636e-03, +-1.57604318113799030283e-03, +-1.45887993299307315576e-03, +-1.34128858503558523983e-03, +-1.22333055337022866653e-03, +-1.10506727559064096139e-03, +-9.86560179161664061245e-04, +-8.67870649892684017067e-04, +-7.49060000517653913794e-04, +-6.30189439397319385409e-04, +-5.11320039360376723744e-04, +-3.92512706698102461101e-04, +-2.73828150328942268588e-04, +-1.55326851148111989192e-04, +-3.70690315771187548660e-05, + 8.08853746707290755880e-05, + 1.98476752594946217068e-04, + 3.15645835666873892950e-04, + 4.32333735328772883737e-04, + 5.48481970218807931942e-04, + 6.64032495107181436854e-04, + 7.78927729529055225960e-04, + 8.93110586101435741449e-04, + 1.00652449850903457675e-03, + 1.11911344914620018882e-03, + 1.23082199640186964844e-03, + 1.34159530157362035657e-03, + 1.45137915539899904453e-03, + 1.56012000419063017430e-03, + 1.66776497556303743633e-03, + 1.77426190373947069608e-03, + 1.87955935442584700854e-03, + 1.98360664924133621098e-03, + 2.08635388969323877853e-03, + 2.18775198068548414054e-03, + 2.28775265355017198149e-03, + 2.38630848859077522237e-03, + 2.48337293712776532861e-03, + 2.57890034303572641614e-03, + 2.67284596376264485876e-03, + 2.76516599082240414204e-03, + 2.85581756975021973724e-03, + 2.94475881951346621368e-03, + 3.03194885136837165643e-03, + 3.11734778715522806505e-03, + 3.20091677702330967489e-03, + 3.28261801657889207284e-03, + 3.36241476344812956906e-03, + 3.44027135324883812095e-03, + 3.51615321496371192184e-03, + 3.59002688570913630964e-03, + 3.66186002489374750821e-03, + 3.73162142776055534565e-03, + 3.79928103830806575963e-03, + 3.86480996158482074943e-03, + 3.92818047535295911815e-03, + 3.98936604111683416202e-03, + 4.04834131451196205242e-03, + 4.10508215505163594206e-03, + 4.15956563522717256282e-03, + 4.21177004895932887568e-03, + 4.26167491939793193628e-03, + 4.30926100606804449861e-03, + 4.35451031136011804806e-03, + 4.39740608636303952073e-03, + 4.43793283603874291060e-03, + 4.47607632373735360443e-03, + 4.51182357505270758419e-03, + 4.54516288101758283297e-03, + 4.57608380063932208837e-03, + 4.60457716277592760817e-03, + 4.63063506735364276146e-03, + 4.65425088592728592590e-03, + 4.67541926158465074442e-03, + 4.69413610819694772369e-03, + 4.71039860901748680400e-03, + 4.72420521463094104236e-03, + 4.73555564025632692166e-03, + 4.74445086240650633347e-03, + 4.75089311490801708554e-03, + 4.75488588428478291259e-03, + 4.75643390451007622849e-03, + 4.75554315113093165057e-03, + 4.75222083476989180795e-03, + 4.74647539400918638819e-03, + 4.73831648766260323663e-03, + 4.72775498644069803317e-03, + 4.71480296401554071356e-03, + 4.69947368749087587836e-03, + 4.68178160728457970485e-03, + 4.66174234643011633356e-03, + 4.63937268930397338912e-03, + 4.61469056978682824754e-03, + 4.58771505886557909998e-03, + 4.55846635168473662131e-03, + 4.52696575405490270194e-03, + 4.49323566842705062613e-03, + 4.45729957934127077324e-03, + 4.41918203835877602265e-03, + 4.37890864848652049124e-03, + 4.33650604810387890753e-03, + 4.29200189440092326476e-03, + 4.24542484633809186906e-03, + 4.19680454713776754372e-03, + 4.14617160631750546196e-03, + 4.09355758127592610218e-03, + 4.03899495844180136256e-03, + 3.98251713399709519198e-03, + 3.92415839418544434153e-03, + 3.86395389521696766208e-03, + 3.80193964278122088427e-03, + 3.73815247117977034197e-03, + 3.67263002209005122098e-03, + 3.60541072297290579943e-03, + 3.53653376513536534670e-03, + 3.46603908146142026050e-03, + 3.39396732382294752731e-03, + 3.32035984018316321711e-03, + 3.24525865140575702286e-03, + 3.16870642778174132007e-03, + 3.09074646528776763449e-03, + 3.01142266158806225576e-03, + 2.93077949179369311866e-03, + 2.84886198399182102511e-03, + 2.76571569455873623317e-03, + 2.68138668326939897182e-03, + 2.59592148821740460393e-03, + 2.50936710055862152030e-03, + 2.42177093909172859790e-03, + 2.33318082468986958203e-03, + 2.24364495459622101392e-03, + 2.15321187659778126924e-03, + 2.06193046309074068043e-03, + 1.96984988505084042051e-03, + 1.87701958592308018950e-03, + 1.78348925544364851972e-03, + 1.68930880340843595812e-03, + 1.59452833340149326656e-03, + 1.49919811649695529192e-03, + 1.40336856494826384134e-03, + 1.30709020587860356294e-03, + 1.21041365498514362324e-03, + 1.11338959027166444805e-03, + 1.01606872582251793642e-03, + 9.18501785631088349393e-04, + 8.20739477496859018597e-04, + 7.22832467003395990300e-04, + 6.24831351591239583451e-04, + 5.26786634738466547599e-04, + 4.28748700261665177755e-04, + 3.30767786750949313850e-04, + 2.32893962150942354693e-04, + 1.35177098501164551355e-04, + 3.76668468481058423122e-05, +-5.95873876588743519559e-05, +-1.56536470474729711095e-04, +-2.53131562157722037748e-04, +-3.49324142647419787298e-04, +-4.45066035310075810549e-04, +-5.40309430740103734635e-04, +-6.35006910305014118934e-04, +-7.29111469423506203084e-04, +-8.22576540564630594166e-04, +-9.15356015957640898294e-04, +-1.00740427000084128463e-03, +-1.09867618135961594636e-03, +-1.18912715474222760448e-03, +-1.27871314234389459909e-03, +-1.36739066494837155016e-03, +-1.45511683267735177083e-03, +-1.54184936537829454448e-03, +-1.62754661264047644116e-03, +-1.71216757343079406702e-03, +-1.79567191533962417817e-03, +-1.87801999342815861480e-03, +-1.95917286866888803315e-03, +-2.03909232597019587571e-03, +-2.11774089177778042717e-03, +-2.19508185124423979562e-03, +-2.27107926495981587295e-03, +-2.34569798523625184378e-03, +-2.41890367193748701338e-03, +-2.49066280784942736815e-03, +-2.56094271358263403382e-03, +-2.62971156200168766290e-03, +-2.69693839217458606120e-03, +-2.76259312283697608739e-03, +-2.82664656536508410861e-03, +-2.88907043625251033769e-03, +-2.94983736908550680730e-03, +-3.00892092601204481916e-03, +-3.06629560870052934873e-03, +-3.12193686878331445531e-03, +-3.17582111778177576464e-03, +-3.22792573650879186659e-03, +-3.27822908394535990351e-03, +-3.32671050558861836413e-03, +-3.37335034126782541686e-03, +-3.41812993242640843911e-03, +-3.46103162886747485125e-03, +-3.50203879496072990885e-03, +-3.54113581530953033458e-03, +-3.57830809987640932265e-03, +-3.61354208856588636489e-03, +-3.64682525526394910736e-03, +-3.67814611133359227815e-03, +-3.70749420856602597552e-03, +-3.73486014158783824479e-03, +-3.76023554972410066835e-03, +-3.78361311831824139590e-03, +-3.80498657950949356263e-03, +-3.82435071246891309174e-03, +-3.84170134309564249159e-03, +-3.85703534317483227867e-03, +-3.87035062899941184958e-03, +-3.88164615945781315415e-03, +-3.89092193359018290177e-03, +-3.89817898761586753217e-03, +-3.90341939143522623223e-03, +-3.90664624460901419717e-03, +-3.90786367181894002398e-03, +-3.90707681781324485393e-03, +-3.90429184184126710708e-03, +-3.89951591158146492616e-03, +-3.89275719656733548701e-03, +-3.88402486111620462786e-03, +-3.87332905676572971168e-03, +-3.86068091422367464308e-03, +-3.84609253483633988652e-03, +-3.82957698158139896172e-03, +-3.81114826959133828205e-03, +-3.79082135621343309026e-03, +-3.76861213061301580582e-03, +-3.74453740292646350060e-03, +-3.71861489297091191847e-03, +-3.69086321851783442580e-03, +-3.66130188313754665122e-03, +-3.62995126362247863203e-03, +-3.59683259699652849509e-03, +-3.56196796711877707378e-03, +-3.52538029088927777621e-03, +-3.48709330406542271710e-03, +-3.44713154669716278014e-03, +-3.40552034818984500006e-03, +-3.36228581200323853317e-03, +-3.31745479999584480524e-03, +-3.27105491642360043589e-03, +-3.22311449160199306810e-03, +-3.17366256524132884023e-03, +-3.12272886946435550976e-03, +-3.07034381151609402430e-03, +-3.01653845617577253541e-03, +-2.96134450788043245700e-03, +-2.90479429257073850854e-03, +-2.84692073926870632683e-03, +-2.78775736139794984292e-03, +-2.72733823785672839513e-03, +-2.66569799385409870324e-03, +-2.60287178151993913236e-03, +-2.53889526029965357373e-03, +-2.47380457714372692726e-03, +-2.40763634650355490621e-03, +-2.34042763014413865083e-03, +-2.27221591678447533066e-03, +-2.20303910157702452152e-03, +-2.13293546543681959357e-03, +-2.06194365423175264909e-03, +-1.99010265784496783933e-03, +-1.91745178912041433321e-03, +-1.84403066270314016858e-03, +-1.76987917378504866148e-03, +-1.69503747676780160310e-03, +-1.61954596385395933195e-03, +-1.54344524357734455208e-03, +-1.46677611928450082716e-03, +-1.38957956757772282952e-03, +-1.31189671673156917249e-03, +-1.23376882509377769348e-03, +-1.15523725948148982788e-03, +-1.07634347358468449377e-03, +-9.97128986387143959394e-04, +-9.17635360616648500243e-04, +-8.37904181234895789956e-04, +-7.57977033978787513406e-04, +-6.77895483963235779418e-04, +-5.97701054357152421204e-04, +-5.17435205142649512489e-04, +-4.37139311968777596797e-04, +-3.56854645110210024969e-04, +-2.76622348541154185371e-04, +-1.96483419135612727945e-04, +-1.16478686003570469231e-04, +-3.66487899740422618075e-05, + 4.29658367651341511670e-05, + 1.22324990860946911401e-04, + 2.01388717811737909388e-04, + 2.80117331797544979934e-04, + 3.58471435313892643378e-04, + 4.36411938600040889922e-04, + 5.13900078851591240840e-04, + 5.90897439209055901944e-04, + 6.67365967512406946770e-04, + 7.43267994812951346417e-04, + 8.18566253633950927961e-04, + 8.93223895970637264512e-04, + 9.67204511021861590946e-04, + 1.04047214264425358192e-03, + 1.11299130652140420249e-03, + 1.18472700703946731866e-03, + 1.25564475386154045418e-03, + 1.32571057819342382096e-03, + 1.39489104873262805863e-03, + 1.46315328729405358735e-03, + 1.53046498410463441449e-03, + 1.59679441276025036248e-03, + 1.66211044483838841015e-03, + 1.72638256415947395801e-03, + 1.78958088069116868016e-03, + 1.85167614408905580742e-03, + 1.91263975686785663195e-03, + 1.97244378719760738577e-03, + 2.03106098131931389963e-03, + 2.08846477557452425353e-03, + 2.14462930804391795764e-03, + 2.19952942979019039696e-03, + 2.25314071570019555310e-03, + 2.30543947492238164229e-03, + 2.35640276089497556142e-03, + 2.40600838096100867747e-03, + 2.45423490556669890092e-03, + 2.50106167703914496897e-03, + 2.54646881794065452556e-03, + 2.59043723899601840976e-03, + 2.63294864659046256791e-03, + 2.67398554983521103204e-03, + 2.71353126719851020857e-03, + 2.75156993270003411012e-03, + 2.78808650166653335112e-03, + 2.82306675604716231925e-03, + 2.85649730928709153985e-03, + 2.88836561075816750793e-03, + 2.91865994974546466220e-03, + 2.94736945898928888107e-03, + 2.97448411778179853254e-03, + 2.99999475461813899443e-03, + 3.02389304940205334848e-03, + 3.04617153520601608579e-03, + 3.06682359958635559691e-03, + 3.08584348545404892755e-03, + 3.10322629150200672218e-03, + 3.11896797218987227585e-03, + 3.13306533728775369815e-03, + 3.14551605098039102626e-03, + 3.15631863053354591933e-03, + 3.16547244452441024071e-03, + 3.17297771063858400492e-03, + 3.17883549303571563346e-03, + 3.18304769928660826611e-03, + 3.18561707688456985377e-03, + 3.18654720933417290318e-03, + 3.18584251182050994661e-03, + 3.18350822646264360050e-03, + 3.17955041715474407901e-03, + 3.17397596399888754642e-03, + 3.16679255733362226624e-03, + 3.15800869136252529770e-03, + 3.14763365738724267343e-03, + 3.13567753664971719460e-03, + 3.12215119278838691003e-03, + 3.10706626391348732577e-03, + 3.09043515430657261128e-03, + 3.07227102574976181429e-03, + 3.05258778849025729646e-03, + 3.03140009184578061371e-03, + 3.00872331445699433758e-03, + 2.98457355419296660459e-03, + 2.95896761771581541176e-03, + 2.93192300971099667137e-03, + 2.90345792178986830678e-03, + 2.87359122107115833381e-03, + 2.84234243844815569202e-03, + 2.80973175654865899714e-03, + 2.77577999739489662823e-03, + 2.74050860977057735360e-03, + 2.70393965630238552328e-03, + 2.66609580026378606421e-03, + 2.62700029210837524354e-03, + 2.58667695574077254050e-03, + 2.54515017453282822377e-03, + 2.50244487709332368713e-03, + 2.45858652279897166651e-03, + 2.41360108709495107052e-03, + 2.36751504657360840878e-03, + 2.32035536383917847733e-03, + 2.27214947216734537011e-03, + 2.22292525996793232518e-03, + 2.17271105505975571301e-03, + 2.12153560876561335380e-03, + 2.06942807983705873154e-03, + 2.01641801821680422338e-03, + 1.96253534864859182849e-03, + 1.90781035414268307880e-03, + 1.85227365930619859540e-03, + 1.79595621354771339470e-03, + 1.73888927416449511586e-03, + 1.68110438932177089048e-03, + 1.62263338093348468728e-03, + 1.56350832745304072283e-03, + 1.50376154658367453161e-03, + 1.44342557791726690958e-03, + 1.38253316551135724960e-03, + 1.32111724041281413007e-03, + 1.25921090313770521994e-03, + 1.19684740611688275949e-03, + 1.13406013611574898320e-03, + 1.07088259663794954646e-03, + 1.00734839032173340879e-03, + 9.43491201338451197442e-04, + 8.79344777802133358187e-04, + 8.14942914198997676867e-04, + 7.50319433846045077789e-04, + 6.85508171388117602645e-04, + 6.20542955341616764633e-04, + 5.55457590694125209752e-04, + 4.90285841569116395515e-04, + 4.25061413963795440944e-04, + 3.59817938569106346609e-04, + 2.94588953680933085706e-04, + 2.29407888210245771441e-04, + 1.64308044801349289110e-04, + 9.93225830661220992091e-05, + 3.44845029432159748818e-05, +-3.01733718103322993271e-05, +-9.46184099865878051579e-05, +-1.58818189144901994068e-04, +-2.22740511673599295237e-04, +-2.86353420686933518319e-04, +-3.49625215749474168095e-04, +-4.12524468420490651472e-04, +-4.75020037611034338584e-04, +-5.37081084745966554420e-04, +-5.98677088724102000189e-04, +-6.59777860668749548644e-04, +-7.20353558462378845868e-04, +-7.80374701058222453379e-04, +-8.39812182561741876058e-04, +-8.98637286076072534964e-04, +-9.56821697304657218380e-04, +-1.01433751790445296839e-03, +-1.07115727858425125243e-03, +-1.12725395194157021125e-03, +-1.18260096503265514645e-03, +-1.23717221166938983953e-03, +-1.29094206443821453087e-03, +-1.34388538643541812813e-03, +-1.39597754271321623266e-03, +-1.44719441143244622640e-03, +-1.49751239471598309415e-03, +-1.54690842919921311277e-03, +-1.59535999627203944548e-03, +-1.64284513200888535912e-03, +-1.68934243678199938477e-03, +-1.73483108455441971917e-03, +-1.77929083184826127527e-03, +-1.82270202638530284291e-03, +-1.86504561539608984359e-03, +-1.90630315359404723698e-03, +-1.94645681081197273812e-03, +-1.98548937929780454012e-03, +-2.02338428066662365593e-03, +-2.06012557250690765687e-03, +-2.09569795463821536424e-03, +-2.13008677501847496286e-03, +-2.16327803529848140124e-03, +-2.19525839602226170363e-03, +-2.22601518147149193827e-03, +-2.25553638415244925991e-03, +-2.28381066892440051305e-03, +-2.31082737676846549160e-03, +-2.33657652819600639496e-03, +-2.36104882629574550773e-03, +-2.38423565941946538627e-03, +-2.40612910350581450311e-03, +-2.42672192404203967281e-03, +-2.44600757766397268814e-03, +-2.46398021339438002067e-03, +-2.48063467352028057047e-03, +-2.49596649410964519650e-03, +-2.50997190516864723125e-03, +-2.52264783044025284534e-03, +-2.53399188684540720151e-03, +-2.54400238356825665262e-03, +-2.55267832078691359055e-03, +-2.56001938805160448795e-03, +-2.56602596231194192769e-03, +-2.57069910559561132235e-03, +-2.57404056234069840772e-03, +-2.57605275638400242275e-03, +-2.57673878760806066013e-03, +-2.57610242824962915389e-03, +-2.57414811887259368725e-03, +-2.57088096400836900457e-03, +-2.56630672746716416779e-03, +-2.56043182732341697075e-03, +-2.55326333057917390437e-03, +-2.54480894750897836121e-03, +-2.53507702569032763312e-03, +-2.52407654372365647388e-03, +-2.51181710464612895778e-03, +-2.49830892904353337597e-03, +-2.48356284786475705814e-03, +-2.46759029494360467016e-03, +-2.45040329923257435216e-03, +-2.43201447675357512387e-03, +-2.41243702227060758184e-03, +-2.39168470068965325834e-03, +-2.36977183819085321370e-03, +-2.34671331309871259233e-03, +-2.32252454649548413859e-03, +-2.29722149258377488293e-03, +-2.27082062880380698353e-03, +-2.24333894571130537665e-03, +-2.21479393662223902547e-03, +-2.18520358703003540410e-03, +-2.15458636380176215414e-03, +-2.12296120415960722083e-03, +-2.09034750445369690852e-03, +-2.05676510873303809365e-03, +-2.02223429712087166693e-03, +-1.98677577400132665889e-03, +-1.95041065602380068143e-03, +-1.91316045993188566660e-03, +-1.87504709022398054208e-03, +-1.83609282665202818569e-03, +-1.79632031156571974305e-03, +-1.75575253710894539118e-03, +-1.71441283227574312563e-03, +-1.67232484983291908656e-03, +-1.62951255311622692640e-03, +-1.58600020270752910083e-03, +-1.54181234300042021082e-03, +-1.49697378866114633872e-03, +-1.45150961099237444871e-03, +-1.40544512420743054025e-03, +-1.35880587162187237323e-03, +-1.31161761177006727826e-03, +-1.26390630445442453227e-03, +-1.21569809673418671551e-03, +-1.16701930886166653674e-03, +-1.11789642017300181083e-03, +-1.06835605494137557414e-03, +-1.01842496819956130141e-03, +-9.68130031539442812739e-04, +-9.17498218896290623249e-04, +-8.66556592324564493868e-04, +-8.15332287772978616183e-04, +-7.63852500866257408917e-04, +-7.12144472700820384964e-04, +-6.60235475661517237297e-04, +-6.08152799267011124132e-04, +-5.55923736050680200420e-04, +-5.03575567484773503439e-04, +-4.51135549954315671906e-04, +-3.98630900788171399930e-04, +-3.46088784354618185513e-04, +-2.93536298227804867602e-04, +-2.41000459432347881880e-04, +-1.88508190773214112049e-04, +-1.36086307257084302303e-04, +-8.37615026124415208318e-05, +-3.15603359146758591044e-05, + 2.04907816767023618287e-05, + 7.23656000628412833693e-05, + 1.24038043225600054433e-04, + 1.75482222116205200833e-04, + 2.26672447407071596913e-04, + 2.77583242099614419147e-04, + 3.28189353983021332804e-04, + 3.78465767937005519422e-04, + 4.28387718073507952569e-04, + 4.77930699711027453993e-04, + 5.27070481176294264314e-04, + 5.75783115427220041314e-04, + 6.24044951492278227381e-04, + 6.71832645720683982113e-04, + 7.19123172837888647094e-04, + 7.65893836801815361230e-04, + 8.12122281454607207463e-04, + 8.57786500964706813931e-04, + 9.02864850055145489773e-04, + 9.47336054012924352885e-04, + 9.91179218475344821562e-04, + 1.03437383898850724685e-03, + 1.07689981033424705438e-03, + 1.11873743562118156160e-03, + 1.15986743513579325555e-03, + 1.20027095494985164281e-03, + 1.23992957528063201672e-03, + 1.27882531860024116835e-03, + 1.31694065749045157408e-03, + 1.35425852224024464987e-03, + 1.39076230818266951932e-03, + 1.42643588276789089024e-03, + 1.46126359237003949389e-03, + 1.49523026882479484305e-03, + 1.52832123569547530945e-03, + 1.56052231426488533308e-03, + 1.59181982925111196493e-03, + 1.62220061424500194142e-03, + 1.65165201686719317030e-03, + 1.68016190364333106375e-03, + 1.70771866459552704512e-03, + 1.73431121754877184786e-03, + 1.75992901215076880984e-03, + 1.78456203360429659956e-03, + 1.80820080611094821665e-03, + 1.83083639602529585529e-03, + 1.85246041471891220720e-03, + 1.87306502115368290161e-03, + 1.89264292416397640097e-03, + 1.91118738444732896159e-03, + 1.92869221626372814270e-03, + 1.94515178884347187879e-03, + 1.96056102750367033591e-03, + 1.97491541447399011552e-03, + 1.98821098943195847739e-03, + 2.00044434974860733945e-03, + 2.01161265044509608366e-03, + 2.02171360386141883703e-03, + 2.03074547903829647627e-03, + 2.03870710081329245544e-03, + 2.04559784863279697439e-03, + 2.05141765508121132200e-03, + 2.05616700412915255278e-03, + 2.05984692910230610119e-03, + 2.06245901037309994214e-03, + 2.06400537277705341602e-03, + 2.06448868275625058155e-03, + 2.06391214523207744413e-03, + 2.06227950020990537586e-03, + 2.05959501911819184081e-03, + 2.05586350088483903534e-03, + 2.05109026775365885925e-03, + 2.04528116084394225374e-03, + 2.03844253545626581670e-03, + 2.03058125612778830188e-03, + 2.02170469144040887075e-03, + 2.01182070858521491047e-03, + 2.00093766768695948202e-03, + 1.98906441589210680049e-03, + 1.97621028122438920777e-03, + 1.96238506621177182659e-03, + 1.94759904128888393197e-03, + 1.93186293797900990321e-03, + 1.91518794185986402506e-03, + 1.89758568531769714928e-03, + 1.87906824009385019746e-03, + 1.85964810962852347687e-03, + 1.83933822120627122297e-03, + 1.81815191790804173144e-03, + 1.79610295037441560807e-03, + 1.77320546838494034515e-03, + 1.74947401225873200130e-03, + 1.72492350408103120758e-03, + 1.69956923876105037673e-03, + 1.67342687492632539309e-03, + 1.64651242565860508361e-03, + 1.61884224907680703345e-03, + 1.59043303877220510226e-03, + 1.56130181410158168538e-03, + 1.53146591034349164456e-03, + 1.50094296872333799256e-03, + 1.46975092631300560328e-03, + 1.43790800581038743892e-03, + 1.40543270520465083014e-03, + 1.37234378733301696889e-03, + 1.33866026933477191320e-03, + 1.30440141200818598630e-03, + 1.26958670907636713213e-03, + 1.23423587636767762184e-03, + 1.19836884091695044206e-03, + 1.16200572999298904278e-03, + 1.12516686005846404395e-03, + 1.08787272566834868938e-03, + 1.05014398831246302812e-03, + 1.01200146520824866246e-03, + 9.73466118049983288388e-04, + 9.34559041719948196611e-04, + 8.95301452967915711335e-04, + 8.55714679064593008659e-04, + 8.15820146435422468428e-04, + 7.75639369280203805866e-04, + 7.35193938184691589237e-04, + 6.94505508730360781103e-04, + 6.53595790107610935191e-04, + 6.12486533739071471218e-04, + 5.71199521918073420228e-04, + 5.29756556468897262142e-04, + 4.88179447433947737416e-04, + 4.46490001794050709802e-04, + 4.04710012227305993091e-04, + 3.62861245912609686835e-04, + 3.20965433382992511909e-04, + 2.79044257434640438631e-04, + 2.37119342097372800019e-04, + 1.95212241671636533603e-04, + 1.53344429837704167947e-04, + 1.11537288842718541599e-04, + 6.98120987704314377789e-05, + 2.81900268993452554395e-05, +-1.33078828458379828427e-05, +-5.46607203438825674300e-05, +-9.58477196232063128950e-05, +-1.36848269099311073286e-04, +-1.77641921698430010380e-04, +-2.18208404862630192013e-04, +-2.58527630431676846631e-04, +-2.98579704396867049668e-04, +-3.38344936521953437280e-04, +-3.77803849827058782322e-04, +-4.16937189930904319925e-04, +-4.55725934246739843459e-04, +-4.94151301028182598010e-04, +-5.32194758260364701556e-04, +-5.69838032392598397777e-04, +-6.07063116908156791794e-04, +-6.43852280727741713151e-04, +-6.80188076442613171781e-04, +-7.16053348373450011463e-04, +-7.51431240451819475352e-04, +-7.86305203920363614614e-04, +-8.20659004848588277854e-04, +-8.54476731460626398769e-04, +-8.87742801272211191736e-04, +-9.20441968033579760618e-04, +-9.52559328475276884118e-04, +-9.84080328854130366098e-04, +-1.01499077129671671886e-03, +-1.04527681993767346084e-03, +-1.07492500685012399610e-03, +-1.10392223776622968451e-03, +-1.13225579758538573774e-03, +-1.15991335566776048067e-03, +-1.18688297091152023324e-03, +-1.21315309661150744040e-03, +-1.23871258509778933189e-03, +-1.26355069215218973264e-03, +-1.28765708120147479195e-03, +-1.31102182728572635648e-03, +-1.33363542080036233568e-03, +-1.35548877101096445358e-03, +-1.37657320933958870861e-03, +-1.39688049242180935793e-03, +-1.41640280493340441764e-03, +-1.43513276218638474030e-03, +-1.45306341249334513427e-03, +-1.47018823930013145355e-03, +-1.48650116308605430814e-03, +-1.50199654303180877256e-03, +-1.51666917845484855790e-03, +-1.53051431001215848537e-03, +-1.54352762067077827791e-03, +-1.55570523644627803014e-03, +-1.56704372690943645810e-03, +-1.57754010546188694168e-03, +-1.58719182938115940286e-03, +-1.59599679963599232028e-03, +-1.60395336047266818397e-03, +-1.61106029877347285521e-03, +-1.61731684318832920691e-03, +-1.62272266304074063749e-03, +-1.62727786700950075895e-03, +-1.63098300158752559583e-03, +-1.63383904931938927878e-03, +-1.63584742681915007098e-03, +-1.63700998257036147918e-03, +-1.63732899451001076216e-03, +-1.63680716739846910703e-03, +-1.63544762997745404300e-03, +-1.63325393191824947553e-03, +-1.63023004056244216753e-03, +-1.62638033745757639228e-03, +-1.62170961469021174955e-03, +-1.61622307101895478811e-03, +-1.60992630781018361379e-03, +-1.60282532477918769794e-03, +-1.59492651553961163439e-03, +-1.58623666296416683703e-03, +-1.57676293435965995428e-03, +-1.56651287645941865272e-03, +-1.55549441023637930251e-03, +-1.54371582554013535814e-03, +-1.53118577556127515200e-03, +-1.51791327112649242562e-03, +-1.50390767482801038582e-03, +-1.48917869499094052133e-03, +-1.47373637948217746547e-03, +-1.45759110936466060836e-03, +-1.44075359240074425682e-03, +-1.42323485640868073465e-03, +-1.40504624247599204864e-03, +-1.38619939803382081524e-03, +-1.36670626979641294217e-03, +-1.34657909656966815262e-03, +-1.32583040193301449593e-03, +-1.30447298679896685550e-03, +-1.28251992185438013459e-03, +-1.25998453988795662377e-03, +-1.23688042800817435581e-03, +-1.21322141975630610686e-03, +-1.18902158711867676766e-03, +-1.16429523244280098797e-03, +-1.13905688026204581637e-03, +-1.11332126903301116203e-03, +-1.08710334279067352171e-03, +-1.06041824272541424130e-03, +-1.03328129868704887868e-03, +-1.00570802062011207742e-03, +-9.77714089935322180555e-04, +-9.49315350821759501229e-04, +-9.20527801504691478400e-04, +-8.91367585453492765508e-04, +-8.61850982544499480062e-04, +-8.31994400183724228809e-04, +-8.01814364393843201882e-04, +-7.71327510870362977047e-04, +-7.40550576011879011992e-04, +-7.09500387928816301369e-04, +-6.78193857435692871310e-04, +-6.46647969031396334730e-04, +-6.14879771872516131710e-04, +-5.82906370744061324771e-04, +-5.50744917032461615489e-04, +-5.18412599705563741960e-04, +-4.85926636304230086336e-04, +-4.53304263950078342206e-04, +-4.20562730374023118537e-04, +-3.87719284970423796848e-04, +-3.54791169881019867287e-04, +-3.21795611113349097968e-04, +-2.88749809698345409788e-04, +-2.55670932891157169815e-04, +-2.22576105419946933131e-04, +-1.89482400786797724242e-04, +-1.56406832625384566377e-04, +-1.23366346119315335164e-04, +-9.03778094855688048136e-05, +-5.74580055274082543144e-05, +-2.46236232605249242254e-05, + 8.10875038316639484403e-06, + 4.07226387702898438674e-05, + 7.32016836950174766508e-05, + 1.05529653418793463730e-04, + 1.37690450616703013997e-04, + 1.69668120226623675949e-04, + 2.01446857197505152211e-04, + 2.33011014133184106998e-04, + 2.64345108828066273181e-04, + 2.95433831690941053547e-04, + 3.26262053053821875562e-04, + 3.56814830362236329840e-04, + 3.87077415243466558745e-04, + 4.17035260449873101951e-04, + 4.46674026673809685620e-04, + 4.75979589231274630330e-04, + 5.04938044610982032269e-04, + 5.33535716886269443388e-04, + 5.61759163986835612092e-04, + 5.89595183827354429873e-04, + 6.17030820290651992738e-04, + 6.44053369062530110985e-04, + 6.70650383315962803771e-04, + 6.96809679241917109133e-04, + 7.22519341424928177552e-04, + 7.47767728060641924219e-04, + 7.72543476013702731450e-04, + 7.96835505713403631674e-04, + 8.20633025885535226200e-04, + 8.43925538118381487161e-04, + 8.66702841260924973336e-04, + 8.88955035651854165446e-04, + 9.10672527177615212350e-04, + 9.31846031157871484973e-04, + 9.52466576057239681409e-04, + 9.72525507021732124775e-04, + 9.92014489238877755425e-04, + 1.01092551112014119447e-03, + 1.02925088730489687483e-03, + 1.04698326148487523037e-03, + 1.06411560904814419225e-03, + 1.08064123954212140503e-03, + 1.09655379895474709012e-03, + 1.11184727181350227060e-03, + 1.12651598310145530275e-03, + 1.14055459999043234086e-03, + 1.15395813339070935251e-03, + 1.16672193931725690953e-03, + 1.17884172007230573521e-03, + 1.19031352524443380207e-03, + 1.20113375252423222606e-03, + 1.21129914833666986994e-03, + 1.22080680829065105208e-03, + 1.22965417744607123825e-03, + 1.23783905039882846655e-03, + 1.24535957118451323482e-03, + 1.25221423300135711529e-03, + 1.25840187775329488164e-03, + 1.26392169541390537828e-03, + 1.26877322321232639292e-03, + 1.27295634464211107444e-03, + 1.27647128829414154005e-03, + 1.27931862651490548498e-03, + 1.28149927389138891531e-03, + 1.28301448556399880392e-03, + 1.28386585536898346210e-03, + 1.28405531381196435364e-03, + 1.28358512587416814105e-03, + 1.28245788865312404514e-03, + 1.28067652883962455890e-03, + 1.27824430003284665244e-03, + 1.27516477989559045420e-03, + 1.27144186715168476705e-03, + 1.26707977842766580760e-03, + 1.26208304494093768826e-03, + 1.25645650903666696377e-03, + 1.25020532057574596321e-03, + 1.24333493317623205304e-03, + 1.23585110031071486285e-03, + 1.22775987126220184967e-03, + 1.21906758694106096864e-03, + 1.20978087556570016413e-03, + 1.19990664820977745338e-03, + 1.18945209421860830651e-03, + 1.17842467649774342194e-03, + 1.16683212667649549056e-03, + 1.15468244014949755240e-03, + 1.14198387099919015063e-03, + 1.12874492680236585690e-03, + 1.11497436332383317165e-03, + 1.10068117910044980384e-03, + 1.08587460991860403070e-03, + 1.07056412318845268865e-03, + 1.05475941221827552129e-03, + 1.03847039039213777552e-03, + 1.02170718525430208670e-03, + 1.00448013250386408712e-03, + 9.86799769902908796571e-04, + 9.68676831101775311604e-04, + 9.50122239384842536686e-04, + 9.31147101340516931967e-04, + 9.11762700458799784341e-04, + 8.91980490660106628206e-04, + 8.71812089758989324645e-04, + 8.51269272866356447108e-04, + 8.30363965733769732354e-04, + 8.09108238043540397427e-04, + 7.87514296648406260902e-04, + 7.65594478764287304610e-04, + 7.43361245119910263486e-04, + 7.20827173067144330761e-04, + 6.98004949655533580080e-04, + 6.74907364674943543829e-04, + 6.51547303669901115876e-04, + 6.27937740929578719871e-04, + 6.04091732456894250046e-04, + 5.80022408920566161228e-04, + 5.55742968593996586671e-04, + 5.31266670284408345712e-04, + 5.06606826256191336046e-04, + 4.81776795151971288286e-04, + 4.56789974915332633570e-04, + 4.31659795718581772855e-04, + 4.06399712899354833857e-04, + 3.81023199909761244551e-04, + 3.55543741281616379035e-04, + 3.29974825611307478416e-04, + 3.04329938567904757871e-04, + 2.78622555928232935440e-04, + 2.52866136642138929734e-04, + 2.27074115931597155090e-04, + 2.01259898427254919819e-04, + 1.75436851345555256277e-04, + 1.49618297710086417540e-04, + 1.23817509620332964109e-04, + 9.80477015714136803867e-05, + 7.23220238277867656044e-05, + 4.66535558543199922808e-05, + 2.10552998080745397132e-05, +-4.45982590633637267685e-06, +-2.98789930144383005840e-05, +-5.51894696797388301145e-05, +-8.03786267385361320997e-05, +-1.05433943858796803006e-04, +-1.30343015620240231141e-04, +-1.55093557512704107414e-04, +-1.79673411849813922459e-04, +-2.04070553595469639328e-04, +-2.28273096100298591472e-04, +-2.52269296745275168909e-04, +-2.76047562490193821964e-04, +-2.99596455324310003560e-04, +-3.22904697616543522477e-04, +-3.45961177363105203825e-04, +-3.68754953329960058744e-04, +-3.91275260088006534946e-04, +-4.13511512938510329696e-04, +-4.35453312726917203881e-04, +-4.57090450542803317623e-04, +-4.78412912303817451296e-04, +-4.99410883221915679296e-04, +-5.20074752149766658671e-04, +-5.40395115805737333292e-04, +-5.60362782875298238647e-04, +-5.79968777987699369778e-04, +-5.99204345565891864818e-04, +-6.18060953548384053174e-04, +-6.36530296981365232775e-04, +-6.54604301479925370678e-04, +-6.72275126556943374879e-04, +-6.89535168818290744586e-04, +-7.06377065023390971615e-04, +-7.22793695009926024340e-04, +-7.38778184481572101731e-04, +-7.54323907658020135873e-04, +-7.69424489786242268852e-04, +-7.84073809512324942927e-04, +-7.98266001112985629749e-04, +-8.11995456586320977881e-04, +-8.25256827601124256372e-04, +-8.38045027304191287275e-04, +-8.50355231985365717443e-04, +-8.62182882599891249782e-04, +-8.73523686147764872115e-04, +-8.84373616909959786754e-04, +-8.94728917541413090037e-04, +-9.04586100020679756244e-04, +-9.13941946456355816704e-04, +-9.22793509750267264627e-04, +-9.31138114117751138944e-04, +-9.38973355465201283722e-04, +-9.46297101625169024067e-04, +-9.53107492449534513500e-04, +-9.59402939761150449702e-04, +-9.65182127164483996684e-04, +-9.70444009715949393313e-04, +-9.75187813454562795953e-04, +-9.79413034793723616400e-04, +-9.83119439774883139768e-04, +-9.86307063184082167401e-04, +-9.88976207532291833394e-04, +-9.91127441900544869230e-04, +-9.92761600651050806279e-04, +-9.93879782005378667811e-04, +-9.94483346490992797459e-04, +-9.94573915257405570187e-04, +-9.94153368263331295093e-04, +-9.93223842336246652909e-04, +-9.91787729105850180897e-04, +-9.89847672812951264940e-04, +-9.87406567995411906316e-04, +-9.84467557052782528404e-04, +-9.81034027691367847834e-04, +-9.77109610251477699733e-04, +-9.72698174918703792335e-04, +-9.67803828821115733234e-04, +-9.62430913014279427325e-04, +-9.56583999356122919276e-04, +-9.50267887273650141942e-04, +-9.43487600423628257514e-04, +-9.36248383249343269982e-04, +-9.28555697435622562526e-04, +-9.20415218264345998470e-04, +-9.11832830872733794518e-04, +-9.02814626416679100358e-04, +-8.93366898141493941121e-04, +-8.83496137362504399722e-04, +-8.73209029357859358757e-04, +-8.62512449176020662943e-04, +-8.51413457360529739998e-04, +-8.39919295594453380396e-04, +-8.28037382267176572288e-04, +-8.15775307966064137412e-04, +-8.03140830895733765817e-04, +-7.90141872227454497395e-04, +-7.76786511381427125823e-04, +-7.63082981244709722575e-04, +-7.49039663327390583050e-04, +-7.34665082859875225377e-04, +-7.19967903833961626534e-04, +-7.04956923990644160512e-04, +-6.89641069757283018196e-04, +-6.74029391137054853869e-04, +-6.58131056553546409972e-04, +-6.41955347653322514097e-04, +-6.25511654069284880192e-04, +-6.08809468147721304272e-04, +-5.91858379642030605315e-04, +-5.74668070375839888306e-04, +-5.57248308878482566560e-04, +-5.39608944995842118066e-04, +-5.21759904479256251923e-04, +-5.03711183555554655941e-04, +-4.85472843480994986718e-04, +-4.67055005082172224832e-04, +-4.48467843286585717087e-04, +-4.29721581645848931235e-04, +-4.10826486854523479156e-04, +-3.91792863267230776457e-04, +-3.72631047417096349181e-04, +-3.53351402538234474118e-04, +-3.33964313095238879339e-04, +-3.14480179322441726845e-04, +-2.94909411775696268711e-04, +-2.75262425899514299663e-04, +-2.55549636612443630684e-04, +-2.35781452913229664075e-04, +-2.15968272510589943134e-04, +-1.96120476479425779204e-04, +-1.76248423945933802622e-04, +-1.56362446804383454146e-04, +-1.36472844468305155993e-04, +-1.16589878658458767635e-04, +-9.67237682303544415822e-05, +-7.68846840437216406863e-05, +-5.70827438766376965410e-05, +-3.73280073865603565495e-05, +-1.76304711208225556719e-05, + 1.99993642088864226016e-06, + 2.15533596699292954036e-05, + 4.10200208154242509364e-05, + 6.03902245722433725860e-05, + 7.96543628875890849517e-05, + 9.88029195844659414733e-05, + 1.17826474939476195025e-04, + 1.36715710193023647035e-04, + 1.55461411989631342456e-04, + 1.74054476746553134919e-04, + 1.92485914948569894868e-04, + 2.10746855366906229437e-04, + 2.28828549200575789499e-04, + 2.46722374138184409598e-04, + 2.64419838338276027342e-04, + 2.81912584326679917842e-04, + 2.99192392808960154656e-04, + 3.16251186396444155819e-04, + 3.33081033244039836395e-04, + 3.49674150598494463179e-04, + 3.66022908255491080231e-04, + 3.82119831924034101915e-04, + 3.97957606496917735885e-04, + 4.13529079225828470872e-04, + 4.28827262799762372065e-04, + 4.43845338325564724331e-04, + 4.58576658209470361914e-04, + 4.73014748938412597258e-04, + 4.87153313760160528844e-04, + 5.00986235261103489760e-04, + 5.14507577840937952753e-04, + 5.27711590083254872101e-04, + 5.40592707021128712937e-04, + 5.53145552297087950144e-04, + 5.65364940216665540391e-04, + 5.77245877694797693454e-04, + 5.88783566094626962042e-04, + 5.99973402958039613193e-04, + 6.10810983627539487439e-04, + 6.21292102758916895203e-04, + 6.31412755724494408928e-04, + 6.41169139906554250846e-04, + 6.50557655880656818606e-04, + 6.59574908488803728079e-04, + 6.68217707802125100019e-04, + 6.76483069973211437013e-04, + 6.84368217977891248049e-04, + 6.91870582246639927691e-04, + 6.98987801185634960270e-04, + 7.05717721587660520161e-04, + 7.12058398933015208009e-04, + 7.18008097580767590783e-04, + 7.23565290850654123378e-04, + 7.28728660995954687085e-04, + 7.33497099067867354590e-04, + 7.37869704671835252748e-04, + 7.41845785616332496076e-04, + 7.45424857454791262544e-04, + 7.48606642921267949158e-04, + 7.51391071260577316469e-04, + 7.53778277453638493114e-04, + 7.55768601338868977087e-04, + 7.57362586630487056617e-04, + 7.58560979834606492235e-04, + 7.59364729064121901821e-04, + 7.59774982753388386167e-04, + 7.59793088273752925850e-04, + 7.59420590451042459845e-04, + 7.58659229986178283191e-04, + 7.57510941780111337653e-04, + 7.55977853164323059486e-04, + 7.54062282038194995303e-04, + 7.51766734914572948463e-04, + 7.49093904874909206383e-04, + 7.46046669435407165151e-04, + 7.42628088325620098163e-04, + 7.38841401181018265533e-04, + 7.34690025151058076665e-04, + 7.30177552424332988561e-04, + 7.25307747672431467334e-04, + 7.20084545414128533031e-04, + 7.14512047301645285974e-04, + 7.08594519330652482768e-04, + 7.02336388975790940938e-04, + 6.95742242253507572024e-04, + 6.88816820714019178648e-04, + 6.81565018364235775117e-04, + 6.73991878523528100201e-04, + 6.66102590614281019760e-04, + 6.57902486889110115278e-04, + 6.49397039096706574744e-04, + 6.40591855088354865909e-04, + 6.31492675367040820315e-04, + 6.22105369581239602515e-04, + 6.12435932965378496476e-04, + 6.02490482729133372541e-04, + 5.92275254397530565020e-04, + 5.81796598104019854238e-04, + 5.71060974838680235344e-04, + 5.60074952653592437156e-04, + 5.48845202827616417997e-04, + 5.37378495992671769733e-04, + 5.25681698223757196999e-04, + 5.13761767094866308656e-04, + 5.01625747702958151193e-04, + 4.89280768662212254237e-04, + 4.76734038070840296462e-04, + 4.63992839452548365767e-04, + 4.51064527674926475653e-04, + 4.37956524847056961718e-04, + 4.24676316198432479525e-04, + 4.11231445941475173573e-04, + 3.97629513119952544397e-04, + 3.83878167445365014142e-04, + 3.69985105123653247247e-04, + 3.55958064674343052560e-04, + 3.41804822744478146133e-04, + 3.27533189919382002140e-04, + 3.13151006532530441166e-04, + 2.98666138476795246359e-04, + 2.84086473019086157080e-04, + 2.69419914620704385386e-04, + 2.54674380765407412045e-04, + 2.39857797797613132851e-04, + 2.24978096772516947353e-04, + 2.10043209320515654199e-04, + 1.95061063527882452839e-04, + 1.80039579835930709352e-04, + 1.64986666960563460723e-04, + 1.49910217834334317253e-04, + 1.34818105573139893332e-04, + 1.19718179469376976285e-04, + 1.04618261013640937926e-04, + 8.95261399470057895635e-05, + 7.44495703456539838043e-05, + 5.93962667399166655609e-05, + 4.43739002695007426613e-05, + 2.93900948769175320138e-05, + 1.44524235407680616859e-05, +-4.31595449223615991972e-07, +-1.52545021735661563586e-05, +-3.00088987191676871767e-05, +-4.46874527685018162865e-05, +-5.92829011400601544354e-05, +-7.37880532784749535325e-05, +-8.81957946927382018627e-05, +-1.02499090340838023227e-04, +-1.16690987959360069175e-04, +-1.30764621336392747363e-04, +-1.44713213526426610466e-04, +-1.58530080005720515508e-04, +-1.72208631766646892702e-04, +-1.85742378349807455221e-04, +-1.99124930812504506716e-04, +-2.12350004632196330849e-04, +-2.25411422543850048289e-04, +-2.38303117309836905331e-04, +-2.51019134421297284484e-04, +-2.63553634729709143104e-04, +-2.75900897007725623075e-04, +-2.88055320438154207046e-04, +-3.00011427029988502792e-04, +-3.11763863960725555544e-04, +-3.23307405843803333592e-04, +-3.34636956920517840506e-04, +-3.45747553175349475393e-04, +-3.56634364374105745227e-04, +-3.67292696023986241921e-04, +-3.77717991254969290369e-04, +-3.87905832621729396159e-04, +-3.97851943825608877700e-04, +-4.07552191355998907722e-04, +-4.17002586050548289687e-04, +-4.26199284573830689850e-04, +-4.35138590813964924123e-04, +-4.43816957196747625784e-04, +-4.52230985917061883723e-04, +-4.60377430087148228118e-04, +-4.68253194801565195918e-04, +-4.75855338118517359660e-04, +-4.83181071957494603746e-04, +-4.90227762913035460673e-04, +-4.96992932984516386924e-04, +-5.03474260221955485957e-04, +-5.09669579287852308157e-04, +-5.15576881935093001182e-04, +-5.21194317400982664451e-04, +-5.26520192717613616691e-04, +-5.31552972938706402850e-04, +-5.36291281283125418830e-04, +-5.40733899195399727276e-04, +-5.44879766323496587781e-04, +-5.48727980414253735213e-04, +-5.52277797126791330021e-04, +-5.55528629764419335478e-04, +-5.58480048925468798571e-04, +-5.61131782073551080119e-04, +-5.63483713027851970505e-04, +-5.65535881373998238451e-04, +-5.67288481796187900146e-04, +-5.68741863331195915583e-04, +-5.69896528545036479795e-04, +-5.70753132632961161612e-04, +-5.71312482443646482352e-04, +-5.71575535428334754844e-04, +-5.71543398515829263219e-04, +-5.71217326914227299835e-04, +-5.70598722840296476537e-04, +-5.69689134177503594091e-04, +-5.68490253063648432949e-04, +-5.67003914409159020388e-04, +-5.65232094347102977452e-04, +-5.63176908616005544687e-04, +-5.60840610876602073745e-04, +-5.58225590963675973900e-04, +-5.55334373074175820066e-04, +-5.52169613892796438438e-04, +-5.48734100656311134595e-04, +-5.45030749157866334711e-04, +-5.41062601692576870642e-04, +-5.36832824945712001018e-04, +-5.32344707824832300003e-04, +-5.27601659237243400015e-04, +-5.22607205814143416754e-04, +-5.17364989582876229866e-04, +-5.11878765588764158417e-04, +-5.06152399467916375153e-04, +-5.00189864972510559588e-04, +-4.93995241450078683386e-04, +-4.87572711278240109554e-04, +-4.80926557256444178138e-04, +-4.74061159956301635728e-04, +-4.66980995031984519490e-04, +-4.59690630492344271939e-04, +-4.52194723936275402073e-04, +-4.44498019752993822097e-04, +-4.36605346288767746325e-04, +-4.28521612981757975790e-04, +-4.20251807466636860457e-04, +-4.11800992650551039072e-04, +-4.03174303762152705464e-04, +-3.94376945375264067670e-04, +-3.85414188409003615268e-04, +-3.76291367105835428391e-04, +-3.67013875989376269545e-04, +-3.57587166803538351878e-04, +-3.48016745434793248019e-04, +-3.38308168819116130647e-04, +-3.28467041835364367049e-04, +-3.18499014186804374482e-04, +-3.08409777272385283997e-04, +-2.98205061049476030047e-04, +-2.87890630889810130322e-04, +-2.77472284430191329634e-04, +-2.66955848419733049459e-04, +-2.56347175565217071970e-04, +-2.45652141376338599681e-04, +-2.34876641012365765249e-04, +-2.24026586131914569105e-04, +-2.13107901747536509227e-04, +-2.02126523086630768746e-04, +-1.91088392460356650080e-04, +-1.79999456142178738786e-04, +-1.68865661257607132476e-04, +-1.57692952686686938598e-04, +-1.46487269980864699605e-04, +-1.35254544295716316437e-04, +-1.24000695341184972607e-04, +-1.12731628350718165836e-04, +-1.01453231070878122327e-04, +-9.01713707729724520340e-05, +-7.88918912880573160781e-05, +-6.76206100668247551966e-05, +-5.63633152658752571273e-05, +-4.51257628616542845251e-05, +-3.39136737935608547517e-05, +-2.27327311375149941554e-05, +-1.15885773114489628905e-05, +-4.86811313915871210201e-07, + 1.05670140028143166991e-05, + 2.15673946238210968425e-05, + 3.25088780256781116596e-05, + 4.33860657922279085714e-05, + 5.41936161910015515536e-05, + 6.49262467088870516650e-05, + 7.55787365460706083136e-05, + 8.61459290670060090240e-05, + 9.66227342073920110596e-05, + 1.07004130835977286562e-04, + 1.17285169070277186945e-04, + 1.27460972545122102045e-04, + 1.37526740632994235337e-04, + 1.47477750615313961575e-04, + 1.57309359803685470123e-04, + 1.67017007610150564068e-04, + 1.76596217565703518526e-04, + 1.86042599286130139018e-04, + 1.95351850384440511605e-04, + 2.04519758329024586505e-04, + 2.13542202246907178919e-04, + 2.22415154671328456478e-04, + 2.31134683232958544662e-04, + 2.39696952294124378952e-04, + 2.48098224525461843754e-04, + 2.56334862424394095085e-04, + 2.64403329774836909783e-04, + 2.72300193047718441016e-04, + 2.80022122741781036813e-04, + 2.87565894664178829838e-04, + 2.94928391150552234555e-04, + 3.02106602224121655823e-04, + 3.09097626693513312206e-04, + 3.15898673188933149566e-04, + 3.22507061136495965393e-04, + 3.28920221670429965485e-04, + 3.35135698482898333403e-04, + 3.41151148611357961198e-04, + 3.46964343163231182625e-04, + 3.52573167977838467131e-04, + 3.57975624225448146778e-04, + 3.63169828943500801448e-04, + 3.68154015509882480677e-04, + 3.72926534053389822573e-04, + 3.77485851801332371845e-04, + 3.81830553364452182901e-04, + 3.85959340959241372672e-04, + 3.89871034567797159973e-04, + 3.93564572035445218046e-04, + 3.97039009106330996121e-04, + 4.00293519397200458273e-04, + 4.03327394309708944353e-04, + 4.06140042881526601437e-04, + 4.08730991576614218711e-04, + 4.11099884015009905264e-04, + 4.13246480642570374747e-04, + 4.15170658341088754176e-04, + 4.16872409979225850337e-04, + 4.18351843904797517006e-04, + 4.19609183378898695574e-04, + 4.20644765952442063056e-04, + 4.21459042785672199482e-04, + 4.22052577911266981522e-04, + 4.22426047441667507944e-04, + 4.22580238721291740270e-04, + 4.22516049424304497659e-04, + 4.22234486598678352993e-04, + 4.21736665657268593004e-04, + 4.21023809316662376602e-04, + 4.20097246484596811584e-04, + 4.18958411096749831423e-04, + 4.17608840903733937334e-04, + 4.16050176209156481050e-04, + 4.14284158559614175323e-04, + 4.12312629387525297810e-04, + 4.10137528607722027553e-04, + 4.07760893168739989995e-04, + 4.05184855559753253750e-04, + 4.02411642274163466621e-04, + 3.99443572230806823956e-04, + 3.96283055153818239771e-04, + 3.92932589912160215497e-04, + 3.89394762819913727372e-04, + 3.85672245898332176350e-04, + 3.81767795100792530199e-04, + 3.77684248501704115941e-04, + 3.73424524450519546449e-04, + 3.68991619691936916479e-04, + 3.64388607453439920380e-04, + 3.59618635501351871335e-04, + 3.54684924166520241986e-04, + 3.49590764340821041987e-04, + 3.44339515445693598438e-04, + 3.38934603373838513624e-04, + 3.33379518405329915154e-04, + 3.27677813099311473176e-04, + 3.21833100162536569697e-04, + 3.15849050295926377270e-04, + 3.09729390020389752213e-04, + 3.03477899483178554640e-04, + 2.97098410245953236785e-04, + 2.90594803055835239260e-04, + 2.83971005600701430303e-04, + 2.77230990249963083708e-04, + 2.70378771782053405493e-04, + 2.63418405099919501929e-04, + 2.56353982935728650153e-04, + 2.49189633546102382294e-04, + 2.41929518399063687127e-04, + 2.34577829853976687832e-04, + 2.27138788835770893786e-04, + 2.19616642504623810770e-04, + 2.12015661922379533436e-04, + 2.04340139716986798554e-04, + 1.96594387746109900425e-04, + 1.88782734761210285561e-04, + 1.80909524073276134666e-04, + 1.72979111221486337802e-04, + 1.64995861645938764022e-04, + 1.56964148365684399598e-04, + 1.48888349663314485498e-04, + 1.40772846777168322190e-04, + 1.32622021602487612625e-04, + 1.24440254402532454779e-04, + 1.16231921530969174315e-04, + 1.08001393166544268506e-04, + 9.97530310612700842022e-05, + 9.14911863031805467012e-05, + 8.32201970948494534723e-05, + 7.49443865486733659534e-05, + 6.66680605000458429647e-05, + 5.83955053395394390486e-05, + 5.01309858650572228258e-05, + 4.18787431550387222699e-05, + 3.36429924637896997147e-05, + 2.54279211398450498503e-05, + 1.72376865684373168860e-05, + 9.07641413898224680109e-06, + 9.48195238618905657624e-07, +-7.14291472735570851774e-06, +-1.51928982871868691030e-05, +-2.31977778255819772578e-05, +-3.11536174769894797995e-05, +-3.90565249883959565128e-05, +-4.69026535507838503733e-05, +-5.46882035983796400101e-05, +-6.24094245749816497679e-05, +-7.00626166665431140837e-05, +-7.76441324992083051551e-05, +-8.51503788021582837904e-05, +-9.25778180344744060573e-05, +-9.99229699753842974660e-05, +-1.07182413277143970569e-04, +-1.14352786980001299723e-04, +-1.21430791988570707662e-04, +-1.28413192508978856029e-04, +-1.35296817446291592216e-04, +-1.42078561761593261028e-04, +-1.48755387788243690359e-04, +-1.55324326506731677858e-04, +-1.61782478777755279195e-04, +-1.68127016532938305905e-04, +-1.74355183922886855866e-04, +-1.80464298422043775347e-04, +-1.86451751890066126042e-04, +-1.92315011589316994193e-04, +-1.98051621158110087483e-04, +-2.03659201539461954481e-04, +-2.09135451865034778822e-04, +-2.14478150293975007752e-04, +-2.19685154806484236054e-04, +-2.24754403951855035284e-04, +-2.29683917550825442361e-04, +-2.34471797352042666748e-04, +-2.39116227642561802579e-04, +-2.43615475812239792083e-04, +-2.47967892871911476695e-04, +-2.52171913925349226639e-04, +-2.56226058594915238626e-04, +-2.60128931400936235906e-04, +-2.63879222094777748236e-04, +-2.67475705945676030771e-04, +-2.70917243981398745550e-04, +-2.74202783182808239749e-04, +-2.77331356632420174182e-04, +-2.80302083617130378106e-04, +-2.83114169685247407150e-04, +-2.85766906657990832612e-04, +-2.88259672595703273380e-04, +-2.90591931718978374165e-04, +-2.92763234284938700901e-04, +-2.94773216418979381367e-04, +-2.96621599902229947550e-04, +-2.98308191915087070681e-04, +-2.99832884737117537181e-04, +-3.01195655403731915589e-04, +-3.02396565319990604306e-04, +-3.03435759831933548735e-04, +-3.04313467755884059594e-04, +-3.05030000866147890746e-04, +-3.05585753341585221812e-04, +-3.05981201171519584091e-04, +-3.06216901521509134165e-04, +-3.06293492059487573384e-04, +-3.06211690242816218007e-04, +-3.05972292566802656771e-04, +-3.05576173775270109809e-04, +-3.05024286033762090722e-04, +-3.04317658065994024481e-04, +-3.03457394254183585730e-04, +-3.02444673703895100005e-04, +-3.01280749274062569550e-04, +-2.99966946572861902810e-04, +-2.98504662920123960135e-04, +-2.96895366276984148252e-04, +-2.95140594143503544149e-04, +-2.93241952424972839204e-04, +-2.91201114267648395687e-04, +-2.89019818864694969657e-04, +-2.86699870233074851408e-04, +-2.84243135962187955679e-04, +-2.81651545935045764021e-04, +-2.78927091022785277833e-04, +-2.76071821753329086409e-04, +-2.73087846955029312987e-04, +-2.69977332376105608885e-04, +-2.66742499280753122669e-04, +-2.63385623022735818576e-04, +-2.59909031597333319095e-04, +-2.56315104172533353259e-04, +-2.52606269600299821604e-04, +-2.48785004908817504021e-04, +-2.44853833776614545140e-04, +-2.40815324989414303834e-04, +-2.36672090880646487053e-04, +-2.32426785756489917047e-04, +-2.28082104306388832628e-04, +-2.23640779999901656528e-04, +-2.19105583470820145051e-04, +-2.14479320889489653368e-04, +-2.09764832324187768019e-04, +-2.04964990092551698191e-04, +-2.00082697103893516945e-04, +-1.95120885193399471553e-04, +-1.90082513449059745374e-04, +-1.84970566532296863812e-04, +-1.79788052993171517313e-04, +-1.74538003581126675585e-04, +-1.69223469552129467206e-04, +-1.63847520973145840571e-04, +-1.58413245024881097671e-04, +-1.52923744303641519389e-04, +-1.47382135123237027838e-04, +-1.41791545817854290970e-04, +-1.36155115046730930926e-04, +-1.30475990101566258683e-04, +-1.24757325217510580588e-04, +-1.19002279888661194524e-04, +-1.13214017188868415280e-04, +-1.07395702098746854882e-04, +-1.01550499839754549119e-04, +-9.56815742161736681884e-05, +-8.97920859658150297307e-05, +-8.38851911202858713332e-05, +-7.79640393756770905178e-05, +-7.20317724744152869908e-05, +-6.60915225991128571850e-05, +-6.01464107792394842228e-05, +-5.41995453113256703899e-05, +-4.82540201935260191645e-05, +-4.23129135752554075560e-05, +-3.63792862227040107682e-05, +-3.04561800008946262114e-05, +-2.45466163730380569304e-05, +-1.86535949179281487331e-05, +-1.27800918660038342780e-05, +-6.92905865481930068159e-06, +-1.10342050454853296994e-06, + 4.69392498575835322107e-06, + 1.04601092206202085443e-05, + 1.61922939685309686330e-05, + 2.18876726998310187900e-05, + 2.75434719013333585431e-05, + 3.31569523672128619587e-05, + 3.87254104655551669952e-05, + 4.42461793799820151014e-05, + 4.97166303258813707623e-05, + 5.51341737406907975117e-05, + 6.04962604476992873623e-05, + 6.58003827929482047439e-05, + 7.10440757547033927043e-05, + 7.62249180250887078177e-05, + 8.13405330633888576592e-05, + 8.63885901206668644324e-05, + 9.13668052352641340674e-05, + 9.62729421987680101039e-05, + 1.01104813492143344174e-04, + 1.05860281191625613681e-04, + 1.10537257844079884095e-04, + 1.15133707311478630493e-04, + 1.19647645584220456037e-04, + 1.24077141563022885209e-04, + 1.28420317809117991549e-04, + 1.32675351262483061940e-04, + 1.36840473927932757339e-04, + 1.40913973528841685815e-04, + 1.44894194128284206635e-04, + 1.48779536717473748154e-04, + 1.52568459771325131390e-04, + 1.56259479770980684197e-04, + 1.59851171693240460712e-04, + 1.63342169466755023468e-04, + 1.66731166394932026195e-04, + 1.70016915545461323039e-04, + 1.73198230106457167626e-04, + 1.76273983709174160992e-04, + 1.79243110717270954634e-04, + 1.82104606482673126973e-04, + 1.84857527568029053264e-04, + 1.87500991935841927272e-04, + 1.90034179104279262861e-04, + 1.92456330269822776862e-04, + 1.94766748396794513220e-04, + 1.96964798273908584360e-04, + 1.99049906537954266611e-04, + 2.01021561664790589848e-04, + 2.02879313927801336551e-04, + 2.04622775323984274973e-04, + 2.06251619467897348657e-04, + 2.07765581453663538119e-04, + 2.09164457685255029832e-04, + 2.10448105675328230946e-04, + 2.11616443812851108683e-04, + 2.12669451099812634523e-04, + 2.13607166857295168675e-04, + 2.14429690401230681543e-04, + 2.15137180688158456340e-04, + 2.15729855931309154023e-04, + 2.16207993187385875055e-04, + 2.16571927914393662145e-04, + 2.16822053500895369719e-04, + 2.16958820767090094714e-04, + 2.16982737438119145310e-04, + 2.16894367590011544417e-04, + 2.16694331068704375103e-04, + 2.16383302882573573273e-04, + 2.15962012568937173273e-04, + 2.15431243534988864970e-04, + 2.14791832373643112571e-04, + 2.14044668154778804569e-04, + 2.13190691692375993652e-04, + 2.12230894788062836786e-04, + 2.11166319451582256295e-04, + 2.09998057098713050445e-04, + 2.08727247727178962314e-04, + 2.07355079071098812689e-04, + 2.05882785734526249080e-04, + 2.04311648304645308329e-04, + 2.02642992445200404404e-04, + 2.00878187970725529407e-04, + 1.99018647902181230460e-04, + 1.97065827504565370225e-04, + 1.95021223307131414326e-04, + 1.92886372106789062567e-04, + 1.90662849955323298245e-04, + 1.88352271131035512233e-04, + 1.85956287095443860338e-04, + 1.83476585435658924713e-04, + 1.80914888793067202884e-04, + 1.78272953778979965879e-04, + 1.75552569877858596036e-04, + 1.72755558338776385452e-04, + 1.69883771055775014205e-04, + 1.66939089437739287235e-04, + 1.63923423268464666259e-04, + 1.60838709557554023410e-04, + 1.57686911382826176059e-04, + 1.54470016724860052760e-04, + 1.51190037294350436165e-04, + 1.47849007352938516474e-04, + 1.44448982528168725411e-04, + 1.40992038623224621736e-04, + 1.37480270422103131650e-04, + 1.33915790490908510934e-04, + 1.30300727975883427756e-04, + 1.26637227398848910710e-04, + 1.22927447450726668463e-04, + 1.19173559783751544113e-04, + 1.15377747803056433318e-04, + 1.11542205458248867627e-04, + 1.07669136035655032668e-04, + 1.03760750951825973841e-04, + 9.98192685489614168559e-05, + 9.58469128929003691322e-05, + 9.18459125742597699837e-05, + 8.78184995133790156831e-05, + 8.37669077696560454268e-05, + 7.96933723559265666005e-05, + 7.56001280584259725565e-05, + 7.14894082630083944159e-05, + 6.73634437881340204573e-05, + 6.32244617252882825861e-05, + 5.90746842873461779663e-05, + 5.49163276654787824009e-05, + 5.07516008951872145687e-05, + 4.65827047319741682405e-05, + 4.24118305372229097931e-05, + 3.82411591748462793188e-05, + 3.40728599191875283292e-05, + 2.99090893747361998109e-05, + 2.57519904081409751117e-05, + 2.16036910930649429937e-05, + 1.74663036683280136440e-05, + 1.33419235098453462380e-05, + 9.23262811685928130563e-06, + 5.14047611288089638620e-06, + 1.06750626183722631479e-06, +-2.98426350016022994691e-06, +-7.01283701696614740918e-06, +-1.10162408480615069031e-05, +-1.49925251873214083662e-05, +-1.89397647644820879499e-05, +-2.28560597288927702187e-05, +-2.67395365152196406880e-05, +-3.05883486907130078530e-05, +-3.44006777836602540958e-05, +-3.81747340927275210175e-05, +-4.19087574768357373853e-05, +-4.56010181252311126428e-05, +-4.92498173074900873615e-05, +-5.28534881031252298821e-05, +-5.64103961105393312886e-05, +-5.99189401350206662131e-05, +-6.33775528555675324869e-05, +-6.67847014702764807609e-05, +-7.01388883200425772204e-05, +-7.34386514903965126506e-05, +-7.66825653912348156535e-05, +-7.98692413142890845568e-05, +-8.29973279680875074835e-05, +-8.60655119903289004060e-05, +-8.90725184374467171371e-05, +-9.20171112512619700620e-05, +-9.48980937025603441979e-05, +-9.77143088115187759442e-05, +-1.00464639744859388255e-04, +-1.03148010189625194497e-04, +-1.05763384703536859194e-04, +-1.08309769041847384465e-04, +-1.10786210460631133696e-04, +-1.13191797996501934058e-04, +-1.15525662722708351705e-04, +-1.17786977981613268270e-04, +-1.19974959593534190815e-04, +-1.22088866041986484267e-04, +-1.24127998635342794240e-04, +-1.26091701644931496271e-04, +-1.27979362419654144924e-04, +-1.29790411477168272404e-04, +-1.31524322571708625470e-04, +-1.33180612738637493483e-04, +-1.34758842315833984394e-04, +-1.36258614942015598460e-04, +-1.37679577532133398362e-04, +-1.39021420229953017716e-04, +-1.40283876337992947491e-04, +-1.41466722224963323403e-04, +-1.42569777210869091466e-04, +-1.43592903429972301504e-04, +-1.44536005671797138268e-04, +-1.45399031200369268681e-04, +-1.46181969551921958151e-04, +-1.46884852311272975705e-04, +-1.47507752867118645777e-04, +-1.48050786146473433835e-04, +-1.48514108328523704045e-04, +-1.48897916538148837292e-04, +-1.49202448519377127998e-04, +-1.49427982289073205905e-04, +-1.49574835771129388594e-04, +-1.49643366411473540236e-04, +-1.49633970774193841890e-04, +-1.49547084119100584043e-04, +-1.49383179961047775483e-04, +-1.49142769611348204603e-04, +-1.48826401701621687922e-04, +-1.48434661690425537565e-04, +-1.47968171353023028678e-04, +-1.47427588254649171362e-04, +-1.46813605207650059491e-04, +-1.46126949712865211208e-04, +-1.45368383385638768636e-04, +-1.44538701366849164877e-04, +-1.43638731719351636813e-04, +-1.42669334810229859632e-04, +-1.41631402679272359055e-04, +-1.40525858394075560832e-04, +-1.39353655392192250567e-04, +-1.38115776810750613777e-04, +-1.36813234803965936073e-04, +-1.35447069848972789655e-04, +-1.34018350040412986173e-04, +-1.32528170374222436503e-04, +-1.30977652021046207277e-04, +-1.29367941589733019114e-04, +-1.27700210381360810966e-04, +-1.25975653634228948810e-04, +-1.24195489760284478228e-04, +-1.22360959573421820921e-04, +-1.20473325510130619526e-04, +-1.18533870842929396042e-04, +-1.16543898887054415644e-04, +-1.14504732200871589131e-04, +-1.12417711780453782031e-04, +-1.10284196248804102999e-04, +-1.08105561040170155152e-04, +-1.05883197579935365976e-04, +-1.03618512460517512327e-04, +-1.01312926613771452371e-04, +-9.89678744803231588006e-05, +-9.65848031763287176834e-05, +-9.41651716580904694746e-05, +-9.17104498849975562341e-05, +-8.92221179812627604834e-05, +-8.67016653968825132086e-05, +-8.41505900682881210822e-05, +-8.15703975791493105397e-05, +-7.89626003217504745472e-05, +-7.63287166594104368560e-05, +-7.36702700903663770804e-05, +-7.09887884135877711683e-05, +-6.82858028969257033506e-05, +-6.55628474480432515319e-05, +-6.28214577885690295556e-05, +-6.00631706318681429140e-05, +-5.72895228648756703262e-05, +-5.45020507343892520119e-05, +-5.17022890382489225453e-05, +-4.88917703218011553620e-05, +-4.60720240800406300981e-05, +-4.32445759658305523042e-05, +-4.04109470046085756875e-05, +-3.75726528159311059401e-05, +-3.47312028422512456081e-05, +-3.18880995853173453093e-05, +-2.90448378505280945666e-05, +-2.62029039996194488388e-05, +-2.33637752120533564114e-05, +-2.05289187554215721418e-05, +-1.76997912652334544591e-05, +-1.48778380343994300278e-05, +-1.20644923127652564947e-05, +-9.26117461698225729130e-06, +-6.46929205104167329041e-06, +-3.69023763779291335841e-06, +-9.25389661709245930119e-07, + 1.82388897678174475935e-06, + 4.55625139514285705999e-06, + 7.27036735044587330100e-06, + 9.96492384873170706833e-06, + 1.26386257417392112551e-05, + 1.52901963107384078629e-05, + 1.79183778372582360025e-05, + 2.05219321604610694255e-05, + 2.30996412209251530034e-05, + 2.56503075906517305266e-05, + 2.81727549890619002719e-05, + 3.06658287848128515438e-05, + 3.31283964832040277388e-05, + 3.55593481990333369126e-05, + 3.79575971147140200598e-05, + 4.03220799234941648030e-05, + 4.26517572576077638367e-05, + 4.49456141012434531802e-05, + 4.72026601881682524812e-05, + 4.94219303839001843038e-05, + 5.16024850522865696258e-05, + 5.37434104064078973302e-05, + 5.58438188436953509251e-05, + 5.79028492651570688234e-05, + 5.99196673786599580684e-05, + 6.18934659861721192748e-05, + 6.38234652549182388762e-05, + 6.57089129723729151135e-05, + 6.75490847850720971908e-05, + 6.93432844211934012709e-05, + 7.10908438968675459669e-05, + 7.27911237062255626245e-05, + 7.44435129951590121491e-05, + 7.60474297187843856823e-05, + 7.76023207826402985129e-05, + 7.91076621676173416964e-05, + 8.05629590386577253093e-05, + 8.19677458372435649003e-05, + 8.33215863577352583002e-05, + 8.46240738076027652209e-05, + 8.58748308515986194002e-05, + 8.70735096399619166833e-05, + 8.82197918207153089585e-05, + 8.93133885361372406803e-05, + 9.03540404035136604684e-05, + 9.13415174802592236660e-05, + 9.22756192135239819386e-05, + 9.31561743743901176599e-05, + 9.39830409767967284683e-05, + 9.47561061813165863036e-05, + 9.54752861839191087042e-05, + 9.61405260898756268200e-05, + 9.67517997729504849579e-05, + 9.73091097200465650948e-05, + 9.78124868614685578656e-05, + 9.82619903869737118746e-05, + 9.86577075477993088205e-05, + 9.89997534448505824923e-05, + 9.92882708032377870244e-05, + 9.95234297333714079334e-05, + 9.97054274788150226867e-05, + 9.98344881511112553288e-05, + 9.99108624517949686465e-05, + 9.99348273818228400017e-05, + 9.99066859386446587009e-05, + 9.98267668011501124433e-05, + 9.96954240027345068914e-05, + 9.95130365927253445271e-05, + 9.92800082864197933671e-05, + 9.89967671039888494865e-05, + 9.86637649985053661076e-05, + 9.82814774733607114231e-05, + 9.78504031893375142773e-05, + 9.73710635616093991710e-05, + 9.68440023469432334675e-05, + 9.62697852213858742314e-05, + 9.56489993487133770321e-05, + 9.49822529399337749968e-05, + 9.42701748041285732824e-05, + 9.35134138909305995691e-05, + 9.27126388249273401896e-05, + 9.18685374322917528561e-05, + 9.09818162599413001162e-05, + 9.00532000875254733281e-05, + 8.90834314325462917842e-05, + 8.80732700489246370709e-05, + 8.70234924193121910140e-05, + 8.59348912414666484460e-05, + 8.48082749089950011304e-05, + 8.36444669867888660050e-05, + 8.24443056814470995493e-05, + 8.12086433070261377561e-05, + 7.99383457464084788138e-05, + 7.86342919086182418845e-05, + 7.72973731824044141140e-05, + 7.59284928863964466827e-05, + 7.45285657161542757073e-05, + 7.30985171884366598380e-05, + 7.16392830829906657707e-05, + 7.01518088821840928807e-05, + 6.86370492088033058069e-05, + 6.70959672623157418921e-05, + 6.55295342539230995203e-05, + 6.39387288407061954269e-05, + 6.23245365591873072856e-05, + 6.06879492586022889272e-05, + 5.90299645341966667546e-05, + 5.73515851608610711097e-05, + 5.56538185273922726215e-05, + 5.39376760716902238437e-05, + 5.22041727171985520334e-05, + 5.04543263108674547410e-05, + 4.86891570629490461476e-05, + 4.69096869889039770705e-05, + 4.51169393537250871997e-05, + 4.33119381189441731090e-05, + 4.14957073926132242688e-05, + 3.96692708825496971343e-05, + 3.78336513531005402778e-05, + 3.59898700857156045134e-05, + 3.41389463435847715115e-05, + 3.22818968406223129981e-05, + 3.04197352150379130334e-05, + 2.85534715077610400016e-05, + 2.66841116459819329256e-05, + 2.48126569320371454517e-05, + 2.29401035378939945552e-05, + 2.10674420054833346785e-05, + 1.91956567530948109463e-05, + 1.73257255880832701685e-05, + 1.54586192260933851384e-05, + 1.35953008170508304306e-05, + 1.17367254781075038266e-05, + 9.88383983376396622401e-06, + 8.03758156337068200962e-06, + 6.19887895622111748366e-06, + 4.36865047440966400299e-06, + 2.54780432366209949829e-06, + 7.37238032308926373124e-07, +-1.06216196140181903275e-06, +-2.84952071350109670505e-06, +-4.62397516982719811819e-06, +-6.38467455271440543276e-06, +-8.13078073870770317037e-06, +-9.86146862713564825958e-06, +-1.15759264994108745933e-05, +-1.32733563689023272133e-05, +-1.49529743212684799525e-05, +-1.66140108451148118640e-05, +-1.82557111528464673220e-05, +-1.98773354916211406247e-05, +-2.14781594442844695424e-05, +-2.30574742201769104257e-05, +-2.46145869357362549322e-05, +-2.61488208847895399478e-05, +-2.76595157984633117411e-05, +-2.91460280946186709296e-05, +-3.06077311167595817127e-05, +-3.20440153623401097595e-05, +-3.34542887004032530218e-05, +-3.48379765785163355760e-05, +-3.61945222189482393904e-05, +-3.75233868040389463073e-05, +-3.88240496507459911801e-05, +-4.00960083743247562354e-05, +-4.13387790411311751020e-05, +-4.25518963105175459442e-05, +-4.37349135658282231866e-05, +-4.48874030344820757594e-05, +-4.60089558971416373264e-05, +-4.70991823859845203494e-05, +-4.81577118720843649186e-05, +-4.91841929419274583989e-05, +-5.01782934630889257735e-05, +-5.11397006390924718810e-05, +-5.20681210535034743074e-05, +-5.29632807032923507936e-05, +-5.38249250215106612256e-05, +-5.46528188893461618547e-05, +-5.54467466376069967565e-05, +-5.62065120377057097340e-05, +-5.69319382822057842072e-05, +-5.76228679550160513534e-05, +-5.82791629913088267694e-05, +-5.89007046272428875285e-05, +-5.94873933395923440545e-05, +-6.00391487753712058541e-05, +-6.05559096715516123285e-05, +-6.10376337649892107507e-05, +-6.14842976926593108057e-05, +-6.18958968823238233226e-05, +-6.22724454337409338497e-05, +-6.26139759905511322129e-05, +-6.29205396029612726468e-05, +-6.31922055813587270996e-05, +-6.34290613409973911456e-05, +-6.36312122378911084342e-05, +-6.37987813960626292450e-05, +-6.39319095262928170339e-05, +-6.40307547365266211065e-05, +-6.40954923340890131856e-05, +-6.41263146198697370432e-05, +-6.41234306746411955895e-05, +-6.40870661376762528177e-05, +-6.40174629778308577552e-05, +-6.39148792572699500983e-05, +-6.37795888880064606964e-05, +-6.36118813814352140369e-05, +-6.34120615910403414867e-05, +-6.31804494484613599157e-05, +-6.29173796931019454690e-05, +-6.26232015954722085176e-05, +-6.22982786744524704445e-05, +-6.19429884086736173409e-05, +-6.15577219422070999163e-05, +-6.11428837847619450737e-05, +-6.06988915065878725514e-05, +-6.02261754282833389803e-05, +-5.97251783057105978649e-05, +-5.91963550102224186499e-05, +-5.86401722044022619997e-05, +-5.80571080135254614690e-05, +-5.74476516929463732093e-05, +-5.68123032916220525477e-05, +-5.61515733119774190850e-05, +-5.54659823663211952113e-05, +-5.47560608300273307289e-05, +-5.40223484916846797155e-05, +-5.32653942004291476500e-05, +-5.24857555106721337967e-05, +-5.16839983244288007024e-05, +-5.08606965314631670927e-05, +-5.00164316474561513313e-05, +-4.91517924504131009438e-05, +-4.82673746155130051357e-05, +-4.73637803486131881954e-05, +-4.64416180186217908985e-05, +-4.55015017889379735677e-05, +-4.45440512481755157082e-05, +-4.35698910403685871315e-05, +-4.25796504948757788397e-05, +-4.15739632561744871879e-05, +-4.05534669137558035886e-05, +-3.95188026323245935744e-05, +-3.84706147824963234157e-05, +-3.74095505721943694328e-05, +-3.63362596789495190404e-05, +-3.52513938832865674302e-05, +-3.41556067034013181253e-05, +-3.30495530313091846969e-05, +-3.19338887706706398895e-05, +-3.08092704764648499791e-05, +-2.96763549967042926164e-05, +-2.85357991163705457791e-05, +-2.73882592037593264182e-05, +-2.62343908594002619289e-05, +-2.50748485677371487745e-05, +-2.39102853517339171191e-05, +-2.27413524305865331410e-05, +-2.15686988806957918462e-05, +-2.03929713000709965051e-05, +-1.92148134763324269733e-05, +-1.80348660584579070906e-05, +-1.68537662324394557363e-05, +-1.56721474009943186837e-05, +-1.44906388674901791041e-05, +-1.33098655242168735925e-05, +-1.21304475451532646111e-05, +-1.09530000833746117339e-05, +-9.77813297322283117563e-06, +-8.60645043737828595960e-06, +-7.43855079896758336784e-06, +-6.27502619881871961423e-06, +-5.11646231799598331854e-06, +-3.96343810572348692644e-06, +-2.81652551282231002175e-06, +-1.67628923075757107106e-06, +-5.43286436407872494914e-07, + 5.81933457334323180159e-07, + 1.69882904504591760570e-06, + 2.80686716623920578712e-06, + 3.90552313671397189482e-06, + 4.99428097372263609408e-06, + 6.07263361485467176461e-06, + 7.14008313057028191911e-06, + 8.19614093029787374922e-06, + 9.24032796203801469698e-06, + 1.02721749054007427328e-05, + 1.12912223580112092028e-05, + 1.22970210152323833412e-05, + 1.32891318431440794091e-05, + 1.42671262447347562611e-05, + 1.52305862192577593330e-05, + 1.61791045147036835158e-05, + 1.71122847733627428900e-05, + 1.80297416704377348772e-05, + 1.89311010456723673200e-05, + 1.98160000279815890877e-05, + 2.06840871530521841883e-05, + 2.15350224739038173570e-05, + 2.23684776643877086669e-05, + 2.31841361156243059649e-05, + 2.39816930253700516258e-05, + 2.47608554803058473310e-05, + 2.55213425312606982502e-05, + 2.62628852613713497754e-05, + 2.69852268471835885421e-05, + 2.76881226127196124491e-05, + 2.83713400765207057253e-05, + 2.90346589916937132319e-05, + 2.96778713789779565021e-05, + 3.03007815528719345064e-05, + 3.09032061408479746811e-05, + 3.14849740956869842052e-05, + 3.20459267009823244011e-05, + 3.25859175698492306789e-05, + 3.31048126368919349237e-05, + 3.36024901434722378835e-05, + 3.40788406163417342690e-05, + 3.45337668396904437789e-05, + 3.49671838206697444440e-05, + 3.53790187484598781464e-05, + 3.57692109469451898635e-05, + 3.61377118210646532115e-05, + 3.64844847969168087159e-05, + 3.68095052556900961707e-05, + 3.71127604615011769638e-05, + 3.73942494832178994610e-05, + 3.76539831103605689643e-05, + 3.78919837631567116656e-05, + 3.81082853968511798366e-05, + 3.83029334003578804196e-05, + 3.84759844893473848450e-05, + 3.86275065938727009992e-05, + 3.87575787406301688963e-05, + 3.88662909299569613790e-05, + 3.89537440076727901374e-05, + 3.90200495318706458425e-05, + 3.90653296347647622198e-05, + 3.90897168797087779285e-05, + 3.90933541134949965766e-05, + 3.90763943140510594358e-05, + 3.90390004336481431357e-05, + 3.89813452377418961383e-05, + 3.89036111395635601957e-05, + 3.88059900305833037435e-05, + 3.86886831069694882507e-05, + 3.85519006921667821723e-05, + 3.83958620557194456086e-05, + 3.82207952284667728518e-05, + 3.80269368142381611136e-05, + 3.78145317981768458210e-05, + 3.75838333518232266695e-05, + 3.73351026350875769854e-05, + 3.70686085952445174832e-05, + 3.67846277630824283257e-05, + 3.64834440463398959695e-05, + 3.61653485205640830985e-05, + 3.58306392175243310777e-05, + 3.54796209113175163119e-05, + 3.51126049022988697399e-05, + 3.47299087989734188192e-05, + 3.43318562979863894208e-05, + 3.39187769623452468762e-05, + 3.34910059980102160423e-05, + 3.30488840289914551757e-05, + 3.25927568710847293757e-05, + 3.21229753043848019326e-05, + 3.16398948447075694127e-05, + 3.11438755140624220878e-05, + 3.06352816103032127987e-05, + 3.01144814760946232977e-05, + 2.95818472673267157311e-05, + 2.90377547211135299580e-05, + 2.84825829235031577303e-05, + 2.79167140770347614077e-05, + 2.73405332682701918481e-05, + 2.67544282354346262150e-05, + 2.61587891362891606750e-05, + 2.55540083163661297088e-05, + 2.49404800776966532080e-05, + 2.43186004481496464925e-05, + 2.36887669515123128053e-05, + 2.30513783784305334912e-05, + 2.24068345583368003357e-05, + 2.17555361324791958683e-05, + 2.10978843281734282551e-05, + 2.04342807343983282075e-05, + 1.97651270788443597626e-05, + 1.90908250065320015982e-05, + 1.84117758601161542057e-05, + 1.77283804619801040644e-05, + 1.70410388982337398535e-05, + 1.63501503047186065565e-05, + 1.56561126551311619623e-05, + 1.49593225513600180476e-05, + 1.42601750161419401356e-05, + 1.35590632881392743862e-05, + 1.28563786195291532370e-05, + 1.21525100762025804540e-05, + 1.14478443406703827613e-05, + 1.07427655177589017509e-05, + 1.00376549431903564451e-05, + 9.33289099512935430329e-06, + 8.62884890878591384318e-06, + 7.92590059414905157801e-06, + 7.22441445693406108369e-06, + 6.52475522282227181239e-06, + 5.82728376506354903543e-06, + 5.13235693551778566856e-06, + 4.44032739920081165146e-06, + 3.75154347240349402752e-06, + 3.06634896445295587704e-06, + 2.38508302317038128695e-06, + 1.70807998408878326806e-06, + 1.03566922349157826689e-06, + 3.68175015318385312927e-07, +-2.94083608003316195796e-07, +-9.50792990756428532175e-07, +-1.60164498510903015186e-06, +-2.24633707822957432882e-06, +-2.88457251529725585548e-06, +-3.51606041836507742817e-06, +-4.14051590104719538038e-06, +-4.75766017899043685381e-06, +-5.36722067610390392149e-06, +-5.96893112651196722918e-06, +-6.56253167221256118968e-06, +-7.14776895641407462845e-06, +-7.72439621252695393942e-06, +-8.29217334879925126829e-06, +-8.85086702857723481774e-06, +-9.40025074617520820593e-06, +-9.94010489835155732234e-06, +-1.04702168513777000056e-05, +-1.09903810036992033189e-05, +-1.15003988441811452764e-05, +-1.20000790059446446682e-05, +-1.24892373157938542529e-05, +-1.29676968392356399312e-05, +-1.34352879211056542826e-05, +-1.38918482218078280619e-05, +-1.43372227491767596487e-05, +-1.47712638859842104608e-05, +-1.51938314131016376365e-05, +-1.56047925283423453849e-05, +-1.60040218609994824601e-05, +-1.63914014821137958761e-05, +-1.67668209104843766012e-05, +-1.71301771144641440945e-05, +-1.74813745095637493407e-05, +-1.78203249518961361498e-05, +-1.81469477275017576168e-05, +-1.84611695375891659296e-05, +-1.87629244797279366534e-05, +-1.90521540250400636825e-05, +-1.93288069914307297748e-05, +-1.95928395129016073037e-05, +-1.98442150049985344194e-05, +-2.00829041264385711751e-05, +-2.03088847369703611226e-05, +-2.05221418515166891200e-05, +-2.07226675906578703594e-05, +-2.09104611275098419107e-05, +-2.10855286310533183536e-05, +-2.12478832059765801270e-05, +-2.13975448290907599989e-05, +-2.15345402823791832330e-05, +-2.16589030827471214040e-05, +-2.17706734085350807535e-05, +-2.18698980228635944017e-05, +-2.19566301938759495123e-05, +-2.20309296119498917597e-05, +-2.20928623039478315611e-05, +-2.21425005445764114633e-05, +-2.21799227649298888801e-05, +-2.22052134582895725366e-05, +-2.22184630832555388114e-05, +-2.22197679642845197419e-05, +-2.22092301897129874779e-05, +-2.21869575073414682510e-05, +-2.21530632176585956473e-05, +-2.21076660647849037526e-05, +-2.20508901252157237687e-05, +-2.19828646944432693725e-05, +-2.19037241715403474508e-05, +-2.18136079417860268177e-05, +-2.17126602574166129554e-05, +-2.16010301165839486721e-05, +-2.14788711406044598715e-05, +-2.13463414495824367763e-05, +-2.12036035364909901271e-05, +-2.10508241397952941727e-05, +-2.08881741147017592605e-05, +-2.07158283031179152496e-05, +-2.05339654024071466103e-05, +-2.03427678330234534560e-05, +-2.01424216051101083219e-05, +-1.99331161841466409333e-05, +-1.97150443557298639234e-05, +-1.94884020895712982066e-05, +-1.92533884027966296513e-05, +-1.90102052226298810192e-05, +-1.87590572485473988781e-05, +-1.85001518139830994003e-05, +-1.82336987476685074346e-05, +-1.79599102346913299191e-05, +-1.76790006773522863739e-05, +-1.73911865559027042601e-05, +-1.70966862892450109082e-05, +-1.67957200956739338487e-05, +-1.64885098537402634234e-05, +-1.61752789633142813903e-05, +-1.58562522069297573337e-05, +-1.55316556114829399716e-05, +-1.52017163103647922620e-05, +-1.48666624061033995360e-05, +-1.45267228335893107877e-05, +-1.41821272239584706039e-05, +-1.38331057692081632425e-05, +-1.34798890876143142534e-05, +-1.31227080900243395635e-05, +-1.27617938470932148766e-05, +-1.23973774575348411156e-05, +-1.20296899174529279452e-05, +-1.16589619908198458004e-05, +-1.12854240811699317332e-05, +-1.09093061045693789425e-05, +-1.05308373639278654549e-05, +-1.01502464247116462527e-05, +-9.76776099211927309387e-06, +-9.38360778978138410360e-06, +-8.99801244003842426661e-06, +-8.61119934585468618966e-06, +-8.22339157442569339263e-06, +-7.83481074252833694781e-06, +-7.44567690366960780872e-06, +-7.05620843708181691813e-06, +-6.66662193861726721860e-06, +-6.27713211358587016620e-06, +-5.88795167158394612084e-06, +-5.49929122336098261949e-06, +-5.11135917976332167136e-06, +-4.72436165279991700163e-06, +-4.33850235886762889933e-06, +-3.95398252417811778438e-06, +-3.57100079241896547341e-06, +-3.18975313468634483958e-06, +-2.81043276172503517281e-06, +-2.43323003850372685734e-06, +-2.05833240115816176063e-06, +-1.68592427633299744872e-06, +-1.31618700294525707091e-06, +-9.49298756398597503033e-07, +-5.85434475269598042740e-07, +-2.24765790491995588430e-07, + 1.32539042944795253329e-07, + 4.86315211761806101974e-07, + 8.36401407601896179804e-07, + 1.18263988767470755612e-06, + 1.52487653281902728484e-06, + 1.86296090296814218483e-06, + 2.19674629001149769367e-06, + 2.52608976803993208671e-06, + 2.85085224096945087408e-06, + 3.17089848753367322990e-06, + 3.48609720364736703897e-06, + 3.79632104212865399887e-06, + 4.10144664978819417086e-06, + 4.40135470188026015846e-06, + 4.69592993391712774085e-06, + 4.98506117085352237869e-06, + 5.26864135364426027284e-06, + 5.54656756317971894038e-06, + 5.81874104161062011015e-06, + 6.08506721106972112904e-06, + 6.34545568979961026893e-06, + 6.59982030570251321293e-06, + 6.84807910732276385433e-06, + 7.09015437227939167509e-06, + 7.32597261316240703008e-06, + 7.55546458091406095787e-06, + 7.77856526571271897894e-06, + 7.99521389537842829865e-06, + 8.20535393132500495055e-06, + 8.40893306208027325446e-06, + 8.60590319439752568476e-06, + 8.79622044198663719764e-06, + 8.97984511188937595011e-06, + 9.15674168852855148177e-06, + 9.32687881545792753647e-06, + 9.49022927484590670408e-06, + 9.64676996472301928230e-06, + 9.79648187402453286072e-06, + 9.93935005546419846816e-06, + 1.00753635962716102202e-05, + 1.02045155868300701406e-05, + 1.03268030872496085793e-05, + 1.04422270919149080961e-05, + 1.05507924920450241771e-05, + 1.06525080363035427313e-05, + 1.07473862895008009574e-05, + 1.08354435894281464503e-05, + 1.09167000018650293508e-05, + 1.09911792738028123146e-05, + 1.10589087849281107333e-05, + 1.11199194974072203387e-05, + 1.11742459040198995155e-05, + 1.12219259746838584705e-05, + 1.12630011014179261237e-05, + 1.12975160417893515888e-05, + 1.13255188608912239713e-05, + 1.13470608718986725231e-05, + 1.13621965752502408455e-05, + 1.13709835965033970314e-05, + 1.13734826229117897745e-05, + 1.13697573387741017237e-05, + 1.13598743596030994434e-05, + 1.13439031651642332040e-05, + 1.13219160314340630866e-05, + 1.12939879615281848059e-05, + 1.12601966156488724434e-05, + 1.12206222401028280833e-05, + 1.11753475954396282394e-05, + 1.11244578837614569632e-05, + 1.10680406752547680398e-05, + 1.10061858339946508134e-05, + 1.09389854430727538072e-05, + 1.08665337290993678862e-05, + 1.07889269861304655274e-05, + 1.07062634990703402997e-05, + 1.06186434666001975772e-05, + 1.05261689236834371503e-05, + 1.04289436636973722826e-05, + 1.03270731602417616547e-05, + 1.02206644886739122943e-05, + 1.01098262474197981978e-05, + 9.99466847911029713993e-06, + 9.87530259159213775891e-06, + 9.75184127886138886650e-06, + 9.62439844196833259673e-06, + 9.49308910994118403798e-06, + 9.35802936077670613891e-06, + 9.21933624254407122552e-06, + 9.07712769464878633412e-06, + 8.93152246930307774312e-06, + 8.78264005324776636302e-06, + 8.63060058977119588699e-06, + 8.47552480106907815021e-06, + 8.31753391098935562125e-06, + 8.15674956820603695338e-06, + 7.99329376986349665764e-06, + 7.82728878573373623468e-06, + 7.65885708292866533933e-06, + 7.48812125120667820171e-06, + 7.31520392891465129538e-06, + 7.14022772960352193400e-06, + 6.96331516935741928119e-06, + 6.78458859487234582688e-06, + 6.60417011232208535555e-06, + 6.42218151704836629878e-06, + 6.23874422410881874162e-06, + 6.05397919971873245333e-06, + 5.86800689361913014930e-06, + 5.68094717240549469965e-06, + 5.49291925384726654124e-06, + 5.30404164223008170432e-06, + 5.11443206475166292147e-06, + 4.92420740899910160668e-06, + 4.73348366153649160803e-06, + 4.54237584763147922608e-06, + 4.35099797214519011545e-06, + 4.15946296161273383862e-06, + 3.96788260753767942779e-06, + 3.77636751092580240556e-06, + 3.58502702807880729068e-06, + 3.39396921767065449759e-06, + 3.20330078912824216524e-06, + 3.01312705233424288917e-06, + 2.82355186867183291849e-06, + 2.63467760343009042062e-06, + 2.44660507958478551702e-06, + 2.25943353297212192994e-06, + 2.07326056886889636990e-06, + 1.88818211999486711094e-06, + 1.70429240594666796266e-06, + 1.52168389407997070498e-06, + 1.34044726184580192320e-06, + 1.16067136059360877587e-06, + 9.82443180850182688139e-07, + 8.05847819080474491893e-07, + 6.30968445938113515307e-07, + 4.57886276012498259056e-07, + 2.86680539075394581232e-07, + 1.17428452831952805658e-07, +-4.97948028199512061526e-08, +-2.14916110022078276637e-07, +-3.77864435677151772163e-07, +-5.38570852660314438457e-07, +-6.96968559519905157610e-07, +-8.52992898671310133264e-07, +-1.00658137308563959240e-06, +-1.15767366147595502125e-06, +-1.30621163198739205903e-06, +-1.45213935439566631263e-06, +-1.59540311081938818504e-06, +-1.73595140495523324136e-06, +-1.87373496984242769148e-06, +-2.00870677416657680066e-06, +-2.14082202711105138891e-06, +-2.27003818176825526611e-06, +-2.39631493712127321177e-06, +-2.51961423860721225935e-06, +-2.63990027727692722499e-06, +-2.75713948756333368392e-06, +-2.87130054367384340272e-06, +-2.98235435462072420536e-06, +-3.09027405790690176183e-06, +-3.19503501188302714502e-06, +-3.29661478679241666049e-06, +-3.39499315452328387347e-06, +-3.49015207708610277043e-06, +-3.58207569383478124936e-06, +-3.67075030745277205795e-06, +-3.75616436872432333914e-06, +-3.83830846011024974469e-06, +-3.91717527815298500760e-06, +-3.99275961473000555479e-06, +-4.06505833718047160103e-06, +-4.13407036732752447398e-06, +-4.19979665941946242550e-06, +-4.26224017701520252964e-06, +-4.32140586883761345266e-06, +-4.37730064362061373922e-06, +-4.42993334397458008860e-06, +-4.47931471929707665449e-06, +-4.52545739775462975901e-06, +-4.56837585736176623178e-06, +-4.60808639618528355489e-06, +-4.64460710170019533535e-06, +-4.67795781932549308073e-06, +-4.70816012016700297387e-06, +-4.73523726799615031957e-06, +-4.75921418549265574824e-06, +-4.78011741977943205404e-06, +-4.79797510727910759225e-06, +-4.81281693792077799724e-06, +-4.82467411872585649209e-06, +-4.83357933680284597292e-06, +-4.83956672177992600872e-06, +-4.84267180770512457676e-06, +-4.84293149444327853537e-06, +-4.84038400859978304718e-06, +-4.83506886400059992306e-06, +-4.82702682175797029301e-06, +-4.81629984995190550901e-06, +-4.80293108295687288677e-06, +-4.78696478044319962005e-06, +-4.76844628608297569874e-06, +-4.74742198598980721643e-06, +-4.72393926692184768618e-06, +-4.69804647427729357874e-06, +-4.66979286991168869255e-06, +-4.63922858980587374532e-06, +-4.60640460161349042157e-06, +-4.57137266211669161266e-06, +-4.53418527461856474313e-06, +-4.49489564630047438049e-06, +-4.45355764557232873177e-06, +-4.41022575944365265741e-06, +-4.36495505094285770681e-06, +-4.31780111661199634214e-06, +-4.26882004410400630158e-06, +-4.21806836990897163306e-06, +-4.16560303723581088566e-06, +-4.11148135407525745674e-06, +-4.05576095146995474136e-06, +-3.99849974201671793024e-06, +-3.93975587862589741230e-06, +-3.87958771356253902739e-06, +-3.81805375779311230168e-06, +-3.75521264066174805207e-06, +-3.69112306991899966841e-06, +-3.62584379212629908306e-06, +-3.55943355345803456996e-06, +-3.49195106092336089756e-06, +-3.42345494402936616337e-06, +-3.35400371690614687047e-06, +-3.28365574091441607464e-06, +-3.21246918775588953681e-06, +-3.14050200310536497332e-06, +-3.06781187078386562419e-06, +-2.99445617749091577548e-06, +-2.92049197811430259292e-06, +-2.84597596163407434304e-06, +-2.77096441763784568063e-06, +-2.69551320346391274513e-06, +-2.61967771198731242738e-06, +-2.54351284006417954935e-06, +-2.46707295764927670231e-06, +-2.39041187760002226610e-06, +-2.31358282618092573712e-06, +-2.23663841428083219829e-06, +-2.15963060935584024358e-06, +-2.08261070810834870857e-06, +-2.00562930991492076031e-06, +-1.92873629101175331357e-06, +-1.85198077944850633880e-06, +-1.77541113081986172875e-06, +-1.69907490478282910220e-06, +-1.62301884236816257159e-06, +-1.54728884409369261285e-06, +-1.47192994888573774293e-06, +-1.39698631381516495750e-06, +-1.32250119465412662692e-06, +-1.24851692725776004904e-06, +-1.17507490977594879706e-06, +-1.10221558569852023006e-06, +-1.02997842773779330541e-06, +-9.58401922550402422422e-07, +-8.87523556300846598974e-07, +-8.17379801068637194395e-07, +-7.48006102099267160073e-07, +-6.79436865899721901669e-07, +-6.11705449178669713405e-07, +-5.44844148629825548117e-07, +-4.78884191557767192135e-07, +-4.13855727343869051617e-07, +-3.49787819750522529807e-07, +-2.86708440059940296556e-07, +-2.24644461044386128961e-07, +-1.63621651764123018711e-07, +-1.03664673187799380991e-07, +-4.47970746308059675830e-08, + 0 /* Need a final zero coefficient */ + diff --git a/libk3b/plugin/libsamplerate/samplerate.c b/libk3b/plugin/libsamplerate/samplerate.c new file mode 100644 index 0000000..58ad40a --- /dev/null +++ b/libk3b/plugin/libsamplerate/samplerate.c @@ -0,0 +1,301 @@ +/* +** Copyright (C) 2002,2003 Erik de Castro Lopo +** +** 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 2 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, write to the Free Software +** Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include +#include +#include + +#include "config.h" + +#include "samplerate.h" +#include "common.h" + +SRC_STATE * +src_new (int converter_type, int channels, int *error) +{ SRC_PRIVATE *psrc ; + + if (error) + *error = SRC_ERR_NO_ERROR ; + + if (channels < 1) + { if (error) + *error = SRC_ERR_BAD_CHANNEL_COUNT ; + return NULL ; + } ; + + if ((psrc = calloc (1, sizeof (*psrc))) == NULL) + { if (error) + *error = SRC_ERR_MALLOC_FAILED ; + return NULL ; + } ; + + psrc->channels = channels ; + + if (sinc_set_converter (psrc, converter_type) != SRC_ERR_NO_ERROR && + zoh_set_converter (psrc, converter_type) != SRC_ERR_NO_ERROR && + linear_set_converter (psrc, converter_type) != SRC_ERR_NO_ERROR) + { if (error) + *error = SRC_ERR_BAD_CONVERTER ; + free (psrc) ; + psrc = NULL ; + } ; + + src_reset ((SRC_STATE*) psrc) ; + + return (SRC_STATE*) psrc ; +} /* src_new */ + +SRC_STATE * +src_delete (SRC_STATE *state) +{ SRC_PRIVATE *psrc ; + + psrc = (SRC_PRIVATE*) state ; + if (psrc) + { if (psrc->private_data) + free (psrc->private_data) ; + memset (psrc, 0, sizeof (SRC_PRIVATE)) ; + free (psrc) ; + } ; + + return NULL ; +} /* src_state */ + +int +src_process (SRC_STATE *state, SRC_DATA *data) +{ SRC_PRIVATE *psrc ; + int error ; + + psrc = (SRC_PRIVATE*) state ; + + if (psrc == NULL) + return SRC_ERR_BAD_STATE ; + if (psrc->process == NULL) + return SRC_ERR_BAD_PROC_PTR ; + + /* Check for valid SRC_DATA first. */ + if (data == NULL) + return SRC_ERR_BAD_DATA ; + /* Check src_ratio is in range. */ + if (data->src_ratio < (1.0 / SRC_MAX_RATIO) || data->src_ratio > (1.0 * SRC_MAX_RATIO)) + return SRC_ERR_BAD_SRC_RATIO ; + + /* And that data_in and data_out are valid. */ + if (data->data_in == NULL || data->data_out == NULL) + return SRC_ERR_BAD_DATA_PTR ; + + if (data->data_in == NULL) + data->input_frames = 0 ; + + if (data->data_in < data->data_out) + { if (data->data_in + data->input_frames * psrc->channels > data->data_out) + { /*-printf ("data_in: %p data_out: %p\n", + data->data_in + data->input_frames * psrc->channels, data->data_out) ;-*/ + return SRC_ERR_DATA_OVERLAP ; + } ; + } + else if (data->data_out + data->output_frames * psrc->channels > data->data_in) + { /*-printf ("data_out: %p (%p) data_in: %p\n", data->data_out, + data->data_out + data->output_frames * psrc->channels, data->data_in) ;-*/ + return SRC_ERR_DATA_OVERLAP ; + } ; + + if (data->input_frames < 0) + data->input_frames = 0 ; + if (data->output_frames < 0) + data->output_frames = 0 ; + + /* Set the input and output counts to zero. */ + data->input_frames_used = 0 ; + data->output_frames_gen = 0 ; + + /* Special case for when last_ratio has not been set. */ + if (psrc->last_ratio < (1.0 / SRC_MAX_RATIO)) + psrc->last_ratio = data->src_ratio ; + + /* Now process. */ + error = psrc->process (psrc, data) ; + + return error ; +} /* src_process */ + +int +src_set_ratio (SRC_STATE *state, double new_ratio) +{ SRC_PRIVATE *psrc ; + + psrc = (SRC_PRIVATE*) state ; + + if (psrc == NULL) + return SRC_ERR_BAD_STATE ; + if (psrc->process == NULL) + return SRC_ERR_BAD_PROC_PTR ; + + psrc->last_ratio = new_ratio ; + + return SRC_ERR_NO_ERROR ; +} /* src_set_ratio */ + +int +src_reset (SRC_STATE *state) +{ SRC_PRIVATE *psrc ; + + if ((psrc = (SRC_PRIVATE*) state) == NULL) + return SRC_ERR_BAD_STATE ; + + if (psrc->reset != NULL) + psrc->reset (psrc) ; + + psrc->last_position = 0.0 ; + psrc->last_ratio = 0.0 ; + + psrc->error = SRC_ERR_NO_ERROR ; + + return SRC_ERR_NO_ERROR ; +} /* src_reset */ + +/*============================================================================== +** Control functions. +*/ + +const char * +src_get_name (int converter_type) +{ const char *desc ; + + if ((desc = sinc_get_name (converter_type)) != NULL) + return desc ; + + if ((desc = zoh_get_name (converter_type)) != NULL) + return desc ; + + if ((desc = linear_get_name (converter_type)) != NULL) + return desc ; + + return NULL ; +} /* src_get_name */ + +const char * +src_get_description (int converter_type) +{ const char *desc ; + + if ((desc = sinc_get_description (converter_type)) != NULL) + return desc ; + + if ((desc = zoh_get_description (converter_type)) != NULL) + return desc ; + + if ((desc = linear_get_description (converter_type)) != NULL) + return desc ; + + return NULL ; +} /* src_get_description */ + +const char * +src_get_version (void) +{ return "libsamplerate-k3b";/*PACKAGE "-" VERSION ;*/ +} /* src_get_version */ + +int +src_is_valid_ratio (double ratio) +{ + if (ratio < (1.0 / SRC_MAX_RATIO) || ratio > (1.0 * SRC_MAX_RATIO)) + return SRC_FALSE ; + + return SRC_TRUE ; +} /* src_is_valid_ratio */ + +/*============================================================================== +** Error reporting functions. +*/ + +int +src_error (SRC_STATE *state) +{ if (state) + return ((SRC_PRIVATE*) state)->error ; + return SRC_ERR_NO_ERROR ; +} /* src_error */ + +const char* +src_strerror (int error) +{ + switch (error) + { case SRC_ERR_NO_ERROR : + return "No error" ; + case SRC_ERR_MALLOC_FAILED : + return "Malloc failed." ; + case SRC_ERR_BAD_STATE : + return "SRC_STATE pointer is NULL." ; + case SRC_ERR_BAD_DATA : + return "SRC_DATA pointer is NULL." ; + case SRC_ERR_BAD_DATA_PTR : + return "SRC_DATA->data_out is NULL." ; + case SRC_ERR_NO_PRIVATE : + return "Internal error. No private data." ; + case SRC_ERR_BAD_SRC_RATIO : + return "SRC ratio outside [-12, 12] range." ; + case SRC_ERR_BAD_SINC_STATE : + return "src_process() called without reset after end_of_input." ; + case SRC_ERR_BAD_PROC_PTR : + return "Internal error. No process pointer." ; + case SRC_ERR_SHIFT_BITS : + return "Internal error. SHIFT_BITS too large." ; + case SRC_ERR_FILTER_LEN : + return "Internal error. Filter length too large." ; + case SRC_ERR_BAD_CONVERTER : + return "Bad converter number." ; + case SRC_ERR_BAD_CHANNEL_COUNT : + return "Channel count must be >= 1." ; + case SRC_ERR_SINC_BAD_BUFFER_LEN : + return "Internal error. Bad buffer length. Please report this." ; + case SRC_ERR_SIZE_INCOMPATIBILITY : + return "Internal error. Input data / internal buffer size difference. Please report this." ; + case SRC_ERR_BAD_PRIV_PTR : + return "Internal error. Private pointer is NULL. Please report this." ; + + case SRC_ERR_DATA_OVERLAP : + return "Input and output data arrays overlap." ; + + case SRC_ERR_MAX_ERROR : + return "Placeholder. No error defined for this error number." ; + + default : break ; + } + + return NULL ; +} /* src_strerror */ + +/*============================================================================== +** Simple interface for performing a single conversion from input buffer to +** output buffer at a fixed conversion ratio. +*/ + +int +src_simple (SRC_DATA *src_data, int converter, int channels) +{ SRC_STATE *src_state ; + int error ; + + if ((src_state = src_new (converter, channels, &error)) == NULL) + return error ; + + src_data->end_of_input = 1 ; /* Only one buffer worth of input. */ + + error = src_process (src_state, src_data) ; + + src_state = src_delete (src_state) ; + + return error ; +} /* src_simple */ + diff --git a/libk3b/plugin/libsamplerate/samplerate.h b/libk3b/plugin/libsamplerate/samplerate.h new file mode 100644 index 0000000..dfc4448 --- /dev/null +++ b/libk3b/plugin/libsamplerate/samplerate.h @@ -0,0 +1,138 @@ +/* +** Copyright (C) 2002,2003 Erik de Castro Lopo +** +** 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 2 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, write to the Free Software +** Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +/* +** API documentation is available here: +** http://www.mega-nerd.com/SRC/api.html +*/ + +#ifndef SAMPLERATE_H +#define SAMPLERATE_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef struct SRC_STATE_tag SRC_STATE ; + +typedef struct +{ float *data_in, *data_out ; + + long input_frames, output_frames ; + long input_frames_used, output_frames_gen ; + + int end_of_input ; + + double src_ratio ; +} SRC_DATA ; + +/* +** Simple interface for performing a single conversion from input buffer to +** output buffer at a fixed conversion ratio. +*/ +int src_simple (SRC_DATA *data, int converter_type, int channels) ; + +/* +** Initialisation function : return an anonymous pointer to the internal state +** of the converter. Choose a converter from the enums below. +*/ + +SRC_STATE* src_new (int converter_type, int channels, int *error) ; + +/* +** Cleanup all internal allocations. +** Always returns NULL. +*/ + +SRC_STATE* src_delete (SRC_STATE *state) ; + +/* +** This library contains a number of different sample rate converters, +** numbered 0 through N. +** +** Return a string giving either a name or a more full description of each +** sample rate converter or NULL if no sample rate converter exists for +** the given value. The converters are sequentially numbered from 0 to N. +*/ + +const char *src_get_name (int converter_type) ; +const char *src_get_description (int converter_type) ; +const char *src_get_version (void) ; + +/* +** Processing function. +** Returns non zero on error. +*/ + +int src_process (SRC_STATE *state, SRC_DATA *data) ; + +/* +** Set a new SRC ratio. This allows step responses +** in the conversion ratio. +** Returns non zero on error. +*/ + +int src_set_ratio (SRC_STATE *state, double new_ratio) ; + +/* +** Reset the internal SRC state. +** Does not modify the quality settings. +** Does not free any memory allocations. +** Returns non zero on error. +*/ + +int src_reset (SRC_STATE *state) ; + +/* +** Return TRUE if ratio is a valid conversion ratio, FALSE +** otherwise. +*/ + +int src_is_valid_ratio (double ratio) ; + +/* +** Return an error number. +*/ + +int src_error (SRC_STATE *state) ; + +/* +** Convert the error number into a string. +*/ +const char* src_strerror (int error) ; + +/* +** The following enums can be used to set the interpolator type +** using the function src_set_converter(). +*/ + +enum +{ + SRC_SINC_BEST_QUALITY = 0, + SRC_SINC_MEDIUM_QUALITY = 1, + SRC_SINC_FASTEST = 2, + SRC_ZERO_ORDER_HOLD = 3, + SRC_LINEAR = 4 +} ; + + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* SAMPLERATE_H */ diff --git a/libk3b/plugin/libsamplerate/src_linear.c b/libk3b/plugin/libsamplerate/src_linear.c new file mode 100644 index 0000000..c1736d2 --- /dev/null +++ b/libk3b/plugin/libsamplerate/src_linear.c @@ -0,0 +1,194 @@ +/* +** Copyright (C) 2002,2003 Erik de Castro Lopo +** +** 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 2 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, write to the Free Software +** Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include +#include +#include + +#include "config.h" +#include "float_cast.h" +#include "common.h" + +static void linear_reset (SRC_PRIVATE *psrc) ; + +/*======================================================================================== +*/ + +#define LINEAR_MAGIC_MARKER MAKE_MAGIC('l','i','n','e','a','r') + +typedef struct +{ int linear_magic_marker ; + int channels ; + long in_count, in_used ; + long out_count, out_gen ; + float last_value [1] ; +} LINEAR_DATA ; + +/*---------------------------------------------------------------------------------------- +*/ +int +linear_process (SRC_PRIVATE *psrc, SRC_DATA *data) +{ LINEAR_DATA *linear ; + double src_ratio, input_index ; + int ch ; + + if (psrc->private_data == NULL) + return SRC_ERR_NO_PRIVATE ; + + linear = (LINEAR_DATA*) psrc->private_data ; + + linear->in_count = data->input_frames * linear->channels ; + linear->out_count = data->output_frames * linear->channels ; + linear->in_used = linear->out_gen = 0 ; + + src_ratio = psrc->last_ratio ; + input_index = psrc->last_position ; + + /* Calculate samples before first sample in input array. */ + while (input_index > 0.0 && input_index < 1.0 && linear->out_gen < linear->out_count) + { + if (linear->in_used + input_index > linear->in_count) + break ; + + if (fabs (psrc->last_ratio - data->src_ratio) > SRC_MIN_RATIO_DIFF) + src_ratio = psrc->last_ratio + linear->out_gen * (data->src_ratio - psrc->last_ratio) / (linear->out_count - 1) ; + + for (ch = 0 ; ch < linear->channels ; ch++) + { data->data_out [linear->out_gen] = linear->last_value [ch] + input_index * + (data->data_in [ch] - linear->last_value [ch]) ; + linear->out_gen ++ ; + } ; + + /* Figure out the next index. */ + input_index += 1.0 / src_ratio ; + } ; + + /* Main processing loop. */ + while (linear->out_gen < linear->out_count) + { + linear->in_used += linear->channels * lrint (floor (input_index)) ; + input_index -= floor (input_index) ; + + if (linear->in_used + input_index > linear->in_count) + break ; + + if (fabs (psrc->last_ratio - data->src_ratio) > SRC_MIN_RATIO_DIFF) + src_ratio = psrc->last_ratio + linear->out_gen * (data->src_ratio - psrc->last_ratio) / (linear->out_count - 1) ; + + for (ch = 0 ; ch < linear->channels ; ch++) + { data->data_out [linear->out_gen] = data->data_in [linear->in_used + ch] + input_index * + (data->data_in [linear->in_used + linear->channels + ch] - data->data_in [linear->in_used + ch]) ; + linear->out_gen ++ ; + } ; + + /* Figure out the next index. */ + input_index += 1.0 / src_ratio ; + } ; + +/*- if (input_index > linear->in_count - linear->in_used) + { input_index -= linear->in_count - linear->in_used ; + linear->in_used = linear->in_count ; + puts ("XXXXXXXXXX") ; /+*-exit (1) ;-*+/ + } ; +-*/ + + psrc->last_position = input_index ; + + for (ch = 0 ; ch < linear->channels ; ch++) + { linear->last_value [ch] = data->data_in [linear->in_used - linear->channels + ch] ; + +/*- data->data_out [0 + ch] = -0.9 ; + data->data_out [linear->out_gen - linear->channels + ch] = 0.9 ; -*/ + } ; + + /* Save current ratio rather then target ratio. */ + psrc->last_ratio = src_ratio ; + + data->input_frames_used = linear->in_used / linear->channels ; + data->output_frames_gen = linear->out_gen / linear->channels ; + + return SRC_ERR_NO_ERROR ; +} /* linear_process */ + +/*------------------------------------------------------------------------------ +*/ + +const char* +linear_get_name (int src_enum) +{ + if (src_enum == SRC_LINEAR) + return "Linear Interpolator" ; + + return NULL ; +} /* linear_get_name */ + +const char* +linear_get_description (int src_enum) +{ + if (src_enum == SRC_LINEAR) + return "Linear interpolator, very fast, poor quality." ; + + return NULL ; +} /* linear_get_descrition */ + +int +linear_set_converter (SRC_PRIVATE *psrc, int src_enum) +{ LINEAR_DATA *linear ; + + if (src_enum != SRC_LINEAR) + return SRC_ERR_BAD_CONVERTER ; + + if (psrc->private_data != NULL) + { linear = (LINEAR_DATA*) psrc->private_data ; + if (linear->linear_magic_marker != LINEAR_MAGIC_MARKER) + { free (psrc->private_data) ; + psrc->private_data = NULL ; + } ; + } ; + + if (psrc->private_data == NULL) + { linear = calloc (1, sizeof (*linear) + psrc->channels * sizeof (float)) ; + if (linear == NULL) + return SRC_ERR_MALLOC_FAILED ; + psrc->private_data = linear ; + } ; + + linear->linear_magic_marker = LINEAR_MAGIC_MARKER ; + linear->channels = psrc->channels ; + + psrc->process = linear_process ; + psrc->reset = linear_reset ; + + linear_reset (psrc) ; + + return SRC_ERR_NO_ERROR ; +} /* linear_set_converter */ + +/*=================================================================================== +*/ + +static void +linear_reset (SRC_PRIVATE *psrc) +{ LINEAR_DATA *linear ; + + linear = (LINEAR_DATA*) psrc->private_data ; + if (linear == NULL) + return ; + + memset (linear->last_value, 0, sizeof (linear->last_value [0]) * linear->channels) ; +} /* linear_reset */ diff --git a/libk3b/plugin/libsamplerate/src_sinc.c b/libk3b/plugin/libsamplerate/src_sinc.c new file mode 100644 index 0000000..ddfc06b --- /dev/null +++ b/libk3b/plugin/libsamplerate/src_sinc.c @@ -0,0 +1,471 @@ +/* +** Copyright (C) 2002,2003 Erik de Castro Lopo +** +** 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 2 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, write to the Free Software +** Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include +#include +#include + +#include "config.h" +#include "float_cast.h" +#include "common.h" + +#define SINC_MAGIC_MARKER MAKE_MAGIC(' ','s','i','n','c',' ') + +#define ARRAY_LEN(x) ((int) (sizeof (x) / sizeof ((x) [0]))) + +/*======================================================================================== +** Macros for handling the index into the array for the filter. +** Double precision floating point is not accurate enough so use a 64 bit +** fixed point value instead. SHIFT_BITS (current value of 48) is the number +** of bits to the right of the decimal point. +** The rest of the macros are for retrieving the fractional and integer parts +** and for converting floats and ints to the fixed point format or from the +** fixed point type back to integers and floats. +*/ + +#define MAKE_INCREMENT_T(x) ((increment_t) (x)) + +#define SHIFT_BITS 16 +#define FP_ONE ((double) (((increment_t) 1) << SHIFT_BITS)) + +#define DOUBLE_TO_FP(x) (lrint ((x) * FP_ONE)) +#define INT_TO_FP(x) (((increment_t) (x)) << SHIFT_BITS) + +#define FP_FRACTION_PART(x) ((x) & ((((increment_t) 1) << SHIFT_BITS) - 1)) +#define FP_INTEGER_PART(x) ((x) & (((increment_t) -1) << SHIFT_BITS)) + +#define FP_TO_INT(x) (((x) >> SHIFT_BITS)) +#define FP_TO_DOUBLE(x) (FP_FRACTION_PART (x) / FP_ONE) + +/*======================================================================================== +*/ + +typedef int32_t increment_t ; +typedef float coeff_t ; + +enum +{ + STATE_BUFFER_START = 101, + STATE_DATA_CONTINUE = 102, + STATE_BUFFER_END = 103, + STATE_FINISHED +} ; + +typedef struct +{ int sinc_magic_marker ; + + int channels ; + long in_count, in_used ; + long out_count, out_gen ; + + int coeff_half_len, index_inc ; + int has_diffs ; + + double src_ratio, input_index ; + + int coeff_len ; + coeff_t const *coeffs ; + + int b_current, b_end, b_real_end, b_len ; + float *pdata ; + float buffer [1] ; +} SINC_FILTER ; + +static double calc_output (SINC_FILTER *filter, increment_t increment, increment_t start_filter_index, int ch) ; + +static void prepare_data (SINC_FILTER *filter, SRC_DATA *data, int half_filter_chan_len) ; + +static void sinc_reset (SRC_PRIVATE *psrc) ; + +static coeff_t const high_qual_coeffs [] = +{ +#include "high_qual_coeffs.h" +} ; /* high_qual_coeffs */ + +static coeff_t const mid_qual_coeffs [] = +{ +#include "mid_qual_coeffs.h" +} ; /* mid_qual_coeffs */ + +static coeff_t const fastest_coeffs [] = +{ +#include "fastest_coeffs.h" +} ; /* fastest_coeffs */ + +/*---------------------------------------------------------------------------------------- +*/ + +const char* +sinc_get_name (int src_enum) +{ + switch (src_enum) + { case SRC_SINC_BEST_QUALITY : + return "Best Sinc Interpolator" ; + + case SRC_SINC_MEDIUM_QUALITY : + return "Medium Sinc Interpolator" ; + + case SRC_SINC_FASTEST : + return "Fastest Sinc Interpolator" ; + } ; + + return NULL ; +} /* sinc_get_descrition */ + +const char* +sinc_get_description (int src_enum) +{ + switch (src_enum) + { case SRC_SINC_BEST_QUALITY : + return "Band limitied sinc interpolation, best quality, 97dB SNR, 96% BW." ; + + case SRC_SINC_MEDIUM_QUALITY : + return "Band limitied sinc interpolation, medium quality, 97dB SNR, 90% BW." ; + + case SRC_SINC_FASTEST : + return "Band limitied sinc interpolation, fastest, 97dB SNR, 80% BW." ; + } ; + + return NULL ; +} /* sinc_get_descrition */ + +int +sinc_set_converter (SRC_PRIVATE *psrc, int src_enum) +{ SINC_FILTER *filter, temp_filter ; + int count ; + + /* Quick sanity check. */ + if (SHIFT_BITS >= sizeof (increment_t) * 8 - 1) + return SRC_ERR_SHIFT_BITS ; + + if (psrc->private_data != NULL) + { filter = (SINC_FILTER*) psrc->private_data ; + if (filter->sinc_magic_marker != SINC_MAGIC_MARKER) + { free (psrc->private_data) ; + psrc->private_data = NULL ; + } ; + } ; + + memset (&temp_filter, 0, sizeof (temp_filter)) ; + + temp_filter.sinc_magic_marker = SINC_MAGIC_MARKER ; + temp_filter.channels = psrc->channels ; + + psrc->process = sinc_process ; + psrc->reset = sinc_reset ; + + switch (src_enum) + { case SRC_SINC_BEST_QUALITY : + temp_filter.coeffs = high_qual_coeffs ; + temp_filter.coeff_half_len = (sizeof (high_qual_coeffs) / sizeof (coeff_t)) - 1 ; + temp_filter.index_inc = 128 ; + temp_filter.has_diffs = SRC_FALSE ; + temp_filter.coeff_len = sizeof (high_qual_coeffs) / sizeof (coeff_t) ; + break ; + + case SRC_SINC_MEDIUM_QUALITY : + temp_filter.coeffs = mid_qual_coeffs ; + temp_filter.coeff_half_len = (sizeof (mid_qual_coeffs) / sizeof (coeff_t)) - 1 ; + temp_filter.index_inc = 128 ; + temp_filter.has_diffs = SRC_FALSE ; + temp_filter.coeff_len = sizeof (mid_qual_coeffs) / sizeof (coeff_t) ; + break ; + + case SRC_SINC_FASTEST : + temp_filter.coeffs = fastest_coeffs ; + temp_filter.coeff_half_len = (sizeof (fastest_coeffs) / sizeof (coeff_t)) - 1 ; + temp_filter.index_inc = 128 ; + temp_filter.has_diffs = SRC_FALSE ; + temp_filter.coeff_len = sizeof (fastest_coeffs) / sizeof (coeff_t) ; + break ; + + default : + return SRC_ERR_BAD_CONVERTER ; + } ; + + /* + ** FIXME : This needs to be looked at more closely to see if there is + ** a better way. Need to look at prepare_data () at the same time. + */ + + temp_filter.b_len = 1000 + 2 * lrint (ceil (temp_filter.coeff_len / (temp_filter.index_inc * 1.0) * SRC_MAX_RATIO)) ; + temp_filter.b_len *= temp_filter.channels ; + + if ((filter = calloc (1, sizeof (SINC_FILTER) + sizeof (filter->buffer [0]) * (temp_filter.b_len + temp_filter.channels))) == NULL) + return SRC_ERR_MALLOC_FAILED ; + + *filter = temp_filter ; + memset (&temp_filter, 0xEE, sizeof (temp_filter)) ; + + psrc->private_data = filter ; + + sinc_reset (psrc) ; + + count = (filter->coeff_half_len * INT_TO_FP (1)) / FP_ONE ; + + if (abs (count - filter->coeff_half_len) >= 1) + return SRC_ERR_FILTER_LEN ; + + return SRC_ERR_NO_ERROR ; +} /* sinc_set_converter */ + +static void +sinc_reset (SRC_PRIVATE *psrc) +{ SINC_FILTER *filter ; + + filter = (SINC_FILTER*) psrc->private_data ; + if (filter == NULL) + return ; + + filter->b_current = filter->b_end = 0 ; + filter->b_real_end = -1 ; + + filter->src_ratio = filter->input_index = 0.0 ; + + memset (filter->buffer, 0, filter->b_len * sizeof (filter->buffer [0])) ; + + /* Set this for a sanity check */ + memset (filter->buffer + filter->b_len, 0xAA, filter->channels * sizeof (filter->buffer [0])) ; +} /* sinc_reset */ + +/*======================================================================================== +** Beware all ye who dare pass this point. There be dragons here. +*/ + +int +sinc_process (SRC_PRIVATE *psrc, SRC_DATA *data) +{ SINC_FILTER *filter ; + double input_index, src_ratio, count, float_increment, terminate ; + increment_t increment, start_filter_index ; + int half_filter_chan_len, samples_in_hand, ch ; + + if (psrc->private_data == NULL) + return SRC_ERR_NO_PRIVATE ; + + filter = (SINC_FILTER*) psrc->private_data ; + + /* If there is not a problem, this will be optimised out. */ + if (sizeof (filter->buffer [0]) != sizeof (data->data_in [0])) + return SRC_ERR_SIZE_INCOMPATIBILITY ; + + filter->in_count = data->input_frames * filter->channels ; + filter->out_count = data->output_frames * filter->channels ; + filter->in_used = filter->out_gen = 0 ; + + src_ratio = psrc->last_ratio ; + + /* Check the sample rate ratio wrt the buffer len. */ + count = (filter->coeff_half_len + 2.0) / filter->index_inc ; + if (MIN (psrc->last_ratio, data->src_ratio) < 1.0) + count /= MIN (psrc->last_ratio, data->src_ratio) ; + count = lrint (ceil (count)) ; + + /* Maximum coefficientson either side of center point. */ + half_filter_chan_len = filter->channels * (lrint (count) + 1) ; + + input_index = psrc->last_position ; + if (input_index >= 1.0) + { filter->b_current = (filter->b_current + filter->channels * lrint (floor (input_index))) % filter->b_len ; + input_index -= floor (input_index) ; + } ; + + float_increment = filter->index_inc ; + + filter->b_current = (filter->b_current + filter->channels * lrint (floor (input_index))) % filter->b_len ; + input_index -= floor (input_index) ; + + terminate = 1.0 / src_ratio + 1e-20 ; + + /* Main processing loop. */ + while (filter->out_gen < filter->out_count) + { + /* Need to reload buffer? */ + samples_in_hand = (filter->b_end - filter->b_current + filter->b_len) % filter->b_len ; + + if (samples_in_hand <= half_filter_chan_len) + { prepare_data (filter, data, half_filter_chan_len) ; + + samples_in_hand = (filter->b_end - filter->b_current + filter->b_len) % filter->b_len ; + if (samples_in_hand <= half_filter_chan_len) + break ; + } ; + + /* This is the termination condition. */ + if (filter->b_real_end >= 0) + { if (filter->b_current + input_index + terminate >= filter->b_real_end) + break ; + } ; + + if (fabs (psrc->last_ratio - data->src_ratio) > 1e-10) + src_ratio = psrc->last_ratio + filter->out_gen * (data->src_ratio - psrc->last_ratio) / (filter->out_count - 1) ; + + float_increment = filter->index_inc * 1.0 ; + if (src_ratio < 1.0) + float_increment = filter->index_inc * src_ratio ; + + increment = DOUBLE_TO_FP (float_increment) ; + + start_filter_index = DOUBLE_TO_FP (input_index * float_increment) ; + + for (ch = 0 ; ch < filter->channels ; ch++) + { data->data_out [filter->out_gen] = (float_increment / filter->index_inc) * + calc_output (filter, increment, start_filter_index, ch) ; + filter->out_gen ++ ; + } ; + + /* Figure out the next index. */ + input_index += 1.0 / src_ratio ; + + filter->b_current = (filter->b_current + filter->channels * lrint (floor (input_index))) % filter->b_len ; + input_index -= floor (input_index) ; + } ; + + psrc->last_position = input_index ; + + /* Save current ratio rather then target ratio. */ + psrc->last_ratio = src_ratio ; + + data->input_frames_used = filter->in_used / filter->channels ; + data->output_frames_gen = filter->out_gen / filter->channels ; + + return SRC_ERR_NO_ERROR ; +} /* sinc_process */ + +/*---------------------------------------------------------------------------------------- +*/ + +static void +prepare_data (SINC_FILTER *filter, SRC_DATA *data, int half_filter_chan_len) +{ int len = 0 ; + + if (filter->b_real_end >= 0) + return ; /* This doesn't make sense, so return. */ + + if (filter->b_current == 0) + { /* Initial state. Set up zeros at the start of the buffer and + ** then load new data after that. + */ + len = filter->b_len - 2 * half_filter_chan_len ; + + filter->b_current = filter->b_end = half_filter_chan_len ; + } + else if (filter->b_end + half_filter_chan_len + filter->channels < filter->b_len) + { /* Load data at current end position. */ + len = MAX (filter->b_len - filter->b_current - half_filter_chan_len, 0) ; + } + else + { /* Move data at end of buffer back to the start of the buffer. */ + len = filter->b_end - filter->b_current ; + memmove (filter->buffer, filter->buffer + filter->b_current - half_filter_chan_len, + (half_filter_chan_len + len) * sizeof (filter->buffer [0])) ; + + filter->b_current = half_filter_chan_len ; + filter->b_end = filter->b_current + len ; + + /* Now load data at current end of buffer. */ + len = MAX (filter->b_len - filter->b_current - half_filter_chan_len, 0) ; + } ; + + len = MIN (filter->in_count - filter->in_used, len) ; + len -= (len % filter->channels) ; + + memcpy (filter->buffer + filter->b_end, data->data_in + filter->in_used, + len * sizeof (filter->buffer [0])) ; + + filter->b_end += len ; + filter->in_used += len ; + + if (filter->in_used == filter->in_count && + filter->b_end - filter->b_current < 2 * half_filter_chan_len && data->end_of_input) + { /* Handle the case where all data in the current buffer has been + ** consumed and this is the last buffer. + */ + + if (filter->b_len - filter->b_end < half_filter_chan_len + 5) + { /* If necessary, move data down to the start of the buffer. */ + len = filter->b_end - filter->b_current ; + memmove (filter->buffer, filter->buffer + filter->b_current - half_filter_chan_len, + (half_filter_chan_len + len) * sizeof (filter->buffer [0])) ; + + filter->b_current = half_filter_chan_len ; + filter->b_end = filter->b_current + len ; + } ; + + filter->b_real_end = filter->b_end ; + len = half_filter_chan_len + 5 ; + + memset (filter->buffer + filter->b_end, 0, len * sizeof (filter->buffer [0])) ; + filter->b_end += len ; + } ; + + return ; +} /* prepare_data */ + + +static double +calc_output (SINC_FILTER *filter, increment_t increment, increment_t start_filter_index, int ch) +{ double fraction, left, right, icoeff ; + increment_t filter_index, max_filter_index ; + int data_index, coeff_count, indx ; + + /* Convert input parameters into fixed point. */ + max_filter_index = INT_TO_FP (filter->coeff_half_len) ; + + /* First apply the left half of the filter. */ + filter_index = start_filter_index ; + coeff_count = (max_filter_index - filter_index) / increment ; + filter_index = filter_index + coeff_count * increment ; + data_index = filter->b_current - filter->channels * coeff_count ; + + left = 0.0 ; + do + { fraction = FP_TO_DOUBLE (filter_index) ; + indx = FP_TO_INT (filter_index) ; + + icoeff = filter->coeffs [indx] + fraction * (filter->coeffs [indx + 1] - filter->coeffs [indx]) ; + + left += icoeff * filter->buffer [data_index + ch] ; + + filter_index -= increment ; + data_index = data_index + filter->channels ; + } + while (filter_index >= MAKE_INCREMENT_T (0)) ; + + /* Now apply the right half of the filter. */ + filter_index = increment - start_filter_index ; + coeff_count = (max_filter_index - filter_index) / increment ; + filter_index = filter_index + coeff_count * increment ; + data_index = filter->b_current + filter->channels * (1 + coeff_count) ; + + right = 0.0 ; + do + { fraction = FP_TO_DOUBLE (filter_index) ; + indx = FP_TO_INT (filter_index) ; + + icoeff = filter->coeffs [indx] + fraction * (filter->coeffs [indx + 1] - filter->coeffs [indx]) ; + + right += icoeff * filter->buffer [data_index + ch] ; + + filter_index -= increment ; + data_index = data_index - filter->channels ; + } + while (filter_index > MAKE_INCREMENT_T (0)) ; + + return (left + right) ; +} /* calc_output */ + diff --git a/libk3b/plugin/libsamplerate/src_zoh.c b/libk3b/plugin/libsamplerate/src_zoh.c new file mode 100644 index 0000000..7e18d87 --- /dev/null +++ b/libk3b/plugin/libsamplerate/src_zoh.c @@ -0,0 +1,186 @@ +/* +** Copyright (C) 2002,2003 Erik de Castro Lopo +** +** 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 2 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, write to the Free Software +** Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include +#include +#include + +#include "config.h" +#include "float_cast.h" +#include "common.h" + +static void zoh_reset (SRC_PRIVATE *psrc) ; + +/*======================================================================================== +*/ + +#define ZOH_MAGIC_MARKER MAKE_MAGIC('s','r','c','z','o','h') + +typedef struct +{ int zoh_magic_marker ; + int channels ; + long in_count, in_used ; + long out_count, out_gen ; + float last_value [1] ; +} ZOH_DATA ; + +/*---------------------------------------------------------------------------------------- +*/ + +int +zoh_process (SRC_PRIVATE *psrc, SRC_DATA *data) +{ ZOH_DATA *zoh ; + double src_ratio, input_index ; + int ch ; + + if (psrc->private_data == NULL) + return SRC_ERR_NO_PRIVATE ; + + zoh = (ZOH_DATA*) psrc->private_data ; + + zoh->in_count = data->input_frames * zoh->channels ; + zoh->out_count = data->output_frames * zoh->channels ; + zoh->in_used = zoh->out_gen = 0 ; + + src_ratio = psrc->last_ratio ; + input_index = psrc->last_position ; + + /* Calculate samples before first sample in input array. */ + while (input_index > 0.0 && input_index < 1.0 && zoh->out_gen < zoh->out_count) + { + if (zoh->in_used + input_index >= zoh->in_count) + break ; + + if (fabs (psrc->last_ratio - data->src_ratio) > SRC_MIN_RATIO_DIFF) + src_ratio = psrc->last_ratio + zoh->out_gen * (data->src_ratio - psrc->last_ratio) / (zoh->out_count - 1) ; + + for (ch = 0 ; ch < zoh->channels ; ch++) + { data->data_out [zoh->out_gen] = zoh->last_value [ch] ; + zoh->out_gen ++ ; + } ; + + /* Figure out the next index. */ + input_index += 1.0 / src_ratio ; + } ; + + zoh->in_used += zoh->channels * lrint (floor (input_index)) ; + input_index -= floor (input_index) ; + + /* Main processing loop. */ + while (zoh->out_gen < zoh->out_count && zoh->in_used + input_index < zoh->in_count) + { + if (fabs (psrc->last_ratio - data->src_ratio) > SRC_MIN_RATIO_DIFF) + src_ratio = psrc->last_ratio + zoh->out_gen * (data->src_ratio - psrc->last_ratio) / (zoh->out_count - 1) ; + + for (ch = 0 ; ch < zoh->channels ; ch++) + { data->data_out [zoh->out_gen] = data->data_in [zoh->in_used + ch] ; + zoh->out_gen ++ ; + } ; + + /* Figure out the next index. */ + input_index += 1.0 / src_ratio ; + + zoh->in_used += zoh->channels * lrint (floor (input_index)) ; + input_index -= floor (input_index) ; + } ; + + psrc->last_position = input_index ; + + if (zoh->in_used > 0) + for (ch = 0 ; ch < zoh->channels ; ch++) + zoh->last_value [ch] = data->data_in [zoh->in_used - zoh->channels + ch] ; + + /* Save current ratio rather then target ratio. */ + psrc->last_ratio = src_ratio ; + + data->input_frames_used = zoh->in_used / zoh->channels ; + data->output_frames_gen = zoh->out_gen / zoh->channels ; + + return SRC_ERR_NO_ERROR ; +} /* zoh_process */ + +/*------------------------------------------------------------------------------ +*/ + +const char* +zoh_get_name (int src_enum) +{ + if (src_enum == SRC_ZERO_ORDER_HOLD) + return "ZOH Interpolator" ; + + return NULL ; +} /* zoh_get_name */ + +const char* +zoh_get_description (int src_enum) +{ + if (src_enum == SRC_ZERO_ORDER_HOLD) + return "Zero order hold interpolator, very fast, poor quality." ; + + return NULL ; +} /* zoh_get_descrition */ + +int +zoh_set_converter (SRC_PRIVATE *psrc, int src_enum) +{ ZOH_DATA *zoh = NULL; + + if (src_enum != SRC_ZERO_ORDER_HOLD) + return SRC_ERR_BAD_CONVERTER ; + + if (psrc->private_data != NULL) + { zoh = (ZOH_DATA*) psrc->private_data ; + if (zoh->zoh_magic_marker != ZOH_MAGIC_MARKER) + { free (psrc->private_data) ; + psrc->private_data = NULL ; + } ; + } ; + + if (psrc->private_data == NULL) + { zoh = calloc (1, sizeof (*zoh) + psrc->channels * sizeof (float)) ; + if (zoh == NULL) + return SRC_ERR_MALLOC_FAILED ; + psrc->private_data = zoh ; + } ; + + zoh->zoh_magic_marker = ZOH_MAGIC_MARKER ; + zoh->channels = psrc->channels ; + + psrc->process = zoh_process ; + psrc->reset = zoh_reset ; + + zoh_reset (psrc) ; + + return SRC_ERR_NO_ERROR ; +} /* zoh_set_converter */ + +/*=================================================================================== +*/ + +static void +zoh_reset (SRC_PRIVATE *psrc) +{ ZOH_DATA *zoh ; + + zoh = (ZOH_DATA*) psrc->private_data ; + if (zoh == NULL) + return ; + + zoh->channels = psrc->channels ; + memset (zoh->last_value, 0, sizeof (zoh->last_value [0]) * zoh->channels) ; + + return ; +} /* zoh_reset */ diff --git a/libk3b/projects/Makefile.am b/libk3b/projects/Makefile.am new file mode 100644 index 0000000..1a07372 --- /dev/null +++ b/libk3b/projects/Makefile.am @@ -0,0 +1,32 @@ +AM_CPPFLAGS= -I$(srcdir)/../../src -I$(srcdir)/../core -I$(srcdir)/../plugin -I$(srcdir)/../../libk3bdevice -I$(srcdir)/../tools -I$(srcdir)/datacd -I$(srcdir)/audiocd -I$(srcdir)/mixedcd -I$(srcdir)/movixcd -I$(srcdir)/movixdvd -I$(srcdir)/datadvd -I$(srcdir)/videocd -I$(srcdir)/videodvd $(all_includes) + +noinst_LTLIBRARIES = libk3bproject.la + +libk3bproject_la_LIBADD = ./datacd/libdata.la ./datadvd/libdvd.la ./mixedcd/libmixed.la ./videocd/libvcd.la ./videodvd/libvideodvd.la ./movixcd/libmovix.la ./movixdvd/libmovixdvd.la ./audiocd/libaudio.la + +libk3bproject_la_LDFLAGS = $(all_libraries) + +libk3bproject_la_SOURCES = k3babstractwriter.cpp \ + k3bgrowisofswriter.cpp \ + k3bgrowisofshandler.cpp \ + k3bdoc.cpp \ + k3bcdrdaowriter.cpp \ + k3bcdrecordwriter.cpp \ + k3binffilewriter.cpp \ + k3btocfilewriter.cpp \ + k3bimagefilereader.cpp \ + k3bcuefileparser.cpp \ + k3bpipebuffer.cpp + +include_HEADERS = k3bdoc.h \ + k3bgrowisofswriter.h \ + k3bcdrdaowriter.h \ + k3bcdrecordwriter.h \ + k3binffilewriter.h \ + k3btocfilewriter.h \ + k3bcuefileparser.h \ + k3bimagefilereader.h + +SUBDIRS = datacd audiocd mixedcd movixcd videocd datadvd movixdvd videodvd + +METASOURCES = AUTO diff --git a/libk3b/projects/audiocd/Makefile.am b/libk3b/projects/audiocd/Makefile.am new file mode 100644 index 0000000..60942cc --- /dev/null +++ b/libk3b/projects/audiocd/Makefile.am @@ -0,0 +1,35 @@ +AM_CPPFLAGS= -I$(srcdir)/../../../src \ + -I$(srcdir)/.. \ + -I$(srcdir)/../../core \ + -I$(srcdir)/../../plugin \ + -I$(srcdir)/../../cddb \ + -I$(srcdir)/../../../libk3bdevice \ + -I$(srcdir)/../../tools $(all_includes) + +METASOURCES = AUTO + +noinst_LTLIBRARIES = libaudio.la + +libaudio_la_SOURCES = k3baudiojob.cpp \ + k3baudiotrack.cpp \ + k3baudiodoc.cpp \ + k3baudiofile.cpp \ + k3baudiozerodata.cpp \ + k3baudiodatasource.cpp \ + k3baudionormalizejob.cpp \ + k3baudiojobtempdata.cpp \ + k3baudioimager.cpp \ + k3baudiomaxspeedjob.cpp \ + k3baudiocdtracksource.cpp \ + k3baudiocdtrackdrag.cpp \ + k3baudiodatasourceiterator.cpp + +include_HEADERS = k3baudiodoc.h \ + k3baudiojob.h \ + k3baudiocdtrackdrag.h \ + k3baudiotrack.h \ + k3baudiodatasource.h \ + k3baudiofile.h \ + k3baudiozerodata.h \ + k3baudiocdtracksource.h \ + k3baudiodatasourceiterator.h diff --git a/libk3b/projects/audiocd/k3baudiocdtrackdrag.cpp b/libk3b/projects/audiocd/k3baudiocdtrackdrag.cpp new file mode 100644 index 0000000..8429f25 --- /dev/null +++ b/libk3b/projects/audiocd/k3baudiocdtrackdrag.cpp @@ -0,0 +1,109 @@ +/* + * + * $Id: k3baudiocdtrackdrag.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2005 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3baudiocdtrackdrag.h" + +#include +#include +#include +#include +#include + +#include +#include + + +// FIXME: multiple tracks +K3bAudioCdTrackDrag::K3bAudioCdTrackDrag( const K3bDevice::Toc& toc, const QValueList& cdTrackNumbers, + const K3bCddbResultEntry& cddb, + K3bDevice::Device* lastDev, QWidget* dragSource, const char* name ) + : QStoredDrag( "k3b/audio_track_drag", dragSource, name ), + m_toc(toc), + m_cdTrackNumbers(cdTrackNumbers), + m_cddb(cddb), + m_device(lastDev) +{ + QByteArray data; + QDataStream s( data, IO_WriteOnly ); + s << (unsigned int)toc.count(); + for( K3bDevice::Toc::const_iterator it = toc.begin(); it != toc.end(); ++it ) { + const K3bDevice::Track& track = *it; + s << track.firstSector().lba() << track.lastSector().lba(); + } + QTextStream t( s.device() ); + t << cddb.cdArtist << endl + << cddb.cdTitle << endl; + for( unsigned int i = 0; i < toc.count(); ++i ) { + t << cddb.artists[i] << endl + << cddb.titles[i] << endl; + } + + s << (unsigned int)cdTrackNumbers.count(); + + for( QValueList::const_iterator it = cdTrackNumbers.begin(); + it != cdTrackNumbers.end(); ++it ) + s << *it; + + if( lastDev ) + t << lastDev->blockDeviceName() << endl; + else + t << endl; + + // TODO: the rest + setEncodedData( data ); +} + + +bool K3bAudioCdTrackDrag::decode( const QMimeSource* e, + K3bDevice::Toc& toc, QValueList& trackNumbers, + K3bCddbResultEntry& cddb, K3bDevice::Device** dev ) +{ + QByteArray data = e->encodedData( "k3b/audio_track_drag" ); + + QDataStream s( data, IO_ReadOnly ); + + unsigned int trackCnt; + s >> trackCnt; + for( unsigned int i = 0; i < trackCnt; ++i ) { + int fs, ls; + s >> fs; + s >> ls; + toc.append( K3bDevice::Track( fs, ls, K3bDevice::Track::AUDIO ) ); + } + + QTextStream t( s.device() ); + cddb.artists.clear(); + cddb.titles.clear(); + cddb.cdArtist = t.readLine(); + cddb.cdTitle = t.readLine(); + for( unsigned int i = 0; i < trackCnt; ++i ) { + cddb.artists.append( t.readLine() ); + cddb.titles.append( t.readLine() ); + } + + s >> trackCnt; + trackNumbers.clear(); + for( unsigned int i = 0; i < trackCnt; ++i ) { + int trackNumber = 0; + s >> trackNumber; + trackNumbers.append( trackNumber ); + } + + QString devName = t.readLine(); + if( dev && !devName.isEmpty() ) + *dev = k3bcore->deviceManager()->findDevice( devName ); + + return true; +} diff --git a/libk3b/projects/audiocd/k3baudiocdtrackdrag.h b/libk3b/projects/audiocd/k3baudiocdtrackdrag.h new file mode 100644 index 0000000..3148466 --- /dev/null +++ b/libk3b/projects/audiocd/k3baudiocdtrackdrag.h @@ -0,0 +1,50 @@ +/* + * + * $Id: k3baudiocdtrackdrag.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2005 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_AUDIO_CDTRACK_DRAG_H_ +#define _K3B_AUDIO_CDTRACK_DRAG_H_ + +#include +#include +#include + +#include +#include +#include +#include "k3b_export.h" + +class LIBK3B_EXPORT K3bAudioCdTrackDrag : public QStoredDrag +{ + public: + K3bAudioCdTrackDrag( const K3bDevice::Toc& toc, const QValueList& cdTrackNumbers, const K3bCddbResultEntry& cddb, + K3bDevice::Device* lastDev = 0, QWidget* dragSource = 0, const char* name = 0 ); + + const K3bDevice::Toc& toc() const { return m_toc; } + const QValueList& cdTrackNumbers() const { return m_cdTrackNumbers; } + const K3bCddbResultEntry& cddbEntry() const { return m_cddb; } + + bool provides( const char* mimetype ) const { return !qstrcmp( mimetype, "k3b/audio_track_drag" ); } + + static bool canDecode( const QMimeSource* s ) { return s->provides( "k3b/audio_track_drag" ); } + static bool decode( const QMimeSource* s, K3bDevice::Toc&, QValueList& trackNumbers, K3bCddbResultEntry&, K3bDevice::Device** dev = 0 ); + + private: + K3bDevice::Toc m_toc; + QValueList m_cdTrackNumbers; + K3bCddbResultEntry m_cddb; + K3bDevice::Device* m_device; +}; + +#endif diff --git a/libk3b/projects/audiocd/k3baudiocdtracksource.cpp b/libk3b/projects/audiocd/k3baudiocdtracksource.cpp new file mode 100644 index 0000000..b61e865 --- /dev/null +++ b/libk3b/projects/audiocd/k3baudiocdtracksource.cpp @@ -0,0 +1,262 @@ +/* + * + * $Id: k3baudiocdtracksource.cpp 676194 2007-06-16 08:59:19Z trueg $ + * Copyright (C) 2005 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3baudiocdtracksource.h" +#include "k3baudiotrack.h" +#include "k3baudiodoc.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +K3bAudioCdTrackSource::K3bAudioCdTrackSource( const K3bDevice::Toc& toc, int cdTrackNumber, + const K3bCddbResultEntry& cddb, K3bDevice::Device* dev ) + : K3bAudioDataSource(), + m_discId( toc.discId() ), + m_length( toc[cdTrackNumber-1].length() ), + m_toc( toc ), + m_cdTrackNumber( cdTrackNumber ), + m_cddbEntry( cddb ), + m_lastUsedDevice( dev ), + m_cdParanoiaLib( 0 ), + m_initialized( false ) +{ +} + + +K3bAudioCdTrackSource::K3bAudioCdTrackSource( unsigned int discid, const K3b::Msf& length, int cdTrackNumber, + const QString& artist, const QString& title, + const QString& cdArtist, const QString& cdTitle ) + : K3bAudioDataSource(), + m_discId( discid ), + m_length( length ), + m_cdTrackNumber( cdTrackNumber ), + m_lastUsedDevice( 0 ), + m_cdParanoiaLib( 0 ), + m_initialized( false ) +{ + for( int i = 1; i < cdTrackNumber; ++i ) { + m_cddbEntry.titles.append( QString::null ); + m_cddbEntry.artists.append( QString::null ); + } + m_cddbEntry.titles.append( title ); + m_cddbEntry.artists.append( artist ); + m_cddbEntry.cdTitle = cdTitle; + m_cddbEntry.cdArtist = cdArtist; +} + + +K3bAudioCdTrackSource::K3bAudioCdTrackSource( const K3bAudioCdTrackSource& source ) + : K3bAudioDataSource( source ), + m_discId( source.m_discId ), + m_toc( source.m_toc ), + m_cdTrackNumber( source.m_cdTrackNumber ), + m_cddbEntry( source.m_cddbEntry ), + m_lastUsedDevice( source.m_lastUsedDevice ), + m_cdParanoiaLib( 0 ), + m_initialized( false ) +{ +} + + +K3bAudioCdTrackSource::~K3bAudioCdTrackSource() +{ + closeParanoia(); + delete m_cdParanoiaLib; +} + + +bool K3bAudioCdTrackSource::initParanoia() +{ + if( !m_initialized ) { + if( !m_cdParanoiaLib ) + m_cdParanoiaLib = K3bCdparanoiaLib::create(); + + if( m_cdParanoiaLib ) { + m_lastUsedDevice = searchForAudioCD(); + + // ask here for the cd since searchForAudioCD() may also be called from outside + if( !m_lastUsedDevice ) { + // could not find the CD, so ask for it + QString s = i18n("Please insert Audio CD %1%2") + .arg(m_discId, 0, 16) + .arg(m_cddbEntry.cdTitle.isEmpty() || m_cddbEntry.cdArtist.isEmpty() + ? QString::null + : " (" + m_cddbEntry.cdArtist + " - " + m_cddbEntry.cdTitle + ")"); + + while( K3bDevice::Device* dev = K3bThreadWidget::selectDevice( track()->doc()->view(), s ) ) { + if( searchForAudioCD( dev ) ) { + m_lastUsedDevice = dev; + break; + } + } + } + + // user canceled + if( !m_lastUsedDevice ) + return false; + + k3bcore->blockDevice( m_lastUsedDevice ); + + if( m_toc.isEmpty() ) + m_toc = m_lastUsedDevice->readToc(); + + if( !m_cdParanoiaLib->initParanoia( m_lastUsedDevice, m_toc ) ) { + k3bcore->unblockDevice( m_lastUsedDevice ); + return false; + } + + if( doc() ) { + m_cdParanoiaLib->setParanoiaMode( doc()->audioRippingParanoiaMode() ); + m_cdParanoiaLib->setNeverSkip( !doc()->audioRippingIgnoreReadErrors() ); + m_cdParanoiaLib->setMaxRetries( doc()->audioRippingRetries() ); + } + + m_cdParanoiaLib->initReading( m_toc[m_cdTrackNumber-1].firstSector().lba() + startOffset().lba() + m_position.lba(), + m_toc[m_cdTrackNumber-1].firstSector().lba() + lastSector().lba() ); + + // we only block during the initialization because we cannot determine the end of the reading process :( + k3bcore->unblockDevice( m_lastUsedDevice ); + + m_initialized = true; + kdDebug() << "(K3bAudioCdTrackSource) initialized." << endl; + } + } + + return m_initialized; +} + + +void K3bAudioCdTrackSource::closeParanoia() +{ + if( m_cdParanoiaLib && m_initialized ) { + m_cdParanoiaLib->close(); + } + m_initialized = false; +} + + +K3bDevice::Device* K3bAudioCdTrackSource::searchForAudioCD() const +{ + kdDebug() << "(K3bAudioCdTrackSource::searchForAudioCD()" << endl; + // first try the saved device + if( m_lastUsedDevice && searchForAudioCD( m_lastUsedDevice ) ) + return m_lastUsedDevice; + + const QPtrList& devices = k3bcore->deviceManager()->readingDevices(); + for( QPtrListIterator it(devices); *it; ++it ) { + if( searchForAudioCD( *it ) ) { + return *it; + } + } + + kdDebug() << "(K3bAudioCdTrackSource::searchForAudioCD) failed." << endl; + + return 0; +} + + +bool K3bAudioCdTrackSource::searchForAudioCD( K3bDevice::Device* dev ) const +{ + kdDebug() << "(K3bAudioCdTrackSource::searchForAudioCD(" << dev->description() << ")" << endl; + K3bDevice::Toc toc = dev->readToc(); + return ( toc.discId() == m_discId ); +} + + +void K3bAudioCdTrackSource::setDevice( K3bDevice::Device* dev ) +{ + if( dev && dev != m_lastUsedDevice ) { + m_lastUsedDevice = dev; + if( m_initialized ) { + } + } +} + + +K3b::Msf K3bAudioCdTrackSource::originalLength() const +{ + return m_length; +} + + +bool K3bAudioCdTrackSource::seek( const K3b::Msf& msf ) +{ + // HACK: to reinitialize every time we restart the decoding + if( msf == 0 && m_cdParanoiaLib ) + closeParanoia(); + + m_position = msf; + + if( m_cdParanoiaLib ) + m_cdParanoiaLib->initReading( m_toc[m_cdTrackNumber-1].firstSector().lba() + startOffset().lba() + m_position.lba(), + m_toc[m_cdTrackNumber-1].firstSector().lba() + lastSector().lba() ); + + return true; +} + + +int K3bAudioCdTrackSource::read( char* data, unsigned int ) +{ + if( initParanoia() ) { + int status = 0; + char* buf = m_cdParanoiaLib->read( &status, 0, false /* big endian */ ); + if( status == K3bCdparanoiaLib::S_OK ) { + if( buf == 0 ) { + // done + closeParanoia(); + return 0; + } + else { + ++m_position; + ::memcpy( data, buf, CD_FRAMESIZE_RAW ); + return CD_FRAMESIZE_RAW; + } + } + else { + // in case the reading fails we go back to "not initialized" + closeParanoia(); + return -1; + } + } + else + return -1; +} + + +QString K3bAudioCdTrackSource::type() const +{ + return i18n("CD Track"); +} + + +QString K3bAudioCdTrackSource::sourceComment() const +{ + return i18n("Track %1 from Audio CD %2").arg(m_cdTrackNumber).arg(m_discId,0,16); +} + + +K3bAudioDataSource* K3bAudioCdTrackSource::copy() const +{ + return new K3bAudioCdTrackSource( *this ); +} diff --git a/libk3b/projects/audiocd/k3baudiocdtracksource.h b/libk3b/projects/audiocd/k3baudiocdtracksource.h new file mode 100644 index 0000000..6eaaa5b --- /dev/null +++ b/libk3b/projects/audiocd/k3baudiocdtracksource.h @@ -0,0 +1,99 @@ +/* + * + * $Id: k3baudiocdtracksource.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2005 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_AUDIO_CD_TRACK_SOURCE_H_ +#define _K3B_AUDIO_CD_TRACK_SOURCE_H_ + +#include "k3baudiodatasource.h" + +#include +#include + +#include "k3b_export.h" + + +namespace K3bDevice { + class Device; +} +class K3bCdparanoiaLib; + + +/** + * Audio data source which reads it's data directly from an audio CD. + * + * Be aware that since GUI elements are not allowed in sources (other thread) + * the source relies on the audio CD being inserted before any read operations. + * It will search all available devices for the CD starting with the last used drive. + */ +class LIBK3B_EXPORT K3bAudioCdTrackSource : public K3bAudioDataSource +{ + public: + /** + * Default constructor to create a new source. + */ + K3bAudioCdTrackSource( const K3bDevice::Toc& toc, int cdTrackNumber, const K3bCddbResultEntry& cddb, + K3bDevice::Device* dev = 0 ); + + /** + * Constructor to create sources when loading from a project file without toc information + */ + K3bAudioCdTrackSource( unsigned int discid, const K3b::Msf& length, int cdTrackNumber, + const QString& artist, const QString& title, + const QString& cdartist, const QString& cdtitle ); + K3bAudioCdTrackSource( const K3bAudioCdTrackSource& ); + ~K3bAudioCdTrackSource(); + + unsigned int discId() const { return m_discId; } + int cdTrackNumber() const { return m_cdTrackNumber; } + const K3bCddbResultEntry& metaInfo() const { return m_cddbEntry; } + + K3b::Msf originalLength() const; + bool seek( const K3b::Msf& ); + int read( char* data, unsigned int max ); + QString type() const; + QString sourceComment() const; + K3bAudioDataSource* copy() const; + + /** + * Searches for the corresponding Audio CD and returns the device in which it has + * been found or 0 if it could not be found. + */ + K3bDevice::Device* searchForAudioCD() const; + + /** + * Set the device the source should start to look for the CD. + */ + void setDevice( K3bDevice::Device* dev ); + + private: + bool initParanoia(); + void closeParanoia(); + bool searchForAudioCD( K3bDevice::Device* ) const; + + unsigned int m_discId; + K3b::Msf m_length; + K3bDevice::Toc m_toc; + int m_cdTrackNumber; + K3bCddbResultEntry m_cddbEntry; + + // ripping + // we only save the device we last saw the CD in + K3bDevice::Device* m_lastUsedDevice; + K3bCdparanoiaLib* m_cdParanoiaLib; + K3b::Msf m_position; + bool m_initialized; +}; + +#endif diff --git a/libk3b/projects/audiocd/k3baudiodatasource.cpp b/libk3b/projects/audiocd/k3baudiodatasource.cpp new file mode 100644 index 0000000..0f705f4 --- /dev/null +++ b/libk3b/projects/audiocd/k3baudiodatasource.cpp @@ -0,0 +1,210 @@ +/* + * + * $Id: k3baudiodatasource.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3baudiodatasource.h" +#include "k3baudiotrack.h" +#include "k3baudiodoc.h" + + +K3bAudioDataSource::K3bAudioDataSource() + : m_track(0), + m_prev(0), + m_next(0) +{ +} + + +K3bAudioDataSource::K3bAudioDataSource( const K3bAudioDataSource& source ) + : m_track( 0 ), + m_prev( 0 ), + m_next( 0 ), + m_startOffset( source.m_startOffset ), + m_endOffset( source.m_endOffset ) +{ +} + + +K3bAudioDataSource::~K3bAudioDataSource() +{ + take(); +} + + +K3bAudioDoc* K3bAudioDataSource::doc() const +{ + if( m_track ) + return m_track->doc(); + else + return 0; +} + + +K3bAudioDataSource* K3bAudioDataSource::take() +{ + // if we do not have a track we are not in any list + if( m_track ) { + if( !m_prev ) + m_track->setFirstSource( m_next ); + + if( m_prev ) + m_prev->m_next = m_next; + if( m_next ) + m_next->m_prev = m_prev; + + m_prev = m_next = 0; + + emitChange(); + m_track = 0; + } + + return this; +} + + +void K3bAudioDataSource::moveAfter( K3bAudioDataSource* source ) +{ + // cannot create a list outside a track! + if( !source->track() ) + return; + + if( source == this ) + return; + + // remove this from the list + take(); + + K3bAudioDataSource* oldNext = source->m_next; + + // set track as prev + source->m_next = this; + m_prev = source; + + // set oldNext as next + if( oldNext ) + oldNext->m_prev = this; + m_next = oldNext; + + m_track = source->track(); + emitChange(); +} + + +void K3bAudioDataSource::moveAhead( K3bAudioDataSource* source ) +{ + // cannot create a list outside a track! + if( !source->track() ) + return; + + if( source == this ) + return; + + // remove this from the list + take(); + + K3bAudioDataSource* oldPrev = source->m_prev; + + // set track as next + m_next = source; + source->m_prev = this; + + // set oldPrev as prev + m_prev = oldPrev; + if( oldPrev ) + oldPrev->m_next = this; + + m_track = source->track(); + + if( !m_prev ) + m_track->setFirstSource( this ); + + emitChange(); +} + + +void K3bAudioDataSource::emitChange() +{ + if( m_track ) + m_track->sourceChanged( this ); +} + + +K3bAudioDataSource* K3bAudioDataSource::split( const K3b::Msf& pos ) +{ + if( pos < length() ) { + K3bAudioDataSource* s = copy(); + s->setStartOffset( startOffset() + pos ); + s->setEndOffset( endOffset() ); + setEndOffset( startOffset() + pos ); + s->moveAfter( this ); + emitChange(); + return s; + } + else + return 0; +} + + +K3b::Msf K3bAudioDataSource::lastSector() const +{ + if( endOffset() > 0 ) + return endOffset()-1; + else + return originalLength()-1; +} + + +K3b::Msf K3bAudioDataSource::length() const +{ + if( originalLength() == 0 ) + return 0; + else if( lastSector() < m_startOffset ) + return 1; + else + return lastSector() - m_startOffset + 1; +} + + +void K3bAudioDataSource::setStartOffset( const K3b::Msf& msf ) +{ + m_startOffset = msf; + fixupOffsets(); + emitChange(); +} + + +void K3bAudioDataSource::setEndOffset( const K3b::Msf& msf ) +{ + m_endOffset = msf; + fixupOffsets(); + emitChange(); +} + + +void K3bAudioDataSource::fixupOffsets() +{ + // no length available yet + if( originalLength() == 0 ) + return; + + if( startOffset() >= originalLength() ) { + setStartOffset( 0 ); + } + if( endOffset() > originalLength() ) { + setEndOffset( 0 ); // whole source + } + if( endOffset() > 0 && endOffset() <= startOffset() ) { + setEndOffset( startOffset() ); + } +} diff --git a/libk3b/projects/audiocd/k3baudiodatasource.h b/libk3b/projects/audiocd/k3baudiodatasource.h new file mode 100644 index 0000000..d12fd10 --- /dev/null +++ b/libk3b/projects/audiocd/k3baudiodatasource.h @@ -0,0 +1,168 @@ +/* + * + * $Id: k3baudiodatasource.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_AUDIO_DATA_SOURCE_H_ +#define _K3B_AUDIO_DATA_SOURCE_H_ + +#include +#include "k3b_export.h" +class K3bAudioTrack; +class K3bAudioDoc; + + +/** + * An AudioDataSource has an original length which represents the maximum amount of audio + * sectors this source can provide (in special cases this is not true, see K3bAudioZeroData). + * + * It is possible to just use a portion of that data by changing the startOffset and endOffset. + * This will change the actual length of the data provided by this source through the read method. + * + * Sources are part of a list which can be traversed via the prev() and next() methods. This list + * is part of a K3bAudioTrack which in turn is part of a list which is owned by a K3bAudioDoc. + * + * The list may be modified with the take(), moveAfter(), and moveAhead() methods. The source takes + * care of fixing the list and notifying the track about the change (It is also possible to move sources + * from one track to the other). + * + * When a source is deleted it automatically removes itself from it's list. + */ +class LIBK3B_EXPORT K3bAudioDataSource +{ + friend class K3bAudioTrack; + + public: + K3bAudioDataSource(); + + /** + * Create en identical copy except that the copy will not be in any list. + */ + K3bAudioDataSource( const K3bAudioDataSource& ); + virtual ~K3bAudioDataSource(); + + /** + * The original length of the source is the maximum data which is available + * when startOffset is 0 this is the max for endOffset + * + * Be aware that this may change (see K3bAudioZeroData) + */ + virtual K3b::Msf originalLength() const = 0; + + /** + * The default implementation returns the originalLength modified by startOffset and endOffset + */ + virtual K3b::Msf length() const; + + /** + * @return The raw size in pcm samples (16bit, 44800 kHz, stereo) + */ + KIO::filesize_t size() const { return length().audioBytes(); } + + virtual bool seek( const K3b::Msf& ) = 0; + + /** + * Read data from the source. + */ + virtual int read( char* data, unsigned int max ) = 0; + + /** + * Type of the data in readable form. + */ + virtual QString type() const = 0; + + /** + * The source in readable form (this is the filename for files) + */ + virtual QString sourceComment() const = 0; + + /** + * Used in case an error occurred. For now this is used if the + * decoder was not able to decode an audiofile + */ + virtual bool isValid() const { return true; } + + /** + * The doc the source is currently a part of or null. + */ + K3bAudioDoc* doc() const; + K3bAudioTrack* track() const { return m_track; } + + K3bAudioDataSource* prev() const { return m_prev; } + K3bAudioDataSource* next() const { return m_next; } + + K3bAudioDataSource* take(); + + void moveAfter( K3bAudioDataSource* track ); + void moveAhead( K3bAudioDataSource* track ); + + /** + * Set the start offset from the beginning of the source's originalLength. + */ + virtual void setStartOffset( const K3b::Msf& ); + + /** + * Set the end offset from the beginning of the file. The endOffset sector + * is not included in the data. + * The maximum value is originalLength() which means to use all data. + * 0 means the same as originalLength(). + * This has to be bigger than the start offset. + */ + virtual void setEndOffset( const K3b::Msf& ); + + virtual const K3b::Msf& startOffset() const { return m_startOffset; } + + /** + * The end offset. It is the first sector not included in the data. + * If 0 the last sector is determined by the originalLength + */ + virtual const K3b::Msf& endOffset() const { return m_endOffset; } + + /** + * Get the last used sector in the source. + * The default implementation uses originalLength() and endOffset() + */ + virtual K3b::Msf lastSector() const; + + /** + * Create a copy of this source which is not part of a list + */ + virtual K3bAudioDataSource* copy() const = 0; + + /** + * Split the source at position pos and return the splitted source + * on success. + * The new source will be moved after this source. + * + * The default implementation uses copy() to create a new source instance + */ + virtual K3bAudioDataSource* split( const K3b::Msf& pos ); + + protected: + /** + * Informs the parent track about changes. + */ + void emitChange(); + + private: + void fixupOffsets(); + + K3bAudioTrack* m_track; + K3bAudioDataSource* m_prev; + K3bAudioDataSource* m_next; + + K3b::Msf m_startOffset; + K3b::Msf m_endOffset; +}; + +#endif diff --git a/libk3b/projects/audiocd/k3baudiodatasourceiterator.cpp b/libk3b/projects/audiocd/k3baudiodatasourceiterator.cpp new file mode 100644 index 0000000..81e0a59 --- /dev/null +++ b/libk3b/projects/audiocd/k3baudiodatasourceiterator.cpp @@ -0,0 +1,71 @@ +/* + * + * $Id: sourceheader,v 1.3 2005/01/19 13:03:46 trueg Exp $ + * Copyright (C) 2005 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3baudiodatasourceiterator.h" +#include "k3baudiodoc.h" +#include "k3baudiotrack.h" +#include "k3baudiodatasource.h" + + +K3bAudioDataSourceIterator::K3bAudioDataSourceIterator( K3bAudioDoc* doc ) + : m_doc( doc ) +{ + first(); +} + + +K3bAudioDataSource* K3bAudioDataSourceIterator::current() const +{ + return m_currentSource; +} + + +K3bAudioDataSource* K3bAudioDataSourceIterator::next() +{ + m_currentSource = m_currentSource->next(); + if( !m_currentSource ) { + m_currentTrack = m_currentTrack->next(); + if( m_currentTrack ) + m_currentSource = m_currentTrack->firstSource(); + } + + return m_currentSource; +} + + +bool K3bAudioDataSourceIterator::hasNext() const +{ + if( !m_currentSource ) + return false; + if( m_currentSource->next() ) + return true; + if( m_currentTrack->next() ) + return true; + + return false; +} + + +K3bAudioDataSource* K3bAudioDataSourceIterator::first() +{ + m_currentTrack = m_doc->firstTrack(); + + if( m_currentTrack ) + m_currentSource = m_currentTrack->firstSource(); + else + m_currentSource = 0; + + return m_currentSource; +} diff --git a/libk3b/projects/audiocd/k3baudiodatasourceiterator.h b/libk3b/projects/audiocd/k3baudiodatasourceiterator.h new file mode 100644 index 0000000..7a0ce59 --- /dev/null +++ b/libk3b/projects/audiocd/k3baudiodatasourceiterator.h @@ -0,0 +1,61 @@ +/* + * + * $Id: sourceheader,v 1.3 2005/01/19 13:03:46 trueg Exp $ + * Copyright (C) 2005 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_AUDIO_DATA_SOURCE_ITERATOR_H_ +#define _K3B_AUDIO_DATA_SOURCE_ITERATOR_H_ +#include "k3b_export.h" +class K3bAudioDataSource; +class K3bAudioTrack; +class K3bAudioDoc; + + +/** + * This Iterator iterates over the sources in an audio project + * + * Be aware that this iterator does not properly update when the doc + * changes. A manual update can be issued with first(). This is becasue + * an update would either involve slots (this being a QObject) which is + * too much overhead or the AudioDoc would need to have knowledge of all + * the iterators which is also overhead that would be overkill. + */ +class LIBK3B_EXPORT K3bAudioDataSourceIterator +{ + public: + /** + * This will place the iterator on the first source just like first() does. + */ + explicit K3bAudioDataSourceIterator( K3bAudioDoc* ); + + K3bAudioDataSource* current() const; + + bool hasNext() const; + + /** + * \return the next source or 0 if at end. + */ + K3bAudioDataSource* next(); + + /** + * Reset the iterator + */ + K3bAudioDataSource* first(); + + private: + K3bAudioDoc* m_doc; + K3bAudioTrack* m_currentTrack; + K3bAudioDataSource* m_currentSource; +}; + +#endif diff --git a/libk3b/projects/audiocd/k3baudiodoc.cpp b/libk3b/projects/audiocd/k3baudiodoc.cpp new file mode 100644 index 0000000..e7661ba --- /dev/null +++ b/libk3b/projects/audiocd/k3baudiodoc.cpp @@ -0,0 +1,1127 @@ +/* + * + * $Id: k3baudiodoc.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include +#include "k3baudiodoc.h" +#include "k3baudiotrack.h" +#include "k3baudiojob.h" +#include "k3baudiofile.h" +#include "k3baudiozerodata.h" +#include "k3baudiocdtracksource.h" + +#include +#include +#include +#include + + +// QT-includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// KDE-includes +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +class K3bAudioDoc::Private +{ +public: + Private() { + cdTextValidator = new K3bCdTextValidator(); + } + + ~Private() { + delete cdTextValidator; + } + + K3bCdTextValidator* cdTextValidator; +}; + + +K3bAudioDoc::K3bAudioDoc( QObject* parent ) + : K3bDoc( parent ), + m_firstTrack(0), + m_lastTrack(0) +{ + d = new Private; + m_docType = AUDIO; +} + +K3bAudioDoc::~K3bAudioDoc() +{ + // delete all tracks + int i = 1; + int cnt = numOfTracks(); + while( m_firstTrack ) { + kdDebug() << "(K3bAudioDoc::~K3bAudioDoc) deleting track " << i << " of " << cnt << endl; + delete m_firstTrack->take(); + kdDebug() << "(K3bAudioDoc::~K3bAudioDoc) deleted." << endl; + ++i; + } + + delete d; +} + +bool K3bAudioDoc::newDocument() +{ + // delete all tracks + while( m_firstTrack ) + delete m_firstTrack->take(); + + m_normalize = false; + m_hideFirstTrack = false; + m_cdText = false; + m_cdTextData.clear(); + m_audioRippingParanoiaMode = 0; + m_audioRippingRetries = 5; + m_audioRippingIgnoreReadErrors = true; + + return K3bDoc::newDocument(); +} + + +QString K3bAudioDoc::name() const +{ + if( !m_cdTextData.title().isEmpty() ) + return m_cdTextData.title(); + else + return K3bDoc::name(); +} + + +K3bAudioTrack* K3bAudioDoc::firstTrack() const +{ + return m_firstTrack; +} + + +K3bAudioTrack* K3bAudioDoc::lastTrack() const +{ + return m_lastTrack; +} + + +// this one is called by K3bAudioTrack to update the list +void K3bAudioDoc::setFirstTrack( K3bAudioTrack* track ) +{ + m_firstTrack = track; +} + +// this one is called by K3bAudioTrack to update the list +void K3bAudioDoc::setLastTrack( K3bAudioTrack* track ) +{ + m_lastTrack = track; +} + + +KIO::filesize_t K3bAudioDoc::size() const +{ + // This is not really correct but what the user expects ;) + return length().mode1Bytes(); +} + + +K3b::Msf K3bAudioDoc::length() const +{ + K3b::Msf length = 0; + K3bAudioTrack* track = m_firstTrack; + while( track ) { + length += track->length(); + track = track->next(); + } + + return length; +} + + +void K3bAudioDoc::addUrls( const KURL::List& urls ) +{ + // make sure we add them at the end even if urls are in the queue + addTracks( urls, 99 ); +} + + +void K3bAudioDoc::addTracks( const KURL::List& urls, uint position ) +{ + KURL::List allUrls = extractUrlList( K3b::convertToLocalUrls(urls) ); + KURL::List::iterator end( allUrls.end()); + for( KURL::List::iterator it = allUrls.begin(); it != end; it++, position++ ) { + KURL& url = *it; + if( url.path().right(3).lower() == "cue" ) { + // try adding a cue file + if( K3bAudioTrack* newAfter = importCueFile( url.path(), getTrack(position) ) ) { + position = newAfter->trackNumber(); + continue; + } + } + + if( K3bAudioTrack* track = createTrack( url ) ) { + addTrack( track, position ); + + K3bAudioDecoder* dec = static_cast( track->firstSource() )->decoder(); + track->setTitle( dec->metaInfo( K3bAudioDecoder::META_TITLE ) ); + track->setArtist( dec->metaInfo( K3bAudioDecoder::META_ARTIST ) ); + track->setSongwriter( dec->metaInfo( K3bAudioDecoder::META_SONGWRITER ) ); + track->setComposer( dec->metaInfo( K3bAudioDecoder::META_COMPOSER ) ); + track->setCdTextMessage( dec->metaInfo( K3bAudioDecoder::META_COMMENT ) ); + } + } + + emit changed(); + + informAboutNotFoundFiles(); +} + + +KURL::List K3bAudioDoc::extractUrlList( const KURL::List& urls ) +{ + KURL::List allUrls = urls; + KURL::List urlsFromPlaylist; + KURL::List::iterator it = allUrls.begin(); + while( it != allUrls.end() ) { + + const KURL& url = *it; + QFileInfo fi( url.path() ); + + if( !url.isLocalFile() ) { + kdDebug() << url.path() << " no local file" << endl; + it = allUrls.remove( it ); + m_notFoundFiles.append( url ); + } + else if( !fi.exists() ) { + it = allUrls.remove( it ); + kdDebug() << url.path() << " not found" << endl; + m_notFoundFiles.append( url ); + } + else if( fi.isDir() ) { + it = allUrls.remove( it ); + // add all files in the dir + QDir dir(fi.filePath()); + QStringList entries = dir.entryList( QDir::Files ); + KURL::List::iterator oldIt = it; + // add all files into the list after the current item + for( QStringList::iterator dirIt = entries.begin(); + dirIt != entries.end(); ++dirIt ) + it = allUrls.insert( oldIt, KURL::fromPathOrURL( dir.absPath() + "/" + *dirIt ) ); + } + else if( readPlaylistFile( url, urlsFromPlaylist ) ) { + it = allUrls.remove( it ); + KURL::List::iterator oldIt = it; + // add all files into the list after the current item + for( KURL::List::iterator dirIt = urlsFromPlaylist.begin(); + dirIt != urlsFromPlaylist.end(); ++dirIt ) + it = allUrls.insert( oldIt, *dirIt ); + } + else + ++it; + } + + return allUrls; +} + + +bool K3bAudioDoc::readPlaylistFile( const KURL& url, KURL::List& playlist ) +{ + // check if the file is a m3u playlist + // and if so add all listed files + + QFile f( url.path() ); + if( !f.open( IO_ReadOnly ) ) + return false; + + QTextStream t( &f ); + char buf[7]; + t.readRawBytes( buf, 7 ); + if( QString::fromLatin1( buf, 7 ) != "#EXTM3U" ) + return false; + + // skip the first line + t.readLine(); + + // read the file + while( !t.atEnd() ) { + QString line = t.readLine(); + if( line[0] != '#' ) { + KURL mp3url; + // relative paths + if( line[0] != '/' ) + mp3url.setPath( url.directory(false) + line ); + else + mp3url.setPath( line ); + + playlist.append( mp3url ); + } + } + + return true; +} + + +void K3bAudioDoc::addSources( K3bAudioTrack* parent, + const KURL::List& urls, + K3bAudioDataSource* sourceAfter ) +{ + kdDebug() << "(K3bAudioDoc::addSources( " << parent << ", " + << urls.first().path() << ", " + << sourceAfter << " )" << endl; + KURL::List allUrls = extractUrlList( urls ); + KURL::List::const_iterator end(allUrls.end()); + for( KURL::List::const_iterator it = allUrls.begin(); it != end; ++it ) { + if( K3bAudioFile* file = createAudioFile( *it ) ) { + if( sourceAfter ) + file->moveAfter( sourceAfter ); + else + file->moveAhead( parent->firstSource() ); + sourceAfter = file; + } + } + + informAboutNotFoundFiles(); + kdDebug() << "(K3bAudioDoc::addSources) finished." << endl; +} + + +K3bAudioTrack* K3bAudioDoc::importCueFile( const QString& cuefile, K3bAudioTrack* after, K3bAudioDecoder* decoder ) +{ + if( !after ) + after = m_lastTrack; + + kdDebug() << "(K3bAudioDoc::importCueFile( " << cuefile << ", " << after << ")" << endl; + K3bCueFileParser parser( cuefile ); + if( parser.isValid() && parser.toc().contentType() == K3bDevice::AUDIO ) { + + kdDebug() << "(K3bAudioDoc::importCueFile) parsed with image: " << parser.imageFilename() << endl; + + // global cd-text + if( !parser.cdText().title().isEmpty() ) + setTitle( parser.cdText().title() ); + if( !parser.cdText().performer().isEmpty() ) + setPerformer( parser.cdText().performer() ); + + bool reused = true; + if( !decoder ) + decoder = getDecoderForUrl( KURL::fromPathOrURL(parser.imageFilename()), &reused ); + + if( decoder ) { + if( !reused ) + decoder->analyseFile(); + + K3bAudioFile* newFile = 0; + unsigned int i = 0; + for( K3bDevice::Toc::const_iterator it = parser.toc().begin(); + it != parser.toc().end(); ++it ) { + const K3bDevice::Track& track = *it; + + newFile = new K3bAudioFile( decoder, this ); + newFile->setStartOffset( track.firstSector() ); + newFile->setEndOffset( track.lastSector()+1 ); + + K3bAudioTrack* newTrack = new K3bAudioTrack( this ); + newTrack->addSource( newFile ); + newTrack->moveAfter( after ); + + // we do not know the length of the source yet so we have to force the index value + if( track.index0() > 0 ) + newTrack->m_index0Offset = track.length() - track.index0(); + else + newTrack->m_index0Offset = 0; + + // cd-text + newTrack->setTitle( parser.cdText()[i].title() ); + newTrack->setPerformer( parser.cdText()[i].performer() ); + + // add the next track after this one + after = newTrack; + ++i; + } + + // let the last source use the data up to the end of the file + if( newFile ) + newFile->setEndOffset(0); + + return after; + } + } + return 0; +} + + +K3bAudioDecoder* K3bAudioDoc::getDecoderForUrl( const KURL& url, bool* reused ) +{ + K3bAudioDecoder* decoder = 0; + + // check if we already have a proper decoder + if( m_decoderPresenceMap.contains( url.path() ) ) { + decoder = m_decoderPresenceMap[url.path()]; + *reused = true; + } + else if( (decoder = K3bAudioDecoderFactory::createDecoder( url )) ) { + kdDebug() << "(K3bAudioDoc) using " << decoder->className() + << " for decoding of " << url.path() << endl; + + decoder->setFilename( url.path() ); + *reused = false; + } + + return decoder; +} + + +K3bAudioFile* K3bAudioDoc::createAudioFile( const KURL& url ) +{ + if( !QFile::exists( url.path() ) ) { + m_notFoundFiles.append( url.path() ); + kdDebug() << "(K3bAudioDoc) could not find file " << url.path() << endl; + return 0; + } + + bool reused; + K3bAudioDecoder* decoder = getDecoderForUrl( url, &reused ); + if( decoder ) { + if( !reused ) + decoder->analyseFile(); + return new K3bAudioFile( decoder, this ); + } + else { + m_unknownFileFormatFiles.append( url.path() ); + kdDebug() << "(K3bAudioDoc) unknown file type in file " << url.path() << endl; + return 0; + } +} + + +K3bAudioTrack* K3bAudioDoc::createTrack( const KURL& url ) +{ + kdDebug() << "(K3bAudioDoc::createTrack( " << url.path() << " )" << endl; + if( K3bAudioFile* file = createAudioFile( url ) ) { + K3bAudioTrack* newTrack = new K3bAudioTrack( this ); + newTrack->setFirstSource( file ); + return newTrack; + } + else + return 0; +} + + +void K3bAudioDoc::addTrack( const KURL& url, uint position ) +{ + addTracks( KURL::List(url), position ); +} + + + +K3bAudioTrack* K3bAudioDoc::getTrack( unsigned int trackNum ) +{ + K3bAudioTrack* track = m_firstTrack; + unsigned int i = 1; + while( track ) { + if( i == trackNum ) + return track; + track = track->next(); + ++i; + } + + return 0; +} + + +void K3bAudioDoc::addTrack( K3bAudioTrack* track, uint position ) +{ + kdDebug() << "(K3bAudioDoc::addTrack( " << track << ", " << position << " )" << endl; + track->m_parent = this; + if( !m_firstTrack ) + m_firstTrack = m_lastTrack = track; + else if( position == 0 ) + track->moveAhead( m_firstTrack ); + else { + K3bAudioTrack* after = getTrack( position ); + if( after ) + track->moveAfter( after ); + else + track->moveAfter( m_lastTrack ); // just to be sure it's anywhere... + } + + emit changed(); +} + + +void K3bAudioDoc::removeTrack( K3bAudioTrack* track ) +{ + delete track; +} + + +void K3bAudioDoc::moveTrack( K3bAudioTrack* track, K3bAudioTrack* after ) +{ + track->moveAfter( after ); +} + + +QString K3bAudioDoc::typeString() const +{ + return "audio"; +} + + +bool K3bAudioDoc::loadDocumentData( QDomElement* root ) +{ + newDocument(); + + // we will parse the dom-tree and create a K3bAudioTrack for all entries immediately + // this should not take long and so not block the gui + + QDomNodeList nodes = root->childNodes(); + + for( uint i = 0; i < nodes.count(); i++ ) { + + QDomElement e = nodes.item(i).toElement(); + + if( e.isNull() ) + return false; + + if( e.nodeName() == "general" ) { + if( !readGeneralDocumentData( e ) ) + return false; + } + + else if( e.nodeName() == "normalize" ) + setNormalize( e.text() == "yes" ); + + else if( e.nodeName() == "hide_first_track" ) + setHideFirstTrack( e.text() == "yes" ); + + else if( e.nodeName() == "audio_ripping" ) { + QDomNodeList ripNodes = e.childNodes(); + for( uint j = 0; j < ripNodes.length(); j++ ) { + if( ripNodes.item(j).nodeName() == "paranoia_mode" ) + setAudioRippingParanoiaMode( ripNodes.item(j).toElement().text().toInt() ); + else if( ripNodes.item(j).nodeName() == "read_retries" ) + setAudioRippingRetries( ripNodes.item(j).toElement().text().toInt() ); + else if( ripNodes.item(j).nodeName() == "ignore_read_errors" ) + setAudioRippingIgnoreReadErrors( ripNodes.item(j).toElement().text() == "yes" ); + } + } + + // parse cd-text + else if( e.nodeName() == "cd-text" ) { + if( !e.hasAttribute( "activated" ) ) + return false; + + writeCdText( e.attributeNode( "activated" ).value() == "yes" ); + + QDomNodeList cdTextNodes = e.childNodes(); + for( uint j = 0; j < cdTextNodes.length(); j++ ) { + if( cdTextNodes.item(j).nodeName() == "title" ) + setTitle( cdTextNodes.item(j).toElement().text() ); + + else if( cdTextNodes.item(j).nodeName() == "artist" ) + setArtist( cdTextNodes.item(j).toElement().text() ); + + else if( cdTextNodes.item(j).nodeName() == "arranger" ) + setArranger( cdTextNodes.item(j).toElement().text() ); + + else if( cdTextNodes.item(j).nodeName() == "songwriter" ) + setSongwriter( cdTextNodes.item(j).toElement().text() ); + + else if( cdTextNodes.item(j).nodeName() == "composer" ) + setComposer( cdTextNodes.item(j).toElement().text() ); + + else if( cdTextNodes.item(j).nodeName() == "disc_id" ) + setDisc_id( cdTextNodes.item(j).toElement().text() ); + + else if( cdTextNodes.item(j).nodeName() == "upc_ean" ) + setUpc_ean( cdTextNodes.item(j).toElement().text() ); + + else if( cdTextNodes.item(j).nodeName() == "message" ) + setCdTextMessage( cdTextNodes.item(j).toElement().text() ); + } + } + + else if( e.nodeName() == "contents" ) { + + QDomNodeList contentNodes = e.childNodes(); + + for( uint j = 0; j< contentNodes.length(); j++ ) { + + QDomElement trackElem = contentNodes.item(j).toElement(); + + // first of all we need a track + K3bAudioTrack* track = new K3bAudioTrack(); + + + // backwards compatibility + // ----------------------------------------------------------------------------------------------------- + QDomAttr oldUrlAttr = trackElem.attributeNode( "url" ); + if( !oldUrlAttr.isNull() ) { + if( K3bAudioFile* file = + createAudioFile( KURL::fromPathOrURL( oldUrlAttr.value() ) ) ) { + track->addSource( file ); + } + } + // ----------------------------------------------------------------------------------------------------- + + + QDomNodeList trackNodes = trackElem.childNodes(); + for( uint trackJ = 0; trackJ < trackNodes.length(); trackJ++ ) { + + if( trackNodes.item(trackJ).nodeName() == "sources" ) { + QDomNodeList sourcesNodes = trackNodes.item(trackJ).childNodes(); + for( unsigned int sourcesIndex = 0; sourcesIndex < sourcesNodes.length(); sourcesIndex++ ) { + QDomElement sourceElem = sourcesNodes.item(sourcesIndex).toElement(); + if( sourceElem.nodeName() == "file" ) { + if( K3bAudioFile* file = + createAudioFile( KURL::fromPathOrURL( sourceElem.attributeNode( "url" ).value() ) ) ) { + file->setStartOffset( K3b::Msf::fromString( sourceElem.attributeNode( "start_offset" ).value() ) ); + file->setEndOffset( K3b::Msf::fromString( sourceElem.attributeNode( "end_offset" ).value() ) ); + track->addSource( file ); + } + } + else if( sourceElem.nodeName() == "silence" ) { + K3bAudioZeroData* zero = new K3bAudioZeroData(); + zero->setLength( K3b::Msf::fromString( sourceElem.attributeNode( "length" ).value() ) ); + track->addSource( zero ); + } + else if( sourceElem.nodeName() == "cdtrack" ) { + K3b::Msf length = K3b::Msf::fromString( sourceElem.attributeNode( "length" ).value() ); + int titlenum = 0; + unsigned int discid = 0; + QString title, artist, cdTitle, cdArtist; + + QDomNodeList cdTrackSourceNodes = sourceElem.childNodes(); + for( unsigned int cdTrackSourceIndex = 0; cdTrackSourceIndex < cdTrackSourceNodes.length(); ++cdTrackSourceIndex ) { + QDomElement cdTrackSourceItemElem = cdTrackSourceNodes.item(cdTrackSourceIndex).toElement(); + if( cdTrackSourceItemElem.nodeName() == "title_number" ) + titlenum = cdTrackSourceItemElem.text().toInt(); + else if( cdTrackSourceItemElem.nodeName() == "disc_id" ) + discid = cdTrackSourceItemElem.text().toUInt( 0, 16 ); + else if( cdTrackSourceItemElem.nodeName() == "title" ) + title = cdTrackSourceItemElem.text().toInt(); + else if( cdTrackSourceItemElem.nodeName() == "artist" ) + artist = cdTrackSourceItemElem.text().toInt(); + else if( cdTrackSourceItemElem.nodeName() == "cdtitle" ) + cdTitle = cdTrackSourceItemElem.text().toInt(); + else if( cdTrackSourceItemElem.nodeName() == "cdartist" ) + cdArtist = cdTrackSourceItemElem.text().toInt(); + } + + if( discid != 0 && titlenum > 0 ) { + K3bAudioCdTrackSource* cdtrack = new K3bAudioCdTrackSource( discid, length, titlenum, + artist, title, + cdArtist, cdTitle ); + cdtrack->setStartOffset( K3b::Msf::fromString( sourceElem.attributeNode( "start_offset" ).value() ) ); + cdtrack->setEndOffset( K3b::Msf::fromString( sourceElem.attributeNode( "end_offset" ).value() ) ); + track->addSource( cdtrack ); + } + else { + kdDebug() << "(K3bAudioDoc) invalid cdtrack source." << endl; + return false; + } + } + else { + kdDebug() << "(K3bAudioDoc) unknown source type: " << sourceElem.nodeName() << endl; + return false; + } + } + } + + // load cd-text + else if( trackNodes.item(trackJ).nodeName() == "cd-text" ) { + QDomNodeList cdTextNodes = trackNodes.item(trackJ).childNodes(); + for( uint trackCdTextJ = 0; trackCdTextJ < cdTextNodes.length(); trackCdTextJ++ ) { + if( cdTextNodes.item(trackCdTextJ).nodeName() == "title" ) + track->setTitle( cdTextNodes.item(trackCdTextJ).toElement().text() ); + + else if( cdTextNodes.item(trackCdTextJ).nodeName() == "artist" ) + track->setArtist( cdTextNodes.item(trackCdTextJ).toElement().text() ); + + else if( cdTextNodes.item(trackCdTextJ).nodeName() == "arranger" ) + track->setArranger( cdTextNodes.item(trackCdTextJ).toElement().text() ); + + else if( cdTextNodes.item(trackCdTextJ).nodeName() == "songwriter" ) + track->setSongwriter( cdTextNodes.item(trackCdTextJ).toElement().text() ); + + else if( cdTextNodes.item(trackCdTextJ).nodeName() == "composer" ) + track->setComposer( cdTextNodes.item(trackCdTextJ).toElement().text() ); + + else if( cdTextNodes.item(trackCdTextJ).nodeName() == "isrc" ) + track->setIsrc( cdTextNodes.item(trackCdTextJ).toElement().text() ); + + else if( cdTextNodes.item(trackCdTextJ).nodeName() == "message" ) + track->setCdTextMessage( cdTextNodes.item(trackCdTextJ).toElement().text() ); + } + } + + else if( trackNodes.item(trackJ).nodeName() == "index0" ) + track->setIndex0( K3b::Msf::fromString( trackNodes.item(trackJ).toElement().text() ) ); + + // TODO: load other indices + + // load options + else if( trackNodes.item(trackJ).nodeName() == "copy_protection" ) + track->setCopyProtection( trackNodes.item(trackJ).toElement().text() == "yes" ); + + else if( trackNodes.item(trackJ).nodeName() == "pre_emphasis" ) + track->setPreEmp( trackNodes.item(trackJ).toElement().text() == "yes" ); + } + + // add the track + if( track->numberSources() > 0 ) + addTrack( track, 99 ); // append to the end // TODO improve + else { + kdDebug() << "(K3bAudioDoc) no sources. deleting track " << track << endl; + delete track; + } + } + } + } + + informAboutNotFoundFiles(); + + setModified(false); + + return true; +} + +bool K3bAudioDoc::saveDocumentData( QDomElement* docElem ) +{ + QDomDocument doc = docElem->ownerDocument(); + saveGeneralDocumentData( docElem ); + + // add normalize + QDomElement normalizeElem = doc.createElement( "normalize" ); + normalizeElem.appendChild( doc.createTextNode( normalize() ? "yes" : "no" ) ); + docElem->appendChild( normalizeElem ); + + // add hide track + QDomElement hideFirstTrackElem = doc.createElement( "hide_first_track" ); + hideFirstTrackElem.appendChild( doc.createTextNode( hideFirstTrack() ? "yes" : "no" ) ); + docElem->appendChild( hideFirstTrackElem ); + + // save the audio cd ripping settings + // paranoia mode, read retries, and ignore read errors + // ------------------------------------------------------------ + QDomElement ripMain = doc.createElement( "audio_ripping" ); + docElem->appendChild( ripMain ); + + QDomElement ripElem = doc.createElement( "paranoia_mode" ); + ripElem.appendChild( doc.createTextNode( QString::number( audioRippingParanoiaMode() ) ) ); + ripMain.appendChild( ripElem ); + + ripElem = doc.createElement( "read_retries" ); + ripElem.appendChild( doc.createTextNode( QString::number( audioRippingRetries() ) ) ); + ripMain.appendChild( ripElem ); + + ripElem = doc.createElement( "ignore_read_errors" ); + ripElem.appendChild( doc.createTextNode( audioRippingIgnoreReadErrors() ? "yes" : "no" ) ); + ripMain.appendChild( ripElem ); + // ------------------------------------------------------------ + + // save disc cd-text + // ------------------------------------------------------------- + QDomElement cdTextMain = doc.createElement( "cd-text" ); + cdTextMain.setAttribute( "activated", cdText() ? "yes" : "no" ); + QDomElement cdTextElem = doc.createElement( "title" ); + cdTextElem.appendChild( doc.createTextNode( (title())) ); + cdTextMain.appendChild( cdTextElem ); + + cdTextElem = doc.createElement( "artist" ); + cdTextElem.appendChild( doc.createTextNode( (artist())) ); + cdTextMain.appendChild( cdTextElem ); + + cdTextElem = doc.createElement( "arranger" ); + cdTextElem.appendChild( doc.createTextNode( (arranger())) ); + cdTextMain.appendChild( cdTextElem ); + + cdTextElem = doc.createElement( "songwriter" ); + cdTextElem.appendChild( doc.createTextNode( (songwriter())) ); + cdTextMain.appendChild( cdTextElem ); + + cdTextElem = doc.createElement( "composer" ); + cdTextElem.appendChild( doc.createTextNode( composer()) ); + cdTextMain.appendChild( cdTextElem ); + + cdTextElem = doc.createElement( "disc_id" ); + cdTextElem.appendChild( doc.createTextNode( (disc_id())) ); + cdTextMain.appendChild( cdTextElem ); + + cdTextElem = doc.createElement( "upc_ean" ); + cdTextElem.appendChild( doc.createTextNode( (upc_ean())) ); + cdTextMain.appendChild( cdTextElem ); + + cdTextElem = doc.createElement( "message" ); + cdTextElem.appendChild( doc.createTextNode( (cdTextMessage())) ); + cdTextMain.appendChild( cdTextElem ); + + docElem->appendChild( cdTextMain ); + // ------------------------------------------------------------- + + // save the tracks + // ------------------------------------------------------------- + QDomElement contentsElem = doc.createElement( "contents" ); + + for( K3bAudioTrack* track = firstTrack(); track != 0; track = track->next() ) { + + QDomElement trackElem = doc.createElement( "track" ); + + // add sources + QDomElement sourcesParent = doc.createElement( "sources" ); + + for( K3bAudioDataSource* source = track->firstSource(); source; source = source->next() ) { + // TODO: save a source element with a type attribute and start- and endoffset + // then distict between the different source types. + if( K3bAudioFile* file = dynamic_cast(source) ) { + QDomElement sourceElem = doc.createElement( "file" ); + sourceElem.setAttribute( "url", file->filename() ); + sourceElem.setAttribute( "start_offset", file->startOffset().toString() ); + sourceElem.setAttribute( "end_offset", file->endOffset().toString() ); + sourcesParent.appendChild( sourceElem ); + } + else if( K3bAudioZeroData* zero = dynamic_cast(source) ) { + QDomElement sourceElem = doc.createElement( "silence" ); + sourceElem.setAttribute( "length", zero->length().toString() ); + sourcesParent.appendChild( sourceElem ); + } + else if( K3bAudioCdTrackSource* cdTrack = dynamic_cast(source) ) { + QDomElement sourceElem = doc.createElement( "cdtrack" ); + sourceElem.setAttribute( "length", cdTrack->originalLength().toString() ); + sourceElem.setAttribute( "start_offset", cdTrack->startOffset().toString() ); + sourceElem.setAttribute( "end_offset", cdTrack->endOffset().toString() ); + + QDomElement subElem = doc.createElement( "title_number" ); + subElem.appendChild( doc.createTextNode( QString::number(cdTrack->cdTrackNumber()) ) ); + sourceElem.appendChild( subElem ); + + subElem = doc.createElement( "disc_id" ); + subElem.appendChild( doc.createTextNode( QString::number(cdTrack->discId(), 16) ) ); + sourceElem.appendChild( subElem ); + + subElem = doc.createElement( "title" ); + subElem.appendChild( doc.createTextNode( cdTrack->metaInfo().titles[cdTrack->cdTrackNumber()-1] ) ); + sourceElem.appendChild( subElem ); + + subElem = doc.createElement( "artist" ); + subElem.appendChild( doc.createTextNode( cdTrack->metaInfo().artists[cdTrack->cdTrackNumber()-1] ) ); + sourceElem.appendChild( subElem ); + + subElem = doc.createElement( "cdtitle" ); + subElem.appendChild( doc.createTextNode( cdTrack->metaInfo().cdTitle ) ); + sourceElem.appendChild( subElem ); + + subElem = doc.createElement( "cdartist" ); + subElem.appendChild( doc.createTextNode( cdTrack->metaInfo().cdArtist ) ); + sourceElem.appendChild( subElem ); + + sourcesParent.appendChild( sourceElem ); + } + else { + kdError() << "(K3bAudioDoc) saving sources other than file or zero not supported yet." << endl; + return false; + } + } + trackElem.appendChild( sourcesParent ); + + // index 0 + QDomElement index0Elem = doc.createElement( "index0" ); + index0Elem.appendChild( doc.createTextNode( track->index0().toString() ) ); + trackElem.appendChild( index0Elem ); + + // TODO: other indices + + // add cd-text + cdTextMain = doc.createElement( "cd-text" ); + cdTextElem = doc.createElement( "title" ); + cdTextElem.appendChild( doc.createTextNode( (track->title())) ); + cdTextMain.appendChild( cdTextElem ); + + cdTextElem = doc.createElement( "artist" ); + cdTextElem.appendChild( doc.createTextNode( (track->artist())) ); + cdTextMain.appendChild( cdTextElem ); + + cdTextElem = doc.createElement( "arranger" ); + cdTextElem.appendChild( doc.createTextNode( (track->arranger()) ) ); + cdTextMain.appendChild( cdTextElem ); + + cdTextElem = doc.createElement( "songwriter" ); + cdTextElem.appendChild( doc.createTextNode( (track->songwriter()) ) ); + cdTextMain.appendChild( cdTextElem ); + + cdTextElem = doc.createElement( "composer" ); + cdTextElem.appendChild( doc.createTextNode( (track->composer()) ) ); + cdTextMain.appendChild( cdTextElem ); + + cdTextElem = doc.createElement( "isrc" ); + cdTextElem.appendChild( doc.createTextNode( ( track->isrc()) ) ); + cdTextMain.appendChild( cdTextElem ); + + cdTextElem = doc.createElement( "message" ); + cdTextElem.appendChild( doc.createTextNode( (track->cdTextMessage()) ) ); + cdTextMain.appendChild( cdTextElem ); + + trackElem.appendChild( cdTextMain ); + + // add copy protection + QDomElement copyElem = doc.createElement( "copy_protection" ); + copyElem.appendChild( doc.createTextNode( track->copyProtection() ? "yes" : "no" ) ); + trackElem.appendChild( copyElem ); + + // add pre emphasis + copyElem = doc.createElement( "pre_emphasis" ); + copyElem.appendChild( doc.createTextNode( track->preEmp() ? "yes" : "no" ) ); + trackElem.appendChild( copyElem ); + + contentsElem.appendChild( trackElem ); + } + // ------------------------------------------------------------- + + docElem->appendChild( contentsElem ); + + return true; +} + + +int K3bAudioDoc::numOfTracks() const +{ + return ( m_lastTrack ? m_lastTrack->trackNumber() : 0 ); +} + + +K3bBurnJob* K3bAudioDoc::newBurnJob( K3bJobHandler* hdl, QObject* parent ) +{ + return new K3bAudioJob( this, hdl, parent ); +} + + +void K3bAudioDoc::informAboutNotFoundFiles() +{ + if( !m_notFoundFiles.isEmpty() ) { + QStringList l; + for( KURL::List::const_iterator it = m_notFoundFiles.begin(); + it != m_notFoundFiles.end(); ++it ) + l.append( (*it).path() ); + KMessageBox::informationList( qApp->activeWindow(), + i18n("Could not find the following files:"), + l, + i18n("Not Found") ); + + m_notFoundFiles.clear(); + } + if( !m_unknownFileFormatFiles.isEmpty() ) { + QStringList l; + for( KURL::List::const_iterator it = m_unknownFileFormatFiles.begin(); + it != m_unknownFileFormatFiles.end(); ++it ) + l.append( (*it).path() ); + KMessageBox::informationList( qApp->activeWindow(), + i18n("

Unable to handle the following files due to an unsupported format:" + "

You may manually convert these audio files to wave using another " + "application supporting the audio format and then add the wave files " + "to the K3b project."), + l, + i18n("Unsupported Format") ); + + m_unknownFileFormatFiles.clear(); + } +} + + + +void K3bAudioDoc::removeCorruptTracks() +{ +// K3bAudioTrack* track = m_tracks->first(); +// while( track ) { +// if( track->status() != 0 ) { +// removeTrack(track); +// track = m_tracks->current(); +// } +// else +// track = m_tracks->next(); +// } +} + + +void K3bAudioDoc::slotTrackChanged( K3bAudioTrack* track ) +{ + kdDebug() << "(K3bAudioDoc::slotTrackChanged " << track << endl; + setModified( true ); + // if the track is empty now we simply delete it + if( track->firstSource() ) { + emit trackChanged(track); + emit changed(); + } + else { + kdDebug() << "(K3bAudioDoc::slotTrackChanged) track " << track << " empty. Deleting." << endl; + delete track; // this will emit the proper signal + } + kdDebug() << "(K3bAudioDoc::slotTrackChanged done" << track << endl; +} + + +void K3bAudioDoc::slotTrackRemoved( K3bAudioTrack* track ) +{ + setModified( true ); + emit trackRemoved(track); + emit changed(); +} + + +void K3bAudioDoc::increaseDecoderUsage( K3bAudioDecoder* decoder ) +{ + kdDebug() << "(K3bAudioDoc::increaseDecoderUsage)" << endl; + if( !m_decoderUsageCounterMap.contains( decoder ) ) { + m_decoderUsageCounterMap[decoder] = 1; + m_decoderPresenceMap[decoder->filename()] = decoder; + } + else + m_decoderUsageCounterMap[decoder]++; + kdDebug() << "(K3bAudioDoc::increaseDecoderUsage) finished" << endl; +} + + +void K3bAudioDoc::decreaseDecoderUsage( K3bAudioDecoder* decoder ) +{ + m_decoderUsageCounterMap[decoder]--; + if( m_decoderUsageCounterMap[decoder] <= 0 ) { + m_decoderUsageCounterMap.erase(decoder); + m_decoderPresenceMap.erase(decoder->filename()); + delete decoder; + } +} + + +K3bDevice::CdText K3bAudioDoc::cdTextData() const +{ + K3bDevice::CdText text( m_cdTextData ); + text.reserve( numOfTracks() ); + K3bAudioTrack* track = firstTrack(); + while( track ) { + text.append( track->cdText() ); + + track = track->next(); + } + return text; +} + + +K3bDevice::Toc K3bAudioDoc::toToc() const +{ + K3bDevice::Toc toc; + + // FIXME: add MCN + + K3bAudioTrack* track = firstTrack(); + K3b::Msf pos = 0; + while( track ) { + toc.append( track->toCdTrack() ); + track = track->next(); + } + + return toc; +} + + +void K3bAudioDoc::setTitle( const QString& v ) +{ + m_cdTextData.setTitle( v ); + emit changed(); +} + + +void K3bAudioDoc::setArtist( const QString& v ) +{ + setPerformer( v ); +} + + +void K3bAudioDoc::setPerformer( const QString& v ) +{ + QString s( v ); + d->cdTextValidator->fixup( s ); + m_cdTextData.setPerformer( s ); + emit changed(); +} + + +void K3bAudioDoc::setDisc_id( const QString& v ) +{ + QString s( v ); + d->cdTextValidator->fixup( s ); + m_cdTextData.setDiscId( s ); + emit changed(); +} + + +void K3bAudioDoc::setArranger( const QString& v ) +{ + QString s( v ); + d->cdTextValidator->fixup( s ); + m_cdTextData.setArranger( s ); + emit changed(); +} + + +void K3bAudioDoc::setSongwriter( const QString& v ) +{ + QString s( v ); + d->cdTextValidator->fixup( s ); + m_cdTextData.setSongwriter( s ); + emit changed(); +} + + +void K3bAudioDoc::setComposer( const QString& v ) +{ + QString s( v ); + d->cdTextValidator->fixup( s ); + m_cdTextData.setComposer( s ); + emit changed(); +} + + +void K3bAudioDoc::setUpc_ean( const QString& v ) +{ + QString s( v ); + d->cdTextValidator->fixup( s ); + m_cdTextData.setUpcEan( s ); + emit changed(); +} + + +void K3bAudioDoc::setCdTextMessage( const QString& v ) +{ + QString s( v ); + d->cdTextValidator->fixup( s ); + m_cdTextData.setMessage( s ); + emit changed(); +} + +#include "k3baudiodoc.moc" diff --git a/libk3b/projects/audiocd/k3baudiodoc.h b/libk3b/projects/audiocd/k3baudiodoc.h new file mode 100644 index 0000000..87a512e --- /dev/null +++ b/libk3b/projects/audiocd/k3baudiodoc.h @@ -0,0 +1,263 @@ +/* + * + * $Id: k3baudiodoc.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BAUDIODOC_H +#define K3BAUDIODOC_H + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include "k3b_export.h" +#include + +class K3bApp; +class K3bAudioTrack; +class QWidget; +class QTimer; +class QDomDocument; +class QDomElement; +class K3bThreadJob; +class KConfig; +class K3bAudioDataSource; +class K3bAudioDecoder; +class K3bAudioFile; + +/**Document class for an audio project. + *@author Sebastian Trueg + */ + +class LIBK3B_EXPORT K3bAudioDoc : public K3bDoc +{ + Q_OBJECT + + friend class K3bMixedDoc; + friend class K3bAudioTrack; + friend class K3bAudioFile; + + public: + K3bAudioDoc( QObject* ); + ~K3bAudioDoc(); + + QString name() const; + + bool newDocument(); + + bool hideFirstTrack() const { return m_hideFirstTrack; } + int numOfTracks() const; + + bool normalize() const { return m_normalize; } + + K3bAudioTrack* firstTrack() const; + K3bAudioTrack* lastTrack() const; + + /** + * Slow. + * \return the K3bAudioTrack with track number trackNum starting at 1 or 0 if trackNum > numOfTracks() + */ + K3bAudioTrack* getTrack( unsigned int trackNum ); + + /** + * Creates a new audiofile inside this doc which has no track yet. + */ + K3bAudioFile* createAudioFile( const KURL& url ); + + /** get the current size of the project */ + KIO::filesize_t size() const; + K3b::Msf length() const; + + // CD-Text + bool cdText() const { return m_cdText; } + const QString& title() const { return m_cdTextData.title(); } + const QString& artist() const { return m_cdTextData.performer(); } + const QString& disc_id() const { return m_cdTextData.discId(); } + const QString& arranger() const { return m_cdTextData.arranger(); } + const QString& songwriter() const { return m_cdTextData.songwriter(); } + const QString& composer() const { return m_cdTextData.composer(); } + const QString& upc_ean() const { return m_cdTextData.upcEan(); } + const QString& cdTextMessage() const { return m_cdTextData.message(); } + + /** + * Create complete CD-Text including the tracks' data. + */ + K3bDevice::CdText cdTextData() const; + + int audioRippingParanoiaMode() const { return m_audioRippingParanoiaMode; } + int audioRippingRetries() const { return m_audioRippingRetries; } + bool audioRippingIgnoreReadErrors() const { return m_audioRippingIgnoreReadErrors; } + + /** + * Represent the structure of the doc as CD Table of Contents. + */ + K3bDevice::Toc toToc() const; + + K3bBurnJob* newBurnJob( K3bJobHandler*, QObject* parent = 0 ); + + /** + * Shows dialogs. + */ + void informAboutNotFoundFiles(); + + /** + * returns the new after track, ie. the the last added track or null if + * the import failed. + * + * This is a blocking method. + * + * \param cuefile The Cuefile to be imported + * \param after The track after which the new tracks should be inserted + * \param decoder The decoder to be used for the new tracks. If 0 a new one will be created. + * + * BE AWARE THAT THE DECODER HAS TO FIT THE AUDIO FILE IN THE CUE. + */ + K3bAudioTrack* importCueFile( const QString& cuefile, K3bAudioTrack* after, K3bAudioDecoder* decoder = 0 ); + + /** + * Create a decoder for a specific url. If another AudioFileSource with this + * url is already part of this project the associated decoder is returned. + * + * In the first case the decoder will not be initialized yet (K3bAudioDecoder::analyseFile + * is not called yet). + * + * \param url The url for which a decoder is requested. + * \param reused If not null this variable is set to true if the decoder is already in + * use and K3bAudioDecoder::analyseFile() does not have to be called anymore. + */ + K3bAudioDecoder* getDecoderForUrl( const KURL& url, bool* reused = 0 ); + + static bool readPlaylistFile( const KURL& url, KURL::List& playlist ); + + public slots: + void addUrls( const KURL::List& ); + void addTrack( const KURL&, uint ); + void addTracks( const KURL::List&, uint ); + /** + * Adds a track without any testing + * + * Slow because it uses getTrack. + */ + void addTrack( K3bAudioTrack* track, uint position = 0 ); + + void addSources( K3bAudioTrack* parent, const KURL::List& urls, K3bAudioDataSource* sourceAfter = 0 ); + + void removeTrack( K3bAudioTrack* ); + void moveTrack( K3bAudioTrack* track, K3bAudioTrack* after ); + + void setHideFirstTrack( bool b ) { m_hideFirstTrack = b; } + void setNormalize( bool b ) { m_normalize = b; } + + // CD-Text + void writeCdText( bool b ) { m_cdText = b; } + void setTitle( const QString& v ); + void setArtist( const QString& v ); + void setPerformer( const QString& v ); + void setDisc_id( const QString& v ); + void setArranger( const QString& v ); + void setSongwriter( const QString& v ); + void setComposer( const QString& v ); + void setUpc_ean( const QString& v ); + void setCdTextMessage( const QString& v ); + + // Audio-CD Ripping + void setAudioRippingParanoiaMode( int i ) { m_audioRippingParanoiaMode = i; } + void setAudioRippingRetries( int r ) { m_audioRippingRetries = r; } + void setAudioRippingIgnoreReadErrors( bool b ) { m_audioRippingIgnoreReadErrors = b; } + + void removeCorruptTracks(); + + private slots: + void slotTrackChanged( K3bAudioTrack* ); + void slotTrackRemoved( K3bAudioTrack* ); + + signals: + void trackChanged( K3bAudioTrack* ); + void trackRemoved( K3bAudioTrack* ); + + protected: + /** reimplemented from K3bDoc */ + bool loadDocumentData( QDomElement* ); + /** reimplemented from K3bDoc */ + bool saveDocumentData( QDomElement* ); + + QString typeString() const; + + private: + // the stuff for adding files + // --------------------------------------------------------- + K3bAudioTrack* createTrack( const KURL& url ); + + /** + * Handle directories and M3u files + */ + KURL::List extractUrlList( const KURL::List& urls ); + // --------------------------------------------------------- + + /** + * Used by K3bAudioTrack to update the track list + */ + void setFirstTrack( K3bAudioTrack* track ); + /** + * Used by K3bAudioTrack to update the track list + */ + void setLastTrack( K3bAudioTrack* track ); + + /** + * Used by K3bAudioFile to tell the doc that it does not need the decoder anymore. + */ + void decreaseDecoderUsage( K3bAudioDecoder* ); + void increaseDecoderUsage( K3bAudioDecoder* ); + + K3bAudioTrack* m_firstTrack; + K3bAudioTrack* m_lastTrack; + + bool m_hideFirstTrack; + bool m_normalize; + + KURL::List m_notFoundFiles; + KURL::List m_unknownFileFormatFiles; + + // CD-Text + // -------------------------------------------------- + K3bDevice::CdText m_cdTextData; + bool m_cdText; + // -------------------------------------------------- + + // Audio ripping + int m_audioRippingParanoiaMode; + int m_audioRippingRetries; + bool m_audioRippingIgnoreReadErrors; + + // + // decoder housekeeping + // -------------------------------------------------- + // used to check if we may delete a decoder + QMap m_decoderUsageCounterMap; + // used to check if we already have a decoder for a specific file + QMap m_decoderPresenceMap; + + class Private; + Private* d; +}; + + +#endif diff --git a/libk3b/projects/audiocd/k3baudiofile.cpp b/libk3b/projects/audiocd/k3baudiofile.cpp new file mode 100644 index 0000000..2011e73 --- /dev/null +++ b/libk3b/projects/audiocd/k3baudiofile.cpp @@ -0,0 +1,112 @@ +/* + * + * $Id: k3baudiofile.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3baudiofile.h" +#include "k3baudiodoc.h" +#include "k3baudiotrack.h" + +#include + + +K3bAudioFile::K3bAudioFile( K3bAudioDecoder* dec, K3bAudioDoc* doc ) + : K3bAudioDataSource(), + m_doc(doc), + m_decoder(dec), + m_decodedData(0) +{ + // FIXME: somehow make it possible to switch docs + doc->increaseDecoderUsage( m_decoder ); +} + + +K3bAudioFile::K3bAudioFile( const K3bAudioFile& file ) + : K3bAudioDataSource( file ), + m_doc( file.m_doc ), + m_decoder( file.m_decoder ), + m_decodedData(0) +{ + m_doc->increaseDecoderUsage( m_decoder ); +} + + +K3bAudioFile::~K3bAudioFile() +{ + m_doc->decreaseDecoderUsage( m_decoder ); +} + + +QString K3bAudioFile::type() const +{ + return m_decoder->fileType(); +} + + +QString K3bAudioFile::sourceComment() const +{ + return m_decoder->filename().section( "/", -1 ); +} + + +const QString& K3bAudioFile::filename() const +{ + return m_decoder->filename(); +} + + +bool K3bAudioFile::isValid() const +{ + return m_decoder->isValid(); +} + + +K3b::Msf K3bAudioFile::originalLength() const +{ + return m_decoder->length(); +} + + +bool K3bAudioFile::seek( const K3b::Msf& msf ) +{ + // this is valid once the decoder has been initialized. + if( startOffset() + msf <= lastSector() && + m_decoder->seek( startOffset() + msf ) ) { + m_decodedData = msf.audioBytes(); + return true; + } + else + return false; +} + + +int K3bAudioFile::read( char* data, unsigned int max ) +{ + // here we can trust on the decoder to always provide enough data + // see if we decode too much + if( max + m_decodedData > length().audioBytes() ) + max = length().audioBytes() - m_decodedData; + + int read = m_decoder->decode( data, max ); + + if( read > 0 ) + m_decodedData += read; + + return read; +} + + +K3bAudioDataSource* K3bAudioFile::copy() const +{ + return new K3bAudioFile( *this ); +} diff --git a/libk3b/projects/audiocd/k3baudiofile.h b/libk3b/projects/audiocd/k3baudiofile.h new file mode 100644 index 0000000..83f75eb --- /dev/null +++ b/libk3b/projects/audiocd/k3baudiofile.h @@ -0,0 +1,85 @@ +/* + * + * $Id: k3baudiofile.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_AUDIO_FILE_H_ +#define _K3B_AUDIO_FILE_H_ + +#include "k3baudiodatasource.h" + +#include +#include +#include "k3b_export.h" + +class K3bAudioDecoder; +class K3bAudioTrack; + + +/** + * The K3bAudioFile is the most important audio data source. It gets its data + * from an audio file and uses a K3bAudioDecoder to decode this data. + * + * Be aware that it is currently not possible to change the doc of an AudioFile. + * The reason for this is the decoder sharing which is in place to allow gapless + * splitting of audio files into several tracks. + * + * \see K3bAudioDoc::createDecoderForUrl + */ +class LIBK3B_EXPORT K3bAudioFile : public K3bAudioDataSource +{ + public: + /** + * The AudioFile registers itself with the doc. This is part of the + * decoder handling facility in K3bAudioDoc which reuses the same decoder + * for sources with the same url. + * + * Use K3bAudioDoc::getDecoderForUrl to create a decoder. + */ + K3bAudioFile( K3bAudioDecoder*, K3bAudioDoc* ); + K3bAudioFile( const K3bAudioFile& ); + + /** + * The AudioFile deregisters itself from the doc. If it was the last file + * to use the decoder the doc will take care of deleting it. + */ + ~K3bAudioFile(); + + const QString& filename() const; + + /** + * The complete length of the file used by this source. + */ + K3b::Msf originalLength() const; + + QString type() const; + QString sourceComment() const; + + bool isValid() const; + + K3bAudioDecoder* decoder() const { return m_decoder; } + + bool seek( const K3b::Msf& ); + + int read( char* data, unsigned int max ); + + K3bAudioDataSource* copy() const; + + private: + K3bAudioDoc* m_doc; + K3bAudioDecoder* m_decoder; + + unsigned long long m_decodedData; +}; + +#endif diff --git a/libk3b/projects/audiocd/k3baudioimager.cpp b/libk3b/projects/audiocd/k3baudioimager.cpp new file mode 100644 index 0000000..b8a7a11 --- /dev/null +++ b/libk3b/projects/audiocd/k3baudioimager.cpp @@ -0,0 +1,203 @@ +/* + * + * $Id: k3baudioimager.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3baudioimager.h" +#include "k3baudiodoc.h" +#include "k3baudiotrack.h" +#include "k3baudiodatasource.h" + +#include +#include + +#include +#include + +#include + +#include + + +class K3bAudioImager::WorkThread : public K3bThread +{ +public: + WorkThread( K3bAudioDoc* doc ); + + void run(); + + void cancel(); + + bool m_canceled; + int m_fd; + QStringList m_imageNames; + K3bAudioImager::ErrorType lastError; + +private: + K3bAudioDoc* m_doc; +}; + + +K3bAudioImager::WorkThread::WorkThread( K3bAudioDoc* doc ) + : K3bThread(), + m_canceled(false), + m_fd(-1), + m_doc(doc) +{ +} + + +void K3bAudioImager::WorkThread::run() +{ + m_canceled = false; + + emitStarted(); + + lastError = K3bAudioImager::ERROR_UNKNOWN; + + // + // + // + QStringList::iterator imageFileIt = m_imageNames.begin(); + K3bWaveFileWriter waveFileWriter; + + K3bAudioTrack* track = m_doc->firstTrack(); + int trackNumber = 1; + unsigned long long totalSize = m_doc->length().audioBytes(); + unsigned long long totalRead = 0; + char buffer[2352 * 10]; + + while( track ) { + + emitNextTrack( trackNumber, m_doc->numOfTracks() ); + + // + // Seek to the beginning of the track + // + if( !track->seek(0) ) { + emitInfoMessage( i18n("Unable to seek in track %1.").arg(trackNumber), K3bJob::ERROR ); + emitFinished(false); + return; + } + + // + // Initialize the reading + // + int read = 0; + unsigned long long trackRead = 0; + + // + // Create the image file + // + if( m_fd == -1 ) { + if( !waveFileWriter.open( *imageFileIt ) ) { + emitInfoMessage( i18n("Could not open %1 for writing").arg(*imageFileIt), K3bJob::ERROR ); + emitFinished(false); + return; + } + } + + // + // Read data from the track + // + while( (read = track->read( buffer, sizeof(buffer) )) > 0 ) { + if( m_fd == -1 ) { + waveFileWriter.write( buffer, read, K3bWaveFileWriter::BigEndian ); + } + else { + if( ::write( m_fd, reinterpret_cast(buffer), read ) != read ) { + kdDebug() << "(K3bAudioImager::WorkThread) writing to fd " << m_fd << " failed." << endl; + lastError = K3bAudioImager::ERROR_FD_WRITE; + emitFinished(false); + return; + } + } + + if( m_canceled ) { + emitCanceled(); + emitFinished(false); + return; + } + + // + // Emit progress + // + totalRead += read; + trackRead += read; + + emitSubPercent( 100*trackRead/track->length().audioBytes() ); + emitPercent( 100*totalRead/totalSize ); + emitProcessedSubSize( trackRead/1024/1024, track->length().audioBytes()/1024/1024 ); + emitProcessedSize( totalRead/1024/1024, totalSize/1024/1024 ); + } + + if( read < 0 ) { + emitInfoMessage( i18n("Error while decoding track %1.").arg(trackNumber), K3bJob::ERROR ); + kdDebug() << "(K3bAudioImager::WorkThread) read error on track " << trackNumber + << " at pos " << K3b::Msf(trackRead/2352) << endl; + lastError = K3bAudioImager::ERROR_DECODING_TRACK; + emitFinished(false); + return; + } + + track = track->next(); + trackNumber++; + imageFileIt++; + } + + emitFinished(true); +} + + +void K3bAudioImager::WorkThread::cancel() +{ + m_canceled = true; +} + + + + +K3bAudioImager::K3bAudioImager( K3bAudioDoc* doc, K3bJobHandler* jh, QObject* parent, const char* name ) + : K3bThreadJob( jh, parent, name ), + m_doc(doc) +{ + m_thread = new WorkThread(doc); + setThread( m_thread ); +} + + +K3bAudioImager::~K3bAudioImager() +{ + delete m_thread; +} + + +void K3bAudioImager::writeToFd( int fd ) +{ + m_thread->m_fd = fd; +} + + +void K3bAudioImager::setImageFilenames( const QStringList& p ) +{ + m_thread->m_imageNames = p; + m_thread->m_fd = -1; +} + + +K3bAudioImager::ErrorType K3bAudioImager::lastErrorType() const +{ + return m_thread->lastError; +} + +#include "k3baudioimager.moc" diff --git a/libk3b/projects/audiocd/k3baudioimager.h b/libk3b/projects/audiocd/k3baudioimager.h new file mode 100644 index 0000000..df4ae7a --- /dev/null +++ b/libk3b/projects/audiocd/k3baudioimager.h @@ -0,0 +1,59 @@ +/* + * + * $Id: k3baudioimager.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_AUDIO_IMAGER_H_ +#define _K3B_AUDIO_IMAGER_H_ + +#include + +class K3bAudioDoc; + +class K3bAudioImager : public K3bThreadJob +{ + Q_OBJECT + + public: + K3bAudioImager( K3bAudioDoc*, K3bJobHandler*, QObject* parent = 0, const char* name = 0 ); + ~K3bAudioImager(); + + /** + * the data gets written directly into fd instead of the imagefile. + * Be aware that this only makes sense before starting the job. + * To disable just set fd to -1 + */ + void writeToFd( int fd ); + + /** + * Image path. Should be an empty directory or a non-existing + * directory in which case it will be created. + */ + void setImageFilenames( const QStringList& p ); + + enum ErrorType { + ERROR_FD_WRITE, + ERROR_DECODING_TRACK, + ERROR_UNKNOWN + }; + + ErrorType lastErrorType() const; + + private: + K3bAudioDoc* m_doc; + + class WorkThread; + WorkThread* m_thread; +}; + +#endif diff --git a/libk3b/projects/audiocd/k3baudiojob.cpp b/libk3b/projects/audiocd/k3baudiojob.cpp new file mode 100644 index 0000000..c2e62c2 --- /dev/null +++ b/libk3b/projects/audiocd/k3baudiojob.cpp @@ -0,0 +1,864 @@ +/* + * + * $Id: k3baudiojob.cpp 690212 2007-07-20 11:02:13Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3baudiojob.h" + +#include "k3baudioimager.h" +#include +#include "k3baudiotrack.h" +#include "k3baudiodatasource.h" +#include "k3baudionormalizejob.h" +#include "k3baudiojobtempdata.h" +#include "k3baudiomaxspeedjob.h" +#include "k3baudiocdtracksource.h" +#include "k3baudiofile.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + + + +static QString createNonExistingFilesString( const QValueList& items, unsigned int max ) +{ + QString s; + unsigned int cnt = 0; + for( QValueList::const_iterator it = items.begin(); + it != items.end(); ++it ) { + + s += KStringHandler::csqueeze( (*it)->filename(), 60 ); + + ++cnt; + if( cnt >= max || it == items.end() ) + break; + + s += "
"; + } + + if( items.count() > max ) + s += "..."; + + return s; +} + + + +class K3bAudioJob::Private +{ + public: + Private() + : copies(1), + copiesDone(0) { + } + + int copies; + int copiesDone; + int usedSpeed; + + bool useCdText; + bool maxSpeed; + + bool zeroPregap; + bool less4Sec; +}; + + +K3bAudioJob::K3bAudioJob( K3bAudioDoc* doc, K3bJobHandler* hdl, QObject* parent ) + : K3bBurnJob( hdl, parent ), + m_doc( doc ), + m_normalizeJob(0), + m_maxSpeedJob(0) +{ + d = new Private; + + m_audioImager = new K3bAudioImager( m_doc, this, this ); + connect( m_audioImager, SIGNAL(infoMessage(const QString&, int)), + this, SIGNAL(infoMessage(const QString&, int)) ); + connect( m_audioImager, SIGNAL(percent(int)), + this, SLOT(slotAudioDecoderPercent(int)) ); + connect( m_audioImager, SIGNAL(subPercent(int)), + this, SLOT(slotAudioDecoderSubPercent(int)) ); + connect( m_audioImager, SIGNAL(finished(bool)), + this, SLOT(slotAudioDecoderFinished(bool)) ); + connect( m_audioImager, SIGNAL(nextTrack(int, int)), + this, SLOT(slotAudioDecoderNextTrack(int, int)) ); + + m_writer = 0; + m_tempData = new K3bAudioJobTempData( m_doc, this ); +} + + +K3bAudioJob::~K3bAudioJob() +{ + delete d; +} + + +K3bDevice::Device* K3bAudioJob::writer() const +{ + if( m_doc->onlyCreateImages() ) + return 0; // no writer needed -> no blocking on K3bBurnJob + else + return m_doc->burner(); +} + + +K3bDoc* K3bAudioJob::doc() const +{ + return m_doc; +} + + +void K3bAudioJob::start() +{ + jobStarted(); + + m_written = true; + m_canceled = false; + m_errorOccuredAndAlreadyReported = false; + d->copies = m_doc->copies(); + d->copiesDone = 0; + d->useCdText = m_doc->cdText(); + d->usedSpeed = m_doc->speed(); + d->maxSpeed = false; + + if( m_doc->dummy() ) + d->copies = 1; + + emit newTask( i18n("Preparing data") ); + + // + // Check if all files exist + // + QValueList nonExistingFiles; + K3bAudioTrack* track = m_doc->firstTrack(); + while( track ) { + K3bAudioDataSource* source = track->firstSource(); + while( source ) { + if( K3bAudioFile* file = dynamic_cast( source ) ) { + if( !QFile::exists( file->filename() ) ) + nonExistingFiles.append( file ); + } + source = source->next(); + } + track = track->next(); + } + if( !nonExistingFiles.isEmpty() ) { + if( questionYesNo( "

" + i18n("The following files could not be found. Do you want to remove them from the " + "project and continue without adding them to the image?") + + "

" + createNonExistingFilesString( nonExistingFiles, 10 ), + i18n("Warning"), + i18n("Remove missing files and continue"), + i18n("Cancel and go back") ) ) { + for( QValueList::const_iterator it = nonExistingFiles.begin(); + it != nonExistingFiles.end(); ++it ) { + delete *it; + } + } + else { + m_canceled = true; + emit canceled(); + jobFinished(false); + return; + } + } + + // + // Make sure the project is not empty + // + if( m_doc->numOfTracks() == 0 ) { + emit infoMessage( i18n("Please add files to your project first."), ERROR ); + jobFinished(false); + return; + } + + if( m_doc->onTheFly() && !checkAudioSources() ) { + emit infoMessage( i18n("Unable to write on-the-fly with these audio sources."), WARNING ); + m_doc->setOnTheFly(false); + } + + + // we don't need this when only creating image and it is possible + // that the burn device is null + if( !m_doc->onlyCreateImages() ) { + + // + // there are a lot of writers out there which produce coasters + // in dao mode if the CD contains pregaps of length 0 (or maybe already != 2 secs?) + // + // Also most writers do not accept cuesheets with tracks smaller than 4 seconds (a violation + // of the red book standard) in DAO mode. + // + d->zeroPregap = false; + d->less4Sec = false; + track = m_doc->firstTrack(); + while( track ) { + if( track->postGap() == 0 && track->next() != 0 ) // the last track's postgap is always 0 + d->zeroPregap = true; + + if( track->length() < K3b::Msf( 0, 4, 0 ) ) + d->less4Sec = true; + + track = track->next(); + } + + // determine writing mode + if( m_doc->writingMode() == K3b::WRITING_MODE_AUTO ) { + // + // DAO is always the first choice + // RAW second and TAO last + // there are none-DAO writers that are supported by cdrdao + // + // older cdrecord versions do not support the -shorttrack option in RAW writing mode + // + if( !writer()->dao() && writingApp() == K3b::CDRECORD ) { + if(!writer()->supportsRawWriting() && + ( !d->less4Sec || k3bcore->externalBinManager()->binObject("cdrecord")->hasFeature( "short-track-raw" ) ) ) + m_usedWritingMode = K3b::RAW; + else + m_usedWritingMode = K3b::TAO; + } + else { + if( (d->zeroPregap||d->less4Sec) && writer()->supportsRawWriting() ) { + m_usedWritingMode = K3b::RAW; + if( d->less4Sec ) + emit infoMessage( i18n("Tracklengths below 4 seconds violate the Red Book standard."), WARNING ); + } + else + m_usedWritingMode = K3b::DAO; + } + } + else + m_usedWritingMode = m_doc->writingMode(); + + bool cdrecordOnTheFly = false; + bool cdrecordCdText = false; + if( k3bcore->externalBinManager()->binObject("cdrecord") ) { + cdrecordOnTheFly = k3bcore->externalBinManager()->binObject("cdrecord")->hasFeature( "audio-stdin" ); + cdrecordCdText = k3bcore->externalBinManager()->binObject("cdrecord")->hasFeature( "cdtext" ); + } + + // determine writing app + if( writingApp() == K3b::DEFAULT ) { + if( m_usedWritingMode == K3b::DAO ) { + // there are none-DAO writers that are supported by cdrdao + if( !writer()->dao() || + ( !cdrecordOnTheFly && m_doc->onTheFly() ) || + ( d->useCdText && !cdrecordCdText ) || + m_doc->hideFirstTrack() ) + m_usedWritingApp = K3b::CDRDAO; + else + m_usedWritingApp = K3b::CDRECORD; + } + else + m_usedWritingApp = K3b::CDRECORD; + } + else + m_usedWritingApp = writingApp(); + + // on-the-fly writing with cdrecord >= 2.01a13 + if( m_usedWritingApp == K3b::CDRECORD && + m_doc->onTheFly() && + !cdrecordOnTheFly ) { + emit infoMessage( i18n("On-the-fly writing with cdrecord < 2.01a13 not supported."), ERROR ); + m_doc->setOnTheFly(false); + } + + if( m_usedWritingApp == K3b::CDRECORD && + d->useCdText ) { + if( !cdrecordCdText ) { + emit infoMessage( i18n("Cdrecord %1 does not support CD-Text writing.") + .arg(k3bcore->externalBinManager()->binObject("cdrecord")->version), ERROR ); + d->useCdText = false; + } + else if( m_usedWritingMode == K3b::TAO ) { + emit infoMessage( i18n("It is not possible to write CD-Text in TAO mode."), WARNING ); + d->useCdText = false; + } + } + } + + + if( !m_doc->onlyCreateImages() && m_doc->onTheFly() ) { + if( m_doc->speed() == 0 ) { + // try to determine the max possible speed + emit newSubTask( i18n("Determining maximum writing speed") ); + if( !m_maxSpeedJob ) { + m_maxSpeedJob = new K3bAudioMaxSpeedJob( m_doc, this, this ); + connect( m_maxSpeedJob, SIGNAL(percent(int)), + this, SIGNAL(subPercent(int)) ); + connect( m_maxSpeedJob, SIGNAL(finished(bool)), + this, SLOT(slotMaxSpeedJobFinished(bool)) ); + } + m_maxSpeedJob->start(); + return; + } + else { + if( !prepareWriter() ) { + cleanupAfterError(); + jobFinished(false); + return; + } + + if( startWriting() ) { + + // now the writer is running and we can get it's stdin + // we only use this method when writing on-the-fly since + // we cannot easily change the audioDecode fd while it's working + // which we would need to do since we write into several + // image files. + m_audioImager->writeToFd( m_writer->fd() ); + } + else { + // startWriting() already did the cleanup + return; + } + } + } + else { + emit burning(false); + emit infoMessage( i18n("Creating image files in %1").arg(m_doc->tempDir()), INFO ); + emit newTask( i18n("Creating image files") ); + m_tempData->prepareTempFileNames( doc()->tempDir() ); + QStringList filenames; + for( int i = 1; i <= m_doc->numOfTracks(); ++i ) + filenames += m_tempData->bufferFileName( i ); + m_audioImager->setImageFilenames( filenames ); + } + + m_audioImager->start(); +} + + +void K3bAudioJob::slotMaxSpeedJobFinished( bool success ) +{ + d->maxSpeed = success; + if( !success ) + emit infoMessage( i18n("Unable to determine maximum speed for some reason. Ignoring."), WARNING ); + + // now start the writing + // same code as above. See the commecnts there + if( !prepareWriter() ) { + cleanupAfterError(); + jobFinished(false); + return; + } + + if( startWriting() ) + m_audioImager->writeToFd( m_writer->fd() ); + + m_audioImager->start(); +} + + +void K3bAudioJob::cancel() +{ + m_canceled = true; + + if( m_maxSpeedJob ) + m_maxSpeedJob->cancel(); + + if( m_writer ) + m_writer->cancel(); + + m_audioImager->cancel(); + emit infoMessage( i18n("Writing canceled."), K3bJob::ERROR ); + removeBufferFiles(); + emit canceled(); + jobFinished(false); +} + + +void K3bAudioJob::slotWriterFinished( bool success ) +{ + if( m_canceled || m_errorOccuredAndAlreadyReported ) + return; + + if( !success ) { + cleanupAfterError(); + jobFinished(false); + return; + } + else { + d->copiesDone++; + + if( d->copiesDone == d->copies ) { + if( m_doc->onTheFly() || m_doc->removeImages() ) + removeBufferFiles(); + + jobFinished(true); + } + else { + K3bDevice::eject( m_doc->burner() ); + + if( startWriting() ) { + if( m_doc->onTheFly() ) { + // now the writer is running and we can get it's stdin + // we only use this method when writing on-the-fly since + // we cannot easily change the audioDecode fd while it's working + // which we would need to do since we write into several + // image files. + m_audioImager->writeToFd( m_writer->fd() ); + m_audioImager->start(); + } + } + } + } +} + + +void K3bAudioJob::slotAudioDecoderFinished( bool success ) +{ + if( m_canceled || m_errorOccuredAndAlreadyReported ) + return; + + if( !success ) { + if( m_audioImager->lastErrorType() == K3bAudioImager::ERROR_FD_WRITE ) { + // this means that the writer job failed so let's use the error handling there. + return; + } + + emit infoMessage( i18n("Error while decoding audio tracks."), ERROR ); + cleanupAfterError(); + jobFinished(false); + return; + } + + if( m_doc->onlyCreateImages() || !m_doc->onTheFly() ) { + + emit infoMessage( i18n("Successfully decoded all tracks."), SUCCESS ); + + if( m_doc->normalize() ) { + normalizeFiles(); + } + else if( !m_doc->onlyCreateImages() ) { + if( !prepareWriter() ) { + cleanupAfterError(); + jobFinished(false); + } + else + startWriting(); + } + else { + jobFinished(true); + } + } +} + + +void K3bAudioJob::slotAudioDecoderNextTrack( int t, int tt ) +{ + if( m_doc->onlyCreateImages() || !m_doc->onTheFly() ) { + K3bAudioTrack* track = m_doc->getTrack(t); + emit newSubTask( i18n("Decoding audio track %1 of %2%3") + .arg(t) + .arg(tt) + .arg( track->title().isEmpty() || track->artist().isEmpty() + ? QString::null + : " (" + track->artist() + " - " + track->title() + ")" ) ); + } +} + + +bool K3bAudioJob::prepareWriter() +{ + delete m_writer; + + if( m_usedWritingApp == K3b::CDRECORD ) { + + if( !writeInfFiles() ) { + kdDebug() << "(K3bAudioJob) could not write inf-files." << endl; + emit infoMessage( i18n("IO Error. Most likely no space left on harddisk."), ERROR ); + + return false; + } + + K3bCdrecordWriter* writer = new K3bCdrecordWriter( m_doc->burner(), this, this ); + + writer->setWritingMode( m_usedWritingMode ); + writer->setSimulate( m_doc->dummy() ); + writer->setBurnSpeed( d->usedSpeed ); + + writer->addArgument( "-useinfo" ); + + if( d->useCdText ) { + writer->setRawCdText( m_doc->cdTextData().rawPackData() ); + } + + // add all the audio tracks + writer->addArgument( "-audio" ); + + // we only need to pad in one case. cdrecord < 2.01.01a03 cannot handle shorttrack + raw + if( d->less4Sec ) { + if( m_usedWritingMode == K3b::RAW && + !k3bcore->externalBinManager()->binObject( "cdrecord" )->hasFeature( "short-track-raw" ) ) { + writer->addArgument( "-pad" ); + } + else { + // Allow tracks shorter than 4 seconds + writer->addArgument( "-shorttrack" ); + } + } + + K3bAudioTrack* track = m_doc->firstTrack(); + while( track ) { + if( m_doc->onTheFly() ) { + // this is only supported by cdrecord versions >= 2.01a13 + writer->addArgument( QFile::encodeName( m_tempData->infFileName( track ) ) ); + } + else { + writer->addArgument( QFile::encodeName( m_tempData->bufferFileName( track ) ) ); + } + track = track->next(); + } + + m_writer = writer; + } + else { + if( !writeTocFile() ) { + kdDebug() << "(K3bDataJob) could not write tocfile." << endl; + emit infoMessage( i18n("IO Error"), ERROR ); + + return false; + } + + // create the writer + // create cdrdao job + K3bCdrdaoWriter* writer = new K3bCdrdaoWriter( m_doc->burner(), this, this ); + writer->setCommand( K3bCdrdaoWriter::WRITE ); + writer->setSimulate( m_doc->dummy() ); + writer->setBurnSpeed( d->usedSpeed ); + writer->setTocFile( m_tempData->tocFileName() ); + + m_writer = writer; + } + + connect( m_writer, SIGNAL(infoMessage(const QString&, int)), this, SIGNAL(infoMessage(const QString&, int)) ); + connect( m_writer, SIGNAL(percent(int)), this, SLOT(slotWriterJobPercent(int)) ); + connect( m_writer, SIGNAL(processedSize(int, int)), this, SIGNAL(processedSize(int, int)) ); + connect( m_writer, SIGNAL(subPercent(int)), this, SIGNAL(subPercent(int)) ); + connect( m_writer, SIGNAL(processedSubSize(int, int)), this, SIGNAL(processedSubSize(int, int)) ); + connect( m_writer, SIGNAL(nextTrack(int, int)), this, SLOT(slotWriterNextTrack(int, int)) ); + connect( m_writer, SIGNAL(buffer(int)), this, SIGNAL(bufferStatus(int)) ); + connect( m_writer, SIGNAL(deviceBuffer(int)), this, SIGNAL(deviceBuffer(int)) ); + connect( m_writer, SIGNAL(writeSpeed(int, int)), this, SIGNAL(writeSpeed(int, int)) ); + connect( m_writer, SIGNAL(finished(bool)), this, SLOT(slotWriterFinished(bool)) ); + // connect( m_writer, SIGNAL(newTask(const QString&)), this, SIGNAL(newTask(const QString&)) ); + connect( m_writer, SIGNAL(newSubTask(const QString&)), this, SIGNAL(newSubTask(const QString&)) ); + connect( m_writer, SIGNAL(debuggingOutput(const QString&, const QString&)), + this, SIGNAL(debuggingOutput(const QString&, const QString&)) ); + + return true; +} + + +void K3bAudioJob::slotWriterNextTrack( int t, int tt ) +{ + K3bAudioTrack* track = m_doc->getTrack(t); + // t is in range 1..tt + if( m_doc->hideFirstTrack() ) + track = m_doc->getTrack(t+1); + emit newSubTask( i18n("Writing track %1 of %2%3") + .arg(t) + .arg(tt) + .arg( track->title().isEmpty() || track->artist().isEmpty() + ? QString::null + : " (" + track->artist() + " - " + track->title() + ")" ) ); +} + + +void K3bAudioJob::slotWriterJobPercent( int p ) +{ + double totalTasks = d->copies; + double tasksDone = d->copiesDone; + if( m_doc->normalize() ) { + totalTasks+=1.0; + tasksDone+=1.0; + } + if( !m_doc->onTheFly() ) { + totalTasks+=1.0; + tasksDone+=1.0; + } + + emit percent( (int)((100.0*tasksDone + (double)p) / totalTasks) ); +} + + +void K3bAudioJob::slotAudioDecoderPercent( int p ) +{ + if( m_doc->onlyCreateImages() ) { + if( m_doc->normalize() ) + emit percent( p/2 ); + else + emit percent( p ); + } + else if( !m_doc->onTheFly() ) { + double totalTasks = d->copies; + double tasksDone = d->copiesDone; // =0 when creating an image + if( m_doc->normalize() ) { + totalTasks+=1.0; + } + if( !m_doc->onTheFly() ) { + totalTasks+=1.0; + } + + emit percent( (int)((100.0*tasksDone + (double)p) / totalTasks) ); + } +} + + +void K3bAudioJob::slotAudioDecoderSubPercent( int p ) +{ + // when writing on the fly the writer produces the subPercent + if( m_doc->onlyCreateImages() || !m_doc->onTheFly() ) { + emit subPercent( p ); + } +} + + +bool K3bAudioJob::startWriting() +{ + if( m_doc->dummy() ) + emit newTask( i18n("Simulating") ); + else if( d->copies > 1 ) + emit newTask( i18n("Writing Copy %1").arg(d->copiesDone+1) ); + else + emit newTask( i18n("Writing") ); + + + emit newSubTask( i18n("Waiting for media") ); + if( waitForMedia( m_doc->burner() ) < 0 ) { + cancel(); + return false; + } + + // just to be sure we did not get canceled during the async discWaiting + if( m_canceled ) + return false; + + // in case we determined the max possible writing speed we have to reset the speed on the writer job + // here since an inserted media is necessary + // the Max speed job will compare the max speed value with the supported values of the writer + if( d->maxSpeed ) + m_writer->setBurnSpeed( m_maxSpeedJob->maxSpeed() ); + + emit burning(true); + m_writer->start(); + return true; +} + + +void K3bAudioJob::cleanupAfterError() +{ + m_errorOccuredAndAlreadyReported = true; + m_audioImager->cancel(); + + if( m_writer ) + m_writer->cancel(); + + // remove the temp files + removeBufferFiles(); +} + + +void K3bAudioJob::removeBufferFiles() +{ + if ( !m_doc->onTheFly() ) { + emit infoMessage( i18n("Removing temporary files."), INFO ); + } + + // removes buffer images and temp toc or inf files + m_tempData->cleanup(); +} + + +void K3bAudioJob::normalizeFiles() +{ + if( !m_normalizeJob ) { + m_normalizeJob = new K3bAudioNormalizeJob( this, this ); + + connect( m_normalizeJob, SIGNAL(infoMessage(const QString&, int)), + this, SIGNAL(infoMessage(const QString&, int)) ); + connect( m_normalizeJob, SIGNAL(percent(int)), this, SLOT(slotNormalizeProgress(int)) ); + connect( m_normalizeJob, SIGNAL(subPercent(int)), this, SLOT(slotNormalizeSubProgress(int)) ); + connect( m_normalizeJob, SIGNAL(finished(bool)), this, SLOT(slotNormalizeJobFinished(bool)) ); + connect( m_normalizeJob, SIGNAL(newTask(const QString&)), this, SIGNAL(newSubTask(const QString&)) ); + connect( m_normalizeJob, SIGNAL(debuggingOutput(const QString&, const QString&)), + this, SIGNAL(debuggingOutput(const QString&, const QString&)) ); + } + + // add all the files + // TODO: we may need to split the wave files and put them back together! + QValueVector files; + K3bAudioTrack* track = m_doc->firstTrack(); + while( track ) { + files.append( m_tempData->bufferFileName(track) ); + track = track->next(); + } + + m_normalizeJob->setFilesToNormalize( files ); + + emit newTask( i18n("Normalizing volume levels") ); + m_normalizeJob->start(); +} + +void K3bAudioJob::slotNormalizeJobFinished( bool success ) +{ + if( m_canceled || m_errorOccuredAndAlreadyReported ) + return; + + if( success ) { + if( m_doc->onlyCreateImages() ) { + jobFinished(true); + } + else { + // start the writing + if( !prepareWriter() ) { + cleanupAfterError(); + jobFinished(false); + } + else + startWriting(); + } + } + else { + cleanupAfterError(); + jobFinished(false); + } +} + +void K3bAudioJob::slotNormalizeProgress( int p ) +{ + double totalTasks = d->copies+2.0; + double tasksDone = 1; // the decoding has been finished + + emit percent( (int)((100.0*tasksDone + (double)p) / totalTasks) ); +} + + +void K3bAudioJob::slotNormalizeSubProgress( int p ) +{ + emit subPercent( p ); +} + + +bool K3bAudioJob::writeTocFile() +{ + K3bTocFileWriter tocWriter; + tocWriter.setData( m_doc->toToc() ); + tocWriter.setHideFirstTrack( m_doc->hideFirstTrack() ); + if( d->useCdText ) + tocWriter.setCdText( m_doc->cdTextData() ); + if( !m_doc->onTheFly() ) { + QStringList filenames; + for( int i = 1; i <= m_doc->numOfTracks(); ++i ) + filenames += m_tempData->bufferFileName( i ); + tocWriter.setFilenames( filenames ); + } + return tocWriter.save( m_tempData->tocFileName() ); +} + + +bool K3bAudioJob::writeInfFiles() +{ + K3bInfFileWriter infFileWriter; + K3bAudioTrack* track = m_doc->firstTrack(); + while( track ) { + + infFileWriter.setTrack( track->toCdTrack() ); + infFileWriter.setTrackNumber( track->trackNumber() ); + if( !m_doc->onTheFly() ) + infFileWriter.setBigEndian( false ); + + if( !infFileWriter.save( m_tempData->infFileName(track) ) ) + return false; + + track = track->next(); + } + return true; +} + + +// checks if the doc contains sources from an audio cd which cannot be read on-the-fly +bool K3bAudioJob::checkAudioSources() +{ + K3bAudioTrack* track = m_doc->firstTrack(); + K3bAudioDataSource* source = track->firstSource(); + + while( source ) { + + if( K3bAudioCdTrackSource* cdSource = dynamic_cast(source) ) { + // + // If which cases we cannot wite on-the-fly: + // 1. the writing device contains one of the audio cds + // 2. Well, one of the cds is missing + // + K3bDevice::Device* dev = cdSource->searchForAudioCD(); + if( !dev || dev == writer() ) + return false; + else + cdSource->setDevice( dev ); + } + + // next source + source = source->next(); + if( !source ) { + track = track->next(); + if( track ) + source = track->firstSource(); + } + } + + return true; +} + + +QString K3bAudioJob::jobDescription() const +{ + return i18n("Writing Audio CD") + + ( m_doc->title().isEmpty() + ? QString::null + : QString( " (%1)" ).arg(m_doc->title()) ); +} + + +QString K3bAudioJob::jobDetails() const +{ + return ( i18n( "1 track (%1 minutes)", + "%n tracks (%1 minutes)", + m_doc->numOfTracks() ).arg(m_doc->length().toString()) + + ( m_doc->copies() > 1 && !m_doc->dummy() + ? i18n(" - %n copy", " - %n copies", m_doc->copies()) + : QString::null ) ); +} + +#include "k3baudiojob.moc" diff --git a/libk3b/projects/audiocd/k3baudiojob.h b/libk3b/projects/audiocd/k3baudiojob.h new file mode 100644 index 0000000..af37639 --- /dev/null +++ b/libk3b/projects/audiocd/k3baudiojob.h @@ -0,0 +1,107 @@ +/* + * + * $Id: k3baudiojob.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BAUDIOJOB_H +#define K3BAUDIOJOB_H + +#include + + +class K3bAudioDoc; +class K3bAudioImager; +class QFile; +class QDataStream; +class K3bAbstractWriter; +class KTempFile; +class K3bCdrecordWriter; +class K3bAudioNormalizeJob; +class K3bAudioJobTempData; +class K3bDevice::Device; +class K3bAudioMaxSpeedJob; + +/** + *@author Sebastian Trueg + */ +class K3bAudioJob : public K3bBurnJob +{ + Q_OBJECT + + public: + K3bAudioJob( K3bAudioDoc*, K3bJobHandler*, QObject* parent = 0 ); + ~K3bAudioJob(); + + K3bDoc* doc() const; + K3bDevice::Device* writer() const; + + QString jobDescription() const; + QString jobDetails() const; + + public slots: + void cancel(); + void start(); + + protected slots: + // writer slots + void slotWriterFinished( bool success ); + void slotWriterNextTrack(int, int); + void slotWriterJobPercent(int); + + // audiodecoder slots + void slotAudioDecoderFinished( bool ); + void slotAudioDecoderNextTrack( int, int ); + void slotAudioDecoderPercent(int); + void slotAudioDecoderSubPercent( int ); + + // normalizing slots + void slotNormalizeJobFinished( bool ); + void slotNormalizeProgress( int ); + void slotNormalizeSubProgress( int ); + + // max speed + void slotMaxSpeedJobFinished( bool ); + + private: + bool prepareWriter(); + bool startWriting(); + void cleanupAfterError(); + void removeBufferFiles(); + void normalizeFiles(); + bool writeTocFile(); + bool writeInfFiles(); + bool checkAudioSources(); + + K3bAudioDoc* m_doc; + K3bAudioImager* m_audioImager; + K3bAbstractWriter* m_writer; + K3bAudioNormalizeJob* m_normalizeJob; + K3bAudioJobTempData* m_tempData; + K3bAudioMaxSpeedJob* m_maxSpeedJob; + + KTempFile* m_tocFile; + + bool m_canceled; + bool m_errorOccuredAndAlreadyReported; + + bool m_written; + + int m_usedWritingApp; + int m_usedWritingMode; + + class Private; + Private* d; +}; + +#endif diff --git a/libk3b/projects/audiocd/k3baudiojobtempdata.cpp b/libk3b/projects/audiocd/k3baudiojobtempdata.cpp new file mode 100644 index 0000000..af98c2e --- /dev/null +++ b/libk3b/projects/audiocd/k3baudiojobtempdata.cpp @@ -0,0 +1,132 @@ +/* + * + * $Id: k3baudiojobtempdata.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3baudiojobtempdata.h" +#include "k3baudiodoc.h" +#include "k3baudiotrack.h" +#include +#include +#include +#include + +#include +#include +#include + +#include + + +class K3bAudioJobTempData::Private +{ +public: + Private( K3bAudioDoc* _doc ) + : doc(_doc) { + } + + QValueVector bufferFiles; + QValueVector infFiles; + QString tocFile; + + K3bAudioDoc* doc; +}; + + +K3bAudioJobTempData::K3bAudioJobTempData( K3bAudioDoc* doc, QObject* parent, const char* name ) + : QObject( parent, name ) +{ + d = new Private( doc ); +} + + +K3bAudioJobTempData::~K3bAudioJobTempData() +{ + delete d; +} + + +const QString& K3bAudioJobTempData::bufferFileName( int track ) +{ + if( (int)d->bufferFiles.count() < track ) + prepareTempFileNames(); + return d->bufferFiles.at(track-1); +} + +const QString& K3bAudioJobTempData::bufferFileName( K3bAudioTrack* track ) +{ + return bufferFileName( track->trackNumber() ); +} + + +const QString& K3bAudioJobTempData::tocFileName() +{ + if( d->tocFile.isEmpty() ) + prepareTempFileNames(); + return d->tocFile; +} + + +const QString& K3bAudioJobTempData::infFileName( int track ) +{ + if( (int)d->infFiles.count() < track ) + prepareTempFileNames(); + return d->infFiles.at( track - 1 ); +} + +const QString& K3bAudioJobTempData::infFileName( K3bAudioTrack* track ) +{ + return infFileName( track->trackNumber() ); +} + + +K3bAudioDoc* K3bAudioJobTempData::doc() const +{ + return d->doc; +} + + +void K3bAudioJobTempData::prepareTempFileNames( const QString& path ) +{ + d->bufferFiles.clear(); + d->infFiles.clear(); + + QString prefix = K3b::findUniqueFilePrefix( "k3b_audio_", path ) + "_"; + + for( int i = 0; i < d->doc->numOfTracks(); i++ ) { + d->bufferFiles.append( prefix + QString::number( i+1 ).rightJustify( 2, '0' ) + ".wav" ); + d->infFiles.append( prefix + QString::number( i+1 ).rightJustify( 2, '0' ) + ".inf" ); + } + + d->tocFile = prefix + ".toc"; +} + + +void K3bAudioJobTempData::cleanup() +{ + for( uint i = 0; i < d->infFiles.count(); ++i ) { + if( QFile::exists( d->infFiles[i] ) ) + QFile::remove( d->infFiles[i] ); + } + + for( uint i = 0; i < d->bufferFiles.count(); ++i ) { + if( QFile::exists( d->bufferFiles[i] ) ) + QFile::remove( d->bufferFiles[i] ); + } + + if( QFile::exists( d->tocFile ) ) + QFile::remove( d->tocFile ); +} + + +#include "k3baudiojobtempdata.moc" diff --git a/libk3b/projects/audiocd/k3baudiojobtempdata.h b/libk3b/projects/audiocd/k3baudiojobtempdata.h new file mode 100644 index 0000000..72b753f --- /dev/null +++ b/libk3b/projects/audiocd/k3baudiojobtempdata.h @@ -0,0 +1,64 @@ +/* + * + * $Id: k3baudiojobtempdata.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_AUDIO_JOB_TEMPDATA_H_ +#define _K3B_AUDIO_JOB_TEMPDATA_H_ + +#include +#include + +class K3bAudioTrack; +class K3bAudioDoc; +class QTextStream; + + +class K3bAudioJobTempData : public QObject +{ + Q_OBJECT + + public: + K3bAudioJobTempData( K3bAudioDoc* doc, QObject* parent = 0, const char* name = 0 ); + ~K3bAudioJobTempData(); + + const QString& bufferFileName( int track ); + const QString& bufferFileName( K3bAudioTrack* track ); + + const QString& infFileName( int track ); + const QString& infFileName( K3bAudioTrack* track ); + + const QString& tocFileName(); + + K3bAudioDoc* doc() const; + + /** + * use this if you want + * a specific directory + * it defaults to the default K3b temp dir + */ + void prepareTempFileNames( const QString& path = QString::null ); + + /** + * remove all temp files (this does not include the audio buffer files + * since these are not created and thus not handled by the K3bAudioJobTempData) + */ + void cleanup(); + + private: + class Private; + Private* d; +}; + +#endif diff --git a/libk3b/projects/audiocd/k3baudiomaxspeedjob.cpp b/libk3b/projects/audiocd/k3baudiomaxspeedjob.cpp new file mode 100644 index 0000000..975ab89 --- /dev/null +++ b/libk3b/projects/audiocd/k3baudiomaxspeedjob.cpp @@ -0,0 +1,224 @@ +/* + * + * $Id: k3baudiomaxspeedjob.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2005 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3baudiomaxspeedjob.h" +#include "k3baudiotrack.h" +#include "k3baudiodatasource.h" +#include "k3baudiodoc.h" +#include "k3baudiocdtracksource.h" +#include "k3baudiodatasourceiterator.h" + +#include + +#include + +#include +#include + +#include + + +class K3bAudioMaxSpeedJob::WorkThread : public K3bThread +{ +public: + WorkThread( K3bAudioDoc* doc ); + ~WorkThread(); + + void run(); + + int speedTest( K3bAudioDataSource* source ); + void cancel(); + int maxSpeedByMedia() const; + + int maxSpeed; + +private: + K3bAudioDoc* m_doc; + bool m_canceled; + char* m_buffer; +}; + + +K3bAudioMaxSpeedJob::WorkThread::WorkThread( K3bAudioDoc* doc ) + : K3bThread(), + m_doc(doc), + m_canceled(false) +{ + m_buffer = new char[2352*10]; +} + + +K3bAudioMaxSpeedJob::WorkThread::~WorkThread() +{ + delete [] m_buffer; +} + + +void K3bAudioMaxSpeedJob::WorkThread::run() +{ + kdDebug() << k_funcinfo << endl; + m_canceled = false; + + emitStarted(); + + K3bAudioDataSourceIterator it( m_doc ); + + // count sources for minimal progress info + int numSources = 0; + int sourcesDone = 0; + while( it.current() ) { + ++numSources; + it.next(); + } + + bool success = true; + maxSpeed = 175*1000; + it.first(); + + while( it.current() && !m_canceled ) { + if( !it.current()->seek(0) ) { + kdDebug() << "(K3bAudioMaxSpeedJob) seek failed." << endl; + success = false; + break; + } + + // read some data + int speed = speedTest( it.current() ); + + ++sourcesDone; + emitPercent( 100*numSources/sourcesDone ); + + if( speed < 0 ) { + success = false; + break; + } + else if( speed > 0 ) { + // update the max speed + maxSpeed = QMIN( maxSpeed, speed ); + } + + it.next(); + } + + if( m_canceled ) { + emitCanceled(); + success = false; + } + + if( success ) + kdDebug() << "(K3bAudioMaxSpeedJob) max speed: " << maxSpeed << endl; + + emitFinished( success ); +} + +// returns the amount of data read from this source +int K3bAudioMaxSpeedJob::WorkThread::speedTest( K3bAudioDataSource* source ) +{ + // + // in case of an audio track source we only test when the cd is inserted since asking the user would + // confuse him a lot. + // + // FIXME: there is still the problem of the spin up time. + // + if( K3bAudioCdTrackSource* cdts = dynamic_cast( source ) ) { + if( K3bDevice::Device* dev = cdts->searchForAudioCD() ) { + cdts->setDevice( dev ); + } + else { + kdDebug() << "(K3bAudioMaxSpeedJob) ignoring audio cd track source." << endl; + return 0; + } + } + + QTime t; + int dataRead = 0; + int r = 0; + + // start the timer + t.start(); + + // read ten seconds of audio data. This is some value which seemed about right. :) + while( dataRead < 2352*75*10 && (r = source->read( m_buffer, 2352*10 )) > 0 ) { + dataRead += r; + } + + // elapsed millisec + int usedT = t.elapsed(); + + if( r < 0 ) { + kdDebug() << "(K3bAudioMaxSpeedJob) read failure." << endl; + return -1; + } + + // KB/sec (add 1 millisecond to avoid division by 0) + int throughput = (dataRead*1000+usedT)/(usedT+1)/1024; + kdDebug() << "(K3bAudioMaxSpeedJob) throughput: " << throughput + << " (" << dataRead << "/" << usedT << ")" << endl; + + + return throughput; +} + + +void K3bAudioMaxSpeedJob::WorkThread::cancel() +{ + kdDebug() << k_funcinfo << endl; + m_canceled = true; +} + + +int K3bAudioMaxSpeedJob::WorkThread::maxSpeedByMedia() const +{ + int s = 0; + + QValueList speeds = m_doc->burner()->determineSupportedWriteSpeeds(); + // simply use what we have and let the writer decide if the speeds are empty + if( !speeds.isEmpty() ) { + // start with the highest speed and go down the list until we are below our max + QValueListIterator it = speeds.end(); + --it; + while( *it > maxSpeed && it != speeds.begin() ) + --it; + + // this is the first valid speed or the lowest supported one + s = *it; + kdDebug() << "(K3bAudioMaxSpeedJob) using speed factor: " << (s/175) << endl; + } + + return s; +} + + + + +K3bAudioMaxSpeedJob::K3bAudioMaxSpeedJob( K3bAudioDoc* doc, K3bJobHandler* jh, QObject* parent, const char* name ) + : K3bThreadJob( jh, parent, name ) +{ + m_thread = new WorkThread( doc ); + setThread( m_thread ); +} + + +K3bAudioMaxSpeedJob::~K3bAudioMaxSpeedJob() +{ + delete m_thread; +} + + +int K3bAudioMaxSpeedJob::maxSpeed() const +{ + return m_thread->maxSpeedByMedia(); +} +#include "k3baudiomaxspeedjob.moc" diff --git a/libk3b/projects/audiocd/k3baudiomaxspeedjob.h b/libk3b/projects/audiocd/k3baudiomaxspeedjob.h new file mode 100644 index 0000000..876bc7f --- /dev/null +++ b/libk3b/projects/audiocd/k3baudiomaxspeedjob.h @@ -0,0 +1,43 @@ +/* + * + * $Id: k3baudiomaxspeedjob.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2005 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_AUDIO_MAX_SPEED_JOB_H_ +#define _K3B_AUDIO_MAX_SPEED_JOB_H_ + +#include + +class K3bAudioDoc; + + +class K3bAudioMaxSpeedJob : public K3bThreadJob +{ + Q_OBJECT + + public: + K3bAudioMaxSpeedJob( K3bAudioDoc* doc, K3bJobHandler*, QObject* parent = 0, const char* name = 0 ); + ~K3bAudioMaxSpeedJob(); + + /** + * KB/sec + * Only valid if the job finished successfully. + */ + int maxSpeed() const; + + private: + class WorkThread; + WorkThread* m_thread; +}; + +#endif diff --git a/libk3b/projects/audiocd/k3baudionormalizejob.cpp b/libk3b/projects/audiocd/k3baudionormalizejob.cpp new file mode 100644 index 0000000..782712b --- /dev/null +++ b/libk3b/projects/audiocd/k3baudionormalizejob.cpp @@ -0,0 +1,205 @@ +/* + * + * $Id: k3baudionormalizejob.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3baudionormalizejob.h" +#include +#include +#include + +#include +#include + + +K3bAudioNormalizeJob::K3bAudioNormalizeJob( K3bJobHandler* hdl, QObject* parent, const char* name ) + : K3bJob( hdl, parent, name ), + m_process(0) +{ +} + + +K3bAudioNormalizeJob::~K3bAudioNormalizeJob() +{ + if( m_process ) + delete m_process; +} + + +void K3bAudioNormalizeJob::start() +{ + m_canceled = false; + m_currentAction = COMPUTING_LEVELS; + m_currentTrack = 1; + + jobStarted(); + + if( m_process ) + delete m_process; + + m_process = new K3bProcess(); + connect( m_process, SIGNAL(stderrLine(const QString&)), this, SLOT(slotStdLine(const QString&)) ); + connect( m_process, SIGNAL(processExited(KProcess*)), this, SLOT(slotProcessExited(KProcess*)) ); + + const K3bExternalBin* bin = k3bcore->externalBinManager()->binObject( "normalize-audio" ); + + if( !bin ) { + emit infoMessage( i18n("Could not find normalize-audio executable."), ERROR ); + jobFinished(false); + return; + } + + if( !bin->copyright.isEmpty() ) + emit infoMessage( i18n("Using %1 %2 - Copyright (C) %3").arg(bin->name()).arg(bin->version).arg(bin->copyright), INFO ); + + // create the commandline + *m_process << bin; + + // additional user parameters from config + const QStringList& params = bin->userParameters(); + for( QStringList::const_iterator it = params.begin(); it != params.end(); ++it ) + *m_process << *it; + + // end the options + *m_process << "--"; + + // add the files + for( uint i = 0; i < m_files.count(); ++i ) + *m_process << m_files[i]; + + // now start the process + if( !m_process->start( KProcess::NotifyOnExit, KProcess::AllOutput ) ) { + // something went wrong when starting the program + // it "should" be the executable + kdDebug() << "(K3bAudioNormalizeJob) could not start normalize-audio" << endl; + emit infoMessage( i18n("Could not start normalize-audio."), K3bJob::ERROR ); + jobFinished(false); + } +} + + +void K3bAudioNormalizeJob::cancel() +{ + m_canceled = true; + + if( m_process ) + if( m_process->isRunning() ) { + m_process->kill(); + } +} + + +void K3bAudioNormalizeJob::slotStdLine( const QString& line ) +{ + // percent, subPercent, newTask (compute level and adjust) + + // emit newSubTask( i18n("Normalizing track %1 of %2 (%3)").arg(t).arg(tt).arg(m_files.at(t-1)) ); + + emit debuggingOutput( "normalize-audio", line ); + + // wenn "% done" drin: + // wenn ein --% drin ist, so beginnt ein neuer track + // sonst prozent parsen "batch xxx" ist der fortschritt der action + // also ev. den batch fortschritt * 1/2 + + if( line.startsWith( "Applying adjustment" ) ) { + if( m_currentAction == COMPUTING_LEVELS ) { + // starting the adjustment with track 1 + m_currentTrack = 1; + m_currentAction = ADJUSTING_LEVELS; + } + } + + else if( line.contains( "already normalized" ) ) { + // no normalization necessary for the current track + emit infoMessage( i18n("Track %1 is already normalized.").arg(m_currentTrack), INFO ); + m_currentTrack++; + } + + else if( line.contains( "--% done") ) { + if( m_currentAction == ADJUSTING_LEVELS ) { + emit newTask( i18n("Adjusting volume level for track %1 of %2").arg(m_currentTrack).arg(m_files.count()) ); + kdDebug() << "(K3bAudioNormalizeJob) adjusting level for track " + << m_currentTrack + << " " + << m_files.at(m_currentTrack-1) + << endl; + } + else { + emit newTask( i18n("Computing level for track %1 of %2").arg(m_currentTrack).arg(m_files.count()) ); + kdDebug() << "(K3bAudioNormalizeJob) computing level for track " + << m_currentTrack + << " " + << m_files.at(m_currentTrack-1) + << endl; + } + + m_currentTrack++; + } + + else if( int pos = line.find( "% done" ) > 0 ) { + // parse progress: "XXX% done" and "batch XXX% done" + pos -= 3; + bool ok; + // TODO: do not use fixed values + // track progress starts at position 19 in version 0.7.6 + int p = line.mid( 19, 3 ).toInt(&ok); + if( ok ) + emit subPercent( p ); + else + kdDebug() << "(K3bAudioNormalizeJob) subPercent parsing error at pos " + << 19 << " in line '" << line.mid( 19, 3 ) << "'" << endl; + + // batch progress starts at position 50 in version 0.7.6 + p = line.mid( 50, 3 ).toInt(&ok); + if( ok && m_currentAction == COMPUTING_LEVELS ) + emit percent( (int)((double)p/2.0) ); + else if( ok && m_currentAction == ADJUSTING_LEVELS ) + emit percent( 50 + (int)((double)p/2.0) ); + else + kdDebug() << "(K3bAudioNormalizeJob) percent parsing error at pos " + << 50 << " in line '" << line.mid( 50, 3 ) << "'" << endl; + + } +} + + +void K3bAudioNormalizeJob::slotProcessExited( KProcess* p ) +{ + if( p->normalExit() ) { + switch( p->exitStatus() ) { + case 0: + emit infoMessage( i18n("Successfully normalized all tracks."), SUCCESS ); + jobFinished(true); + break; + default: + if( !m_canceled ) { + emit infoMessage( i18n("%1 returned an unknown error (code %2).").arg("normalize-audio").arg(p->exitStatus()), + K3bJob::ERROR ); + emit infoMessage( i18n("Please send me an email with the last output."), K3bJob::ERROR ); + emit infoMessage( i18n("Error while normalizing tracks."), ERROR ); + } + else + emit canceled(); + jobFinished(false); + break; + } + } + else { + emit infoMessage( i18n("%1 did not exit cleanly.").arg("Normalize"), K3bJob::ERROR ); + jobFinished( false ); + } +} + +#include "k3baudionormalizejob.moc" diff --git a/libk3b/projects/audiocd/k3baudionormalizejob.h b/libk3b/projects/audiocd/k3baudionormalizejob.h new file mode 100644 index 0000000..e56086b --- /dev/null +++ b/libk3b/projects/audiocd/k3baudionormalizejob.h @@ -0,0 +1,63 @@ +/* + * + * $Id: k3baudionormalizejob.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_AUDIO_NORMALIZE_JOB_H_ +#define _K3B_AUDIO_NORMALIZE_JOB_H_ + + +#include + +#include + +class K3bProcess; +class KProcess; + + +class K3bAudioNormalizeJob : public K3bJob +{ + Q_OBJECT + + public: + K3bAudioNormalizeJob( K3bJobHandler*, QObject* parent = 0, const char* name = 0 ); + ~K3bAudioNormalizeJob(); + + public slots: + void start(); + void cancel(); + + void setFilesToNormalize( const QValueVector& files ) { m_files = files; } + + private slots: + void slotStdLine( const QString& line ); + void slotProcessExited( KProcess* p ); + + private: + K3bProcess* m_process; + + QValueVector m_files; + bool m_canceled; + + enum Action { + COMPUTING_LEVELS, + ADJUSTING_LEVELS + }; + + int m_currentAction; + int m_currentTrack; +}; + + +#endif diff --git a/libk3b/projects/audiocd/k3baudiotrack.cpp b/libk3b/projects/audiocd/k3baudiotrack.cpp new file mode 100644 index 0000000..a1d12e4 --- /dev/null +++ b/libk3b/projects/audiocd/k3baudiotrack.cpp @@ -0,0 +1,628 @@ +/* + * + * $Id: k3baudiotrack.cpp 620139 2007-01-05 11:59:05Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3baudiotrack.h" +#include "k3baudiodoc.h" +#include "k3baudiodatasource.h" + +#include +#include +#include + +#include + +#include + + + +class K3bAudioTrack::Private +{ +public: + Private() { + cdTextValidator = new K3bCdTextValidator(); + } + + ~Private() { + delete cdTextValidator; + } + + K3bCdTextValidator* cdTextValidator; +}; + + +K3bAudioTrack::K3bAudioTrack() + : m_parent(0), + m_copy(false), + m_preEmp(false), + m_index0Offset(150), + m_prev(0), + m_next(0), + m_firstSource(0), + m_currentSource(0), + m_alreadyReadBytes(0), + m_currentlyDeleting(false) +{ + d = new Private; +} + + +K3bAudioTrack::K3bAudioTrack( K3bAudioDoc* parent ) + : m_parent(parent), + m_copy(false), + m_preEmp(false), + m_index0Offset(150), + m_prev(0), + m_next(0), + m_firstSource(0), + m_currentSource(0), + m_alreadyReadBytes(0), + m_currentlyDeleting(false) +{ + d = new Private; +} + + +K3bAudioTrack::~K3bAudioTrack() +{ + kdDebug() << "(K3bAudioTrack::~K3bAudioTrack) " << this << endl; + // + // It is crucial that we do not emit the changed signal here because otherwise + // the doc will delete us again once we are empty! + // + m_currentlyDeleting = true; + + // fix the list + take(); + + kdDebug() << "(K3bAudioTrack::~K3bAudioTrack) deleting sources." << endl; + + // delete all sources + while( m_firstSource ) + delete m_firstSource->take(); + + kdDebug() << "(K3bAudioTrack::~K3bAudioTrack) finished" << endl; + + delete d; +} + + +void K3bAudioTrack::emitChanged() +{ + if( m_parent ) + m_parent->slotTrackChanged( this ); +} + + +void K3bAudioTrack::setArtist( const QString& a ) +{ + setPerformer( a ); +} + + +void K3bAudioTrack::setPerformer( const QString& a ) +{ + QString s( a ); + d->cdTextValidator->fixup( s ); + m_cdText.setPerformer(s); + emitChanged(); +} + + +void K3bAudioTrack::setTitle( const QString& t ) +{ + QString s( t ); + d->cdTextValidator->fixup( s ); + m_cdText.setTitle(s); + emitChanged(); +} + + +void K3bAudioTrack::setArranger( const QString& t ) +{ + QString s( t ); + d->cdTextValidator->fixup( s ); + m_cdText.setArranger(s); + emitChanged(); +} + + +void K3bAudioTrack::setSongwriter( const QString& t ) +{ + QString s( t ); + d->cdTextValidator->fixup( s ); + m_cdText.setSongwriter(s); + emitChanged(); +} + + +void K3bAudioTrack::setComposer( const QString& t ) +{ + QString s( t ); + d->cdTextValidator->fixup( s ); + m_cdText.setComposer(s); + emitChanged(); +} + + +void K3bAudioTrack::setIsrc( const QString& t ) +{ + m_cdText.setIsrc(t); + emitChanged(); +} + + +void K3bAudioTrack::setCdTextMessage( const QString& t ) +{ + QString s( t ); + d->cdTextValidator->fixup( s ); + m_cdText.setMessage(s); + emitChanged(); +} + + +void K3bAudioTrack::setCdText( const K3bDevice::TrackCdText& cdtext ) +{ + m_cdText = cdtext; + emitChanged(); +} + + +K3bAudioDataSource* K3bAudioTrack::lastSource() const +{ + K3bAudioDataSource* s = m_firstSource; + while( s && s->next() ) + s = s->next(); + return s; +} + + +bool K3bAudioTrack::inList() const +{ + if( doc() ) + return ( doc()->firstTrack() == this || m_prev != 0 ); + else + return false; +} + + +K3b::Msf K3bAudioTrack::length() const +{ + K3b::Msf length; + K3bAudioDataSource* source = m_firstSource; + while( source ) { + length += source->length(); + source = source->next(); + } + return length; +} + + +KIO::filesize_t K3bAudioTrack::size() const +{ + return length().audioBytes(); +} + + +unsigned int K3bAudioTrack::trackNumber() const +{ + if( m_prev ) + return m_prev->trackNumber() + 1; + else + return 1; +} + + +K3b::Msf K3bAudioTrack::index0() const +{ + // we save the index0Offset as length of the resulting pregap + // this way the length of the track does not need to be ready + // when creating the track. + return length() - m_index0Offset; +} + + +K3b::Msf K3bAudioTrack::postGap() const +{ + if( next() ) + return m_index0Offset; + else + return 0; +} + + +void K3bAudioTrack::setIndex0( const K3b::Msf& msf ) +{ + if( msf == 0 ) + m_index0Offset = 0; + else + m_index0Offset = length() - msf; +} + + +K3bAudioTrack* K3bAudioTrack::take() +{ + if( inList() ) { + if( !m_prev ) + doc()->setFirstTrack( m_next ); + if( !m_next ) + doc()->setLastTrack( m_prev ); + + if( m_prev ) + m_prev->m_next = m_next; + if( m_next ) + m_next->m_prev = m_prev; + + m_prev = m_next = 0; + + // remove from doc + if( m_parent ) + m_parent->slotTrackRemoved(this); + m_parent = 0; + } + + return this; +} + + +void K3bAudioTrack::moveAfter( K3bAudioTrack* track ) +{ + kdDebug() << "(K3bAudioTrack::moveAfter( " << track << " )" << endl; + if( !track ) { + if( !doc() ) { + kdDebug() << "(K3bAudioTrack::moveAfter) no parent set" << endl; + return; + } + + // make sure we do not mess up the list + if( doc()->lastTrack() ) + moveAfter( doc()->lastTrack() ); + else { + doc()->setFirstTrack( take() ); + doc()->setLastTrack( this ); + } + } + else if( track == this ) { + kdDebug() << "(K3bAudioTrack::moveAfter) trying to move this after this." << endl; + return; + } + else { + // remove this from the list + take(); + + // set the new parent doc + m_parent = track->doc(); + + K3bAudioTrack* oldNext = track->m_next; + + // set track as prev + track->m_next = this; + m_prev = track; + + // set oldNext as next + if( oldNext ) + oldNext->m_prev = this; + m_next = oldNext; + + if( !m_prev ) + doc()->setFirstTrack( this ); + if( !m_next ) + doc()->setLastTrack( this ); + } + + emitChanged(); +} + + +void K3bAudioTrack::moveAhead( K3bAudioTrack* track ) +{ + if( !track ) { + if( !doc() ) { + kdDebug() << "(K3bAudioTrack::moveAfter) no parent set" << endl; + return; + } + + // make sure we do not mess up the list + if( doc()->firstTrack() ) + moveAhead( doc()->firstTrack() ); + else { + doc()->setFirstTrack( take() ); + doc()->setLastTrack( this ); + } + } + else if( track == this ) { + kdDebug() << "(K3bAudioTrack::moveAhead) trying to move this ahead of this." << endl; + return; + } + else { + // remove this from the list + take(); + + // set the new parent doc + m_parent = track->doc(); + + K3bAudioTrack* oldPrev = track->m_prev; + + // set track as next + m_next = track; + track->m_prev = this; + + // set oldPrev as prev + m_prev = oldPrev; + if( oldPrev ) + oldPrev->m_next = this; + + if( !m_prev ) + doc()->setFirstTrack( this ); + if( !m_next ) + doc()->setLastTrack( this ); + } + + emitChanged(); +} + + +void K3bAudioTrack::merge( K3bAudioTrack* trackToMerge, K3bAudioDataSource* sourceAfter ) +{ + kdDebug() << "(K3bAudioTrack::merge) " << trackToMerge << " into " << this << endl; + if( this == trackToMerge ) { + kdDebug() << "(K3bAudioTrack::merge) trying to merge this with this." << endl; + return; + } + + // remove the track to merge to make sure it does not get deleted by the doc too early + trackToMerge->take(); + + // in case we prepend all of trackToMerge's sources + if( !sourceAfter ) { + kdDebug() << "(K3bAudioTrack::merge) merging " << trackToMerge->firstSource() << endl; + if( m_firstSource ) { + trackToMerge->firstSource()->moveAhead( m_firstSource ); + } + else { + addSource( trackToMerge->firstSource()->take() ); + } + sourceAfter = m_firstSource; + } + + kdDebug() << "(K3bAudioTrack::merge) now merge the other sources." << endl; + // now merge all sources into this track + while( trackToMerge->firstSource() ) { + K3bAudioDataSource* s = trackToMerge->firstSource(); + kdDebug() << "(K3bAudioTrack::merge) merging source " << s << " from track " << s->track() << " into track " + << this << " after source " << sourceAfter << endl; + s->moveAfter( sourceAfter ); + sourceAfter = s; + } + + // TODO: should we also merge the indices? + + // now we can safely delete the track we merged + delete trackToMerge; + + kdDebug() << "(K3bAudioTrack::merge) finished" << endl; + + emitChanged(); +} + + +void K3bAudioTrack::setFirstSource( K3bAudioDataSource* source ) +{ + // reset the reading stuff since this might be a completely new source list + m_currentSource = 0; + m_alreadyReadBytes = 0; + + m_firstSource = source; + while( source ) { + source->m_track = this; + source = source->next(); + } + + emitChanged(); +} + + +void K3bAudioTrack::addSource( K3bAudioDataSource* source ) +{ + if( !source ) + return; + + K3bAudioDataSource* s = m_firstSource; + while( s && s->next() ) + s = s->next(); + if( s ) + source->moveAfter( s ); + else + setFirstSource( source->take() ); +} + + +void K3bAudioTrack::sourceChanged( K3bAudioDataSource* ) +{ + if( m_currentlyDeleting ) + return; + + // TODO: update indices + + if( m_index0Offset > length() ) + m_index0Offset = length()-1; + + emitChanged(); +} + + +int K3bAudioTrack::numberSources() const +{ + K3bAudioDataSource* source = m_firstSource; + int i = 0; + while( source ) { + source = source->next(); + ++i; + } + return i; +} + + +bool K3bAudioTrack::seek( const K3b::Msf& msf ) +{ + K3bAudioDataSource* source = m_firstSource; + + K3b::Msf pos; + while( source && pos + source->length() < msf ) { + pos += source->length(); + source = source->next(); + } + + if( source ) { + m_currentSource = source; + m_alreadyReadBytes = msf.audioBytes(); + return source->seek( msf - pos ); + } + else + return false; +} + + +int K3bAudioTrack::read( char* data, unsigned int max ) +{ + if( !m_currentSource ) { + m_currentSource = m_firstSource; + if( m_currentSource ) + m_currentSource->seek(0); + m_alreadyReadBytes = 0; + } + + int readData = m_currentSource->read( data, max ); + if( readData == 0 ) { + m_currentSource = m_currentSource->next(); + if( m_currentSource ) { + m_currentSource->seek(0); + return read( data, max ); // read from next source + } + } + + m_alreadyReadBytes += readData; + + return readData; +} + + +K3bAudioTrack* K3bAudioTrack::copy() const +{ + K3bAudioTrack* track = new K3bAudioTrack(); + + track->m_copy = m_copy; + track->m_preEmp = m_preEmp; + track->m_index0Offset = m_index0Offset; + track->m_cdText = m_cdText; + K3bAudioDataSource* source = m_firstSource; + while( source ) { + track->addSource( source->copy() ); + source = source->next(); + } + + return track; +} + + +K3bAudioTrack* K3bAudioTrack::split( const K3b::Msf& pos ) +{ + if( pos < length() ) { + // search the source + // pos will be the first sector of the new track + K3b::Msf currentPos; + K3bAudioDataSource* source = firstSource(); + while( source && currentPos + source->length() <= pos ) { + currentPos += source->length(); + source = source->next(); + } + + K3bAudioDataSource* splitSource = 0; + if( currentPos > 0 && currentPos == pos ) { + // no need to split a source + splitSource = source; + } + else { + splitSource = source->split( pos - currentPos ); + } + + // the new track should include all sources from splitSource and below + K3bAudioTrack* splitTrack = new K3bAudioTrack(); + splitTrack->m_cdText = m_cdText; + source = splitSource; + while( source ) { + K3bAudioDataSource* addSource = source; + source = source->next(); + splitTrack->addSource( addSource ); + } + + kdDebug() << "(K3bAudioTrack) moving track " << splitTrack << " after this (" << this << ") with parent " << doc() << endl; + splitTrack->moveAfter( this ); + + return splitTrack; + } + else + return 0; +} + + +K3bDevice::Track K3bAudioTrack::toCdTrack() const +{ + if( !inList() ) + return K3bDevice::Track(); + + K3b::Msf firstSector; + K3bAudioTrack* track = doc()->firstTrack(); + while( track != this ) { + firstSector += track->length(); + track = track->next(); + } + + K3bDevice::Track cdTrack( firstSector, + firstSector + length() - 1, + K3bDevice::Track::AUDIO ); + + // FIXME: auch im audiotrack copy permitted + cdTrack.setCopyPermitted( !copyProtection() ); + cdTrack.setPreEmphasis( preEmp() ); + + // FIXME: add indices != 0 + + // no index 0 for the last track. Or should we allow this??? + if( doc()->lastTrack() != this ) + cdTrack.setIndex0( index0() ); + + // FIXME: convert to QCString + // cdTrack.setIsrc( isrc() ); + + return cdTrack; +} + + +void K3bAudioTrack::debug() +{ + kdDebug() << "Track " << this << endl + << " Prev: " << m_prev << endl + << " Next: " << m_next << endl + << " Sources:" << endl; + K3bAudioDataSource* s = m_firstSource; + while( s ) { + kdDebug() << " " << s << " - Prev: " << s->prev() << " Next: " << s->next() << endl; + s = s->next(); + } +} + + + diff --git a/libk3b/projects/audiocd/k3baudiotrack.h b/libk3b/projects/audiocd/k3baudiotrack.h new file mode 100644 index 0000000..ab0ee1b --- /dev/null +++ b/libk3b/projects/audiocd/k3baudiotrack.h @@ -0,0 +1,214 @@ +/* + * + * $Id: k3baudiotrack.h 620139 2007-01-05 11:59:05Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BAUDIOTRACK_H +#define K3BAUDIOTRACK_H + +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include "k3b_export.h" + +class K3bAudioDecoder; +class K3bAudioDataSource; +class K3bAudioDoc; + + +/** + * @author Sebastian Trueg + */ +class LIBK3B_EXPORT K3bAudioTrack +{ + friend class K3bAudioDataSource; + friend class K3bAudioDoc; + + public: + K3bAudioTrack(); + K3bAudioTrack( K3bAudioDoc* parent ); + ~K3bAudioTrack(); + + K3bAudioDoc* doc() const { return m_parent; } + + K3bDevice::Track toCdTrack() const; + + /** + * @return length of track in frames + */ + K3b::Msf length() const; + KIO::filesize_t size() const; + + const QString& artist() const { return m_cdText.performer(); } + const QString& performer() const { return m_cdText.performer(); } + const QString& title() const { return m_cdText.title(); } + const QString& arranger() const { return m_cdText.arranger(); } + const QString& songwriter() const { return m_cdText.songwriter(); } + const QString& composer() const { return m_cdText.composer(); } + const QString& isrc() const { return m_cdText.isrc(); } + const QString& cdTextMessage() const { return m_cdText.message(); } + const K3bDevice::TrackCdText& cdText() const { return m_cdText; } + + bool copyProtection() const { return m_copy; } + bool preEmp() const { return m_preEmp; } + + /** + * @obsolete use setPerformer + **/ + void setArtist( const QString& a ); + void setPerformer( const QString& a ); + void setTitle( const QString& t ); + void setArranger( const QString& t ); + void setSongwriter( const QString& t ); + void setComposer( const QString& t ); + void setIsrc( const QString& t ); + void setCdTextMessage( const QString& t ); + + void setCdText( const K3bDevice::TrackCdText& cdtext ); + + void setPreEmp( bool b ) { m_preEmp = b; emitChanged(); } + void setCopyProtection( bool b ) { m_copy = b; emitChanged(); } + + K3b::Msf index0() const; + /** + * The length of the postgap, ie. the number of blocks with index0. + * This is always 0 for the last track. + */ + K3b::Msf postGap() const; + void setIndex0( const K3b::Msf& ); + + /** + * \return The track number starting at 1. + */ + unsigned int trackNumber() const; + + /** + * Remove this track from the list and return it. + */ + K3bAudioTrack* take(); + + /** + * Move this track after @p track. + * If @p track is null this track will be merged into the beginning + * of the docs list. + */ + void moveAfter( K3bAudioTrack* track ); + + /** + * Move this track ahead of @p track. + * If @p track is null this track will be appended to the end + * of the docs list. + */ + void moveAhead( K3bAudioTrack* track ); + + /** + * Merge @p trackToMerge into this one. + */ + void merge( K3bAudioTrack* trackToMerge, K3bAudioDataSource* sourceAfter = 0 ); + + K3bAudioTrack* prev() const { return m_prev; } + K3bAudioTrack* next() const { return m_next; } + + /** + * Use with care. + */ + void setFirstSource( K3bAudioDataSource* source ); + K3bAudioDataSource* firstSource() const { return m_firstSource; } + K3bAudioDataSource* lastSource() const; + int numberSources() const; + + /** + * Append source to the end of the sources list. + */ + void addSource( K3bAudioDataSource* source ); + + bool seek( const K3b::Msf& ); + + /** + * Read data from the track. + * + * @return number of read bytes + */ + int read( char* data, unsigned int max ); + + /** + * called by K3bAudioDataSource because of the lack of signals + */ + void sourceChanged( K3bAudioDataSource* ); + + /** + * Create a copy of this track containing copies of all the sources + * but not being part of some list. + */ + K3bAudioTrack* copy() const; + + /** + * Split the track at position pos and return the splitted track + * on success. + * The new track will be moved after this track. + * + * \param pos The position at which to split. \a pos will be the + * first frame in the new track. + */ + K3bAudioTrack* split( const K3b::Msf& pos ); + + /** + * Is this track in a list + */ + bool inList() const; + + private: + /** + * Tells the doc that the track has changed + */ + void emitChanged(); + + void debug(); + + K3bAudioDoc* m_parent; + + /** copy protection */ + bool m_copy; + bool m_preEmp; + + K3b::Msf m_index0Offset; + + K3bDevice::TrackCdText m_cdText; + + // list + K3bAudioTrack* m_prev; + K3bAudioTrack* m_next; + + K3bAudioDataSource* m_firstSource; + + + K3bAudioDataSource* m_currentSource; + long long m_alreadyReadBytes; + + bool m_currentlyDeleting; + + class Private; + Private* d; +}; + + +#endif diff --git a/libk3b/projects/audiocd/k3baudiozerodata.cpp b/libk3b/projects/audiocd/k3baudiozerodata.cpp new file mode 100644 index 0000000..f5c985d --- /dev/null +++ b/libk3b/projects/audiocd/k3baudiozerodata.cpp @@ -0,0 +1,115 @@ +/* + * + * $Id: k3baudiozerodata.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3baudiozerodata.h" +#include "k3baudiotrack.h" + +#include + +#include + + +K3bAudioZeroData::K3bAudioZeroData( const K3b::Msf& len ) + : K3bAudioDataSource(), + m_length(len), + m_writtenData(0) +{ +} + + +K3bAudioZeroData::K3bAudioZeroData( const K3bAudioZeroData& zero ) + : K3bAudioDataSource( zero ), + m_length( zero.m_length ), + m_writtenData( 0 ) +{ +} + + +K3bAudioZeroData::~K3bAudioZeroData() +{ +} + + +void K3bAudioZeroData::setLength( const K3b::Msf& msf ) +{ + if( msf > 0 ) + m_length = msf; + else + m_length = 1; // 1 frame + + m_writtenData = 0; + + emitChange(); +} + + +QString K3bAudioZeroData::type() const +{ + return i18n("Silence"); +} + + +QString K3bAudioZeroData::sourceComment() const +{ + return QString::null; +} + + +bool K3bAudioZeroData::seek( const K3b::Msf& msf ) +{ + if( msf < length() ) { + m_writtenData = msf.audioBytes(); + return true; + } + else + return false; +} + + +int K3bAudioZeroData::read( char* data, unsigned int max ) +{ + if( m_writtenData + max > length().audioBytes() ) + max = length().audioBytes() - m_writtenData; + + m_writtenData += max; + + ::memset( data, 0, max ); + + return max; +} + + +K3bAudioDataSource* K3bAudioZeroData::copy() const +{ + return new K3bAudioZeroData( *this ); +} + + +void K3bAudioZeroData::setStartOffset( const K3b::Msf& pos ) +{ + if( pos >= length() ) + setLength( 1 ); + else + setLength( length() - pos ); +} + + +void K3bAudioZeroData::setEndOffset( const K3b::Msf& pos ) +{ + if( pos < 1 ) + setLength( 1 ); + else + setLength( pos ); +} diff --git a/libk3b/projects/audiocd/k3baudiozerodata.h b/libk3b/projects/audiocd/k3baudiozerodata.h new file mode 100644 index 0000000..8cb2911 --- /dev/null +++ b/libk3b/projects/audiocd/k3baudiozerodata.h @@ -0,0 +1,55 @@ +/* + * + * $Id: k3baudiozerodata.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_AUDIO_ZERO_DATA_H_ +#define _K3B_AUDIO_ZERO_DATA_H_ + +#include "k3baudiodatasource.h" +#include "k3b_export.h" + +class LIBK3B_EXPORT K3bAudioZeroData : public K3bAudioDataSource +{ + public: + K3bAudioZeroData( const K3b::Msf& msf = 150 ); + K3bAudioZeroData( const K3bAudioZeroData& ); + ~K3bAudioZeroData(); + + K3b::Msf originalLength() const { return m_length; } + void setLength( const K3b::Msf& msf ); + + QString type() const; + QString sourceComment() const; + + bool seek( const K3b::Msf& ); + int read( char* data, unsigned int max ); + + K3bAudioDataSource* copy() const; + + /** + * Only changes the length + */ + void setStartOffset( const K3b::Msf& ); + + /** + * Only changes the length + */ + void setEndOffset( const K3b::Msf& ); + + private: + K3b::Msf m_length; + unsigned long long m_writtenData; +}; + +#endif diff --git a/libk3b/projects/datacd/Makefile.am b/libk3b/projects/datacd/Makefile.am new file mode 100644 index 0000000..dea5cb2 --- /dev/null +++ b/libk3b/projects/datacd/Makefile.am @@ -0,0 +1,35 @@ +AM_CPPFLAGS= -I$(srcdir)/.. \ + -I$(srcdir)/../../core \ + -I$(srcdir)/../../plugin \ + -I$(srcdir)/../../../libk3bdevice \ + -I$(srcdir)/../../../src \ + -I$(srcdir)/../../tools \ + -I$(srcdir)/../../jobs \ + -I$(srcdir)/../.. \ + $(all_includes) + +METASOURCES = AUTO + +noinst_LTLIBRARIES = libdata.la + +libdata_la_SOURCES = k3bdatajob.cpp \ + k3bdatadoc.cpp \ + k3bdataitem.cpp \ + k3bdiritem.cpp \ + k3bfileitem.cpp \ + k3bisoimager.cpp \ + k3bmsinfofetcher.cpp \ + k3bbootitem.cpp \ + k3bisooptions.cpp \ + k3bfilecompilationsizehandler.cpp \ + k3bsessionimportitem.cpp \ + k3bmkisofshandler.cpp \ + k3bdatapreparationjob.cpp + +include_HEADERS = k3bdatadoc.h \ + k3bdatajob.h \ + k3bdataitem.h \ + k3bdiritem.h \ + k3bfileitem.h \ + k3bbootitem.h \ + k3bisooptions.h diff --git a/libk3b/projects/datacd/k3bbootitem.cpp b/libk3b/projects/datacd/k3bbootitem.cpp new file mode 100644 index 0000000..e94830e --- /dev/null +++ b/libk3b/projects/datacd/k3bbootitem.cpp @@ -0,0 +1,58 @@ +/* + * + * $Id: k3bbootitem.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bbootitem.h" +#include "k3bdatadoc.h" +#include "k3bdiritem.h" + +#include + +#include + + +K3bBootItem::K3bBootItem( const QString& fileName, K3bDataDoc* doc, K3bDirItem* dir, const QString& k3bName ) + : K3bFileItem( fileName, doc, dir, k3bName, FILE|BOOT_IMAGE ), + m_noBoot(false), + m_bootInfoTable(false), + m_loadSegment(0), + m_loadSize(0), + m_imageType(FLOPPY) +{ + setExtraInfo( i18n("El Torito Boot image") ); +} + + +K3bBootItem::K3bBootItem( const K3bBootItem& item ) + : K3bFileItem( item ), + m_noBoot( item.m_noBoot ), + m_bootInfoTable( item.m_bootInfoTable ), + m_loadSegment( item.m_loadSegment ), + m_loadSize( item.m_loadSize ), + m_imageType( item.m_imageType ), + m_tempPath( item.m_tempPath ) +{ +} + + +K3bBootItem::~K3bBootItem() +{ + take(); +} + + +K3bDataItem* K3bBootItem::copy() const +{ + return new K3bBootItem( *this ); +} diff --git a/libk3b/projects/datacd/k3bbootitem.h b/libk3b/projects/datacd/k3bbootitem.h new file mode 100644 index 0000000..9dd8704 --- /dev/null +++ b/libk3b/projects/datacd/k3bbootitem.h @@ -0,0 +1,66 @@ +/* + * + * $Id: k3bbootitem.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_BOOT_ITEM_H_ +#define _K3B_BOOT_ITEM_H_ + +#include "k3bfileitem.h" + +class K3bBootItem : public K3bFileItem +{ + public: + K3bBootItem( const QString& fileName, K3bDataDoc* doc, K3bDirItem* dir, const QString& k3bName = 0 ); + K3bBootItem( const K3bBootItem& ); + ~K3bBootItem(); + + K3bDataItem* copy() const; + + bool isHideable() const { return false; } + + bool isBootItem() const { return true; } + + enum imageType { FLOPPY, HARDDISK, NONE }; + + void setNoBoot( bool b ) { m_noBoot = b; } + void setBootInfoTable( bool b ) { m_bootInfoTable = b; } + void setLoadSegment( int s ) { m_loadSegment = s; } + void setLoadSize( int s ) { m_loadSize = s; } + void setImageType( int t ) { m_imageType = t; } + + void setTempPath( const QString& p ) { m_tempPath = p; } + + bool noBoot() const { return m_noBoot; } + bool bootInfoTable() const { return m_bootInfoTable; } + int loadSegment() const { return m_loadSegment; } + int loadSize() const { return m_loadSize; } + int imageType() const { return m_imageType; } + + /** + * mkisofs changes boot images on disk. That is why the iso imager + * buffers them and saves the path to the buffered copy here. + */ + const QString& tempPath() const { return m_tempPath; } + + private: + bool m_noBoot; + bool m_bootInfoTable; + int m_loadSegment; + int m_loadSize; + int m_imageType; + + QString m_tempPath; +}; + +#endif diff --git a/libk3b/projects/datacd/k3bdatadoc.cpp b/libk3b/projects/datacd/k3bdatadoc.cpp new file mode 100644 index 0000000..d12c8d2 --- /dev/null +++ b/libk3b/projects/datacd/k3bdatadoc.cpp @@ -0,0 +1,1376 @@ +/* + * + * $Id: k3bdatadoc.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bdatadoc.h" +#include "k3bfileitem.h" +#include "k3bdiritem.h" +#include "k3bsessionimportitem.h" +#include "k3bdatajob.h" +#include "k3bbootitem.h" +#include "k3bspecialdataitem.h" +#include "k3bfilecompilationsizehandler.h" +#include "k3bmkisofshandler.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include +#include + + +/** + * There are two ways to fill a data project with files and folders: + * \li Use the addUrl and addUrls methods + * \li or create your own K3bDirItems and K3bFileItems. The doc will be properly updated + * by the constructors of the items. + */ +K3bDataDoc::K3bDataDoc( QObject* parent ) + : K3bDoc( parent ) +{ + m_root = 0; + + m_sizeHandler = new K3bFileCompilationSizeHandler(); +} + +K3bDataDoc::~K3bDataDoc() +{ + delete m_root; + delete m_sizeHandler; + // delete m_oldSessionSizeHandler; +} + + +bool K3bDataDoc::newDocument() +{ + clearImportedSession(); + + m_bootCataloge = 0; + m_oldSessionSize = 0; + m_bExistingItemsReplaceAll = m_bExistingItemsIgnoreAll = false; + + if( m_root ) { + while( m_root->children().getFirst() ) + removeItem( m_root->children().getFirst() ); + } + else + m_root = new K3bRootItem( this ); + + m_sizeHandler->clear(); + + m_multisessionMode = AUTO; + m_dataMode = K3b::DATA_MODE_AUTO; + + m_isoOptions = K3bIsoOptions(); + + return K3bDoc::newDocument(); +} + + +QString K3bDataDoc::name() const +{ + return m_isoOptions.volumeID(); +} + + +void K3bDataDoc::setIsoOptions( const K3bIsoOptions& o ) +{ + m_isoOptions = o; + emit changed(); +} + + +void K3bDataDoc::setVolumeID( const QString& v ) +{ + m_isoOptions.setVolumeID( v ); + emit changed(); +} + + +void K3bDataDoc::addUrls( const KURL::List& urls ) +{ + addUrls( urls, root() ); +} + + +void K3bDataDoc::addUrls( const KURL::List& l, K3bDirItem* dir ) +{ + if( !dir ) + dir = root(); + + KURL::List urls = K3b::convertToLocalUrls(l); + + for( KURL::List::ConstIterator it = urls.begin(); it != urls.end(); ++it ) { + const KURL& url = *it; + QFileInfo f( url.path() ); + QString k3bname = f.absFilePath().section( "/", -1 ); + + // filenames cannot end in backslashes (mkisofs problem. See comments in k3bisoimager.cpp (escapeGraftPoint())) + while( k3bname[k3bname.length()-1] == '\\' ) + k3bname.truncate( k3bname.length()-1 ); + + // backup dummy name + if( k3bname.isEmpty() ) + k3bname = "1"; + + K3bDirItem* newDirItem = 0; + + // rename the new item if an item with that name already exists + int cnt = 0; + bool ok = false; + while( !ok ) { + ok = true; + QString name( k3bname ); + if( cnt > 0 ) + name += QString("_%1").arg(cnt); + if( K3bDataItem* oldItem = dir->find( name ) ) { + if( f.isDir() && oldItem->isDir() ) { + // ok, just reuse the dir + newDirItem = static_cast(oldItem); + } + // directories cannot replace files in an old session (I think) + // and also directories can for sure never be replaced (only be reused as above) + // so we always rename if the old item is a dir. + else if( !oldItem->isFromOldSession() || + f.isDir() || + oldItem->isDir() ) { + ++cnt; + ok = false; + } + } + } + if( cnt > 0 ) + k3bname += QString("_%1").arg(cnt); + + // QFileInfo::exists and QFileInfo::isReadable return false for broken symlinks :( + if( f.isDir() && !f.isSymLink() ) { + if( !newDirItem ) { + newDirItem = new K3bDirItem( k3bname, this, dir ); + newDirItem->setLocalPath( url.path() ); // HACK: see k3bdiritem.h + } + + // recursively add all the files in the directory + QStringList dlist = QDir( f.absFilePath() ).entryList( QDir::All|QDir::System|QDir::Hidden ); + dlist.remove("."); + dlist.remove(".."); + KURL::List newUrls; + for( QStringList::Iterator it = dlist.begin(); it != dlist.end(); ++it ) + newUrls.append( KURL::fromPathOrURL( f.absFilePath() + "/" + *it ) ); + addUrls( newUrls, newDirItem ); + } + else if( f.isSymLink() || f.isFile() ) + (void)new K3bFileItem( url.path(), this, dir, k3bname ); + } + + emit changed(); + + setModified( true ); +} + + +bool K3bDataDoc::nameAlreadyInDir( const QString& name, K3bDirItem* dir ) +{ + if( !dir ) + return false; + else + return ( dir->find( name ) != 0 ); +} + + +K3bDirItem* K3bDataDoc::addEmptyDir( const QString& name, K3bDirItem* parent ) +{ + K3bDirItem* item = new K3bDirItem( name, this, parent ); + + setModified( true ); + + return item; +} + + +KIO::filesize_t K3bDataDoc::size() const +{ + if( m_isoOptions.doNotCacheInodes() ) + return root()->blocks().mode1Bytes() + m_oldSessionSize; + else + return m_sizeHandler->blocks( m_isoOptions.followSymbolicLinks() || + !m_isoOptions.createRockRidge() ).mode1Bytes() + m_oldSessionSize; +} + + +KIO::filesize_t K3bDataDoc::burningSize() const +{ + return size() - m_oldSessionSize; //m_oldSessionSizeHandler->size(); +} + + +K3b::Msf K3bDataDoc::length() const +{ + // 1 block consists of 2048 bytes real data + // and 1 block equals to 1 audio frame + // so this is the way to calculate: + + return K3b::Msf( size() / 2048 ); +} + + +K3b::Msf K3bDataDoc::burningLength() const +{ + return K3b::Msf( burningSize() / 2048 ); +} + + +QString K3bDataDoc::typeString() const +{ + return QString::fromLatin1("data"); +} + + +bool K3bDataDoc::loadDocumentData( QDomElement* rootElem ) +{ + if( !root() ) + newDocument(); + + QDomNodeList nodes = rootElem->childNodes(); + + if( nodes.item(0).nodeName() != "general" ) { + kdDebug() << "(K3bDataDoc) could not find 'general' section." << endl; + return false; + } + if( !readGeneralDocumentData( nodes.item(0).toElement() ) ) + return false; + + + // parse options + // ----------------------------------------------------------------- + if( nodes.item(1).nodeName() != "options" ) { + kdDebug() << "(K3bDataDoc) could not find 'options' section." << endl; + return false; + } + if( !loadDocumentDataOptions( nodes.item(1).toElement() ) ) + return false; + // ----------------------------------------------------------------- + + + + // parse header + // ----------------------------------------------------------------- + if( nodes.item(2).nodeName() != "header" ) { + kdDebug() << "(K3bDataDoc) could not find 'header' section." << endl; + return false; + } + if( !loadDocumentDataHeader( nodes.item(2).toElement() ) ) + return false; + // ----------------------------------------------------------------- + + + + // parse files + // ----------------------------------------------------------------- + if( nodes.item(3).nodeName() != "files" ) { + kdDebug() << "(K3bDataDoc) could not find 'files' section." << endl; + return false; + } + + if( m_root == 0 ) + m_root = new K3bRootItem( this ); + + QDomNodeList filesList = nodes.item(3).childNodes(); + for( uint i = 0; i < filesList.count(); i++ ) { + + QDomElement e = filesList.item(i).toElement(); + if( !loadDataItem( e, root() ) ) + return false; + } + + // ----------------------------------------------------------------- + + // + // Old versions of K3b do not properly save the boot catalog location + // and name. So to ensure we have one around even if loading an old project + // file we create a default one here. + // + if( !m_bootImages.isEmpty() && !m_bootCataloge ) + createBootCatalogeItem( m_bootImages.first()->parent() ); + + + informAboutNotFoundFiles(); + + return true; +} + + +bool K3bDataDoc::loadDocumentDataOptions( QDomElement elem ) +{ + QDomNodeList headerList = elem.childNodes(); + for( uint i = 0; i < headerList.count(); i++ ) { + + QDomElement e = headerList.item(i).toElement(); + if( e.isNull() ) + return false; + + if( e.nodeName() == "rock_ridge") + m_isoOptions.setCreateRockRidge( e.attributeNode( "activated" ).value() == "yes" ); + + else if( e.nodeName() == "joliet") + m_isoOptions.setCreateJoliet( e.attributeNode( "activated" ).value() == "yes" ); + + else if( e.nodeName() == "udf") + m_isoOptions.setCreateUdf( e.attributeNode( "activated" ).value() == "yes" ); + + else if( e.nodeName() == "joliet_allow_103_characters") + m_isoOptions.setJolietLong( e.attributeNode( "activated" ).value() == "yes" ); + + else if( e.nodeName() == "iso_allow_lowercase") + m_isoOptions.setISOallowLowercase( e.attributeNode( "activated" ).value() == "yes" ); + + else if( e.nodeName() == "iso_allow_period_at_begin") + m_isoOptions.setISOallowPeriodAtBegin( e.attributeNode( "activated" ).value() == "yes" ); + + else if( e.nodeName() == "iso_allow_31_char") + m_isoOptions.setISOallow31charFilenames( e.attributeNode( "activated" ).value() == "yes" ); + + else if( e.nodeName() == "iso_omit_version_numbers") + m_isoOptions.setISOomitVersionNumbers( e.attributeNode( "activated" ).value() == "yes" ); + + else if( e.nodeName() == "iso_omit_trailing_period") + m_isoOptions.setISOomitTrailingPeriod( e.attributeNode( "activated" ).value() == "yes" ); + + else if( e.nodeName() == "iso_max_filename_length") + m_isoOptions.setISOmaxFilenameLength( e.attributeNode( "activated" ).value() == "yes" ); + + else if( e.nodeName() == "iso_relaxed_filenames") + m_isoOptions.setISOrelaxedFilenames( e.attributeNode( "activated" ).value() == "yes" ); + + else if( e.nodeName() == "iso_no_iso_translate") + m_isoOptions.setISOnoIsoTranslate( e.attributeNode( "activated" ).value() == "yes" ); + + else if( e.nodeName() == "iso_allow_multidot") + m_isoOptions.setISOallowMultiDot( e.attributeNode( "activated" ).value() == "yes" ); + + else if( e.nodeName() == "iso_untranslated_filenames") + m_isoOptions.setISOuntranslatedFilenames( e.attributeNode( "activated" ).value() == "yes" ); + + else if( e.nodeName() == "follow_symbolic_links") + m_isoOptions.setFollowSymbolicLinks( e.attributeNode( "activated" ).value() == "yes" ); + + else if( e.nodeName() == "create_trans_tbl") + m_isoOptions.setCreateTRANS_TBL( e.attributeNode( "activated" ).value() == "yes" ); + + else if( e.nodeName() == "hide_trans_tbl") + m_isoOptions.setHideTRANS_TBL( e.attributeNode( "activated" ).value() == "yes" ); + + else if( e.nodeName() == "iso_level") + m_isoOptions.setISOLevel( e.text().toInt() ); + + else if( e.nodeName() == "discard_symlinks") + m_isoOptions.setDiscardSymlinks( e.attributeNode( "activated" ).value() == "yes" ); + + else if( e.nodeName() == "discard_broken_symlinks") + m_isoOptions.setDiscardBrokenSymlinks( e.attributeNode( "activated" ).value() == "yes" ); + + else if( e.nodeName() == "preserve_file_permissions") + m_isoOptions.setPreserveFilePermissions( e.attributeNode( "activated" ).value() == "yes" ); + + else if( e.nodeName() == "force_input_charset") + m_isoOptions.setForceInputCharset( e.attributeNode( "activated" ).value() == "yes" ); + + else if( e.nodeName() == "input_charset") + m_isoOptions.setInputCharset( e.text() ); + + else if( e.nodeName() == "do_not_cache_inodes" ) + m_isoOptions.setDoNotCacheInodes( e.attributeNode( "activated" ).value() == "yes" ); + + else if( e.nodeName() == "whitespace_treatment" ) { + if( e.text() == "strip" ) + m_isoOptions.setWhiteSpaceTreatment( K3bIsoOptions::strip ); + else if( e.text() == "extended" ) + m_isoOptions.setWhiteSpaceTreatment( K3bIsoOptions::extended ); + else if( e.text() == "extended" ) + m_isoOptions.setWhiteSpaceTreatment( K3bIsoOptions::replace ); + else + m_isoOptions.setWhiteSpaceTreatment( K3bIsoOptions::noChange ); + } + + else if( e.nodeName() == "whitespace_replace_string") + m_isoOptions.setWhiteSpaceTreatmentReplaceString( e.text() ); + + else if( e.nodeName() == "data_track_mode" ) { + if( e.text() == "mode1" ) + m_dataMode = K3b::MODE1; + else if( e.text() == "mode2" ) + m_dataMode = K3b::MODE2; + else + m_dataMode = K3b::DATA_MODE_AUTO; + } + + else if( e.nodeName() == "multisession" ) { + QString mode = e.text(); + if( mode == "start" ) + setMultiSessionMode( START ); + else if( mode == "continue" ) + setMultiSessionMode( CONTINUE ); + else if( mode == "finish" ) + setMultiSessionMode( FINISH ); + else if( mode == "none" ) + setMultiSessionMode( NONE ); + else + setMultiSessionMode( AUTO ); + } + + else if( e.nodeName() == "verify_data" ) + setVerifyData( e.attributeNode( "activated" ).value() == "yes" ); + + else + kdDebug() << "(K3bDataDoc) unknown option entry: " << e.nodeName() << endl; + } + + return true; +} + + +bool K3bDataDoc::loadDocumentDataHeader( QDomElement headerElem ) +{ + QDomNodeList headerList = headerElem.childNodes(); + for( uint i = 0; i < headerList.count(); i++ ) { + + QDomElement e = headerList.item(i).toElement(); + if( e.isNull() ) + return false; + + if( e.nodeName() == "volume_id" ) + m_isoOptions.setVolumeID( e.text() ); + + else if( e.nodeName() == "application_id" ) + m_isoOptions.setApplicationID( e.text() ); + + else if( e.nodeName() == "publisher" ) + m_isoOptions.setPublisher( e.text() ); + + else if( e.nodeName() == "preparer" ) + m_isoOptions.setPreparer( e.text() ); + + else if( e.nodeName() == "volume_set_id" ) + m_isoOptions.setVolumeSetId( e.text() ); + + else if( e.nodeName() == "volume_set_size" ) + m_isoOptions.setVolumeSetSize( e.text().toInt() ); + + else if( e.nodeName() == "volume_set_number" ) + m_isoOptions.setVolumeSetNumber( e.text().toInt() ); + + else if( e.nodeName() == "system_id" ) + m_isoOptions.setSystemId( e.text() ); + + else + kdDebug() << "(K3bDataDoc) unknown header entry: " << e.nodeName() << endl; + } + + return true; +} + + +bool K3bDataDoc::loadDataItem( QDomElement& elem, K3bDirItem* parent ) +{ + K3bDataItem* newItem = 0; + + if( elem.nodeName() == "file" ) { + QDomElement urlElem = elem.firstChild().toElement(); + if( urlElem.isNull() ) { + kdDebug() << "(K3bDataDoc) file-element without url!" << endl; + return false; + } + + QFileInfo f( urlElem.text() ); + + // We canot use exists() here since this always disqualifies broken symlinks + if( !f.isFile() && !f.isSymLink() ) + m_notFoundFiles.append( urlElem.text() ); + + // broken symlinks are not readable according to QFileInfo which is wrong in our case + else if( f.isFile() && !f.isReadable() ) + m_noPermissionFiles.append( urlElem.text() ); + + else if( !elem.attribute( "bootimage" ).isEmpty() ) { + K3bBootItem* bootItem = new K3bBootItem( urlElem.text(), + this, + parent, + elem.attributeNode( "name" ).value() ); + if( elem.attribute( "bootimage" ) == "floppy" ) + bootItem->setImageType( K3bBootItem::FLOPPY ); + else if( elem.attribute( "bootimage" ) == "harddisk" ) + bootItem->setImageType( K3bBootItem::HARDDISK ); + else + bootItem->setImageType( K3bBootItem::NONE ); + bootItem->setNoBoot( elem.attribute( "no_boot" ) == "yes" ); + bootItem->setBootInfoTable( elem.attribute( "boot_info_table" ) == "yes" ); + bootItem->setLoadSegment( elem.attribute( "load_segment" ).toInt() ); + bootItem->setLoadSize( elem.attribute( "load_size" ).toInt() ); + + newItem = bootItem; + } + + else { + newItem = new K3bFileItem( urlElem.text(), + this, + parent, + elem.attributeNode( "name" ).value() ); + } + } + else if( elem.nodeName() == "special" ) { + if( elem.attributeNode( "type" ).value() == "boot cataloge" ) + createBootCatalogeItem( parent )->setK3bName( elem.attributeNode( "name" ).value() ); + } + else if( elem.nodeName() == "directory" ) { + // This is for the VideoDVD project which already contains the *_TS folders + K3bDirItem* newDirItem = 0; + if( K3bDataItem* item = parent->find( elem.attributeNode( "name" ).value() ) ) { + if( item->isDir() ) { + newDirItem = static_cast(item); + } + else { + kdError() << "(K3bDataDoc) INVALID DOCUMENT: item " << item->k3bPath() << " saved twice" << endl; + return false; + } + } + + if( !newDirItem ) + newDirItem = new K3bDirItem( elem.attributeNode( "name" ).value(), this, parent ); + QDomNodeList childNodes = elem.childNodes(); + for( uint i = 0; i < childNodes.count(); i++ ) { + + QDomElement e = childNodes.item(i).toElement(); + if( !loadDataItem( e, newDirItem ) ) + return false; + } + + newItem = newDirItem; + } + else { + kdDebug() << "(K3bDataDoc) wrong tag in files-section: " << elem.nodeName() << endl; + return false; + } + + // load the sort weight + if( newItem ) + newItem->setSortWeight( elem.attribute( "sort_weight", "0" ).toInt() ); + + return true; +} + + +bool K3bDataDoc::saveDocumentData( QDomElement* docElem ) +{ + QDomDocument doc = docElem->ownerDocument(); + + saveGeneralDocumentData( docElem ); + + // all options + // ---------------------------------------------------------------------- + QDomElement optionsElem = doc.createElement( "options" ); + saveDocumentDataOptions( optionsElem ); + docElem->appendChild( optionsElem ); + // ---------------------------------------------------------------------- + + // the header stuff + // ---------------------------------------------------------------------- + QDomElement headerElem = doc.createElement( "header" ); + saveDocumentDataHeader( headerElem ); + docElem->appendChild( headerElem ); + + + // now do the "real" work: save the entries + // ---------------------------------------------------------------------- + QDomElement topElem = doc.createElement( "files" ); + + QPtrListIterator it( root()->children() ); + for( ; it.current(); ++it ) { + saveDataItem( it.current(), &doc, &topElem ); + } + + docElem->appendChild( topElem ); + // ---------------------------------------------------------------------- + + return true; +} + + +void K3bDataDoc::saveDocumentDataOptions( QDomElement& optionsElem ) +{ + QDomDocument doc = optionsElem.ownerDocument(); + + QDomElement topElem = doc.createElement( "rock_ridge" ); + topElem.setAttribute( "activated", isoOptions().createRockRidge() ? "yes" : "no" ); + optionsElem.appendChild( topElem ); + + topElem = doc.createElement( "joliet" ); + topElem.setAttribute( "activated", isoOptions().createJoliet() ? "yes" : "no" ); + optionsElem.appendChild( topElem ); + + topElem = doc.createElement( "udf" ); + topElem.setAttribute( "activated", isoOptions().createUdf() ? "yes" : "no" ); + optionsElem.appendChild( topElem ); + + topElem = doc.createElement( "joliet_allow_103_characters" ); + topElem.setAttribute( "activated", isoOptions().jolietLong() ? "yes" : "no" ); + optionsElem.appendChild( topElem ); + + topElem = doc.createElement( "iso_allow_lowercase" ); + topElem.setAttribute( "activated", isoOptions().ISOallowLowercase() ? "yes" : "no" ); + optionsElem.appendChild( topElem ); + + topElem = doc.createElement( "iso_allow_period_at_begin" ); + topElem.setAttribute( "activated", isoOptions().ISOallowPeriodAtBegin() ? "yes" : "no" ); + optionsElem.appendChild( topElem ); + + topElem = doc.createElement( "iso_allow_31_char" ); + topElem.setAttribute( "activated", isoOptions().ISOallow31charFilenames() ? "yes" : "no" ); + optionsElem.appendChild( topElem ); + + topElem = doc.createElement( "iso_omit_version_numbers" ); + topElem.setAttribute( "activated", isoOptions().ISOomitVersionNumbers() ? "yes" : "no" ); + optionsElem.appendChild( topElem ); + + topElem = doc.createElement( "iso_omit_trailing_period" ); + topElem.setAttribute( "activated", isoOptions().ISOomitTrailingPeriod() ? "yes" : "no" ); + optionsElem.appendChild( topElem ); + + topElem = doc.createElement( "iso_max_filename_length" ); + topElem.setAttribute( "activated", isoOptions().ISOmaxFilenameLength() ? "yes" : "no" ); + optionsElem.appendChild( topElem ); + + topElem = doc.createElement( "iso_relaxed_filenames" ); + topElem.setAttribute( "activated", isoOptions().ISOrelaxedFilenames() ? "yes" : "no" ); + optionsElem.appendChild( topElem ); + + topElem = doc.createElement( "iso_no_iso_translate" ); + topElem.setAttribute( "activated", isoOptions().ISOnoIsoTranslate() ? "yes" : "no" ); + optionsElem.appendChild( topElem ); + + topElem = doc.createElement( "iso_allow_multidot" ); + topElem.setAttribute( "activated", isoOptions().ISOallowMultiDot() ? "yes" : "no" ); + optionsElem.appendChild( topElem ); + + topElem = doc.createElement( "iso_untranslated_filenames" ); + topElem.setAttribute( "activated", isoOptions().ISOuntranslatedFilenames() ? "yes" : "no" ); + optionsElem.appendChild( topElem ); + + topElem = doc.createElement( "follow_symbolic_links" ); + topElem.setAttribute( "activated", isoOptions().followSymbolicLinks() ? "yes" : "no" ); + optionsElem.appendChild( topElem ); + + topElem = doc.createElement( "create_trans_tbl" ); + topElem.setAttribute( "activated", isoOptions().createTRANS_TBL() ? "yes" : "no" ); + optionsElem.appendChild( topElem ); + + topElem = doc.createElement( "hide_trans_tbl" ); + topElem.setAttribute( "activated", isoOptions().hideTRANS_TBL() ? "yes" : "no" ); + optionsElem.appendChild( topElem ); + + topElem = doc.createElement( "iso_level" ); + topElem.appendChild( doc.createTextNode( QString::number(isoOptions().ISOLevel()) ) ); + optionsElem.appendChild( topElem ); + + topElem = doc.createElement( "discard_symlinks" ); + topElem.setAttribute( "activated", isoOptions().discardSymlinks() ? "yes" : "no" ); + optionsElem.appendChild( topElem ); + + topElem = doc.createElement( "discard_broken_symlinks" ); + topElem.setAttribute( "activated", isoOptions().discardBrokenSymlinks() ? "yes" : "no" ); + optionsElem.appendChild( topElem ); + + topElem = doc.createElement( "preserve_file_permissions" ); + topElem.setAttribute( "activated", isoOptions().preserveFilePermissions() ? "yes" : "no" ); + optionsElem.appendChild( topElem ); + + topElem = doc.createElement( "force_input_charset" ); + topElem.setAttribute( "activated", isoOptions().forceInputCharset() ? "yes" : "no" ); + optionsElem.appendChild( topElem ); + + topElem = doc.createElement( "do_not_cache_inodes" ); + topElem.setAttribute( "activated", isoOptions().doNotCacheInodes() ? "yes" : "no" ); + optionsElem.appendChild( topElem ); + + topElem = doc.createElement( "input_charset" ); + topElem.appendChild( doc.createTextNode( isoOptions().inputCharset() ) ); + optionsElem.appendChild( topElem ); + + + topElem = doc.createElement( "whitespace_treatment" ); + switch( isoOptions().whiteSpaceTreatment() ) { + case K3bIsoOptions::strip: + topElem.appendChild( doc.createTextNode( "strip" ) ); + break; + case K3bIsoOptions::extended: + topElem.appendChild( doc.createTextNode( "extended" ) ); + break; + case K3bIsoOptions::replace: + topElem.appendChild( doc.createTextNode( "replace" ) ); + break; + default: + topElem.appendChild( doc.createTextNode( "noChange" ) ); + break; + } + optionsElem.appendChild( topElem ); + + topElem = doc.createElement( "whitespace_replace_string" ); + topElem.appendChild( doc.createTextNode( isoOptions().whiteSpaceTreatmentReplaceString() ) ); + optionsElem.appendChild( topElem ); + + topElem = doc.createElement( "data_track_mode" ); + if( m_dataMode == K3b::MODE1 ) + topElem.appendChild( doc.createTextNode( "mode1" ) ); + else if( m_dataMode == K3b::MODE2 ) + topElem.appendChild( doc.createTextNode( "mode2" ) ); + else + topElem.appendChild( doc.createTextNode( "auto" ) ); + optionsElem.appendChild( topElem ); + + + // save multisession + topElem = doc.createElement( "multisession" ); + switch( m_multisessionMode ) { + case START: + topElem.appendChild( doc.createTextNode( "start" ) ); + break; + case CONTINUE: + topElem.appendChild( doc.createTextNode( "continue" ) ); + break; + case FINISH: + topElem.appendChild( doc.createTextNode( "finish" ) ); + break; + case NONE: + topElem.appendChild( doc.createTextNode( "none" ) ); + break; + default: + topElem.appendChild( doc.createTextNode( "auto" ) ); + break; + } + optionsElem.appendChild( topElem ); + + topElem = doc.createElement( "verify_data" ); + topElem.setAttribute( "activated", verifyData() ? "yes" : "no" ); + optionsElem.appendChild( topElem ); + // ---------------------------------------------------------------------- +} + + +void K3bDataDoc::saveDocumentDataHeader( QDomElement& headerElem ) +{ + QDomDocument doc = headerElem.ownerDocument(); + + QDomElement topElem = doc.createElement( "volume_id" ); + topElem.appendChild( doc.createTextNode( isoOptions().volumeID() ) ); + headerElem.appendChild( topElem ); + + topElem = doc.createElement( "volume_set_id" ); + topElem.appendChild( doc.createTextNode( isoOptions().volumeSetId() ) ); + headerElem.appendChild( topElem ); + + topElem = doc.createElement( "volume_set_size" ); + topElem.appendChild( doc.createTextNode( QString::number(isoOptions().volumeSetSize()) ) ); + headerElem.appendChild( topElem ); + + topElem = doc.createElement( "volume_set_number" ); + topElem.appendChild( doc.createTextNode( QString::number(isoOptions().volumeSetNumber()) ) ); + headerElem.appendChild( topElem ); + + topElem = doc.createElement( "system_id" ); + topElem.appendChild( doc.createTextNode( isoOptions().systemId() ) ); + headerElem.appendChild( topElem ); + + topElem = doc.createElement( "application_id" ); + topElem.appendChild( doc.createTextNode( isoOptions().applicationID() ) ); + headerElem.appendChild( topElem ); + + topElem = doc.createElement( "publisher" ); + topElem.appendChild( doc.createTextNode( isoOptions().publisher() ) ); + headerElem.appendChild( topElem ); + + topElem = doc.createElement( "preparer" ); + topElem.appendChild( doc.createTextNode( isoOptions().preparer() ) ); + headerElem.appendChild( topElem ); + // ---------------------------------------------------------------------- +} + + +void K3bDataDoc::saveDataItem( K3bDataItem* item, QDomDocument* doc, QDomElement* parent ) +{ + if( K3bFileItem* fileItem = dynamic_cast( item ) ) { + if( m_oldSession.contains( fileItem ) ) { + kdDebug() << "(K3bDataDoc) ignoring fileitem " << fileItem->k3bName() << " from old session while saving..." << endl; + } + else { + QDomElement topElem = doc->createElement( "file" ); + topElem.setAttribute( "name", fileItem->k3bName() ); + QDomElement subElem = doc->createElement( "url" ); + subElem.appendChild( doc->createTextNode( fileItem->localPath() ) ); + topElem.appendChild( subElem ); + + if( item->sortWeight() != 0 ) + topElem.setAttribute( "sort_weight", QString::number(item->sortWeight()) ); + + parent->appendChild( topElem ); + + // add boot options as attributes to preserve compatibility to older K3b versions + if( K3bBootItem* bootItem = dynamic_cast( fileItem ) ) { + if( bootItem->imageType() == K3bBootItem::FLOPPY ) + topElem.setAttribute( "bootimage", "floppy" ); + else if( bootItem->imageType() == K3bBootItem::HARDDISK ) + topElem.setAttribute( "bootimage", "harddisk" ); + else + topElem.setAttribute( "bootimage", "none" ); + + topElem.setAttribute( "no_boot", bootItem->noBoot() ? "yes" : "no" ); + topElem.setAttribute( "boot_info_table", bootItem->bootInfoTable() ? "yes" : "no" ); + topElem.setAttribute( "load_segment", QString::number( bootItem->loadSegment() ) ); + topElem.setAttribute( "load_size", QString::number( bootItem->loadSize() ) ); + } + } + } + else if( item == m_bootCataloge ) { + QDomElement topElem = doc->createElement( "special" ); + topElem.setAttribute( "name", m_bootCataloge->k3bName() ); + topElem.setAttribute( "type", "boot cataloge" ); + + parent->appendChild( topElem ); + } + else if( K3bDirItem* dirItem = dynamic_cast( item ) ) { + QDomElement topElem = doc->createElement( "directory" ); + topElem.setAttribute( "name", dirItem->k3bName() ); + + if( item->sortWeight() != 0 ) + topElem.setAttribute( "sort_weight", QString::number(item->sortWeight()) ); + + QPtrListIterator it( dirItem->children() ); + for( ; it.current(); ++it ) { + saveDataItem( it.current(), doc, &topElem ); + } + + parent->appendChild( topElem ); + } +} + + +void K3bDataDoc::removeItem( K3bDataItem* item ) +{ + if( !item ) + return; + + if( item->isRemoveable() ) { + delete item; + } + else + kdDebug() << "(K3bDataDoc) tried to remove non-removable entry!" << endl; +} + + +void K3bDataDoc::itemRemovedFromDir( K3bDirItem*, K3bDataItem* removedItem ) +{ + // update the project size + if( !removedItem->isFromOldSession() ) + m_sizeHandler->removeFile( removedItem ); + + // update the boot item list + if( removedItem->isBootItem() ) { + m_bootImages.removeRef( static_cast( removedItem ) ); + if( m_bootImages.isEmpty() ) { + delete m_bootCataloge; + m_bootCataloge = 0; + } + } + + emit itemRemoved( removedItem ); + emit changed(); +} + + +void K3bDataDoc::itemAddedToDir( K3bDirItem*, K3bDataItem* item ) +{ + // update the project size + if( !item->isFromOldSession() ) + m_sizeHandler->addFile( item ); + + // update the boot item list + if( item->isBootItem() ) + m_bootImages.append( static_cast( item ) ); + + emit itemAdded( item ); + emit changed(); +} + + +void K3bDataDoc::moveItem( K3bDataItem* item, K3bDirItem* newParent ) +{ + if( !item || !newParent ) { + kdDebug() << "(K3bDataDoc) item or parentitem was NULL while moving." << endl; + return; + } + + if( !item->isMoveable() ) { + kdDebug() << "(K3bDataDoc) item is not movable! " << endl; + return; + } + + item->reparent( newParent ); +} + + +void K3bDataDoc::moveItems( QPtrList itemList, K3bDirItem* newParent ) +{ + if( !newParent ) { + kdDebug() << "(K3bDataDoc) tried to move items to nowhere...!" << endl; + return; + } + + QPtrListIterator it( itemList ); + for( ; it.current(); ++it ) { + // check if newParent is subdir of item + if( K3bDirItem* dirItem = dynamic_cast( it.current() ) ) { + if( dirItem->isSubItem( newParent ) ) { + continue; + } + } + + if( it.current()->isMoveable() ) + it.current()->reparent( newParent ); + } +} + + +K3bBurnJob* K3bDataDoc::newBurnJob( K3bJobHandler* hdl, QObject* parent ) +{ + return new K3bDataJob( this, hdl, parent ); +} + + +QString K3bDataDoc::treatWhitespace( const QString& path ) +{ + + // TODO: + // It could happen that two files with different names + // will have the same name after the treatment + // Perhaps we should add a number at the end or something + // similar (s.a.) + + + if( isoOptions().whiteSpaceTreatment() != K3bIsoOptions::noChange ) { + QString result = path; + + if( isoOptions().whiteSpaceTreatment() == K3bIsoOptions::replace ) { + result.replace( ' ', isoOptions().whiteSpaceTreatmentReplaceString() ); + } + else if( isoOptions().whiteSpaceTreatment() == K3bIsoOptions::strip ) { + result.remove( ' ' ); + } + else if( isoOptions().whiteSpaceTreatment() == K3bIsoOptions::extended ) { + result.truncate(0); + for( uint i = 0; i < path.length(); i++ ) { + if( path[i] == ' ' ) { + if( path[i+1] != ' ' ) + result.append( path[++i].upper() ); + } + else + result.append( path[i] ); + } + } + + kdDebug() << "(K3bDataDoc) converted " << path << " to " << result << endl; + return result; + } + else + return path; +} + + +void K3bDataDoc::prepareFilenames() +{ + m_needToCutFilenames = false; + m_needToCutFilenameItems.clear(); + + // + // if joliet is used cut the names and rename if necessary + // 64 characters for standard joliet and 103 characters for long joliet names + // + // Rockridge supports the full 255 UNIX chars and in case Rockridge is disabled we leave + // it to mkisofs for now since handling all the options to alter the ISO9660 standard it just + // too much. + // + + K3bDataItem* item = root(); + unsigned int maxlen = ( isoOptions().jolietLong() ? 103 : 64 ); + while( (item = item->nextSibling()) ) { + item->setWrittenName( treatWhitespace( item->k3bName() ) ); + + if( isoOptions().createJoliet() && item->writtenName().length() > maxlen ) { + m_needToCutFilenames = true; + item->setWrittenName( K3b::cutFilename( item->writtenName(), maxlen ) ); + m_needToCutFilenameItems.append( item ); + } + + // TODO: check the Joliet charset + } + + // + // 3. check if a directory contains items with the same name + // + prepareFilenamesInDir( root() ); +} + + +void K3bDataDoc::prepareFilenamesInDir( K3bDirItem* dir ) +{ + if( !dir ) + return; + + QPtrList sortedChildren; + QPtrListIterator it( dir->children() ); + + for( it.toLast(); it.current(); --it ) { + K3bDataItem* item = it.current(); + + if( item->isDir() ) + prepareFilenamesInDir( dynamic_cast( item ) ); + + // insertion sort + unsigned int i = 0; + while( i < sortedChildren.count() && item->writtenName() > sortedChildren.at(i)->writtenName() ) + ++i; + + sortedChildren.insert( i, item ); + } + + + if( isoOptions().createJoliet() || isoOptions().createRockRidge() ) { + QPtrList sameNameList; + while( !sortedChildren.isEmpty() ) { + + sameNameList.clear(); + + do { + sameNameList.append( sortedChildren.first() ); + sortedChildren.removeFirst(); + } while( !sortedChildren.isEmpty() && + sortedChildren.first()->writtenName() == sameNameList.first()->writtenName() ); + + if( sameNameList.count() > 1 ) { + // now we need to rename the items + unsigned int maxlen = 255; + if( isoOptions().createJoliet() ) { + if( isoOptions().jolietLong() ) + maxlen = 103; + else + maxlen = 64; + } + + int cnt = 1; + for( QPtrListIterator it( sameNameList ); + it.current(); ++it ) { + it.current()->setWrittenName( K3b::appendNumberToFilename( it.current()->writtenName(), cnt++, maxlen ) ); + } + } + } + } +} + + +void K3bDataDoc::informAboutNotFoundFiles() +{ + if( !m_notFoundFiles.isEmpty() ) { + KMessageBox::informationList( qApp->activeWindow(), i18n("Could not find the following files:"), + m_notFoundFiles, i18n("Not Found") ); + m_notFoundFiles.clear(); + } + + if( !m_noPermissionFiles.isEmpty() ) { + KMessageBox::informationList( qApp->activeWindow(), i18n("No permission to read the following files:"), + m_noPermissionFiles, i18n("No Read Permission") ); + + m_noPermissionFiles.clear(); + } +} + + +void K3bDataDoc::setMultiSessionMode( K3bDataDoc::MultiSessionMode mode ) +{ + if( m_multisessionMode == NONE || m_multisessionMode == START ) + clearImportedSession(); + + m_multisessionMode = mode; +} + + +bool K3bDataDoc::importSession( K3bDevice::Device* device ) +{ + K3bDevice::DiskInfo diskInfo = device->diskInfo(); + // DVD+RW media is reported as non-appendable + if( !diskInfo.appendable() && + !(diskInfo.mediaType() & (K3bDevice::MEDIA_DVD_PLUS_RW|K3bDevice::MEDIA_DVD_RW_OVWR)) ) + return false; + + K3bDevice::Toc toc = device->readToc(); + if( toc.isEmpty() || + toc.last().type() != K3bDevice::Track::DATA ) + return false; + + long startSec = toc.last().firstSector().lba(); + K3bIso9660 iso( device, startSec ); + + if( iso.open() ) { + // remove previously imported sessions + clearImportedSession(); + + // set multisession option + if( m_multisessionMode != FINISH && m_multisessionMode != AUTO ) + m_multisessionMode = CONTINUE; + + // since in iso9660 it is possible that two files share it's data + // simply summing the file sizes could result in wrong values + // that's why we use the size from the toc. This is more accurate + // anyway since there might be files overwritten or removed + m_oldSessionSize = toc.last().lastSector().mode1Bytes(); + + kdDebug() << "(K3bDataDoc) imported session size: " << KIO::convertSize(m_oldSessionSize) << endl; + + // the track size for DVD+RW media and DVD-RW Overwrite media has nothing to do with the filesystem + // size. in that case we need to use the filesystem's size (which is ok since it's one track anyway, + // no real multisession) + if( diskInfo.mediaType() & (K3bDevice::MEDIA_DVD_PLUS_RW|K3bDevice::MEDIA_DVD_RW_OVWR) ) { + m_oldSessionSize = iso.primaryDescriptor().volumeSpaceSize + * iso.primaryDescriptor().logicalBlockSize; + } + + // import some former settings + m_isoOptions.setCreateRockRidge( iso.firstRRDirEntry() != 0 ); + m_isoOptions.setCreateJoliet( iso.firstJolietDirEntry() != 0 ); + m_isoOptions.setVolumeID( iso.primaryDescriptor().volumeId ); + // TODO: also import some other pd fields + + const K3bIso9660Directory* rootDir = iso.firstRRDirEntry(); + // Jrg Schilling says that it is impossible to import the joliet tree for multisession +// if( !rootDir ) +// rootDir = iso.firstJolietDirEntry(); + if( !rootDir ) + rootDir = iso.firstIsoDirEntry(); + + if( rootDir ) { + createSessionImportItems( rootDir, root() ); + emit changed(); + return true; + } + else { + kdDebug() << "(K3bDataDoc::importSession) Could not find primary volume desc." << endl; + return false; + } + } + else { + kdDebug() << "(K3bDataDoc) unable to read toc." << endl; + return false; + } +} + + +void K3bDataDoc::createSessionImportItems( const K3bIso9660Directory* importDir, K3bDirItem* parent ) +{ + Q_ASSERT(importDir); + QStringList entries = importDir->entries(); + entries.remove( "." ); + entries.remove( ".." ); + for( QStringList::const_iterator it = entries.begin(); + it != entries.end(); ++it ) { + const K3bIso9660Entry* entry = importDir->entry( *it ); + K3bDataItem* oldItem = parent->find( entry->name() ); + if( entry->isDirectory() ) { + K3bDirItem* dir = 0; + if( oldItem && oldItem->isDir() ) { + dir = (K3bDirItem*)oldItem; + } + else { + // we overwrite without warning! + if( oldItem ) + removeItem( oldItem ); + dir = new K3bDirItem( entry->name(), this, parent ); + } + + dir->setRemoveable(false); + dir->setRenameable(false); + dir->setMoveable(false); + dir->setHideable(false); + dir->setWriteToCd(false); + dir->setExtraInfo( i18n("From previous session") ); + m_oldSession.append( dir ); + + createSessionImportItems( static_cast(entry), dir ); + } + else { + const K3bIso9660File* file = static_cast(entry); + + // we overwrite without warning! + if( oldItem ) + removeItem( oldItem ); + + K3bSessionImportItem* item = new K3bSessionImportItem( file, this, parent ); + item->setExtraInfo( i18n("From previous session") ); + m_oldSession.append( item ); + } + } +} + + +void K3bDataDoc::clearImportedSession() +{ + // m_oldSessionSizeHandler->clear(); + m_oldSessionSize = 0; + m_oldSession.setAutoDelete(false); + K3bDataItem* item = m_oldSession.first(); + while( !m_oldSession.isEmpty() ) { + if( item == 0 ) + item = m_oldSession.first(); + + if( item->isDir() ) { + K3bDirItem* dir = (K3bDirItem*)item; + if( dir->numDirs() + dir->numFiles() == 0 ) { + // this imported dir is not needed anymore + // since it is empty + m_oldSession.remove(); + delete dir; + } + else { + for( QPtrListIterator it( dir->children() ); it.current(); ++it ) { + if( !m_oldSession.contains(it.current()) ) { + m_oldSession.remove(); + // now the dir becomes a totally normal dir + dir->setRemoveable(true); + dir->setRenameable(true); + dir->setMoveable(true); + dir->setHideable(true); + dir->setWriteToCd(true); + dir->setExtraInfo( "" ); + break; + } + } + } + } + else { + m_oldSession.remove(); + delete item; + } + + item = m_oldSession.next(); + } + + m_multisessionMode = AUTO; + + emit changed(); +} + + +K3bDirItem* K3bDataDoc::bootImageDir() +{ + K3bDataItem* b = m_root->find( "boot" ); + if( !b ) { + b = new K3bDirItem( "boot", this, m_root ); + setModified( true ); + } + + // if we cannot create the dir because there is a file named boot just use the root dir + if( !b->isDir() ) + return m_root; + else + return static_cast(b); +} + + +K3bBootItem* K3bDataDoc::createBootItem( const QString& filename, K3bDirItem* dir ) +{ + if( !dir ) + dir = bootImageDir(); + + K3bBootItem* boot = new K3bBootItem( filename, this, dir ); + + if( !m_bootCataloge ) + createBootCatalogeItem(dir); + + return boot; +} + + +K3bDataItem* K3bDataDoc::createBootCatalogeItem( K3bDirItem* dir ) +{ + if( !m_bootCataloge ) { + QString newName = "boot.catalog"; + int i = 0; + while( dir->alreadyInDirectory( "boot.catalog" ) ) { + ++i; + newName = QString( "boot%1.catalog" ).arg(i); + } + + K3bSpecialDataItem* b = new K3bSpecialDataItem( this, 0, dir, newName ); + m_bootCataloge = b; + m_bootCataloge->setRemoveable(false); + m_bootCataloge->setHideable(false); + m_bootCataloge->setWriteToCd(false); + m_bootCataloge->setExtraInfo( i18n("El Torito boot catalog file") ); + b->setMimeType( i18n("Boot catalog") ); + } + else + m_bootCataloge->reparent( dir ); + + return m_bootCataloge; +} + + +QValueList K3bDataDoc::findItemByLocalPath( const QString& path ) const +{ + Q_UNUSED( path ); + return QValueList(); +} + + +bool K3bDataDoc::sessionImported() const +{ + return !m_oldSession.isEmpty(); +} + +#include "k3bdatadoc.moc" diff --git a/libk3b/projects/datacd/k3bdatadoc.h b/libk3b/projects/datacd/k3bdatadoc.h new file mode 100644 index 0000000..e09177a --- /dev/null +++ b/libk3b/projects/datacd/k3bdatadoc.h @@ -0,0 +1,297 @@ +/* + * + * $Id: k3bdatadoc.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BDATADOC_H +#define K3BDATADOC_H + +#include +#include + +#include "k3bisooptions.h" + +#include +#include +#include + +#include +#include +#include "k3b_export.h" + +class K3bDataItem; +class K3bRootItem; +class K3bDirItem; +class K3bFileItem; +class K3bJob; +class K3bBootItem; +class K3bFileCompilationSizeHandler; + +class KProgressDialog; +//class K3bView; +class KConfig; +class QString; +class QStringList; +class QWidget; +class QDomDocument; +class QDomElement; +class K3bIso9660Directory; + +namespace K3bDevice { + class Device; + class DeviceHandler; +} + + +/** + *@author Sebastian Trueg + */ + +class LIBK3B_EXPORT K3bDataDoc : public K3bDoc +{ + Q_OBJECT + + public: + K3bDataDoc( QObject* parent = 0 ); + virtual ~K3bDataDoc(); + + virtual int type() const { return DATA; } + virtual QString typeString() const; + + virtual QString name() const; + + enum MultiSessionMode { + /** + * Let the K3bDataJob decide if to close the CD or not. + * The decision is based on the state of the inserted media + * (appendable/closed), the size of the project (will it fill + * up the CD?), and the free space on the inserted media. + */ + AUTO, + NONE, + START, + CONTINUE, + FINISH + }; + + K3bRootItem* root() const { return m_root; } + + virtual bool newDocument(); + virtual KIO::filesize_t size() const; + + /** + * This is used for multisession where size() also returnes the imported session's size + */ + virtual KIO::filesize_t burningSize() const; + virtual K3b::Msf length() const; + virtual K3b::Msf burningLength() const; + + /** + * Simply deletes the item if it is removable (meaning isRemovable() returns true. + * Be aware that you can remove items simply by deleting them even if isRemovable() + * returns false. + */ + void removeItem( K3bDataItem* item ); + + /** + * Simply calls reparent. + */ + void moveItem( K3bDataItem* item, K3bDirItem* newParent ); + void moveItems( QPtrList itemList, K3bDirItem* newParent ); + + K3bDirItem* addEmptyDir( const QString& name, K3bDirItem* parent ); + + QString treatWhitespace( const QString& ); + + virtual K3bBurnJob* newBurnJob( K3bJobHandler* hdl, QObject* parent = 0 ); + + MultiSessionMode multiSessionMode() const { return m_multisessionMode; } + void setMultiSessionMode( MultiSessionMode mode ); + + int dataMode() const { return m_dataMode; } + void setDataMode( int m ) { m_dataMode = m; } + + void setVerifyData( bool b ) { m_verifyData = b; } + bool verifyData() const { return m_verifyData; } + + static bool nameAlreadyInDir( const QString&, K3bDirItem* ); + + /** + * Most of the options that map to the mkisofs parameters are grouped + * together in the K3bIsoOptions class to allow easy saving to and loading + * from a KConfig object. + */ + const K3bIsoOptions& isoOptions() const { return m_isoOptions; } + void setIsoOptions( const K3bIsoOptions& ); + + const QPtrList& bootImages() { return m_bootImages; } + K3bDataItem* bootCataloge() { return m_bootCataloge; } + + K3bDirItem* bootImageDir(); + + /** + * Create a boot item and also create a boot cataloge file in case none + * exists in the project. + * + * Calling this method has the same effect like creating a new K3bBootItem + * instance manually and then calling createBootCatalogeItem. + * + * \return The new boot item on success or 0 in case a file with the same + * name already exists. + */ + K3bBootItem* createBootItem( const QString& filename, K3bDirItem* bootDir = 0 ); + + /** + * Create a new boot catalog item. + * For now this is not called automatically for internal reasons. + * + * Call this if you create boot items manually instead of using createBootItem. + * + * The boot catalog is automatically deleted once the last boot item is removed + * from the doc. + * + * \return The new boot catalog item or the old one if it already exists. + */ + K3bDataItem* createBootCatalogeItem( K3bDirItem* bootDir ); + + /** + * This will prepare the filenames as written to the image. + * These filenames are saved in K3bDataItem::writtenName + */ + void prepareFilenames(); + + /** + * Returns true if filenames need to be cut due to the limitations of Joliet. + * + * This is only valid after a call to @p prepareFilenames() + */ + bool needToCutFilenames() const { return m_needToCutFilenames; } + + const QValueList& needToCutFilenameItems() const { return m_needToCutFilenameItems; } + + /** + * Imports a session into the project. This will create K3bSessionImportItems + * and properly set the imported session size. + * Some settings will be adjusted to the imported session (joliet, rr). + * + * Be aware that this method is blocking. + * + * \return true if the old session was successfully imported, false if no + * session could be found. + * + * \see clearImportedSession() + */ + bool importSession( K3bDevice::Device* ); + + bool sessionImported() const; + + /** + * Searches for an item by it's local path. + * + * NOT IMPLEMENTED YET! + * + * \return The items that correspond to the specified local path. + */ + QValueList findItemByLocalPath( const QString& path ) const; + + public slots: + virtual void addUrls( const KURL::List& urls ); + + /** + * Add urls syncroneously + * This method adds files recursively including symlinks, hidden, and system files. + * If a file already exists the new file's name will be appended a number. + */ + virtual void addUrls( const KURL::List& urls, K3bDirItem* dir ); + + void clearImportedSession(); + + /** + * Just a convience method to prevent using setIsoOptions for this + * often used value. + */ + void setVolumeID( const QString& ); + + signals: + void itemRemoved( K3bDataItem* ); + void itemAdded( K3bDataItem* ); + + protected: + /** reimplemented from K3bDoc */ + virtual bool loadDocumentData( QDomElement* root ); + /** reimplemented from K3bDoc */ + virtual bool saveDocumentData( QDomElement* ); + + void saveDocumentDataOptions( QDomElement& optionsElem ); + void saveDocumentDataHeader( QDomElement& headerElem ); + bool loadDocumentDataOptions( QDomElement optionsElem ); + bool loadDocumentDataHeader( QDomElement optionsElem ); + + K3bFileCompilationSizeHandler* m_sizeHandler; + + // K3bFileCompilationSizeHandler* m_oldSessionSizeHandler; + KIO::filesize_t m_oldSessionSize; + + private: + void prepareFilenamesInDir( K3bDirItem* dir ); + void createSessionImportItems( const K3bIso9660Directory*, K3bDirItem* parent ); + + /** + * used by K3bDirItem to inform about removed items. + */ + void itemRemovedFromDir( K3bDirItem* parent, K3bDataItem* removedItem ); + void itemAddedToDir( K3bDirItem* parent, K3bDataItem* addedItem ); + + /** + * load recursivly + */ + bool loadDataItem( QDomElement& e, K3bDirItem* parent ); + /** + * save recursivly + */ + void saveDataItem( K3bDataItem* item, QDomDocument* doc, QDomElement* parent ); + + void informAboutNotFoundFiles(); + + QStringList m_notFoundFiles; + QStringList m_noPermissionFiles; + + K3bRootItem* m_root; + + int m_dataMode; + + bool m_verifyData; + + KIO::filesize_t m_size; + + K3bIsoOptions m_isoOptions; + + MultiSessionMode m_multisessionMode; + QPtrList m_oldSession; + + // boot cd stuff + K3bDataItem* m_bootCataloge; + QPtrList m_bootImages; + + bool m_bExistingItemsReplaceAll; + bool m_bExistingItemsIgnoreAll; + + bool m_needToCutFilenames; + QValueList m_needToCutFilenameItems; + + friend class K3bMixedDoc; + friend class K3bDirItem; +}; + +#endif diff --git a/libk3b/projects/datacd/k3bdataitem.cpp b/libk3b/projects/datacd/k3bdataitem.cpp new file mode 100644 index 0000000..6f2a861 --- /dev/null +++ b/libk3b/projects/datacd/k3bdataitem.cpp @@ -0,0 +1,264 @@ +/* + * + * $Id: k3bdataitem.cpp 659634 2007-04-30 14:51:32Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bdataitem.h" +#include "k3bdiritem.h" +#include "k3bdatadoc.h" +#include + +#include + + +class K3bDataItem::Private +{ +public: + int flags; +}; + + +K3bDataItem::K3bDataItem( K3bDataDoc* doc, K3bDataItem* parent, int flags ) + : m_bHideOnRockRidge(false), + m_bHideOnJoliet(false), + m_bRemoveable(true), + m_bRenameable(true), + m_bMovable(true), + m_bHideable(true), + m_bWriteToCd(true), + m_sortWeight(0) +{ + d = new Private; + d->flags = flags; + + m_doc = doc; + m_bHideOnRockRidge = m_bHideOnJoliet = false; + + if( parent ) + m_parentDir = parent->getDirItem(); + else + m_parentDir = 0; +} + + +K3bDataItem::K3bDataItem( const K3bDataItem& item ) + : m_k3bName( item.m_k3bName ), + m_doc( 0 ), + m_parentDir( 0 ), + m_bHideOnRockRidge( item.m_bHideOnRockRidge ), + m_bHideOnJoliet( item.m_bHideOnJoliet ), + m_bRemoveable( item.m_bRemoveable ), + m_bRenameable( item.m_bRenameable ), + m_bMovable( item.m_bMovable ), + m_bHideable( item.m_bHideable ), + m_bWriteToCd( item.m_bWriteToCd ), + m_extraInfo( item.m_extraInfo ), + m_sortWeight( item.m_sortWeight ) +{ + d = new Private; + d->flags = item.d->flags; +} + + +K3bDataItem::~K3bDataItem() +{ + delete d; +} + + +void K3bDataItem::setFlags( int flags ) +{ + d->flags = flags; +} + + +bool K3bDataItem::isBootItem() const +{ + return d->flags & BOOT_IMAGE; +} + + +KIO::filesize_t K3bDataItem::size() const +{ + return itemSize( m_doc + ? m_doc->isoOptions().followSymbolicLinks() || + !m_doc->isoOptions().createRockRidge() + : false ); +} + + +K3b::Msf K3bDataItem::blocks() const +{ + return itemBlocks( m_doc + ? m_doc->isoOptions().followSymbolicLinks() || + !m_doc->isoOptions().createRockRidge() + : false ); +} + + +K3b::Msf K3bDataItem::itemBlocks( bool followSymbolicLinks ) const +{ + return (long)::ceil( (double)itemSize( followSymbolicLinks ) / 2048.0 ); +} + + +void K3bDataItem::setK3bName( const QString& name ) { + if ( name != m_k3bName ) { + // test for not-allowed characters + if( name.contains('/') ) { + kdDebug() << "(K3bDataItem) name contained invalid characters!" << endl; + return; + } + + if( parent() ) { + K3bDataItem* item = parent()->find( name ); + if( item && item != this ) { + kdDebug() << "(K3bDataItem) item with that name already exists." << endl; + return; + } + } + + m_k3bName = name; + m_doc->setModified(); +} +} + + +const QString& K3bDataItem::k3bName() const +{ + return m_k3bName; +} + + +K3bDataItem* K3bDataItem::take() +{ + if( parent() ) + parent()->takeDataItem( this ); + + return this; +} + + +QString K3bDataItem::k3bPath() const +{ + if( !getParent() ) + return QString::null; // the root item is the only one not having a parent + else if( isDir() ) + return getParent()->k3bPath() + k3bName() + "/"; + else + return getParent()->k3bPath() + k3bName(); +} + + +QString K3bDataItem::writtenPath() const +{ + if( !getParent() ) + return QString::null; // the root item is the only one not having a parent + else if( isDir() ) + return getParent()->writtenPath() + writtenName() + "/"; + else + return getParent()->writtenPath() + writtenName(); +} + + +QString K3bDataItem::iso9660Path() const +{ + if( !getParent() ) + return QString::null; // the root item is the only one not having a parent + else if( isDir() ) + return getParent()->iso9660Path() + iso9660Name() + "/"; + else + return getParent()->iso9660Path() + iso9660Name(); +} + + +K3bDataItem* K3bDataItem::nextSibling() const +{ + K3bDataItem* item = const_cast(this); // urg, but we know that we don't mess with it, so... + K3bDirItem* parentItem = getParent(); + + while( parentItem ) { + if( K3bDataItem* i = parentItem->nextChild( item ) ) + return i; + + item = parentItem; + parentItem = item->getParent(); + } + + return 0; +} + + +void K3bDataItem::reparent( K3bDirItem* newParent ) +{ + // addDataItem will do all the stuff including taking this + newParent->addDataItem( this ); +} + + +bool K3bDataItem::hideOnRockRidge() const +{ + if( !isHideable() ) + return false; + if( getParent() ) + return m_bHideOnRockRidge || getParent()->hideOnRockRidge(); + else + return m_bHideOnRockRidge; +} + + +bool K3bDataItem::hideOnJoliet() const +{ + if( !isHideable() ) + return false; + if( getParent() ) + return m_bHideOnJoliet || getParent()->hideOnJoliet(); + else + return m_bHideOnJoliet; +} + + +void K3bDataItem::setHideOnRockRidge( bool b ) +{ + // there is no use in changing the value if + // it is already set by the parent + if( ( !getParent() || !getParent()->hideOnRockRidge() ) && + b != m_bHideOnRockRidge ) { + m_bHideOnRockRidge = b; + if ( m_doc ) + m_doc->setModified(); +} +} + + +void K3bDataItem::setHideOnJoliet( bool b ) +{ + // there is no use in changing the value if + // it is already set by the parent + if( ( !getParent() || !getParent()->hideOnJoliet() ) && + b != m_bHideOnJoliet ) { + m_bHideOnJoliet = b; + if ( m_doc ) + m_doc->setModified(); +} +} + + +int K3bDataItem::depth() const +{ + if( getParent() ) + return getParent()->depth() + 1; + else + return 0; +} diff --git a/libk3b/projects/datacd/k3bdataitem.h b/libk3b/projects/datacd/k3bdataitem.h new file mode 100644 index 0000000..36cdf05 --- /dev/null +++ b/libk3b/projects/datacd/k3bdataitem.h @@ -0,0 +1,225 @@ +/* + * + * $Id: k3bdataitem.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BDATAITEM_H +#define K3BDATAITEM_H + + +class K3bDirItem; +class K3bDataDoc; + +#include + +#include + +#include +#include "k3b_export.h" + + +/** + *@author Sebastian Trueg + */ +class LIBK3B_EXPORT K3bDataItem +{ + public: + K3bDataItem( K3bDataDoc* doc, K3bDataItem* parent = 0, int flags = 0 ); + + /** + * Default copy constructor. + * + * The result is an exact copy except that no parent dir it set and, thus, also no doc. + */ + K3bDataItem( const K3bDataItem& ); + + virtual ~K3bDataItem(); + + /** + * Return an exact copy of this data item. + * + * The result is an exact copy except that no parent dir it set and, thus, also no doc. + * + * Implementations should use the default constructor. + */ + virtual K3bDataItem* copy() const = 0; + + K3bDirItem* parent() { return m_parentDir; } + K3bDirItem* getParent() const { return m_parentDir; } + + /** + * Remove this item from it's parent and return a pointer to it. + */ + K3bDataItem* take(); + + K3bDataDoc* doc() const { return m_doc; } + virtual const QString& k3bName() const; + virtual void setK3bName( const QString& ); + + /** + * returns the path as defined by the k3b-hierachy, NOT starting with a slash + * (since this is used for graft-points!) + * directories have a trailing "/" + */ + virtual QString k3bPath() const; + + /** + * Returns the name of the item as used on the CD or DVD image. + * + * This is only valid after a call to @p K3bDataDoc::prepareFilenames() + */ + const QString& writtenName() const { return m_writtenName; } + + /** + * \return the pure name used in the Iso9660 tree. + * + * This is only valid after a call to @p K3bDataDoc::prepareFilenames() + */ + const QString& iso9660Name() const { return m_rawIsoName; } + + /** + * Returns the path of the item as written to the CD or DVD image. + * + * This is suited to be used for mkisofs graftpoints. + * + * This is only valid after a call to @p K3bDataDoc::prepareFilenames() + */ + virtual QString writtenPath() const; + + virtual QString iso9660Path() const; + + /** + * Used to set the written name by @p K3bDataDoc::prepareFilenames() + */ + void setWrittenName( const QString& s ) { m_writtenName = s; } + + /** + * Used to set the pure Iso9660 name by @p K3bDataDoc::prepareFilenames() + */ + void setIso9660Name( const QString& s ) { m_rawIsoName = s; } + + virtual K3bDataItem* nextSibling() const; + + /** returns the path to the file on the local filesystem */ + virtual QString localPath() const { return QString::null; } + + /** + * The size of the item + */ + KIO::filesize_t size() const; + + /** + * \return The number of blocks (2048 bytes) occupied by this item. + * This value equals to ceil(size()/2048) + */ + K3b::Msf blocks() const; + + /** + * \returne the dir of the item (or the item itself if it is a dir) + */ + virtual K3bDirItem* getDirItem() const { return getParent(); } + + virtual void reparent( K3bDirItem* ); + + // FIXME: use all these flags and make the isXXX methods + // non-virtual. Then move the parent()->addDataItem call + // to the K3bDataItem constructor + enum ItemFlags { + DIR = 0x1, + FILE = 0x2, + SPECIALFILE = 0x4, + SYMLINK = 0x8, + OLD_SESSION = 0x10, + BOOT_IMAGE = 0x11 + }; + + int flags() const; + + virtual bool isDir() const { return false; } + virtual bool isFile() const { return false; } + virtual bool isSpecialFile() const { return false; } + virtual bool isSymLink() const { return false; } + virtual bool isFromOldSession() const { return false; } + bool isBootItem() const; + + bool hideOnRockRidge() const; + bool hideOnJoliet() const; + + virtual void setHideOnRockRidge( bool b ); + virtual void setHideOnJoliet( bool b ); + + virtual long sortWeight() const { return m_sortWeight; } + virtual void setSortWeight( long w ) { m_sortWeight = w; } + + virtual int depth() const; + + virtual bool isValid() const { return true; } + + // these are all needed for special fileitems like + // imported sessions or the movix filesystem + virtual bool isRemoveable() const { return m_bRemoveable; } + virtual bool isMoveable() const { return m_bMovable; } + virtual bool isRenameable() const { return m_bRenameable; } + virtual bool isHideable() const { return m_bHideable; } + virtual bool writeToCd() const { return m_bWriteToCd; } + virtual const QString& extraInfo() const { return m_extraInfo; } + + void setRenameable( bool b ) { m_bRenameable = b; } + void setMoveable( bool b ) { m_bMovable = b; } + void setRemoveable( bool b ) { m_bRemoveable = b; } + void setHideable( bool b ) { m_bHideable = b; } + void setWriteToCd( bool b ) { m_bWriteToCd = b; } + void setExtraInfo( const QString& i ) { m_extraInfo = i; } + + protected: + virtual KIO::filesize_t itemSize( bool followSymlinks ) const = 0; + + /** + * \param followSymlinks If true symlinks will be followed and their + * size equals the size of the file they are + * pointing to. + * + * \return The number of blocks (2048 bytes) occupied by this item. + */ + virtual K3b::Msf itemBlocks( bool followSymlinks ) const; + + QString m_k3bName; + + void setFlags( int flags ); + + private: + class Private; + Private* d; + + QString m_writtenName; + QString m_rawIsoName; + + K3bDataDoc* m_doc; + K3bDirItem* m_parentDir; + + bool m_bHideOnRockRidge; + bool m_bHideOnJoliet; + bool m_bRemoveable; + bool m_bRenameable; + bool m_bMovable; + bool m_bHideable; + bool m_bWriteToCd; + QString m_extraInfo; + + long m_sortWeight; + + friend class K3bDirItem; +}; + +#endif diff --git a/libk3b/projects/datacd/k3bdatajob.cpp b/libk3b/projects/datacd/k3bdatajob.cpp new file mode 100644 index 0000000..7009a43 --- /dev/null +++ b/libk3b/projects/datacd/k3bdatajob.cpp @@ -0,0 +1,972 @@ +/* + * + * $Id: k3bdatajob.cpp 690187 2007-07-20 09:18:03Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bdatajob.h" +#include "k3bdatadoc.h" +#include "k3bisoimager.h" +#include "k3bmsinfofetcher.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + + +class K3bDataJob::Private +{ +public: + Private() + : usedWritingApp(K3b::CDRECORD), + verificationJob(0) { + } + + K3bDataDoc* doc; + + bool initializingImager; + bool imageFinished; + bool canceled; + + KTempFile* tocFile; + + int usedDataMode; + int usedWritingApp; + int usedWritingMode; + K3bDataDoc::MultiSessionMode usedMultiSessionMode; + + int copies; + int copiesDone; + + K3bVerificationJob* verificationJob; + + K3bFileSplitter imageFile; + K3bActivePipe pipe; +}; + + +K3bDataJob::K3bDataJob( K3bDataDoc* doc, K3bJobHandler* hdl, QObject* parent ) + : K3bBurnJob( hdl, parent ) +{ + d = new Private; + + d->doc = doc; + m_writerJob = 0; + d->tocFile = 0; + + m_isoImager = 0; + + m_msInfoFetcher = new K3bMsInfoFetcher( this, this ); + connect( m_msInfoFetcher, SIGNAL(finished(bool)), this, SLOT(slotMsInfoFetched(bool)) ); + connect( m_msInfoFetcher, SIGNAL(infoMessage(const QString&, int)), this, SIGNAL(infoMessage(const QString&, int)) ); + connect( m_msInfoFetcher, SIGNAL(debuggingOutput(const QString&, const QString&)), + this, SIGNAL(debuggingOutput(const QString&, const QString&)) ); + + d->imageFinished = true; +} + +K3bDataJob::~K3bDataJob() +{ + delete d->tocFile; + delete d; +} + + +K3bDoc* K3bDataJob::doc() const +{ + return d->doc; +} + + +K3bDevice::Device* K3bDataJob::writer() const +{ + if( doc()->onlyCreateImages() ) + return 0; // no writer needed -> no blocking on K3bBurnJob + else + return doc()->burner(); +} + + +void K3bDataJob::start() +{ + jobStarted(); + + d->canceled = false; + d->imageFinished = false; + d->copies = d->doc->copies(); + d->copiesDone = 0; + d->usedMultiSessionMode = d->doc->multiSessionMode(); + + prepareImager(); + + if( d->doc->dummy() ) { + d->doc->setVerifyData( false ); + d->copies = 1; + } + + emit newTask( i18n("Preparing data") ); + + // there is no harm in setting these even if we write on-the-fly + d->imageFile.setName( d->doc->tempDir() ); + d->pipe.readFromIODevice( &d->imageFile ); + + if( d->usedMultiSessionMode == K3bDataDoc::AUTO && !d->doc->onlyCreateImages() ) + determineMultiSessionMode(); + else + prepareWriting(); +} + + +void K3bDataJob::prepareWriting() +{ + if( !d->doc->onlyCreateImages() && + ( d->usedMultiSessionMode == K3bDataDoc::CONTINUE || + d->usedMultiSessionMode == K3bDataDoc::FINISH ) ) { + // no sense continuing the same session twice + // FIXME: why not? + d->copies = 1; + + m_msInfoFetcher->setDevice( d->doc->burner() ); + + if( !waitForMedium() ) { + cancel(); + return; + } + + if( K3b::isMounted( d->doc->burner() ) ) { + emit infoMessage( i18n("Unmounting disk"), INFO ); + K3b::unmount( d->doc->burner() ); + } + + m_msInfoFetcher->start(); + } + else { + m_isoImager->setMultiSessionInfo( QString::null ); + prepareData(); + + d->initializingImager = true; + m_isoImager->init(); + } +} + + +void K3bDataJob::slotMsInfoFetched(bool success) +{ + if( success ) { + // we call this here since in ms mode we might want to check + // the last track's datamode + prepareData(); + + if( d->usedWritingApp == K3b::CDRDAO ) // cdrdao seems to write a 150 blocks pregap that is not used by cdrecord + m_isoImager->setMultiSessionInfo( QString("%1,%2").arg(m_msInfoFetcher->lastSessionStart()).arg(m_msInfoFetcher->nextSessionStart()+150), d->doc->burner() ); + else + m_isoImager->setMultiSessionInfo( m_msInfoFetcher->msInfo(), d->doc->burner() ); + + d->initializingImager = true; + m_isoImager->init(); + } + else { + // the MsInfoFetcher already emitted failure info + cancelAll(); + jobFinished( false ); + } +} + + +void K3bDataJob::writeImage() +{ + d->initializingImager = false; + + emit burning(false); + + // get image file path + if( d->doc->tempDir().isEmpty() ) + d->doc->setTempDir( K3b::findUniqueFilePrefix( d->doc->isoOptions().volumeID() ) + ".iso" ); + + // TODO: check if the image file is part of the project and if so warn the user + // and append some number to make the path unique. + + emit newTask( i18n("Creating image file") ); + emit newSubTask( i18n("Track 1 of 1") ); + emit infoMessage( i18n("Creating image file in %1").arg(d->doc->tempDir()), INFO ); + + m_isoImager->writeToImageFile( d->doc->tempDir() ); + m_isoImager->start(); +} + + +bool K3bDataJob::startOnTheFlyWriting() +{ + if( prepareWriterJob() ) { + if( startWriterJob() ) { + // try a direct connection between the processes + if( m_writerJob->fd() != -1 ) + m_isoImager->writeToFd( m_writerJob->fd() ); + d->initializingImager = false; + m_isoImager->start(); + return true; + } + } + return false; +} + + +void K3bDataJob::cancel() +{ + emit infoMessage( i18n("Writing canceled."), K3bJob::ERROR ); + emit canceled(); + + if( m_writerJob && m_writerJob->active() ) { + // + // lets wait for the writer job to finish + // and let it finish the job for good. + // + cancelAll(); + } + else { + // + // Just cancel all and return + // This is bad design as we should wait for all subjobs to finish + // + cancelAll(); + jobFinished( false ); + } +} + + +void K3bDataJob::slotIsoImagerPercent( int p ) +{ + if( d->doc->onlyCreateImages() ) { + emit subPercent( p ); + emit percent( p ); + } + else if( !d->doc->onTheFly() ) { + double totalTasks = d->copies; + double tasksDone = d->copiesDone; // =0 when creating an image + if( d->doc->verifyData() ) { + totalTasks*=2; + tasksDone*=2; + } + if( !d->doc->onTheFly() ) { + totalTasks+=1.0; + } + + emit subPercent( p ); + emit percent( (int)((100.0*tasksDone + (double)p) / totalTasks) ); + } +} + + +void K3bDataJob::slotIsoImagerFinished( bool success ) +{ + if( d->initializingImager ) { + if( success ) { + if( d->doc->onTheFly() && !d->doc->onlyCreateImages() ) { + if( !startOnTheFlyWriting() ) { + cancelAll(); + jobFinished( false ); + } + } + else { + writeImage(); + } + } + else { + if( m_isoImager->hasBeenCanceled() ) + emit canceled(); + jobFinished( false ); + } + } + else { + // tell the writer that there won't be more data + if( d->doc->onTheFly() && m_writerJob ) + m_writerJob->closeFd(); + + if( !d->doc->onTheFly() || + d->doc->onlyCreateImages() ) { + + if( success ) { + emit infoMessage( i18n("Image successfully created in %1").arg(d->doc->tempDir()), K3bJob::SUCCESS ); + d->imageFinished = true; + + if( d->doc->onlyCreateImages() ) { + jobFinished( true ); + } + else { + if( prepareWriterJob() ) { + startWriterJob(); + d->pipe.writeToFd( m_writerJob->fd(), true ); + d->pipe.open(true); + } + } + } + else { + if( m_isoImager->hasBeenCanceled() ) + emit canceled(); + else + emit infoMessage( i18n("Error while creating ISO image"), ERROR ); + + cancelAll(); + jobFinished( false ); + } + } + else if( !success ) { // on-the-fly + // + // In case the imager failed let's make sure the writer does not emit an unusable + // error message. + // + if( m_writerJob && m_writerJob->active() ) + m_writerJob->setSourceUnreadable( true ); + + // there is one special case which we need to handle here: the iso imager might be canceled + // FIXME: the iso imager should not be able to cancel itself + if( m_isoImager->hasBeenCanceled() && !this->hasBeenCanceled() ) + cancel(); + } + } +} + + +bool K3bDataJob::startWriterJob() +{ + if( d->doc->dummy() ) + emit newTask( i18n("Simulating") ); + else if( d->copies > 1 ) + emit newTask( i18n("Writing Copy %1").arg(d->copiesDone+1) ); + else + emit newTask( i18n("Writing") ); + + // if we append a new session we asked for an appendable cd already + if( d->usedMultiSessionMode == K3bDataDoc::NONE || + d->usedMultiSessionMode == K3bDataDoc::START ) { + + if( !waitForMedium() ) { + return false; + } + } + + emit burning(true); + m_writerJob->start(); + return true; +} + + +void K3bDataJob::slotWriterJobPercent( int p ) +{ + double totalTasks = d->copies; + double tasksDone = d->copiesDone; + if( d->doc->verifyData() ) { + totalTasks*=2; + tasksDone*=2; + } + if( !d->doc->onTheFly() ) { + totalTasks+=1.0; + tasksDone+=1.0; + } + + emit percent( (int)((100.0*tasksDone + (double)p) / totalTasks) ); +} + + +void K3bDataJob::slotWriterNextTrack( int t, int tt ) +{ + emit newSubTask( i18n("Writing Track %1 of %2").arg(t).arg(tt) ); +} + + +void K3bDataJob::slotWriterJobFinished( bool success ) +{ + d->pipe.close(); + + // + // This is a little workaround for the bad cancellation handling in this job + // see cancel() + // + if( d->canceled ) { + if( active() ) + jobFinished( false ); + } + + if( success ) { + // allright + // the writerJob should have emited the "simulation/writing successful" signal + + if( d->doc->verifyData() ) { + if( !d->verificationJob ) { + d->verificationJob = new K3bVerificationJob( this, this ); + connect( d->verificationJob, SIGNAL(infoMessage(const QString&, int)), + this, SIGNAL(infoMessage(const QString&, int)) ); + connect( d->verificationJob, SIGNAL(newTask(const QString&)), + this, SIGNAL(newSubTask(const QString&)) ); + connect( d->verificationJob, SIGNAL(newSubTask(const QString&)), + this, SIGNAL(newSubTask(const QString&)) ); + connect( d->verificationJob, SIGNAL(percent(int)), + this, SLOT(slotVerificationProgress(int)) ); + connect( d->verificationJob, SIGNAL(percent(int)), + this, SIGNAL(subPercent(int)) ); + connect( d->verificationJob, SIGNAL(finished(bool)), + this, SLOT(slotVerificationFinished(bool)) ); + connect( d->verificationJob, SIGNAL(debuggingOutput(const QString&, const QString&)), + this, SIGNAL(debuggingOutput(const QString&, const QString&)) ); + + } + d->verificationJob->clear(); + d->verificationJob->setDevice( d->doc->burner() ); + d->verificationJob->setGrownSessionSize( m_isoImager->size() ); + d->verificationJob->addTrack( 0, m_isoImager->checksum(), m_isoImager->size() ); + + emit burning(false); + + emit newTask( i18n("Verifying written data") ); + + d->verificationJob->start(); + } + else { + d->copiesDone++; + + if( d->copiesDone < d->copies ) { + K3bDevice::eject( d->doc->burner() ); + + bool failed = false; + if( d->doc->onTheFly() ) + failed = !startOnTheFlyWriting(); + else + failed = !startWriterJob(); + + if( failed ) { + cancel(); + } + else if( !d->doc->onTheFly() ) { + d->pipe.writeToFd( m_writerJob->fd(), true ); + d->pipe.open(true); + } + } + else { + cleanup(); + jobFinished(true); + } + } + } + else { + cancelAll(); + jobFinished( false ); + } +} + + +void K3bDataJob::slotVerificationProgress( int p ) +{ + double totalTasks = d->copies*2; + double tasksDone = d->copiesDone*2 + 1; // the writing of the current copy has already been finished + + if( !d->doc->onTheFly() ) { + totalTasks+=1.0; + tasksDone+=1.0; + } + + emit percent( (int)((100.0*tasksDone + (double)p) / totalTasks) ); +} + + +void K3bDataJob::slotVerificationFinished( bool success ) +{ + d->copiesDone++; + + // reconnect our imager which we deconnected for the verification + connectImager(); + + if( k3bcore->globalSettings()->ejectMedia() || d->copiesDone < d->copies ) + K3bDevice::eject( d->doc->burner() ); + + if( !d->canceled && d->copiesDone < d->copies ) { + bool failed = false; + if( d->doc->onTheFly() ) + failed = !startOnTheFlyWriting(); + else + failed = !startWriterJob(); + + if( failed ) + cancel(); + else if( !d->doc->onTheFly() ) { + d->pipe.writeToFd( m_writerJob->fd(), true ); + d->pipe.open(true); + } + } + else { + cleanup(); + jobFinished( success ); + } +} + + +void K3bDataJob::setWriterJob( K3bAbstractWriter* writer ) +{ + // FIXME: progressedsize for multiple copies + m_writerJob = writer; + connect( m_writerJob, SIGNAL(infoMessage(const QString&, int)), this, SIGNAL(infoMessage(const QString&, int)) ); + connect( m_writerJob, SIGNAL(percent(int)), this, SLOT(slotWriterJobPercent(int)) ); + connect( m_writerJob, SIGNAL(processedSize(int, int)), this, SIGNAL(processedSize(int, int)) ); + connect( m_writerJob, SIGNAL(subPercent(int)), this, SIGNAL(subPercent(int)) ); + connect( m_writerJob, SIGNAL(processedSubSize(int, int)), this, SIGNAL(processedSubSize(int, int)) ); + connect( m_writerJob, SIGNAL(nextTrack(int, int)), this, SLOT(slotWriterNextTrack(int, int)) ); + connect( m_writerJob, SIGNAL(buffer(int)), this, SIGNAL(bufferStatus(int)) ); + connect( m_writerJob, SIGNAL(deviceBuffer(int)), this, SIGNAL(deviceBuffer(int)) ); + connect( m_writerJob, SIGNAL(writeSpeed(int, int)), this, SIGNAL(writeSpeed(int, int)) ); + connect( m_writerJob, SIGNAL(finished(bool)), this, SLOT(slotWriterJobFinished(bool)) ); + connect( m_writerJob, SIGNAL(newSubTask(const QString&)), this, SIGNAL(newSubTask(const QString&)) ); + connect( m_writerJob, SIGNAL(debuggingOutput(const QString&, const QString&)), + this, SIGNAL(debuggingOutput(const QString&, const QString&)) ); +} + + +void K3bDataJob::setImager( K3bIsoImager* imager ) +{ + if( m_isoImager != imager ) { + delete m_isoImager; + + m_isoImager = imager; + + connectImager(); + } +} + + +void K3bDataJob::connectImager() +{ + m_isoImager->disconnect( this ); + connect( m_isoImager, SIGNAL(infoMessage(const QString&, int)), this, SIGNAL(infoMessage(const QString&, int)) ); + connect( m_isoImager, SIGNAL(percent(int)), this, SLOT(slotIsoImagerPercent(int)) ); + connect( m_isoImager, SIGNAL(finished(bool)), this, SLOT(slotIsoImagerFinished(bool)) ); + connect( m_isoImager, SIGNAL(debuggingOutput(const QString&, const QString&)), + this, SIGNAL(debuggingOutput(const QString&, const QString&)) ); +} + + +void K3bDataJob::prepareImager() +{ + if( !m_isoImager ) + setImager( new K3bIsoImager( d->doc, this, this ) ); +} + + +bool K3bDataJob::prepareWriterJob() +{ + if( m_writerJob ) + return true; + + // It seems as if cdrecord is not able to append sessions in dao mode whereas cdrdao is + if( d->usedWritingApp == K3b::CDRECORD ) { + K3bCdrecordWriter* writer = new K3bCdrecordWriter( d->doc->burner(), this, this ); + + // cdrecord manpage says that "not all" writers are able to write + // multisession disks in dao mode. That means there are writers that can. + + // Does it really make sence to write DAta ms cds in DAO mode since writing the + // first session of a cd-extra in DAO mode is no problem with my writer while + // writing the second data session is only possible in TAO mode. + if( d->usedWritingMode == K3b::DAO && + d->usedMultiSessionMode != K3bDataDoc::NONE ) + emit infoMessage( i18n("Most writers do not support writing " + "multisession CDs in DAO mode."), INFO ); + + writer->setWritingMode( d->usedWritingMode ); + writer->setSimulate( d->doc->dummy() ); + writer->setBurnSpeed( d->doc->speed() ); + + // multisession + if( d->usedMultiSessionMode == K3bDataDoc::START || + d->usedMultiSessionMode == K3bDataDoc::CONTINUE ) { + writer->addArgument("-multi"); + } + + if( d->doc->onTheFly() && + ( d->usedMultiSessionMode == K3bDataDoc::CONTINUE || + d->usedMultiSessionMode == K3bDataDoc::FINISH ) ) + writer->addArgument("-waiti"); + + if( d->usedDataMode == K3b::MODE1 ) + writer->addArgument( "-data" ); + else { + if( k3bcore->externalBinManager()->binObject("cdrecord") && + k3bcore->externalBinManager()->binObject("cdrecord")->hasFeature( "xamix" ) ) + writer->addArgument( "-xa" ); + else + writer->addArgument( "-xa1" ); + } + + writer->addArgument( QString("-tsize=%1s").arg(m_isoImager->size()) )->addArgument("-"); + + setWriterJob( writer ); + } + else { + // create cdrdao job + K3bCdrdaoWriter* writer = new K3bCdrdaoWriter( d->doc->burner(), this, this ); + writer->setCommand( K3bCdrdaoWriter::WRITE ); + writer->setSimulate( d->doc->dummy() ); + writer->setBurnSpeed( d->doc->speed() ); + // multisession + writer->setMulti( d->usedMultiSessionMode == K3bDataDoc::START || + d->usedMultiSessionMode == K3bDataDoc::CONTINUE ); + + // now write the tocfile + if( d->tocFile ) delete d->tocFile; + d->tocFile = new KTempFile( QString::null, "toc" ); + d->tocFile->setAutoDelete(true); + + if( QTextStream* s = d->tocFile->textStream() ) { + if( d->usedDataMode == K3b::MODE1 ) { + *s << "CD_ROM" << "\n"; + *s << "\n"; + *s << "TRACK MODE1" << "\n"; + } + else { + *s << "CD_ROM_XA" << "\n"; + *s << "\n"; + *s << "TRACK MODE2_FORM1" << "\n"; + } + + *s << "DATAFILE \"-\" " << m_isoImager->size()*2048 << "\n"; + + d->tocFile->close(); + } + else { + kdDebug() << "(K3bDataJob) could not write tocfile." << endl; + emit infoMessage( i18n("IO Error"), ERROR ); + cancelAll(); + return false; + } + + writer->setTocFile( d->tocFile->name() ); + + setWriterJob( writer ); + } + + return true; +} + + +void K3bDataJob::prepareData() +{ + // we don't need this when only creating image and it is possible + // that the burn device is null + if( d->doc->onlyCreateImages() ) + return; + + // first of all we determine the data mode + if( d->doc->dataMode() == K3b::DATA_MODE_AUTO ) { + if( !d->doc->onlyCreateImages() && + ( d->usedMultiSessionMode == K3bDataDoc::CONTINUE || + d->usedMultiSessionMode == K3bDataDoc::FINISH ) ) { + + // try to get the last track's datamode + // we already asked for an appendable cdr when fetching + // the ms info + kdDebug() << "(K3bDataJob) determining last track's datamode..." << endl; + + // FIXME: use a devicethread + K3bDevice::Toc toc = d->doc->burner()->readToc(); + if( toc.isEmpty() ) { + kdDebug() << "(K3bDataJob) could not retrieve toc." << endl; + emit infoMessage( i18n("Unable to determine the last track's datamode. Using default."), ERROR ); + d->usedDataMode = K3b::MODE2; + } + else { + if( toc[toc.count()-1].mode() == K3bDevice::Track::MODE1 ) + d->usedDataMode = K3b::MODE1; + else + d->usedDataMode = K3b::MODE2; + + kdDebug() << "(K3bDataJob) using datamode: " + << (d->usedDataMode == K3b::MODE1 ? "mode1" : "mode2") + << endl; + } + } + else if( d->usedMultiSessionMode == K3bDataDoc::NONE ) + d->usedDataMode = K3b::MODE1; + else + d->usedDataMode = K3b::MODE2; + } + else + d->usedDataMode = d->doc->dataMode(); + + + // determine the writing mode + if( d->doc->writingMode() == K3b::WRITING_MODE_AUTO ) { + // TODO: put this into the cdreocrdwriter and decide based on the size of the + // track + if( writer()->dao() && d->usedDataMode == K3b::MODE1 && + d->usedMultiSessionMode == K3bDataDoc::NONE ) + d->usedWritingMode = K3b::DAO; + else + d->usedWritingMode = K3b::TAO; + } + else + d->usedWritingMode = d->doc->writingMode(); + + + // cdrecord seems to have problems writing xa 1 disks in dao mode? At least on my system! + if( writingApp() == K3b::DEFAULT ) { + if( d->usedWritingMode == K3b::DAO ) { + if( d->usedMultiSessionMode != K3bDataDoc::NONE ) + d->usedWritingApp = K3b::CDRDAO; + else if( d->usedDataMode == K3b::MODE2 ) + d->usedWritingApp = K3b::CDRDAO; + else + d->usedWritingApp = K3b::CDRECORD; + } + else + d->usedWritingApp = K3b::CDRECORD; + } + else + d->usedWritingApp = writingApp(); +} + + +void K3bDataJob::determineMultiSessionMode() +{ + // + // THIS IS ONLY CALLED IF d->doc->multiSessionMode() == K3bDataDoc::AUTO! + // + + if( d->doc->writingMode() == K3b::WRITING_MODE_AUTO || + d->doc->writingMode() == K3b::TAO ) { + emit newSubTask( i18n("Searching for old session") ); + + // + // Wait for the medium. + // In case an old session was imported we always want to continue or finish a multisession CD/DVD. + // Otherwise we wait for everything we could handle and decide what to do in + // determineMultiSessionMode( K3bDevice::DeviceHandler* ) below. + // + + int wantedMediaState = K3bDevice::STATE_INCOMPLETE|K3bDevice::STATE_EMPTY; + if( d->doc->sessionImported() ) + wantedMediaState = K3bDevice::STATE_INCOMPLETE; + + int m = waitForMedia( d->doc->burner(), + wantedMediaState, + K3bDevice::MEDIA_WRITABLE_CD ); + + if( m < 0 ) + cancel(); + else { + // now we need to determine the media's size + connect( K3bDevice::sendCommand( K3bDevice::DeviceHandler::NG_DISKINFO, d->doc->burner() ), + SIGNAL(finished(K3bDevice::DeviceHandler*)), + this, + SLOT(slotDetermineMultiSessionMode(K3bDevice::DeviceHandler*)) ); + } + } + else { + // we need TAO for multisession + d->usedMultiSessionMode = K3bDataDoc::NONE; + + // carry on with the writing + prepareWriting(); + } +} + + +void K3bDataJob::slotDetermineMultiSessionMode( K3bDevice::DeviceHandler* dh ) +{ + // + // This is a little workaround for the bad cancellation handling in this job + // see cancel() + // + if( d->canceled ) { + if( active() ) { + cleanup(); + jobFinished( false ); + } + } + else { + d->usedMultiSessionMode = getMultiSessionMode( dh->diskInfo() ); + + // carry on with the writing + prepareWriting(); + } +} + + +K3bDataDoc::MultiSessionMode K3bDataJob::getMultiSessionMode( const K3bDevice::DiskInfo& info ) +{ + if( info.appendable() ) { + // + // 3 cases: + // 1. the project does not fit -> no multisession (resulting in asking for another media above) + // 2. the project does fit and fills up the CD -> finish multisession + // 3. the project does fit and does not fill up the CD -> continue multisession + // + // In case a session has been imported we do not consider NONE at all. + // + if( d->doc->size() > info.remainingSize().mode1Bytes() && !d->doc->sessionImported() ) + d->usedMultiSessionMode = K3bDataDoc::NONE; + else if( d->doc->size() >= info.remainingSize().mode1Bytes()*9/10 ) + d->usedMultiSessionMode = K3bDataDoc::FINISH; + else + d->usedMultiSessionMode = K3bDataDoc::CONTINUE; + } + + else if( info.empty() ) { + // + // We only close the CD if the project fills up the CD almost completely (90%) + // + if( d->doc->size() >= info.capacity().mode1Bytes()*9/10 || + d->doc->writingMode() == K3b::DAO ) + d->usedMultiSessionMode = K3bDataDoc::NONE; + else + d->usedMultiSessionMode = K3bDataDoc::START; + } + + else { // complete (WE SHOULD ACTUALLY NEVER GET HERE SINCE WE WAIT FOR AN EMPTY/APPENDABLE CD ABOVE!) + // + // Now we decide only based on the project size. + // let's just use a 680 MB CD as our reference + // + if( d->doc->size()/1024/1024 >= 680*9/10 || + d->doc->writingMode() == K3b::DAO ) + d->usedMultiSessionMode = K3bDataDoc::NONE; + else + d->usedMultiSessionMode = K3bDataDoc::START; + } + + return d->usedMultiSessionMode; +} + + +void K3bDataJob::cancelAll() +{ + d->canceled = true; + + m_isoImager->cancel(); + m_msInfoFetcher->cancel(); + if( m_writerJob ) + m_writerJob->cancel(); + if( d->verificationJob ) + d->verificationJob->cancel(); + + d->pipe.close(); + + cleanup(); +} + + +bool K3bDataJob::waitForMedium() +{ + emit newSubTask( i18n("Waiting for a medium") ); + if( waitForMedia( d->doc->burner(), + d->usedMultiSessionMode == K3bDataDoc::CONTINUE || + d->usedMultiSessionMode == K3bDataDoc::FINISH ? + K3bDevice::STATE_INCOMPLETE : + K3bDevice::STATE_EMPTY, + K3bDevice::MEDIA_WRITABLE_CD ) < 0 ) { + return false; + } + else + return !d->canceled; +} + + +QString K3bDataJob::jobDescription() const +{ + if( d->doc->onlyCreateImages() ) { + return i18n("Creating Data Image File"); + } + else if( d->doc->multiSessionMode() == K3bDataDoc::NONE || + d->doc->multiSessionMode() == K3bDataDoc::AUTO ) { + return i18n("Writing Data CD") + + ( d->doc->isoOptions().volumeID().isEmpty() + ? QString::null + : QString( " (%1)" ).arg(d->doc->isoOptions().volumeID()) ); + } + else { + return i18n("Writing Multisession CD") + + ( d->doc->isoOptions().volumeID().isEmpty() + ? QString::null + : QString( " (%1)" ).arg(d->doc->isoOptions().volumeID()) ); + } +} + + +QString K3bDataJob::jobDetails() const +{ + if( d->doc->copies() > 1 && + !d->doc->dummy() && + !(d->doc->multiSessionMode() == K3bDataDoc::CONTINUE || + d->doc->multiSessionMode() == K3bDataDoc::FINISH) ) + return i18n("ISO9660 Filesystem (Size: %1) - %n copy", + "ISO9660 Filesystem (Size: %1) - %n copies", + d->doc->copies() ) + .arg(KIO::convertSize( d->doc->size() )); + else + return i18n("ISO9660 Filesystem (Size: %1)") + .arg(KIO::convertSize( d->doc->size() )); +} + + +K3bDataDoc::MultiSessionMode K3bDataJob::usedMultiSessionMode() const +{ + return d->usedMultiSessionMode; +} + + +void K3bDataJob::cleanup() +{ + if( !d->doc->onTheFly() && d->doc->removeImages() ) { + if( QFile::exists( d->doc->tempDir() ) ) { + d->imageFile.remove(); + emit infoMessage( i18n("Removed image file %1").arg(d->doc->tempDir()), K3bJob::SUCCESS ); + } + } + + if( d->tocFile ) { + delete d->tocFile; + d->tocFile = 0; + } +} + + +bool K3bDataJob::hasBeenCanceled() const +{ + return d->canceled; +} + +#include "k3bdatajob.moc" diff --git a/libk3b/projects/datacd/k3bdatajob.h b/libk3b/projects/datacd/k3bdatajob.h new file mode 100644 index 0000000..58de969 --- /dev/null +++ b/libk3b/projects/datacd/k3bdatajob.h @@ -0,0 +1,111 @@ +/* + * + * $Id: k3bdatajob.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BDATAJOB_H +#define K3BDATAJOB_H + +#include +#include + +#include + +class QString; +class QDataStream; +class K3bAbstractWriter; +class K3bIsoImager; +class KTempFile; +class K3bMsInfoFetcher; + +namespace K3bDevice { + class DeviceHandler; + class DiskInfo; +} + +/** + *@author Sebastian Trueg + */ +class K3bDataJob : public K3bBurnJob +{ + Q_OBJECT + + public: + K3bDataJob( K3bDataDoc*, K3bJobHandler*, QObject* parent = 0 ); + virtual ~K3bDataJob(); + + K3bDoc* doc() const; + K3bDevice::Device* writer() const; + + virtual bool hasBeenCanceled() const; + + virtual QString jobDescription() const; + virtual QString jobDetails() const; + + public slots: + void cancel(); + void start(); + + /** + * Used to specify a non-default writer. + * If this does notget called K3bDataJob determines + * the writer itself. + */ + void setWriterJob( K3bAbstractWriter* ); + void setImager( K3bIsoImager* ); + + protected slots: + void slotIsoImagerFinished( bool success ); + void slotIsoImagerPercent(int); + void slotWriterJobPercent( int p ); + void slotWriterNextTrack( int t, int tt ); + void slotWriterJobFinished( bool success ); + void slotVerificationProgress( int ); + void slotVerificationFinished( bool ); + void slotMsInfoFetched(bool); + void slotDetermineMultiSessionMode( K3bDevice::DeviceHandler* dh ); + void writeImage(); + void cancelAll(); + + /** + * Just a little helper method that makes subclassing easier. + * Basically used for DVD writing. + */ + virtual bool waitForMedium(); + + protected: + virtual void prepareData(); + virtual bool prepareWriterJob(); + virtual void prepareImager(); + virtual void determineMultiSessionMode(); + virtual K3bDataDoc::MultiSessionMode getMultiSessionMode( const K3bDevice::DiskInfo& ); + virtual void cleanup(); + + K3bDataDoc::MultiSessionMode usedMultiSessionMode() const; + + K3bAbstractWriter* m_writerJob; + K3bIsoImager* m_isoImager; + K3bMsInfoFetcher* m_msInfoFetcher; + + private: + bool startWriterJob(); + bool startOnTheFlyWriting(); + void prepareWriting(); + void connectImager(); + + class Private; + Private* d; +}; + +#endif diff --git a/libk3b/projects/datacd/k3bdatapreparationjob.cpp b/libk3b/projects/datacd/k3bdatapreparationjob.cpp new file mode 100644 index 0000000..dd29d6d --- /dev/null +++ b/libk3b/projects/datacd/k3bdatapreparationjob.cpp @@ -0,0 +1,283 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bdatapreparationjob.h" +#include "k3bdatadoc.h" +#include "k3bisooptions.h" + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + + +class K3bDataPreparationJob::Private : public K3bThread +{ +public: + Private( K3bDataDoc* doc ); + + void run(); + void cancel(); + + K3bDataDoc* doc; + + QValueList nonExistingItems; + QString listOfRenamedItems; + QValueList folderSymLinkItems; + + K3bThreadJob* threadJob; + + bool canceled; +}; + + +K3bDataPreparationJob::Private::Private( K3bDataDoc* _doc ) + : doc(_doc) +{ +} + + +void K3bDataPreparationJob::Private::run() +{ + emitStarted(); + + // clean up + nonExistingItems.clear(); + listOfRenamedItems.truncate(0); + folderSymLinkItems.clear(); + + // initialize filenames in the project + doc->prepareFilenames(); + + // create the message string for the renamed files + if( doc->needToCutFilenames() ) { + int maxlines = 10; + QValueList::const_iterator it; + for( it = doc->needToCutFilenameItems().begin(); + maxlines > 0 && it != doc->needToCutFilenameItems().end(); + ++it, --maxlines ) { + K3bDataItem* item = *it; + listOfRenamedItems += i18n("%1 renamed to %2") + .arg( KStringHandler::csqueeze( item->k3bName(), 30 ) ) + .arg( KStringHandler::csqueeze( item->writtenName(), 30 ) ); + listOfRenamedItems += "
"; + } + if( it != doc->needToCutFilenameItems().end() ) + listOfRenamedItems += "..."; + } + + // + // Check for missing files and folder symlinks + // + K3bDataItem* item = doc->root(); + while( (item = item->nextSibling()) ) { + + if( item->isSymLink() ) { + if( doc->isoOptions().followSymbolicLinks() ) { + QFileInfo f( K3b::resolveLink( item->localPath() ) ); + if( !f.exists() ) { + nonExistingItems.append( item ); + } + else if( f.isDir() ) { + folderSymLinkItems.append( item ); + } + } + } + else if( item->isFile() && !QFile::exists( item->localPath() ) ) { + nonExistingItems.append( item ); + } + + if( canceled ) { + emitCanceled(); + emitFinished(false); + return; + } + } + + + emitFinished( true ); +} + + +void K3bDataPreparationJob::Private::cancel() +{ + canceled = true; +} + + + + +static QString createItemsString( const QValueList& items, unsigned int max ) +{ + QString s; + unsigned int cnt = 0; + for( QValueList::const_iterator it = items.begin(); + it != items.end(); ++it ) { + + s += KStringHandler::csqueeze( (*it)->localPath(), 60 ); + + ++cnt; + if( cnt >= max || it == items.end() ) + break; + + s += "
"; + } + + if( items.count() > max ) + s += "..."; + + return s; +} + + +K3bDataPreparationJob::K3bDataPreparationJob( K3bDataDoc* doc, K3bJobHandler* hdl, QObject* parent ) + : K3bJob( hdl, parent ) +{ + d = new Private( doc ); + d->threadJob = new K3bThreadJob( d, this, this ); + connectSubJob( d->threadJob, SLOT(slotWorkDone(bool)), K3bJob::DEFAULT_SIGNAL_CONNECTION ); +} + + +K3bDataPreparationJob::~K3bDataPreparationJob() +{ + delete d; +} + + +void K3bDataPreparationJob::start() +{ + if( !active() ) { + d->canceled = false; + jobStarted(); + d->threadJob->start(); + } +} + + +void K3bDataPreparationJob::slotWorkDone( bool success ) +{ + if( success ) { + if( !d->listOfRenamedItems.isEmpty() ) { + if( !questionYesNo( "

" + i18n("Some filenames need to be shortened due to the %1 char restriction " + "of the Joliet extensions. If the Joliet extensions are disabled filenames " + "do not have to be shortened but long filenames will not be available on " + "Windows systems.") + .arg( d->doc->isoOptions().jolietLong() ? 103 : 64 ) + + "

" + d->listOfRenamedItems, + i18n("Warning"), + i18n("Shorten Filenames"), + i18n("Disable Joliet extensions") ) ) { + // No -> disable joliet + // for now we enable RockRidge to be sure we did not lie above (keep long filenames) + K3bIsoOptions op = d->doc->isoOptions(); + op.setCreateJoliet( false ); + op.setCreateRockRidge( true ); + d->doc->setIsoOptions( op ); + d->doc->prepareFilenames(); + } + } + + // + // The joliet extension encodes the volume desc in UCS-2, i.e. uses 16 bit for each char. + // Thus, the max length here is 16. + // + if( d->doc->isoOptions().createJoliet() && + d->doc->isoOptions().volumeID().length() > 16 ) { + if( !questionYesNo( "

" + i18n("The Joliet extensions (which are needed for long filenames on Windows systems) " + "restrict the length of the volume descriptior (the name of the filesystem) " + "to %1 characters. The selected descriptor '%2' is longer than that. Do you " + "want it to be cut or do you want to go back and change it manually?") + .arg( 16 ).arg( d->doc->isoOptions().volumeID() ), + i18n("Warning"), + i18n("Cut volume descriptor in the Joliet tree"), + i18n("Cancel and go back") ) ) { + d->canceled = true; + emit canceled(); + jobFinished( false ); + return; + } + } + + // + // Check for missing files + // + if( !d->nonExistingItems.isEmpty() ) { + if( questionYesNo( "

" + i18n("The following files could not be found. Do you want to remove them from the " + "project and continue without adding them to the image?") + + "

" + createItemsString( d->nonExistingItems, 10 ), + i18n("Warning"), + i18n("Remove missing files and continue"), + i18n("Cancel and go back") ) ) { + for( QValueList::const_iterator it = d->nonExistingItems.begin(); + it != d->nonExistingItems.end(); ++it ) { + delete *it; + } + } + else { + d->canceled = true; + emit canceled(); + jobFinished(false); + return; + } + } + + // + // Warn about symlinks to folders + // + if( d->doc->isoOptions().followSymbolicLinks() && !d->folderSymLinkItems.isEmpty() ) { + if( !questionYesNo( "

" + i18n("K3b is not able to follow symbolic links to folders after they have been added " + "to the project. Do you want to continue " + "without writing the symbolic links to the image?") + + "

" + createItemsString( d->folderSymLinkItems, 10 ), + i18n("Warning"), + i18n("Discard symbolic links to folders"), + i18n("Cancel and go back") ) ) { + d->canceled = true; + emit canceled(); + jobFinished(false); + return; + } + } + + jobFinished( true ); + } + else { + if( d->canceled ) + emit canceled(); + jobFinished(false); + } +} + + +void K3bDataPreparationJob::cancel() +{ + d->cancel(); +} + + +bool K3bDataPreparationJob::hasBeenCanceled() const +{ + return d->canceled; +} + +#include "k3bdatapreparationjob.moc" diff --git a/libk3b/projects/datacd/k3bdatapreparationjob.h b/libk3b/projects/datacd/k3bdatapreparationjob.h new file mode 100644 index 0000000..1c83a42 --- /dev/null +++ b/libk3b/projects/datacd/k3bdatapreparationjob.h @@ -0,0 +1,51 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_DATA_PREPARATION_JOB_H_ +#define _K3B_DATA_PREPARATION_JOB_H_ + +#include + + +class K3bDataDoc; +class K3bJobHandler; + +/** + * The K3bDataPreparationJob performs some checks on the data in a data project + * It is used by th K3bIsoImager. + */ +class K3bDataPreparationJob : public K3bJob +{ + Q_OBJECT + + public: + K3bDataPreparationJob( K3bDataDoc* doc, K3bJobHandler* hdl, QObject* parent ); + ~K3bDataPreparationJob(); + + bool hasBeenCanceled() const; + + public slots: + void start(); + void cancel(); + + private slots: + void slotWorkDone( bool success ); + + private: + class Private; + Private* d; +}; + +#endif diff --git a/libk3b/projects/datacd/k3bdiritem.cpp b/libk3b/projects/datacd/k3bdiritem.cpp new file mode 100644 index 0000000..3ea3236 --- /dev/null +++ b/libk3b/projects/datacd/k3bdiritem.cpp @@ -0,0 +1,406 @@ +/* + * + * $Id: k3bdiritem.cpp 652578 2007-04-11 14:21:04Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bdiritem.h" +#include "k3bdatadoc.h" +#include "k3bsessionimportitem.h" +#include "k3bfileitem.h" + +#include +#include + +#include + + +K3bDirItem::K3bDirItem(const QString& name, K3bDataDoc* doc, K3bDirItem* parentDir) + : K3bDataItem( doc, parentDir ), + m_size(0), + m_followSymlinksSize(0), + m_blocks(0), + m_followSymlinksBlocks(0), + m_files(0), + m_dirs(0) +{ + m_k3bName = name; + + // add automagically like a qlistviewitem + if( parent() ) + parent()->addDataItem( this ); +} + + +K3bDirItem::K3bDirItem( const K3bDirItem& item ) + : K3bDataItem( item ), + m_size(0), + m_followSymlinksSize(0), + m_blocks(0), + m_followSymlinksBlocks(0), + m_files(0), + m_dirs(0), + m_localPath( item.m_localPath ) +{ + for( QPtrListIterator it( item.children() ); *it; ++it ) + addDataItem( (*it)->copy() ); +} + +K3bDirItem::~K3bDirItem() +{ + // delete all children + // doing this by hand is much saver than using the + // auto-delete feature since some of the items' destructors + // may change the list + K3bDataItem* i = m_children.first(); + while( i ) { + // it is important to use takeDataItem here to be sure + // the size gets updated properly + takeDataItem(i); + delete i; + i = m_children.first(); + } + + // this has to be done after deleting the children + // because the directory itself has a size of 0 in K3b + // and all it's files' sizes have already been substracted + take(); +} + + +K3bDataItem* K3bDirItem::copy() const +{ + return new K3bDirItem( *this ); +} + + +K3bDirItem* K3bDirItem::getDirItem() const +{ + return const_cast(this); +} + +K3bDirItem* K3bDirItem::addDataItem( K3bDataItem* item ) +{ + // check if we are a subdir of item + if( K3bDirItem* dirItem = dynamic_cast(item) ) { + if( dirItem->isSubItem( this ) ) { + kdDebug() << "(K3bDirItem) trying to move a dir item down in it's own tree." << endl; + return this; + } + } + + if( m_children.findRef( item ) == -1 ) { + if( item->isFile() ) { + // do we replace an old item? + QString name = item->k3bName(); + int cnt = 1; + while( K3bDataItem* oldItem = find( name ) ) { + if( !oldItem->isDir() && oldItem->isFromOldSession() ) { + // in this case we remove this item from it's parent and save it in the new one + // to be able to recover it + oldItem->take(); + static_cast(oldItem)->setReplaceItem( static_cast(item) ); + static_cast(item)->setReplacedItemFromOldSession( oldItem ); + break; + } + else { + // + // add a counter to the filename + // + if( item->k3bName()[item->k3bName().length()-4] == '.' ) + name = item->k3bName().left( item->k3bName().length()-4 ) + QString::number(cnt++) + item->k3bName().right(4); + else + name = item->k3bName() + QString::number(cnt++); + } + } + item->setK3bName( name ); + } + + m_children.append( item->take() ); + updateSize( item, false ); + if( item->isDir() ) + updateFiles( ((K3bDirItem*)item)->numFiles(), ((K3bDirItem*)item)->numDirs()+1 ); + else + updateFiles( 1, 0 ); + + item->m_parentDir = this; + + // inform the doc + if( doc() ) + doc()->itemAddedToDir( this, item ); + } + + return this; +} + + +K3bDataItem* K3bDirItem::takeDataItem( K3bDataItem* item ) +{ + int x = m_children.findRef( item ); + if( x > -1 ) { + K3bDataItem* item = m_children.take(); + updateSize( item, true ); + if( item->isDir() ) + updateFiles( -1*((K3bDirItem*)item)->numFiles(), -1*((K3bDirItem*)item)->numDirs()-1 ); + else + updateFiles( -1, 0 ); + + item->m_parentDir = 0; + + // inform the doc + if( doc() ) + doc()->itemRemovedFromDir( this, item ); + + if( item->isFile() ) { + // restore the item imported from an old session + if( static_cast(item)->replaceItemFromOldSession() ) + addDataItem( static_cast(item)->replaceItemFromOldSession() ); + } + + return item; + } + else + return 0; +} + + +K3bDataItem* K3bDirItem::nextSibling() const +{ + if( !m_children.isEmpty() ) + return m_children.getFirst(); + else + return K3bDataItem::nextSibling(); +} + + +K3bDataItem* K3bDirItem::nextChild( K3bDataItem* prev ) const +{ + // search for prev in children + if( m_children.findRef( prev ) < 0 ) { + return 0; + } + else + return m_children.next(); +} + + +bool K3bDirItem::alreadyInDirectory( const QString& filename ) const +{ + return (find( filename ) != 0); +} + + +K3bDataItem* K3bDirItem::find( const QString& filename ) const +{ + for( QPtrListIterator it( m_children ); it.current(); ++it ) { + if( it.current()->k3bName() == filename ) + return it.current(); + } + return 0; +} + + +K3bDataItem* K3bDirItem::findByPath( const QString& p ) +{ + if( p.isEmpty() || p == "/" ) + return this; + + QString path = p; + if( path.startsWith("/") ) + path = path.mid(1); + int pos = path.find( "/" ); + if( pos < 0 ) + return find( path ); + else { + // do it recursivly + K3bDataItem* item = find( path.left(pos) ); + if( item && item->isDir() ) + return ((K3bDirItem*)item)->findByPath( path.mid( pos+1 ) ); + else + return 0; + } +} + + +bool K3bDirItem::mkdir( const QString& dirPath ) +{ + // + // An absolut path always starts at the root item + // + if( dirPath[0] == '/' ) { + if( parent() ) + return parent()->mkdir( dirPath ); + else + return mkdir( dirPath.mid( 1 ) ); + } + + if( findByPath( dirPath ) ) + return false; + + QString restPath; + QString dirName; + int pos = dirPath.find( '/' ); + if( pos == -1 ) { + dirName = dirPath; + } + else { + dirName = dirPath.left( pos ); + restPath = dirPath.mid( pos+1 ); + } + + K3bDataItem* dir = find( dirName ); + if( !dir ) + dir = new K3bDirItem( dirName, doc(), this ); + else if( !dir->isDir() ) + return false; + + if( !restPath.isEmpty() ) + return static_cast(dir)->mkdir( restPath ); + + return true; +} + + +KIO::filesize_t K3bDirItem::itemSize( bool followsylinks ) const +{ + if( followsylinks ) + return m_followSymlinksSize; + else + return m_size; +} + + +K3b::Msf K3bDirItem::itemBlocks( bool followSymlinks ) const +{ + if( followSymlinks ) + return m_followSymlinksBlocks; + else + return m_blocks; +} + + +bool K3bDirItem::isSubItem( K3bDataItem* item ) const +{ + if( dynamic_cast(item) == this ) + return true; + + K3bDirItem* d = item->parent(); + while( d ) { + if( d == this ) { + return true; + } + d = d->parent(); + } + + return false; +} + + +long K3bDirItem::numFiles() const +{ + return m_files; +} + + +long K3bDirItem::numDirs() const +{ + return m_dirs; +} + + +bool K3bDirItem::isRemoveable() const +{ + if( !K3bDataItem::isRemoveable() ) + return false; + + for( QPtrListIterator it( m_children ); it.current(); ++it ) { + if( !it.current()->isRemoveable() ) + return false; + } + + return true; +} + + +void K3bDirItem::updateSize( K3bDataItem* item, bool removed ) +{ + if ( !item->isFromOldSession() ) { + if( removed ) { + m_followSymlinksSize -= item->itemSize( true ); + m_size -= item->itemSize( false ); + m_followSymlinksBlocks -= item->itemBlocks( true ).lba(); + m_blocks -= item->itemBlocks( false ).lba(); + } + else { + m_followSymlinksSize += item->itemSize( true ); + m_size += item->itemSize( false ); + m_followSymlinksBlocks += item->itemBlocks( true ).lba(); + m_blocks += item->itemBlocks( false ).lba(); + } + } + + if( parent() ) + parent()->updateSize( item, removed ); +} + +void K3bDirItem::updateFiles( long files, long dirs ) +{ + m_files += files; + m_dirs += dirs; + if( parent() ) + parent()->updateFiles( files, dirs ); +} + + +bool K3bDirItem::isFromOldSession() const +{ + for( QPtrListIterator it( m_children ); it.current(); ++it ) { + if( (*it)->isFromOldSession() ) + return true; + } + return false; +} + + +bool K3bDirItem::writeToCd() const +{ + // check if this dir contains items to write + for( QPtrListIterator it( m_children ); it.current(); ++it ) { + if( (*it)->writeToCd() ) + return true; + } + return K3bDataItem::writeToCd(); +} + + +K3bRootItem::K3bRootItem( K3bDataDoc* doc ) + : K3bDirItem( "root", doc, 0 ) +{ +} + + +K3bRootItem::~K3bRootItem() +{ +} + + +const QString& K3bRootItem::k3bName() const +{ + return doc()->isoOptions().volumeID(); +} + + +void K3bRootItem::setK3bName( const QString& text ) +{ + doc()->setVolumeID( text ); +} diff --git a/libk3b/projects/datacd/k3bdiritem.h b/libk3b/projects/datacd/k3bdiritem.h new file mode 100644 index 0000000..a64b4fd --- /dev/null +++ b/libk3b/projects/datacd/k3bdiritem.h @@ -0,0 +1,155 @@ +/* + * + * $Id: k3bdiritem.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BDIRITEM_H +#define K3BDIRITEM_H + + +#include +#include + +#include + +#include "k3bdataitem.h" +#include "k3b_export.h" +class K3bDataDoc; + +/** + *@author Sebastian Trueg + */ + +class LIBK3B_EXPORT K3bDirItem : public K3bDataItem +{ + public: + K3bDirItem( const QString& name, K3bDataDoc*, K3bDirItem* parentDir = 0 ); + + /** + * Default copy constructor. Copies the dir including all children. However, none of the + * children will have set a doc and the copy dir will not have set a parent dir. + */ + K3bDirItem( const K3bDirItem& ); + + virtual ~K3bDirItem(); + + K3bDataItem* copy() const; + + K3bDirItem* getDirItem() const; + + const QPtrList& children() const { return m_children; } + K3bDirItem* addDataItem( K3bDataItem* item ); + K3bDataItem* takeDataItem( K3bDataItem* item ); + + K3bDataItem* nextSibling() const; + K3bDataItem* nextChild( K3bDataItem* ) const; + + bool alreadyInDirectory( const QString& fileName ) const; + K3bDataItem* find( const QString& filename ) const; + K3bDataItem* findByPath( const QString& ); + + long numFiles() const; + long numDirs() const; + + bool isEmpty() const { return ( numDirs() + numFiles() == 0 ); } + + /** + * returns true if item is a subItem of + * this dir item + * (returns also true if item == this + */ + bool isSubItem( K3bDataItem* item ) const; + + bool isDir() const { return true; } + + virtual bool isRemoveable() const; + + /** + * \return true if some child is from an old session. + */ + virtual bool isFromOldSession() const; + + /** + * Recursively creates a directory. + */ + bool mkdir( const QString& dir ); + + void setLocalPath( const QString& p ) { m_localPath = p; } + QString localPath() const { return m_localPath; } + + /** + * \reimplemented + */ + bool writeToCd() const; + + protected: + /** + * Normally one does not use this method but K3bDataItem::size() + * + * This method does not take into account the possibility to share the data + * between files with the same inode in an iso9660 filesystem. + * For that one has to use K3bFileCompilationSizeHandler. + */ + KIO::filesize_t itemSize( bool followSymlinks ) const; + + /* + * Normally one does not use this method but K3bDataItem::blocks() + */ + K3b::Msf itemBlocks( bool followSymlinks ) const; + + private: + /** + * this recursivly updates the size of the directories. + * The size of this dir and the parent dir is updated. + * These values are just used for user information. + */ + void updateSize( K3bDataItem*, bool removed = false ); + /** + * Updates the number of files and directories. These values are + * just used for user information. + */ + void updateFiles( long files, long dirs ); + + mutable QPtrList m_children; + + // size of the items simply added + KIO::filesize_t m_size; + KIO::filesize_t m_followSymlinksSize; + + // number of blocks (2048 bytes) used by all the items + long m_blocks; + long m_followSymlinksBlocks; + + long m_files; + long m_dirs; + + // HACK: store the original path to be able to use it's permissions + // remove this once we have a backup project + QString m_localPath; +}; + + +class K3bRootItem : public K3bDirItem +{ + public: + K3bRootItem( K3bDataDoc* ); + ~K3bRootItem(); + + const QString& k3bName() const; + void setK3bName( const QString& ); + + bool isMoveable() const { return false; } + bool isRemoveable() const { return false; } +}; +#endif diff --git a/libk3b/projects/datacd/k3bfilecompilationsizehandler.cpp b/libk3b/projects/datacd/k3bfilecompilationsizehandler.cpp new file mode 100644 index 0000000..0ddab76 --- /dev/null +++ b/libk3b/projects/datacd/k3bfilecompilationsizehandler.cpp @@ -0,0 +1,228 @@ +/* + * + * $Id: k3bfilecompilationsizehandler.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bfilecompilationsizehandler.h" +#include "k3bfileitem.h" + +#include + +#include +#include +#include + + +// TODO: remove the items from the project if the savedSize differs +// with some info-widget: "Files xxx have changed on disk. Removing them from the project." +// or we just update the sizes! + + +static long usedBlocks( const KIO::filesize_t& bytes ) +{ + if( bytes % 2048 ) + return bytes/2048 + 1; + else + return bytes/2048; +} + + +class InodeInfo +{ +public: + InodeInfo() { + number = 0; + savedSize = 0; + } + + /** + * How often has the file with + * the corresponding inode been added + */ + int number; + + /** + * The size of the first added file. This has to be saved + * to check further addings and to avoid the following situation: + * A file with inode 1 is added, then deleted. Another file is created + * at inode 1 and added to the project. Now the first file gets + * removed and then the second. If we had not saved the size we would + * have added the size of the first and removed the size of the second + * file resulting in a corrupted project size. + * This way we always use the size of the first added file and may + * warn the user if sizes differ. + */ + KIO::filesize_t savedSize; + + KIO::filesize_t completeSize() const { return savedSize*number; } + + /** + * In an iso9660 filesystem a file occupies complete blocks of 2048 bytes. + */ + K3b::Msf blocks() const { return K3b::Msf( usedBlocks(savedSize) ); } + + QPtrList items; +}; + + +class K3bFileCompilationSizeHandler::Private +{ +public: + Private() + : size(0) { + } + + void clear() { + inodeMap.clear(); + size = 0; + blocks = 0; + } + + void addFile( K3bFileItem* item, bool followSymlinks ) { + InodeInfo& inodeInfo = inodeMap[item->localId(followSymlinks)]; + + inodeInfo.items.append( item ); + + if( inodeInfo.number == 0 ) { + inodeInfo.savedSize = item->itemSize( followSymlinks ); + + size += inodeInfo.savedSize; + blocks += inodeInfo.blocks(); + } + + inodeInfo.number++; + } + + void addSpecialItem( K3bDataItem* item ) { + // special files do not have a corresponding local file + // so we just add their k3bSize + size += item->size(); + blocks += usedBlocks(item->size()); + specialItems.append( item ); + } + + void removeFile( K3bFileItem* item, bool followSymlinks ) { + InodeInfo& inodeInfo = inodeMap[item->localId(followSymlinks)]; + + if( inodeInfo.items.findRef( item ) == -1 ) { + kdError() << "(K3bFileCompilationSizeHandler) " + << item->localPath() + << " has been removed without being added!" << endl; + } + else { + if( item->itemSize(followSymlinks) != inodeInfo.savedSize ) { + kdError() << "(K3bFileCompilationSizeHandler) savedSize differs!" << endl; + } + + inodeInfo.items.removeRef( item ); + inodeInfo.number--; + if( inodeInfo.number == 0 ) { + size -= inodeInfo.savedSize; + blocks -= inodeInfo.blocks(); + } + } + } + + void removeSpecialItem( K3bDataItem* item ) { + // special files do not have a corresponding local file + // so we just substract their k3bSize + if( specialItems.findRef( item ) == -1 ) { + kdError() << "(K3bFileCompilationSizeHandler) Special item " + << item->k3bName() + << " has been removed without being added!" << endl; + } + else { + specialItems.removeRef( item ); + size -= item->size(); + blocks -= usedBlocks(item->size()); + } + } + + + /** + * This maps from inodes to the number of occurrences of the inode. + */ + QMap inodeMap; + + KIO::filesize_t size; + K3b::Msf blocks; + + QPtrList specialItems; +}; + + + +K3bFileCompilationSizeHandler::K3bFileCompilationSizeHandler() +{ + d_symlinks = new Private; + d_noSymlinks = new Private; +} + +K3bFileCompilationSizeHandler::~K3bFileCompilationSizeHandler() +{ + delete d_symlinks; + delete d_noSymlinks; +} + + +const KIO::filesize_t& K3bFileCompilationSizeHandler::size( bool followSymlinks ) const +{ + if( followSymlinks ) + return d_noSymlinks->size; + else + return d_symlinks->size; +} + + +const K3b::Msf& K3bFileCompilationSizeHandler::blocks( bool followSymlinks ) const +{ + if( followSymlinks ) + return d_noSymlinks->blocks; + else + return d_symlinks->blocks; +} + + +void K3bFileCompilationSizeHandler::addFile( K3bDataItem* item ) +{ + if( item->isSpecialFile() ) { + d_symlinks->addSpecialItem( item ); + d_noSymlinks->addSpecialItem( item ); + } + else if( item->isFile() ) { + K3bFileItem* fileItem = static_cast( item ); + d_symlinks->addFile( fileItem, false ); + d_noSymlinks->addFile( fileItem, true ); + } +} + + +void K3bFileCompilationSizeHandler::removeFile( K3bDataItem* item ) +{ + if( item->isSpecialFile() ) { + d_symlinks->removeSpecialItem( item ); + d_noSymlinks->removeSpecialItem( item ); + } + else if( item->isFile() ) { + K3bFileItem* fileItem = static_cast( item ); + d_symlinks->removeFile( fileItem, false ); + d_noSymlinks->removeFile( fileItem, true ); + } +} + + +void K3bFileCompilationSizeHandler::clear() +{ + d_symlinks->clear(); + d_noSymlinks->clear(); +} diff --git a/libk3b/projects/datacd/k3bfilecompilationsizehandler.h b/libk3b/projects/datacd/k3bfilecompilationsizehandler.h new file mode 100644 index 0000000..c996657 --- /dev/null +++ b/libk3b/projects/datacd/k3bfilecompilationsizehandler.h @@ -0,0 +1,73 @@ +/* + * + * $Id: k3bfilecompilationsizehandler.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_FILECOMPILATION_SIZE_HANDLER_H_ +#define _K3B_FILECOMPILATION_SIZE_HANDLER_H_ + + +#include +#include + +class K3bDataItem; + + +/** + * This class maintains a map of indoes and the number + * of files in the doc that belong to that inode. + * This way a more accurate size calculation is possible + * + * It has to be noted that the sizes of the directories + * are only locally true. That means that in some cases + * the root directory of the project may show a much + * higher size than calculated by this class. + */ +class K3bFileCompilationSizeHandler +{ + public: + K3bFileCompilationSizeHandler(); + ~K3bFileCompilationSizeHandler(); + + /** + * This does NOT equal blocks() * 2048. + * This is the sum of the actual file sizes. + */ + const KIO::filesize_t& size( bool followSymlinks = false ) const; + + /** + * Number of blocks the files will occupy. + */ + const K3b::Msf& blocks( bool followSymlinks = false ) const; + + /** + * This will increase the counter for the inode of + * the file in url and update the totel size. + */ + void addFile( K3bDataItem* ); + + /** + * This will decrease the counter for the inode of + * the file in url and update the totel size. + */ + void removeFile( K3bDataItem* ); + + void clear(); + + private: + class Private; + Private* d_symlinks; + Private* d_noSymlinks; +}; + +#endif diff --git a/libk3b/projects/datacd/k3bfileitem.cpp b/libk3b/projects/datacd/k3bfileitem.cpp new file mode 100644 index 0000000..d9e288f --- /dev/null +++ b/libk3b/projects/datacd/k3bfileitem.cpp @@ -0,0 +1,300 @@ +/* + * + * $Id: k3bfileitem.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include +#include + +#include "k3bfileitem.h" +#include "k3bdatadoc.h" +#include "k3bdiritem.h" +#include "k3bisooptions.h" +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + + +bool operator==( const K3bFileItem::Id& id1, const K3bFileItem::Id& id2 ) +{ + return ( id1.device == id2.device && id1.inode == id2.inode ); +} + + +bool operator<( const K3bFileItem::Id& id1, const K3bFileItem::Id& id2 ) +{ + if( id1.device == id2.device ) + return ( id1.inode < id2.inode ); + else + return ( id1.device < id2.device ); +} + + +bool operator>( const K3bFileItem::Id& id1, const K3bFileItem::Id& id2 ) +{ + return !( id2 < id1 || id1 == id2 ); +} + + + +K3bFileItem::K3bFileItem( const QString& filePath, K3bDataDoc* doc, K3bDirItem* dir, const QString& k3bName, int flags ) + : K3bDataItem( doc, dir, flags ), + m_replacedItemFromOldSession(0), + m_localPath(filePath) +{ + if( k3bName.isEmpty() ) + m_k3bName = filePath.section( '/', -1 ); + else + m_k3bName = k3bName; + + // we determine the size here to avoid problems with removed or renamed files + // we need to use lstat here since for symlinks both KDE and QT return the size of the file pointed to + // instead the size of the link. + k3b_struct_stat statBuf; + if( k3b_lstat( QFile::encodeName(filePath), &statBuf ) ) { + m_size = K3b::filesize( filePath ); + m_id.inode = 0; + m_id.device = 0; + m_bSymLink = false; + + kdError() << "(KFileItem) lstat failed: " << strerror(errno) << endl; + + // since we have no proper inode info, disable the inode caching in the doc + if( doc ) { + K3bIsoOptions o( doc->isoOptions() ); + o.setDoNotCacheInodes( true ); + doc->setIsoOptions( o ); + } + } + else { + m_size = (KIO::filesize_t)statBuf.st_size; + + m_bSymLink = S_ISLNK(statBuf.st_mode); + + // + // integrate the device number into the inode since files on different + // devices may have the same inode number! + // + m_id.inode = statBuf.st_ino; + m_id.device = statBuf.st_dev; + } + + m_idFollowed = m_id; + m_sizeFollowed = m_size; + + if( isSymLink() ) { + k3b_struct_stat statBuf; + if( k3b_stat( QFile::encodeName(filePath), &statBuf ) == 0 ) { + m_idFollowed.inode = statBuf.st_ino; + m_idFollowed.device = statBuf.st_dev; + + m_sizeFollowed = (KIO::filesize_t)statBuf.st_size; + } + } + + // add automagically like a qlistviewitem + if( parent() ) + parent()->addDataItem( this ); +} + + +K3bFileItem::K3bFileItem( const k3b_struct_stat* stat, + const k3b_struct_stat* followedStat, + const QString& filePath, K3bDataDoc* doc, K3bDirItem* dir, const QString& k3bName ) + : K3bDataItem( doc, dir ), + m_replacedItemFromOldSession(0), + m_localPath(filePath) +{ + if( k3bName.isEmpty() ) + m_k3bName = filePath.section( '/', -1 ); + else + m_k3bName = k3bName; + + m_size = (KIO::filesize_t)stat->st_size; + m_bSymLink = S_ISLNK(stat->st_mode); + + // + // integrate the device number into the inode since files on different + // devices may have the same inode number! + // + m_id.inode = stat->st_ino; + m_id.device = stat->st_dev; + + if( isSymLink() ) { + m_idFollowed.inode = followedStat->st_ino; + m_idFollowed.device = followedStat->st_dev; + + m_sizeFollowed = (KIO::filesize_t)followedStat->st_size; + } + else { + m_idFollowed = m_id; + m_sizeFollowed = m_size; + } + + if( parent() ) + parent()->addDataItem( this ); +} + + +K3bFileItem::K3bFileItem( const K3bFileItem& item ) + : K3bDataItem( item ), + m_replacedItemFromOldSession(0), + m_size( item.m_size ), + m_sizeFollowed( item.m_sizeFollowed ), + m_id( item.m_id ), + m_idFollowed( item.m_idFollowed ), + m_localPath( item.m_localPath ), + m_bSymLink( item.m_bSymLink ) +{ +} + + +K3bFileItem::~K3bFileItem() +{ + // remove this from parentdir + take(); +} + + +K3bDataItem* K3bFileItem::copy() const +{ + return new K3bFileItem( *this ); +} + + +KIO::filesize_t K3bFileItem::itemSize( bool followSymlinks ) const +{ + if( followSymlinks ) + return m_sizeFollowed; + else + return m_size; +} + + +K3bFileItem::Id K3bFileItem::localId() const +{ + return localId( doc() ? doc()->isoOptions().followSymbolicLinks() || !doc()->isoOptions().createRockRidge() : false ); +} + + +K3bFileItem::Id K3bFileItem::localId( bool followSymlinks ) const +{ + if( followSymlinks ) + return m_idFollowed; + else + return m_id; +} + + +bool K3bFileItem::exists() const +{ + return true; +} + +QString K3bFileItem::absIsoPath() +{ + // return m_dir->absIsoPath() + m_isoName; + return QString::null; +} + + +QString K3bFileItem::localPath() const +{ + return m_localPath; +} + +K3bDirItem* K3bFileItem::getDirItem() const +{ + return getParent(); +} + + +bool K3bFileItem::isSymLink() const +{ + return m_bSymLink; +} + + +QString K3bFileItem::linkDest() const +{ + return QFileInfo( localPath() ).readLink(); +} + + +bool K3bFileItem::isValid() const +{ + if( isSymLink() ) { + + // this link is not valid if we cannot follow it if we want to + if( doc()->isoOptions().followSymbolicLinks() ) { + return QFile::exists( K3b::resolveLink( localPath() ) ); + } + + QString dest = linkDest(); + + if( dest[0] == '/' ) + return false; // absolut links can never be part of the compilation! + + // parse the link + K3bDirItem* dir = getParent(); + + QStringList tokens = QStringList::split( QRegExp("/+"), dest ); // two slashes or more do the same as one does! + + unsigned int i = 0; + while( i < tokens.size() ) { + if( tokens[i] == "." ) { + // ignore it + } + else if( tokens[i] == ".." ) { + // change the directory + dir = dir->parent(); + if( dir == 0 ) + return false; + } + else { + // search for the item in dir + K3bDataItem* d = dir->find( tokens[i] ); + if( d == 0 ) + return false; + + if( d->isDir() ) { + // change directory + dir = (K3bDirItem*)d; + } + else { + if( i+1 != tokens.size() ) + return false; // if di is a file we need to be at the last token + else + return (dest[dest.length()-1] != '/'); // if the link destination ends with a slash + // it can only point to a directory! + } + } + + i++; + } + + return true; + } + else + return true; +} diff --git a/libk3b/projects/datacd/k3bfileitem.h b/libk3b/projects/datacd/k3bfileitem.h new file mode 100644 index 0000000..f23644f --- /dev/null +++ b/libk3b/projects/datacd/k3bfileitem.h @@ -0,0 +1,124 @@ +/* + * + * $Id: k3bfileitem.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BFILEITEM_H +#define K3BFILEITEM_H + + +#include "k3bdataitem.h" +#include + +#include +#include + +#include "k3b_export.h" + +class K3bDataDoc; +class K3bDirItem; + + +/** + *@author Sebastian Trueg + */ +class LIBK3B_EXPORT K3bFileItem : public K3bDataItem +{ +public: + /** + * Creates a new K3bFileItem + */ + K3bFileItem( const QString& fileName, K3bDataDoc* doc, K3bDirItem* dir, const QString& k3bName = 0, int flags = 0 ); + + /** + * Constructor for optimized file item creation which does no additional stat. + * + * Used by K3b to speedup file item creation. + */ + K3bFileItem( const k3b_struct_stat* stat, + const k3b_struct_stat* followedStat, + const QString& fileName, K3bDataDoc* doc, K3bDirItem* dir, const QString& k3bName = 0 ); + + /** + * Default copy constructor + * Creates a copy of the fileitem. The copy, however, is not an exact duplicate of this item. + * The copy does not have a parent dir set and any old session items are set to 0. + */ + K3bFileItem( const K3bFileItem& ); + + virtual ~K3bFileItem(); + + virtual K3bDataItem* copy() const; + + bool exists() const; + + QString absIsoPath(); + + /** reimplemented from K3bDataItem */ + QString localPath() const; + + /** + * Identification of the files on the local device. + */ + struct Id { + dev_t device; + ino_t inode; + }; + + /** + * This is not the normal inode number but it also contains + * the device number. + */ + Id localId() const; + + /** + * The id of the file the symlink is pointing to + */ + Id localId( bool followSymlinks ) const; + + K3bDirItem* getDirItem() const; + + bool isSymLink() const; + QString linkDest() const; + bool isFile() const { return true; } + + /** returns true if the item is not a link or + * if the link's destination is part of the compilation */ + bool isValid() const; + + K3bDataItem* replaceItemFromOldSession() const { return m_replacedItemFromOldSession; } + void setReplacedItemFromOldSession( K3bDataItem* item ) { m_replacedItemFromOldSession = item; } + + /** + * Normally one does not use this method but K3bDataItem::size() + */ + KIO::filesize_t itemSize( bool followSymlinks ) const; + + private: + K3bDataItem* m_replacedItemFromOldSession; + + KIO::filesize_t m_size; + KIO::filesize_t m_sizeFollowed; + Id m_id; + Id m_idFollowed; + + QString m_localPath; + bool m_bSymLink; +}; + +bool operator==( const K3bFileItem::Id&, const K3bFileItem::Id& ); +bool operator<( const K3bFileItem::Id&, const K3bFileItem::Id& ); +bool operator>( const K3bFileItem::Id&, const K3bFileItem::Id& ); + +#endif diff --git a/libk3b/projects/datacd/k3bisoimager.cpp b/libk3b/projects/datacd/k3bisoimager.cpp new file mode 100644 index 0000000..f44d3ab --- /dev/null +++ b/libk3b/projects/datacd/k3bisoimager.cpp @@ -0,0 +1,1187 @@ +/* + * + * $Id: k3bisoimager.cpp 655085 2007-04-17 17:48:36Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include +#include + +#include "k3bisoimager.h" +#include "k3bdiritem.h" +#include "k3bbootitem.h" +#include "k3bdatadoc.h" +#include "k3bdatapreparationjob.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +int K3bIsoImager::s_imagerSessionCounter = 0; + + +class K3bIsoImager::Private +{ +public: + Private() + : pipe(0) { + } + + ~Private() { + delete pipe; + } + + QString imagePath; + K3bFileSplitter imageFile; + const K3bExternalBin* mkisofsBin; + + enum LinkHandling { + KEEP_ALL, + FOLLOW, + DISCARD_ALL, + DISCARD_BROKEN + }; + + int usedLinkHandling; + + bool knownError; + + K3bActivePipe* pipe; + K3bDataPreparationJob* dataPreparationJob; +}; + + +K3bIsoImager::K3bIsoImager( K3bDataDoc* doc, K3bJobHandler* hdl, QObject* parent, const char* name ) + : K3bJob( hdl, parent, name ), + m_pathSpecFile(0), + m_rrHideFile(0), + m_jolietHideFile(0), + m_sortWeightFile(0), + m_process( 0 ), + m_processExited(false), + m_doc( doc ), + m_noDeepDirectoryRelocation( false ), + m_importSession( false ), + m_device(0), + m_mkisofsPrintSizeResult( 0 ), + m_fdToWriteTo(-1) +{ + d = new Private(); + d->dataPreparationJob = new K3bDataPreparationJob( doc, this, this ); + connectSubJob( d->dataPreparationJob, + SLOT(slotDataPreparationDone(bool)), + DEFAULT_SIGNAL_CONNECTION ); +} + + +K3bIsoImager::~K3bIsoImager() +{ + cleanup(); + delete d; +} + + +bool K3bIsoImager::active() const +{ + return K3bJob::active(); +} + + +void K3bIsoImager::writeToFd( int fd ) +{ + m_fdToWriteTo = fd; +} + + +void K3bIsoImager::writeToImageFile( const QString& path ) +{ + d->imagePath = path; + m_fdToWriteTo = -1; +} + + +void K3bIsoImager::slotReceivedStderr( const QString& line ) +{ + parseMkisofsOutput( line ); + emit debuggingOutput( "mkisofs", line ); +} + + +void K3bIsoImager::handleMkisofsProgress( int p ) +{ + emit percent( p ); +} + + +void K3bIsoImager::handleMkisofsInfoMessage( const QString& line, int type ) +{ + emit infoMessage( line, type ); + if( type == ERROR ) + d->knownError = true; +} + + +void K3bIsoImager::slotProcessExited( KProcess* p ) +{ + kdDebug() << k_funcinfo << endl; + + m_processExited = true; + + d->pipe->close(); + + emit debuggingOutput( "K3bIsoImager", + QString("Pipe throughput: %1 bytes read, %2 bytes written.") + .arg(d->pipe->bytesRead()).arg(d->pipe->bytesWritten()) ); + + if( d->imageFile.isOpen() ) { + d->imageFile.close(); + + if( m_canceled || p->exitStatus() != 0 ) { + d->imageFile.remove(); + emit infoMessage( i18n("Removed incomplete image file %1.").arg(d->imageFile.name()), WARNING ); + } + } + + if( m_canceled ) { + emit canceled(); + jobFinished(false); + } + else { + if( p->normalExit() ) { + if( p->exitStatus() == 0 ) { + jobFinished( !mkisofsReadError() ); + } + else { + switch( p->exitStatus() ) { + case 104: + // connection reset by peer + // This only happens if cdrecord does not finish successfully + // so we may leave the error handling to it meaning we handle this + // as a known error + break; + + case 2: + // mkisofs seems to have a bug that prevents to use filenames + // that contain one or more backslashes + // mkisofs 1.14 has the bug, 1.15a40 not + // TODO: find out the version that fixed the bug + if( m_containsFilesWithMultibleBackslashes && + !k3bcore->externalBinManager()->binObject( "mkisofs" )->hasFeature( "backslashed_filenames" ) ) { + emit infoMessage( i18n("Due to a bug in mkisofs <= 1.15a40, K3b is unable to handle " + "filenames that contain more than one backslash:"), ERROR ); + + break; + } + // otherwise just fall through + + default: + if( !d->knownError && !mkisofsReadError() ) { + emit infoMessage( i18n("%1 returned an unknown error (code %2).").arg("mkisofs").arg(p->exitStatus()), + K3bJob::ERROR ); + emit infoMessage( i18n("Please send me an email with the last output."), K3bJob::ERROR ); + } + } + + jobFinished( false ); + } + } + else { + emit infoMessage( i18n("%1 did not exit cleanly.").arg("mkisofs"), ERROR ); + jobFinished( false ); + } + } + + cleanup(); +} + + +void K3bIsoImager::cleanup() +{ + // remove all temp files + delete m_pathSpecFile; + delete m_rrHideFile; + delete m_jolietHideFile; + delete m_sortWeightFile; + + // remove boot-images-temp files + for( QStringList::iterator it = m_tempFiles.begin(); + it != m_tempFiles.end(); ++it ) + QFile::remove( *it ); + m_tempFiles.clear(); + + m_pathSpecFile = m_jolietHideFile = m_rrHideFile = m_sortWeightFile = 0; + + delete m_process; + m_process = 0; + + clearDummyDirs(); +} + + +void K3bIsoImager::init() +{ + jobStarted(); + + cleanup(); + + d->dataPreparationJob->start(); +} + + +void K3bIsoImager::slotDataPreparationDone( bool success ) +{ + if( success ) { + // + // We always calculate the image size. It does not take long and at least the mixed job needs it + // anyway + // + startSizeCalculation(); + } + else { + if( d->dataPreparationJob->hasBeenCanceled() ) { + m_canceled = true; + emit canceled(); + } + jobFinished( false ); + } +} + + +void K3bIsoImager::calculateSize() +{ + jobStarted(); + startSizeCalculation(); +} + + +void K3bIsoImager::startSizeCalculation() +{ + d->mkisofsBin = initMkisofs(); + if( !d->mkisofsBin ) { + jobFinished( false ); + return; + } + + initVariables(); + + delete m_process; + m_process = new K3bProcess(); + m_process->setRunPrivileged(true); + m_process->setSplitStdout(true); + + emit debuggingOutput( "Used versions", "mkisofs: " + d->mkisofsBin->version ); + + *m_process << d->mkisofsBin; + + if( !prepareMkisofsFiles() || + !addMkisofsParameters(true) ) { + cleanup(); + jobFinished( false ); + return; + } + + // add empty dummy dir since one path-spec is needed + // ??? Seems it is not needed after all. At least mkisofs 1.14 and above don't need it. ??? + // *m_process << dummyDir(); + + kdDebug() << "***** mkisofs calculate size parameters:\n"; + const QValueList& args = m_process->args(); + QString s; + for( QValueList::const_iterator it = args.begin(); it != args.end(); ++it ) { + s += *it + " "; + } + kdDebug() << s << endl << flush; + emit debuggingOutput("mkisofs calculate size command:", s); + + // since output changed during mkisofs version changes we grab both + // stdout and stderr + + // mkisofs version >= 1.15 (don't know about 1.14!) + // the extends on stdout (as lonely number) + // and error and warning messages on stderr + + // mkisofs >= 1.13 + // everything is written to stderr + // last line is: "Total extents scheduled to be written = XXXXX" + + // TODO: use K3bProcess::OutputCollector instead iof our own two slots. + + connect( m_process, SIGNAL(receivedStderr(KProcess*, char*, int)), + this, SLOT(slotCollectMkisofsPrintSizeStderr(KProcess*, char*, int)) ); + connect( m_process, SIGNAL(stdoutLine(const QString&)), + this, SLOT(slotCollectMkisofsPrintSizeStdout(const QString&)) ); + connect( m_process, SIGNAL(processExited(KProcess*)), + this, SLOT(slotMkisofsPrintSizeFinished()) ); + + // we also want error messages + connect( m_process, SIGNAL(stderrLine( const QString& )), + this, SLOT(slotReceivedStderr( const QString& )) ); + + m_collectedMkisofsPrintSizeStdout = QString::null; + m_collectedMkisofsPrintSizeStderr = QString::null; + m_mkisofsPrintSizeResult = 0; + + if( !m_process->start( KProcess::NotifyOnExit, KProcess::AllOutput ) ) { + emit infoMessage( i18n("Could not start %1.").arg("mkisofs"), K3bJob::ERROR ); + cleanup(); + + jobFinished( false ); + return; + } +} + + +void K3bIsoImager::slotCollectMkisofsPrintSizeStderr(KProcess*, char* data , int len) +{ + emit debuggingOutput( "mkisofs", QString::fromLocal8Bit( data, len ) ); + m_collectedMkisofsPrintSizeStderr.append( QString::fromLocal8Bit( data, len ) ); +} + + +void K3bIsoImager::slotCollectMkisofsPrintSizeStdout( const QString& line ) +{ + // newer versions of mkisofs outut additional lines of junk before the size :( + // so we only use the last line + emit debuggingOutput( "mkisofs", line ); + m_collectedMkisofsPrintSizeStdout = line; +} + + +void K3bIsoImager::slotMkisofsPrintSizeFinished() +{ + if( m_canceled ) { + emit canceled(); + jobFinished( false ); + return; + } + + bool success = true; + + // if m_collectedMkisofsPrintSizeStdout is not empty we have a recent version of + // mkisofs and parsing is very easy (s.o.) + if( !m_collectedMkisofsPrintSizeStdout.isEmpty() ) { + kdDebug() << "(K3bIsoImager) iso size: " << m_collectedMkisofsPrintSizeStdout << endl; + m_mkisofsPrintSizeResult = m_collectedMkisofsPrintSizeStdout.toInt( &success ); + } + else { + // parse the stderr output + // I hope parsing the last line is enough! + int pos = m_collectedMkisofsPrintSizeStderr.findRev( "extents scheduled to be written" ); + + if( pos == -1 ) + success = false; + else + m_mkisofsPrintSizeResult = m_collectedMkisofsPrintSizeStderr.mid( pos+33 ).toInt( &success ); + } + + emit debuggingOutput( "K3bIsoImager", + QString("mkisofs print size result: %1 (%2 bytes)") + .arg(m_mkisofsPrintSizeResult) + .arg(Q_UINT64(m_mkisofsPrintSizeResult)*2048ULL) ); + + cleanup(); + + + if( success ) { + jobFinished( true ); + } + else { + m_mkisofsPrintSizeResult = 0; + kdDebug() << "(K3bIsoImager) Parsing mkisofs -print-size failed: " << m_collectedMkisofsPrintSizeStdout << endl; + emit infoMessage( i18n("Could not determine size of resulting image file."), ERROR ); + jobFinished( false ); + } +} + + +void K3bIsoImager::initVariables() +{ + m_containsFilesWithMultibleBackslashes = false; + m_processExited = false; + m_canceled = false; + d->knownError = false; + + // determine symlink handling + // follow links superseeds discard all links which superseeds discard broken links + // without rockridge we follow the links or discard all + if( m_doc->isoOptions().followSymbolicLinks() ) + d->usedLinkHandling = Private::FOLLOW; + else if( m_doc->isoOptions().discardSymlinks() ) + d->usedLinkHandling = Private::DISCARD_ALL; + else if( m_doc->isoOptions().createRockRidge() ) { + if( m_doc->isoOptions().discardBrokenSymlinks() ) + d->usedLinkHandling = Private::DISCARD_BROKEN; + else + d->usedLinkHandling = Private::KEEP_ALL; + } + else { + d->usedLinkHandling = Private::FOLLOW; + } + + m_sessionNumber = s_imagerSessionCounter++; +} + + +void K3bIsoImager::start() +{ + jobStarted(); + + cleanup(); + + d->mkisofsBin = initMkisofs(); + if( !d->mkisofsBin ) { + jobFinished( false ); + return; + } + + initVariables(); + + m_process = new K3bProcess(); + m_process->setRunPrivileged(true); + + *m_process << d->mkisofsBin; + + // prepare the filenames as written to the image + m_doc->prepareFilenames(); + + if( !prepareMkisofsFiles() || + !addMkisofsParameters() ) { + cleanup(); + jobFinished( false ); + return; + } + + connect( m_process, SIGNAL(processExited(KProcess*)), + this, SLOT(slotProcessExited(KProcess*)) ); + + connect( m_process, SIGNAL(stderrLine( const QString& )), + this, SLOT(slotReceivedStderr( const QString& )) ); + + // + // Check the image file + if( m_fdToWriteTo == -1 ) { + d->imageFile.setName( d->imagePath ); + if( !d->imageFile.open( IO_WriteOnly ) ) { + emit infoMessage( i18n("Could not open %1 for writing").arg(d->imagePath), ERROR ); + cleanup(); + jobFinished(false); + return; + } + } + + // + // Open the active pipe which does the streaming + delete d->pipe; + if( m_doc->verifyData() ) + d->pipe = new K3bChecksumPipe(); + else + d->pipe = new K3bActivePipe(); + + if( m_fdToWriteTo == -1 ) + d->pipe->writeToIODevice( &d->imageFile ); + else + d->pipe->writeToFd( m_fdToWriteTo ); + d->pipe->open(); + m_process->writeToFd( d->pipe->in() ); + + + kdDebug() << "***** mkisofs parameters:\n"; + const QValueList& args = m_process->args(); + QString s; + for( QValueList::const_iterator it = args.begin(); it != args.end(); ++it ) { + s += *it + " "; + } + kdDebug() << s << endl << flush; + emit debuggingOutput("mkisofs command:", s); + + if( !m_process->start( KProcess::NotifyOnExit, KProcess::AllOutput) ) { + // something went wrong when starting the program + // it "should" be the executable + kdDebug() << "(K3bIsoImager) could not start mkisofs" << endl; + emit infoMessage( i18n("Could not start %1.").arg("mkisofs"), K3bJob::ERROR ); + jobFinished( false ); + cleanup(); + } +} + + +void K3bIsoImager::cancel() +{ + m_canceled = true; + + if( m_process && !m_processExited ) { + m_process->kill(); + } + else if( active() ) { + emit canceled(); + jobFinished(false); + } +} + + +void K3bIsoImager::setMultiSessionInfo( const QString& info, K3bDevice::Device* dev ) +{ + m_multiSessionInfo = info; + m_device = dev; +} + + +// iso9660 + RR use some latin1 variant. So we need to cut the desc fields +// counting 8bit chars. The GUI should take care of restricting the length +// and the charset +static void truncateTheHardWay( QString& s, int max ) +{ + QCString cs = s.utf8(); + cs.truncate(max); + s = QString::fromUtf8( cs ); +} + + +bool K3bIsoImager::addMkisofsParameters( bool printSize ) +{ + // add multisession info + if( !m_multiSessionInfo.isEmpty() ) { + *m_process << "-cdrecord-params" << m_multiSessionInfo; + if( m_device ) + *m_process << "-prev-session" << m_device->blockDeviceName(); + } + + // add the arguments + *m_process << "-gui"; + *m_process << "-graft-points"; + + if( printSize ) + *m_process << "-print-size" << "-quiet"; + + if( !m_doc->isoOptions().volumeID().isEmpty() ) { + QString s = m_doc->isoOptions().volumeID(); + truncateTheHardWay(s, 32); // ensure max length + *m_process << "-volid" << s; + } + else { + emit infoMessage( i18n("No volume id specified. Using default."), WARNING ); + *m_process << "-volid" << "CDROM"; + } + + QString s = m_doc->isoOptions().volumeSetId(); + truncateTheHardWay(s, 128); // ensure max length + *m_process << "-volset" << s; + + s = m_doc->isoOptions().applicationID(); + truncateTheHardWay(s, 128); // ensure max length + *m_process << "-appid" << s; + + s = m_doc->isoOptions().publisher(); + truncateTheHardWay(s, 128); // ensure max length + *m_process << "-publisher" << s; + + s = m_doc->isoOptions().preparer(); + truncateTheHardWay(s, 128); // ensure max length + *m_process << "-preparer" << s; + + s = m_doc->isoOptions().systemId(); + truncateTheHardWay(s, 32); // ensure max length + *m_process << "-sysid" << s; + + s = m_doc->isoOptions().abstractFile(); + truncateTheHardWay(s, 37); // ensure max length + if ( !s.isEmpty() ) + *m_process << "-abstract" << s; + + s = m_doc->isoOptions().copyrightFile(); + truncateTheHardWay(s, 37); // ensure max length + if ( !s.isEmpty() ) + *m_process << "-copyright" << s; + + s = m_doc->isoOptions().bibliographFile(); + truncateTheHardWay(s, 37); // ensure max length + if ( !s.isEmpty() ) + *m_process << "-biblio" << s; + + int volsetSize = m_doc->isoOptions().volumeSetSize(); + int volsetSeqNo = m_doc->isoOptions().volumeSetNumber(); + if( volsetSeqNo > volsetSize ) { + kdDebug() << "(K3bIsoImager) invalid volume set sequence number: " << volsetSeqNo + << " with volume set size: " << volsetSize << endl; + volsetSeqNo = volsetSize; + } + *m_process << "-volset-size" << QString::number(volsetSize); + *m_process << "-volset-seqno" << QString::number(volsetSeqNo); + + if( m_sortWeightFile ) { + *m_process << "-sort" << m_sortWeightFile->name(); + } + + if( m_doc->isoOptions().createRockRidge() ) { + if( m_doc->isoOptions().preserveFilePermissions() ) + *m_process << "-rock"; + else + *m_process << "-rational-rock"; + if( m_rrHideFile ) + *m_process << "-hide-list" << m_rrHideFile->name(); + } + + if( m_doc->isoOptions().createJoliet() ) { + *m_process << "-joliet"; + if( m_doc->isoOptions().jolietLong() ) + *m_process << "-joliet-long"; + if( m_jolietHideFile ) + *m_process << "-hide-joliet-list" << m_jolietHideFile->name(); + } + + if( m_doc->isoOptions().doNotCacheInodes() ) + *m_process << "-no-cache-inodes"; + + // + // Check if we have files > 2 GB and enable udf in that case. + // + bool filesGreaterThan2Gb = false; + K3bDataItem* item = m_doc->root(); + while( (item = item->nextSibling()) ) { + if( item->isFile() && item->size() > 2LL*1024LL*1024LL*1024LL ) { + filesGreaterThan2Gb = true; + break; + } + } + + if( filesGreaterThan2Gb ) { + emit infoMessage( i18n("Found files bigger than 2 GB. These files will only be fully accessible if mounted with UDF."), + WARNING ); + + // in genisoimage 1.1.3 "they" silently introduced this aweful parameter + if ( d->mkisofsBin->hasFeature( "genisoimage" ) && d->mkisofsBin->version >= K3bVersion( 1, 1, 3 ) ) { + *m_process << "-allow-limited-size"; + } + } + + bool udf = m_doc->isoOptions().createUdf(); + if( !udf && filesGreaterThan2Gb ) { + emit infoMessage( i18n("Enabling UDF extension."), INFO ); + udf = true; + } + if( udf ) + *m_process << "-udf"; + + if( m_doc->isoOptions().ISOuntranslatedFilenames() ) { + *m_process << "-untranslated-filenames"; + } + else { + if( m_doc->isoOptions().ISOallowPeriodAtBegin() ) + *m_process << "-allow-leading-dots"; + if( m_doc->isoOptions().ISOallow31charFilenames() ) + *m_process << "-full-iso9660-filenames"; + if( m_doc->isoOptions().ISOomitVersionNumbers() && !m_doc->isoOptions().ISOmaxFilenameLength() ) + *m_process << "-omit-version-number"; + if( m_doc->isoOptions().ISOrelaxedFilenames() ) + *m_process << "-relaxed-filenames"; + if( m_doc->isoOptions().ISOallowLowercase() ) + *m_process << "-allow-lowercase"; + if( m_doc->isoOptions().ISOnoIsoTranslate() ) + *m_process << "-no-iso-translate"; + if( m_doc->isoOptions().ISOallowMultiDot() ) + *m_process << "-allow-multidot"; + if( m_doc->isoOptions().ISOomitTrailingPeriod() ) + *m_process << "-omit-period"; + } + + if( m_doc->isoOptions().ISOmaxFilenameLength() ) + *m_process << "-max-iso9660-filenames"; + + if( m_noDeepDirectoryRelocation ) + *m_process << "-disable-deep-relocation"; + + // We do our own following +// if( m_doc->isoOptions().followSymbolicLinks() || !m_doc->isoOptions().createRockRidge() ) +// *m_process << "-follow-links"; + + if( m_doc->isoOptions().createTRANS_TBL() ) + *m_process << "-translation-table"; + if( m_doc->isoOptions().hideTRANS_TBL() ) + *m_process << "-hide-joliet-trans-tbl"; + + *m_process << "-iso-level" << QString::number(m_doc->isoOptions().ISOLevel()); + + if( m_doc->isoOptions().forceInputCharset() ) + *m_process << "-input-charset" << m_doc->isoOptions().inputCharset(); + + *m_process << "-path-list" << QFile::encodeName(m_pathSpecFile->name()); + + + // boot stuff + if( !m_doc->bootImages().isEmpty() ) { + bool first = true; + for( QPtrListIterator it( m_doc->bootImages() ); + *it; ++it ) { + if( !first ) + *m_process << "-eltorito-alt-boot"; + + K3bBootItem* bootItem = *it; + + *m_process << "-eltorito-boot"; + *m_process << bootItem->writtenPath(); + + if( bootItem->imageType() == K3bBootItem::HARDDISK ) { + *m_process << "-hard-disk-boot"; + } + else if( bootItem->imageType() == K3bBootItem::NONE ) { + *m_process << "-no-emul-boot"; + if( bootItem->loadSegment() > 0 ) + *m_process << "-boot-load-seg" << QString::number(bootItem->loadSegment()); + if( bootItem->loadSize() > 0 ) + *m_process << "-boot-load-size" << QString::number(bootItem->loadSize()); + } + + if( bootItem->imageType() != K3bBootItem::NONE && bootItem->noBoot() ) + *m_process << "-no-boot"; + if( bootItem->bootInfoTable() ) + *m_process << "-boot-info-table"; + + first = false; + } + + *m_process << "-eltorito-catalog" << m_doc->bootCataloge()->writtenPath(); + } + + + // additional parameters from config + const QStringList& params = k3bcore->externalBinManager()->binObject( "mkisofs" )->userParameters(); + for( QStringList::const_iterator it = params.begin(); it != params.end(); ++it ) + *m_process << *it; + + return true; +} + + +int K3bIsoImager::writePathSpec() +{ + delete m_pathSpecFile; + m_pathSpecFile = new KTempFile(); + m_pathSpecFile->setAutoDelete(true); + + if( QTextStream* t = m_pathSpecFile->textStream() ) { + // recursive path spec writing + int num = writePathSpecForDir( m_doc->root(), *t ); + + m_pathSpecFile->close(); + + return num; + } + else + return -1; +} + + +int K3bIsoImager::writePathSpecForDir( K3bDirItem* dirItem, QTextStream& stream ) +{ + if( !m_noDeepDirectoryRelocation && dirItem->depth() > 7 ) { + kdDebug() << "(K3bIsoImager) found directory depth > 7. Enabling no deep directory relocation." << endl; + m_noDeepDirectoryRelocation = true; + } + + // now create the graft points + int num = 0; + for( QPtrListIterator it( dirItem->children() ); it.current(); ++it ) { + K3bDataItem* item = it.current(); + bool writeItem = item->writeToCd(); + + if( item->isSymLink() ) { + if( d->usedLinkHandling == Private::DISCARD_ALL || + ( d->usedLinkHandling == Private::DISCARD_BROKEN && + !item->isValid() ) ) + writeItem = false; + + else if( d->usedLinkHandling == Private::FOLLOW ) { + QFileInfo f( K3b::resolveLink( item->localPath() ) ); + if( !f.exists() ) { + emit infoMessage( i18n("Could not follow link %1 to non-existing file %2. Skipping...") + .arg(item->k3bName()) + .arg(f.filePath()), WARNING ); + writeItem = false; + } + else if( f.isDir() ) { + emit infoMessage( i18n("Ignoring link %1 to folder %2. K3b is unable to follow links to folders.") + .arg(item->k3bName()) + .arg(f.filePath()), WARNING ); + writeItem = false; + } + } + } + else if( item->isFile() ) { + QFileInfo f( item->localPath() ); + if( !f.exists() ) { + emit infoMessage( i18n("Could not find file %1. Skipping...").arg(item->localPath()), WARNING ); + writeItem = false; + } + else if( !f.isReadable() ) { + emit infoMessage( i18n("Could not read file %1. Skipping...").arg(item->localPath()), WARNING ); + writeItem = false; + } + } + + if( writeItem ) { + num++; + + // some versions of mkisofs seem to have a bug that prevents to use filenames + // that contain one or more backslashes + if( item->writtenPath().contains("\\") ) + m_containsFilesWithMultibleBackslashes = true; + + + if( item->isDir() ) { + stream << escapeGraftPoint( item->writtenPath() ) + << "=" + << escapeGraftPoint( dummyDir( static_cast(item) ) ) << "\n"; + + int x = writePathSpecForDir( dynamic_cast(item), stream ); + if( x >= 0 ) + num += x; + else + return -1; + } + else { + writePathSpecForFile( static_cast(item), stream ); + } + } + } + + return num; +} + + +void K3bIsoImager::writePathSpecForFile( K3bFileItem* item, QTextStream& stream ) +{ + stream << escapeGraftPoint( item->writtenPath() ) + << "="; + + if( m_doc->bootImages().containsRef( dynamic_cast(item) ) ) { // boot-image-backup-hack + + // create temp file + KTempFile temp; + QString tempPath = temp.name(); + temp.unlink(); + + if( !KIO::NetAccess::copy( KURL(item->localPath()), KURL::fromPathOrURL(tempPath) ) ) { + emit infoMessage( i18n("Failed to backup boot image file %1").arg(item->localPath()), ERROR ); + return; + } + + static_cast(item)->setTempPath( tempPath ); + + m_tempFiles.append(tempPath); + stream << escapeGraftPoint( tempPath ) << "\n"; + } + else if( item->isSymLink() && d->usedLinkHandling == Private::FOLLOW ) + stream << escapeGraftPoint( K3b::resolveLink( item->localPath() ) ) << "\n"; + else + stream << escapeGraftPoint( item->localPath() ) << "\n"; +} + + +bool K3bIsoImager::writeRRHideFile() +{ + delete m_rrHideFile; + m_rrHideFile = new KTempFile(); + m_rrHideFile->setAutoDelete(true); + + if( QTextStream* t = m_rrHideFile->textStream() ) { + + K3bDataItem* item = m_doc->root(); + while( item ) { + if( item->hideOnRockRidge() ) { + if( !item->isDir() ) // hiding directories does not work (all dirs point to the dummy-dir) + *t << escapeGraftPoint( item->localPath() ) << endl; + } + item = item->nextSibling(); + } + + m_rrHideFile->close(); + return true; + } + else + return false; +} + + +bool K3bIsoImager::writeJolietHideFile() +{ + delete m_jolietHideFile; + m_jolietHideFile = new KTempFile(); + m_jolietHideFile->setAutoDelete(true); + + if( QTextStream* t = m_jolietHideFile->textStream() ) { + + K3bDataItem* item = m_doc->root(); + while( item ) { + if( item->hideOnRockRidge() ) { + if( !item->isDir() ) // hiding directories does not work (all dirs point to the dummy-dir but we could introduce a second hidden dummy dir) + *t << escapeGraftPoint( item->localPath() ) << endl; + } + item = item->nextSibling(); + } + + m_jolietHideFile->close(); + return true; + } + else + return false; +} + + +bool K3bIsoImager::writeSortWeightFile() +{ + delete m_sortWeightFile; + m_sortWeightFile = new KTempFile(); + m_sortWeightFile->setAutoDelete(true); + + if( QTextStream* t = m_sortWeightFile->textStream() ) { + // + // We need to write the local path in combination with the sort weight + // mkisofs will take care of multiple entries for one local file and always + // use the highest weight + // + K3bDataItem* item = m_doc->root(); + while( (item = item->nextSibling()) ) { // we skip the root here + if( item->sortWeight() != 0 ) { + if( m_doc->bootImages().containsRef( dynamic_cast(item) ) ) { // boot-image-backup-hack + *t << escapeGraftPoint( static_cast(item)->tempPath() ) << " " << item->sortWeight() << endl; + } + else if( item->isDir() ) { + // + // Since we use dummy dirs for all directories in the filesystem and mkisofs uses the local path + // for sorting we need to create a different dummy dir for every sort weight value. + // + *t << escapeGraftPoint( dummyDir( static_cast(item) ) ) << " " << item->sortWeight() << endl; + } + else + *t << escapeGraftPoint( item->localPath() ) << " " << item->sortWeight() << endl; + } + } + + m_sortWeightFile->close(); + return true; + } + else + return false; +} + + +QString K3bIsoImager::escapeGraftPoint( const QString& str ) +{ + QString enc = str; + + // + // mkisofs manpage (-graft-points) is incorrect (as of mkisofs 2.01.01) + // + // Actually an equal sign needs to be escaped with one backslash only + // Single backslashes inside a filename can be used without change + // while single backslashes at the end of a filename need to be escaped + // with two backslashes. + // + // There is one more problem though: the name in the iso tree can never + // in any number of backslashes. mkisofs simply cannot handle it. So we + // need to remove these slashes somewhere or ignore those files (we do + // that in K3bDataDoc::addUrls) + // + + // + // we do not use QString::replace to have full control + // this might be slow since QString::insert is slow but we don't care + // since this is only called to prepare the iso creation which is not + // time critical. :) + // + + unsigned int pos = 0; + while( pos < enc.length() ) { + // escape every equal sign with one backslash + if( enc[pos] == '=' ) { + enc.insert( pos, "\\" ); + pos += 2; + } + else if( enc[pos] == '\\' ) { + // escape every occurrence of two backslashes with two backslashes + if( pos+1 < enc.length() && enc[pos+1] == '\\' ) { + enc.insert( pos, "\\\\" ); + pos += 4; + } + // escape the last single backslash in the filename (see above) + else if( pos == enc.length()-1 ) { + enc.insert( pos, "\\" ); + pos += 2; + } + else + ++pos; + } + else + ++pos; + } + +// enc.replace( "\\\\", "\\\\\\\\" ); +// enc.replace( "=", "\\=" ); + + return enc; +} + + +bool K3bIsoImager::prepareMkisofsFiles() +{ + // write path spec file + // ---------------------------------------------------- + int num = writePathSpec(); + if( num < 0 ) { + emit infoMessage( i18n("Could not write temporary file"), K3bJob::ERROR ); + return false; + } + else if( num == 0 ) { + emit infoMessage( i18n("No files to be written."), K3bJob::ERROR ); + return false; + } + + if( m_doc->isoOptions().createRockRidge() ) { + if( !writeRRHideFile() ) { + emit infoMessage( i18n("Could not write temporary file"), K3bJob::ERROR ); + return false; + } + } + + if( m_doc->isoOptions().createJoliet() ) { + if( !writeJolietHideFile() ) { + emit infoMessage( i18n("Could not write temporary file"), K3bJob::ERROR ); + return false ; + } + } + + if( !writeSortWeightFile() ) { + emit infoMessage( i18n("Could not write temporary file"), K3bJob::ERROR ); + return false; + } + + return true; +} + + +QString K3bIsoImager::dummyDir( K3bDirItem* dir ) +{ + // + // since we use virtual folders in order to have folders with different weight factors and different + // permissions we create different dummy dirs to be passed to mkisofs + // + + QDir _appDir( locateLocal( "appdata", "temp/" ) ); + + // + // create a unique isoimager session id + // This might become important in case we will allow multiple instances of the isoimager + // to run at the same time. + // + QString jobId = qApp->sessionId() + "_" + QString::number( m_sessionNumber ); + + if( !_appDir.cd( jobId ) ) { + _appDir.mkdir( jobId ); + _appDir.cd( jobId ); + } + + QString name( "dummydir_" ); + name += QString::number( dir->sortWeight() ); + + bool perm = false; + k3b_struct_stat statBuf; + if( !dir->localPath().isEmpty() ) { + // permissions + if( k3b_stat( QFile::encodeName(dir->localPath()), &statBuf ) == 0 ) { + name += "_"; + name += QString::number( statBuf.st_uid ); + name += "_"; + name += QString::number( statBuf.st_gid ); + name += "_"; + name += QString::number( statBuf.st_mode ); + name += "_"; + name += QString::number( statBuf.st_mtime ); + + perm = true; + } + } + + + if( !_appDir.cd( name ) ) { + + kdDebug() << "(K3bIsoImager) creating dummy dir: " << _appDir.absPath() << "/" << name << endl; + + _appDir.mkdir( name ); + _appDir.cd( name ); + + if( perm ) { + ::chmod( QFile::encodeName( _appDir.absPath() ), statBuf.st_mode ); + ::chown( QFile::encodeName( _appDir.absPath() ), statBuf.st_uid, statBuf.st_gid ); + struct utimbuf tb; + tb.actime = tb.modtime = statBuf.st_mtime; + ::utime( QFile::encodeName( _appDir.absPath() ), &tb ); + } + } + + return _appDir.absPath() + "/"; +} + + +void K3bIsoImager::clearDummyDirs() +{ + QString jobId = qApp->sessionId() + "_" + QString::number( m_sessionNumber ); + QDir appDir( locateLocal( "appdata", "temp/" ) ); + if( appDir.cd( jobId ) ) { + QStringList dummyDirEntries = appDir.entryList( "dummydir*", QDir::Dirs ); + for( QStringList::iterator it = dummyDirEntries.begin(); it != dummyDirEntries.end(); ++it ) + appDir.rmdir( *it ); + appDir.cdUp(); + appDir.rmdir( jobId ); + } +} + + +QCString K3bIsoImager::checksum() const +{ + if( K3bChecksumPipe* p = dynamic_cast( d->pipe ) ) + return p->checksum(); + else + return QCString(); +} + + +bool K3bIsoImager::hasBeenCanceled() const +{ + return m_canceled; +} + +#include "k3bisoimager.moc" diff --git a/libk3b/projects/datacd/k3bisoimager.h b/libk3b/projects/datacd/k3bisoimager.h new file mode 100644 index 0000000..82501ba --- /dev/null +++ b/libk3b/projects/datacd/k3bisoimager.h @@ -0,0 +1,188 @@ +/* + * + * $Id: k3bisoimager.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef K3B_ISO_IMAGER_H +#define K3B_ISO_IMAGER_H + +#include +#include "k3bmkisofshandler.h" + +#include +#include + +class K3bDataDoc; +class K3bDirItem; +class K3bDataItem; +class K3bFileItem; +class QTextStream; +class K3bProcess; +class KProcess; +class K3bDevice::Device; +class KTempFile; + + +class K3bIsoImager : public K3bJob, public K3bMkisofsHandler +{ + Q_OBJECT + + public: + K3bIsoImager( K3bDataDoc*, K3bJobHandler*, QObject* parent = 0, const char* name = 0 ); + virtual ~K3bIsoImager(); + + virtual bool active() const; + + int size() const { return m_mkisofsPrintSizeResult; } + + virtual bool hasBeenCanceled() const; + + /** + * Get the checksum calculated during the creation of the image. + */ + QCString checksum() const; + + public slots: + /** + * Starts the actual image creation. Always run init() + * before starting the image creation + */ + virtual void start(); + virtual void cancel(); + + /** + * Initialize the image creator. This calculates the image size and performs + * some checks on the project. + * + * The initialization process also finishes with the finished() signal just + * like a normal job operation. Get the calculated image size via size() + */ + virtual void init(); + + /** + * Only calculates the size of the image without the additional checks in + * init() + * + * Use this if you need to recalculate the image size for example if the + * multisession info changed. + */ + virtual void calculateSize(); + + /** + * lets the isoimager write directly into fd instead of writing + * to an image file. + * Be aware that this only makes sense before starting the job. + * To disable just set @p fd to -1 + */ + void writeToFd( int fd ); + + void writeToImageFile( const QString& path ); + + /** + * If dev == 0 K3bIsoImager will ignore the data in the previous session. + * This is usable for CD-Extra. + */ + void setMultiSessionInfo( const QString&, K3bDevice::Device* dev = 0 ); + + K3bDevice::Device* device() const { return m_device; } + K3bDataDoc* doc() const { return m_doc; } + + protected: + virtual void handleMkisofsProgress( int ); + virtual void handleMkisofsInfoMessage( const QString&, int ); + + virtual bool addMkisofsParameters( bool printSize = false ); + + /** + * calls writePathSpec, writeRRHideFile, and writeJolietHideFile + */ + bool prepareMkisofsFiles(); + + /** + * The dummy dir is used to create dirs on the iso-filesystem. + * + * @return an empty dummy dir for use with K3bDirItems. + */ + QString dummyDir( K3bDirItem* ); + + void outputData(); + void initVariables(); + virtual void cleanup(); + void clearDummyDirs(); + + /** + * @returns The number of entries written or -1 on error + */ + virtual int writePathSpec(); + bool writeRRHideFile(); + bool writeJolietHideFile(); + bool writeSortWeightFile(); + + // used by writePathSpec + virtual int writePathSpecForDir( K3bDirItem* dirItem, QTextStream& stream ); + virtual void writePathSpecForFile( K3bFileItem*, QTextStream& stream ); + QString escapeGraftPoint( const QString& str ); + + KTempFile* m_pathSpecFile; + KTempFile* m_rrHideFile; + KTempFile* m_jolietHideFile; + KTempFile* m_sortWeightFile; + + K3bProcess* m_process; + + bool m_processExited; + bool m_canceled; + + protected slots: + virtual void slotReceivedStderr( const QString& ); + virtual void slotProcessExited( KProcess* ); + + private slots: + void slotCollectMkisofsPrintSizeStderr(KProcess*, char*, int); + void slotCollectMkisofsPrintSizeStdout( const QString& ); + void slotMkisofsPrintSizeFinished(); + void slotDataPreparationDone( bool success ); + + private: + void startSizeCalculation(); + + class Private; + Private* d; + + K3bDataDoc* m_doc; + + bool m_noDeepDirectoryRelocation; + + bool m_importSession; + QString m_multiSessionInfo; + K3bDevice::Device* m_device; + + // used for mkisofs -print-size parsing + QString m_collectedMkisofsPrintSizeStdout; + QString m_collectedMkisofsPrintSizeStderr; + int m_mkisofsPrintSizeResult; + + QStringList m_tempFiles; + + int m_fdToWriteTo; + + bool m_containsFilesWithMultibleBackslashes; + + // used to create a unique session id + static int s_imagerSessionCounter; + + int m_sessionNumber; +}; + + +#endif diff --git a/libk3b/projects/datacd/k3bisooptions.cpp b/libk3b/projects/datacd/k3bisooptions.cpp new file mode 100644 index 0000000..bd7314d --- /dev/null +++ b/libk3b/projects/datacd/k3bisooptions.cpp @@ -0,0 +1,216 @@ +/* + * + * $Id: k3bisooptions.cpp 639665 2007-03-05 16:29:52Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bisooptions.h" +#include +#include +#include + +#include +#include +#include + + +K3bIsoOptions::K3bIsoOptions() + : m_volumeID( "K3b data project" ), + m_applicationID( QString("K3B THE CD KREATOR (C) 1998-2006 SEBASTIAN TRUEG AND THE K3B TEAM") ), + m_systemId( K3b::systemName().upper() ), + m_inputCharset( "iso8859-1" ), + m_whiteSpaceTreatmentReplaceString( "_" ) +{ + m_bForceInputCharset = false; + + m_createRockRidge = true; + m_createJoliet = true; + m_createUdf = false; + m_ISOallowLowercase = false; + m_ISOallowPeriodAtBegin = false; + m_ISOallow31charFilenames = true; + m_ISOomitVersionNumbers = false; + m_ISOomitTrailingPeriod = false; + m_ISOmaxFilenameLength = false; + m_ISOrelaxedFilenames = false; + m_ISOnoIsoTranslate = false; + m_ISOallowMultiDot = false; + m_ISOuntranslatedFilenames = false; + m_followSymbolicLinks = false; + m_createTRANS_TBL = false; + m_hideTRANS_TBL = false; + m_jolietLong = true; + + m_doNotCacheInodes = true; + + m_isoLevel = 2; + + m_discardSymlinks = false; + m_discardBrokenSymlinks = false; + + m_preserveFilePermissions = false; + + m_whiteSpaceTreatment = noChange; + + m_volumeSetSize = 1; + m_volumeSetNumber = 1; +} + + +void K3bIsoOptions::save( KConfigBase* c, bool saveVolumeDesc ) +{ + if( saveVolumeDesc ) { + c->writeEntry( "volume id", m_volumeID ); + c->writeEntry( "application id", m_applicationID ); + c->writeEntry( "preparer", m_preparer ); + c->writeEntry( "publisher", m_publisher ); + c->writeEntry( "system id", m_systemId ); + c->writeEntry( "volume set id", m_volumeSetId ); + c->writeEntry( "volume set size", m_volumeSetSize ); + c->writeEntry( "volume set number", m_volumeSetNumber ); + c->writeEntry( "abstract file", m_abstractFile ); + c->writeEntry( "copyright file", m_copyrightFile ); + c->writeEntry( "bibliograph file", m_bibliographFile ); + } + + c->writeEntry( "rock_ridge", m_createRockRidge ); + c->writeEntry( "joliet", m_createJoliet ); + c->writeEntry( "udf", m_createUdf ); + + // save iso-level + c->writeEntry( "iso_level", m_isoLevel ); + + c->writeEntry( "create TRANS_TBL", m_createTRANS_TBL ); + c->writeEntry( "hide TRANS_TBL", m_hideTRANS_TBL ); + c->writeEntry( "untranslated filenames", m_ISOuntranslatedFilenames ); + c->writeEntry( "allow 31 character filenames", m_ISOallow31charFilenames ); + c->writeEntry( "max ISO filenames", m_ISOmaxFilenameLength ); + c->writeEntry( "allow beginning period", m_ISOallowPeriodAtBegin ); + c->writeEntry( "relaxed filenames", m_ISOrelaxedFilenames ); + c->writeEntry( "omit version numbers", m_ISOomitVersionNumbers ); + c->writeEntry( "omit trailing period", m_ISOomitTrailingPeriod ); + c->writeEntry( "no iSO translation", m_ISOnoIsoTranslate ); + c->writeEntry( "allow multiple dots", m_ISOallowMultiDot ); + c->writeEntry( "allow lowercase filenames", m_ISOallowLowercase ); + // c->writeEntry( "follow symbolic links", m_followSymbolicLinks ); + + c->writeEntry( "joliet long", m_jolietLong ); + + c->writeEntry( "force input charset", m_bForceInputCharset ); + c->writeEntry( "input charset", m_inputCharset ); + + c->writeEntry( "do not cache inodes", m_doNotCacheInodes ); + + // save whitespace-treatment + switch( m_whiteSpaceTreatment ) { + case strip: + c->writeEntry( "white_space_treatment", "strip" ); + break; + case extended: + c->writeEntry( "white_space_treatment", "extended" ); + break; + case replace: + c->writeEntry( "white_space_treatment", "replace" ); + break; + default: + c->writeEntry( "white_space_treatment", "noChange" ); + } + + c->writeEntry( "whitespace replace string", m_whiteSpaceTreatmentReplaceString ); + + c->writeEntry( "discard symlinks", discardSymlinks() ); + c->writeEntry( "discard broken symlinks", discardBrokenSymlinks() ); + + c->writeEntry( "preserve file permissions", m_preserveFilePermissions ); +} + + +K3bIsoOptions K3bIsoOptions::load( KConfigBase* c, bool loadVolumeDesc ) +{ + K3bIsoOptions options; + + if( loadVolumeDesc ) { + options.setVolumeID( c->readEntry( "volume id", options.volumeID() ) ); + options.setApplicationID( c->readEntry( "application id", options.applicationID() ) ); + options.setPreparer( c->readEntry( "preparer", options.preparer() ) ); + options.setPublisher( c->readEntry( "publisher", options.publisher() ) ); + options.setSystemId( c->readEntry( "system id", options.systemId() ) ); + options.setVolumeSetId( c->readEntry( "volume set id", options.volumeSetId() ) ); + options.setVolumeSetSize( c->readNumEntry( "volume set size", options.volumeSetSize() ) ); + options.setVolumeSetNumber( c->readNumEntry( "volume set number", options.volumeSetNumber() ) ); + options.setAbstractFile( c->readEntry( "abstract file", options.abstractFile() ) ); + options.setCoprightFile( c->readEntry( "copyright file", options.copyrightFile() ) ); + options.setBibliographFile( c->readEntry( "bibliograph file", options.bibliographFile() ) ); + } + + options.setForceInputCharset( c->readBoolEntry( "force input charset", options.forceInputCharset() ) ); + if( options.forceInputCharset() ) + options.setInputCharset( c->readEntry( "input charset", options.inputCharset() ) ); + + options.setCreateRockRidge( c->readBoolEntry( "rock_ridge", options.createRockRidge() ) ); + options.setCreateJoliet( c->readBoolEntry( "joliet", options.createJoliet() ) ); + options.setCreateUdf( c->readBoolEntry( "udf", options.createUdf() ) ); + + options.setISOLevel( c->readNumEntry( "iso_level", options.ISOLevel() ) ); + + options.setCreateTRANS_TBL( c->readBoolEntry( "create TRANS_TBL", options.createTRANS_TBL() ) ); + options.setHideTRANS_TBL( c->readBoolEntry( "hide TRANS_TBL", options.hideTRANS_TBL() ) ); + + // + // We need to use the memeber variables here instead of the access methods + // which do not return the actual value of the member variables but the value + // representing the use in mkisofs (i.e. ISOomitVersionNumbers is also enabled + // if ISOmaxFilenameLength is enabled. + // + options.setISOuntranslatedFilenames( c->readBoolEntry( "untranslated filenames", options.m_ISOuntranslatedFilenames ) ); + options.setISOallow31charFilenames( c->readBoolEntry( "allow 31 character filenames", options.m_ISOallow31charFilenames ) ); + options.setISOmaxFilenameLength( c->readBoolEntry( "max ISO filenames", options.m_ISOmaxFilenameLength ) ); + options.setISOallowPeriodAtBegin( c->readBoolEntry( "allow beginning period", options.m_ISOallowPeriodAtBegin ) ); + options.setISOrelaxedFilenames( c->readBoolEntry( "relaxed filenames", options.m_ISOrelaxedFilenames ) ); + options.setISOomitVersionNumbers( c->readBoolEntry( "omit version numbers", options.m_ISOomitVersionNumbers ) ); + options.setISOnoIsoTranslate( c->readBoolEntry( "no iSO translation", options.m_ISOnoIsoTranslate ) ); + options.setISOallowMultiDot( c->readBoolEntry( "allow multiple dots", options.m_ISOallowMultiDot ) ); + options.setISOallowLowercase( c->readBoolEntry( "allow lowercase filenames", options.m_ISOallowLowercase ) ); + options.setISOomitTrailingPeriod( c->readBoolEntry( "omit trailing period", options.m_ISOomitTrailingPeriod ) ); + + // options.setFollowSymbolicLinks( c->readBoolEntry( "follow symbolic links", options.m_followSymbolicLinks ) ); + + options.setJolietLong( c->readBoolEntry( "joliet long", options.jolietLong() ) ); + + options.setDoNotCacheInodes( c->readBoolEntry( "do not cache inodes", options.doNotCacheInodes() ) ); + + QString w = c->readEntry( "white_space_treatment", "noChange" ); + if( w == "replace" ) + options.setWhiteSpaceTreatment( replace ); + else if( w == "strip" ) + options.setWhiteSpaceTreatment( strip ); + else if( w == "extended" ) + options.setWhiteSpaceTreatment( extended ); + else + options.setWhiteSpaceTreatment( noChange ); + + options.setWhiteSpaceTreatmentReplaceString( c->readEntry( "whitespace replace string", options.whiteSpaceTreatmentReplaceString() ) ); + + options.setDiscardSymlinks( c->readBoolEntry("discard symlinks", options.discardSymlinks() ) ); + options.setDiscardBrokenSymlinks( c->readBoolEntry("discard broken symlinks", options.discardBrokenSymlinks() ) ); + + options.setPreserveFilePermissions( c->readBoolEntry( "preserve file permissions", options.preserveFilePermissions() ) ); + + return options; +} + + +K3bIsoOptions K3bIsoOptions::defaults() +{ + // let the constructor create defaults + return K3bIsoOptions(); +} diff --git a/libk3b/projects/datacd/k3bisooptions.h b/libk3b/projects/datacd/k3bisooptions.h new file mode 100644 index 0000000..254c998 --- /dev/null +++ b/libk3b/projects/datacd/k3bisooptions.h @@ -0,0 +1,183 @@ +/* + * + * $Id: k3bisooptions.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef K3B_ISO_OPTIONS_H +#define K3B_ISO_OPTIONS_H + +#include +#include "k3b_export.h" + +class KConfigBase; + + +class LIBK3B_EXPORT K3bIsoOptions +{ + public: + K3bIsoOptions(); + + bool forceInputCharset() const { return m_bForceInputCharset; } + const QString& inputCharset() const { return m_inputCharset; } + + void setForceInputCharset( bool b ) { m_bForceInputCharset = b; } + void setInputCharset( const QString& cs ) { m_inputCharset = cs; } + + + // -- mkisofs-options ---------------------------------------------------------------------- + bool createRockRidge() const { return m_createRockRidge; } + bool createJoliet() const { return m_createJoliet; } + bool createUdf() const { return m_createUdf; } + bool ISOallowLowercase() const { return m_ISOallowLowercase || ISOuntranslatedFilenames(); } + bool ISOallowPeriodAtBegin() const { return m_ISOallowPeriodAtBegin || ISOuntranslatedFilenames(); } + bool ISOallow31charFilenames() const { return m_ISOallow31charFilenames || ISOmaxFilenameLength() || ISOuntranslatedFilenames(); } + bool ISOomitVersionNumbers() const { return m_ISOomitVersionNumbers || ISOmaxFilenameLength(); } + bool ISOomitTrailingPeriod() const { return m_ISOomitTrailingPeriod || ISOuntranslatedFilenames(); } + bool ISOmaxFilenameLength() const { return m_ISOmaxFilenameLength || ISOuntranslatedFilenames(); } + bool ISOrelaxedFilenames() const { return m_ISOrelaxedFilenames || ISOuntranslatedFilenames(); } + bool ISOnoIsoTranslate() const { return m_ISOnoIsoTranslate; } + bool ISOallowMultiDot() const { return m_ISOallowMultiDot || ISOuntranslatedFilenames(); } + bool ISOuntranslatedFilenames() const { return m_ISOuntranslatedFilenames; } + bool followSymbolicLinks() const { return m_followSymbolicLinks; } + bool createTRANS_TBL() const { return m_createTRANS_TBL; } + bool hideTRANS_TBL() const { return m_hideTRANS_TBL; } + bool jolietLong() const { return m_jolietLong; } + + bool preserveFilePermissions() const { return m_preserveFilePermissions; } + + int ISOLevel() const { return m_isoLevel; } + const QString& systemId() const { return m_systemId; } + const QString& applicationID() const { return m_applicationID; } + const QString& volumeID() const { return m_volumeID; } + const QString& volumeSetId() const { return m_volumeSetId; } + int volumeSetSize() const { return m_volumeSetSize; } + int volumeSetNumber() const { return m_volumeSetNumber; } + const QString& publisher() const { return m_publisher; } + const QString& preparer() const { return m_preparer; } + const QString& abstractFile() const { return m_abstractFile; } + const QString& copyrightFile() const { return m_copyrightFile; } + const QString& bibliographFile() const { return m_bibliographFile; } + + void setCreateRockRidge( bool b ) { m_createRockRidge = b; } + void setCreateJoliet( bool b ) { m_createJoliet = b; } + void setCreateUdf( bool b ) { m_createUdf = b; } + void setISOallowLowercase( bool b ) { m_ISOallowLowercase = b; } + void setISOallowPeriodAtBegin( bool b ) { m_ISOallowPeriodAtBegin = b; } + void setISOallow31charFilenames( bool b ) { m_ISOallow31charFilenames = b; } + void setISOomitVersionNumbers( bool b ) { m_ISOomitVersionNumbers = b; } + void setISOomitTrailingPeriod( bool b ) { m_ISOomitTrailingPeriod = b; } + void setISOmaxFilenameLength( bool b ) { m_ISOmaxFilenameLength = b; } + void setISOrelaxedFilenames( bool b ) { m_ISOrelaxedFilenames = b; } + void setISOnoIsoTranslate( bool b ) { m_ISOnoIsoTranslate = b; } + void setISOallowMultiDot( bool b ) { m_ISOallowMultiDot = b; } + void setISOuntranslatedFilenames( bool b ) { m_ISOuntranslatedFilenames = b; } + void setFollowSymbolicLinks( bool b ) { m_followSymbolicLinks = b; } + void setCreateTRANS_TBL( bool b ) { m_createTRANS_TBL = b; } + void setHideTRANS_TBL( bool b ) { m_hideTRANS_TBL = b; } + void setJolietLong( bool b ) { m_jolietLong = b; } + + void setISOLevel( int i ) { m_isoLevel = i; } + void setSystemId( const QString& s ) { m_systemId = s; } + void setApplicationID( const QString& s ) { m_applicationID = s; } + + /** + * Set the filesystems volume id. + * + * max length for this field is 32 chars. + */ + void setVolumeID( const QString& s ) { m_volumeID = s; } + void setVolumeSetId( const QString& s ) { m_volumeSetId = s; } + void setVolumeSetSize( int size ) { m_volumeSetSize = size; } + void setVolumeSetNumber( int n ) { m_volumeSetNumber = n; } + void setPublisher( const QString& s ) { m_publisher = s; } + void setPreparer( const QString& s ) { m_preparer = s; } + void setAbstractFile( const QString& s ) { m_abstractFile = s; } + void setCoprightFile( const QString& s ) { m_copyrightFile = s; } + void setBibliographFile( const QString& s ) { m_bibliographFile = s; } + + void setPreserveFilePermissions( bool b ) { m_preserveFilePermissions = b; } + // ----------------------------------------------------------------- mkisofs-options ----------- + + enum whiteSpaceTreatments { noChange = 0, replace = 1, strip = 2, extended = 3 }; + + void setWhiteSpaceTreatment( int i ) { m_whiteSpaceTreatment = i; } + int whiteSpaceTreatment() const { return m_whiteSpaceTreatment; } + const QString& whiteSpaceTreatmentReplaceString() const { return m_whiteSpaceTreatmentReplaceString; } + void setWhiteSpaceTreatmentReplaceString( const QString& s ) { m_whiteSpaceTreatmentReplaceString = s; } + + bool discardSymlinks() const { return m_discardSymlinks; } + void setDiscardSymlinks( bool b ) { m_discardSymlinks = b; } + + bool discardBrokenSymlinks() const { return m_discardBrokenSymlinks; } + void setDiscardBrokenSymlinks( bool b ) { m_discardBrokenSymlinks = b; } + + bool doNotCacheInodes() const { return m_doNotCacheInodes; } + void setDoNotCacheInodes( bool b ) { m_doNotCacheInodes = b; } + + void save( KConfigBase* c, bool saveVolumeDesc = true ); + + static K3bIsoOptions load( KConfigBase* c, bool loadVolumeDesc = true ); + static K3bIsoOptions defaults(); + + private: + // volume descriptor + QString m_volumeID; + QString m_applicationID; + QString m_preparer; + QString m_publisher; + QString m_systemId; + QString m_volumeSetId; + QString m_abstractFile; + QString m_copyrightFile; + QString m_bibliographFile; + + int m_volumeSetSize; + int m_volumeSetNumber; + + bool m_bForceInputCharset; + QString m_inputCharset; + + // mkisofs options ------------------------------------- + bool m_createRockRidge; // -r or -R + bool m_createJoliet; // -J + bool m_createUdf; // -udf + bool m_ISOallowLowercase; // -allow-lowercase + bool m_ISOallowPeriodAtBegin; // -L + bool m_ISOallow31charFilenames; // -I + bool m_ISOomitVersionNumbers; // -N + bool m_ISOomitTrailingPeriod; // -d + bool m_ISOmaxFilenameLength; // -max-iso9660-filenames (forces -N) + bool m_ISOrelaxedFilenames; // -relaxed-filenames + bool m_ISOnoIsoTranslate; // -no-iso-translate + bool m_ISOallowMultiDot; // -allow-multidot + bool m_ISOuntranslatedFilenames; // -U (forces -d, -I, -L, -N, -relaxed-filenames, -allow-lowercase, -allow-multidot, -no-iso-translate) + bool m_followSymbolicLinks; // -f + bool m_createTRANS_TBL; // -T + bool m_hideTRANS_TBL; // -hide-joliet-trans-tbl + + bool m_preserveFilePermissions; // if true -R instead of -r is used + bool m_jolietLong; + + bool m_doNotCacheInodes; + + int m_isoLevel; + + + int m_whiteSpaceTreatment; + QString m_whiteSpaceTreatmentReplaceString; + + bool m_discardSymlinks; + bool m_discardBrokenSymlinks; +}; + +#endif diff --git a/libk3b/projects/datacd/k3bmkisofshandler.cpp b/libk3b/projects/datacd/k3bmkisofshandler.cpp new file mode 100644 index 0000000..a3579ec --- /dev/null +++ b/libk3b/projects/datacd/k3bmkisofshandler.cpp @@ -0,0 +1,150 @@ +/* + * + * $Id: k3bmkisofshandler.cpp 802340 2008-04-29 07:43:07Z trueg $ + * Copyright (C) 2005 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bmkisofshandler.h" + +#include +#include +#include + +#include +#include + +#include + + + +class K3bMkisofsHandler::Private +{ +public: + const K3bExternalBin* mkisofsBin; + double firstProgressValue; + bool readError; +}; + + +K3bMkisofsHandler::K3bMkisofsHandler() +{ + d = new Private; + d->mkisofsBin = 0; +} + + +K3bMkisofsHandler::~K3bMkisofsHandler() +{ + delete d; +} + + +bool K3bMkisofsHandler::mkisofsReadError() const +{ + return d->readError; +} + + +const K3bExternalBin* K3bMkisofsHandler::initMkisofs() +{ + d->mkisofsBin = k3bcore->externalBinManager()->binObject( "mkisofs" ); + + if( d->mkisofsBin ) { + if( !d->mkisofsBin->copyright.isEmpty() ) + handleMkisofsInfoMessage( i18n("Using %1 %2 - Copyright (C) %3") + .arg("mkisofs").arg(d->mkisofsBin->version).arg(d->mkisofsBin->copyright), + K3bJob::INFO ); + + d->firstProgressValue = -1; + d->readError = false; + } + else { + kdDebug() << "(K3bMkisofsHandler) could not find mkisofs executable" << endl; + handleMkisofsInfoMessage( i18n("Mkisofs executable not found."), K3bJob::ERROR ); + } + + return d->mkisofsBin; +} + + +void K3bMkisofsHandler::parseMkisofsOutput( const QString& line ) +{ + if( !line.isEmpty() ) { + if( line.startsWith( d->mkisofsBin->path ) ) { + // error or warning + QString errorLine = line.mid( d->mkisofsBin->path.length() + 2 ); + if( errorLine.startsWith( "Input/output error. Cannot read from" ) ) { + handleMkisofsInfoMessage( i18n("Read error from file '%1'").arg( errorLine.mid( 38, errorLine.length()-40 ) ), + K3bJob::ERROR ); + d->readError = true; + } + else if( errorLine.startsWith( "Value too large for defined data type" ) ) { + handleMkisofsInfoMessage( i18n("Used version of mkisofs does not have large file support."), K3bJob::ERROR ); + handleMkisofsInfoMessage( i18n("Files bigger than 2 GB cannot be handled."), K3bJob::ERROR ); + d->readError = true; + } + } + else if( line.contains( "done, estimate" ) ) { + int p = parseMkisofsProgress( line ); + if( p != -1 ) + handleMkisofsProgress( p ); + } + else if( line.contains( "extents written" ) ) { + handleMkisofsProgress( 100 ); + } + else if( line.startsWith( "Incorrectly encoded string" ) ) { + handleMkisofsInfoMessage( i18n("Encountered an incorrectly encoded filename '%1'") + .arg(line.section( QRegExp("[\\(\\)]"), 1, 1 )), K3bJob::ERROR ); + handleMkisofsInfoMessage( i18n("This may be caused by a system update which changed the local character set."), K3bJob::ERROR ); + handleMkisofsInfoMessage( i18n("You may use convmv (http://j3e.de/linux/convmv/) to fix the filename encoding."), K3bJob::ERROR ); + d->readError = true; + } + else if( line.endsWith( "has not an allowable size." ) ) { + handleMkisofsInfoMessage( i18n("The boot image has an invalid size."), K3bJob::ERROR ); + d->readError = true; + } + else if( line.endsWith( "has multiple partitions." ) ) { + handleMkisofsInfoMessage( i18n("The boot image contains multiple partitions.."), K3bJob::ERROR ); + handleMkisofsInfoMessage( i18n("A hard-disk boot image has to contain a single partition."), K3bJob::ERROR ); + d->readError = true; + } + else { + kdDebug() << "(mkisofs) " << line << endl; + } + } +} + + +int K3bMkisofsHandler::parseMkisofsProgress( const QString& line ) +{ + // + // in multisession mode mkisofs' progress does not start at 0 but at (X+Y)/X + // where X is the data already on the cd and Y the data to create + // This is not very dramatic but kind or ugly. + // We just save the first emitted progress value and to some math ;) + // + + QString perStr = line; + perStr.truncate( perStr.find('%') ); + bool ok; + double p = perStr.toDouble( &ok ); + if( !ok ) { + kdDebug() << "(K3bMkisofsHandler) Parsing did not work for " << perStr << endl; + return -1; + } + else { + if( d->firstProgressValue < 0 ) + d->firstProgressValue = p; + + return( (int)::ceil( (p - d->firstProgressValue)*100.0/(100.0 - d->firstProgressValue) ) ); + } +} diff --git a/libk3b/projects/datacd/k3bmkisofshandler.h b/libk3b/projects/datacd/k3bmkisofshandler.h new file mode 100644 index 0000000..32576bc --- /dev/null +++ b/libk3b/projects/datacd/k3bmkisofshandler.h @@ -0,0 +1,74 @@ +/* + * + * $Id: k3bmkisofshandler.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2005 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_MKISOfS_HANDLER_H_ +#define _K3B_MKISOfS_HANDLER_H_ + +#include + +class K3bExternalBin; + + +/** + * Derive from this to handle mkisofs. + */ +class K3bMkisofsHandler +{ + public: + K3bMkisofsHandler(); + virtual ~K3bMkisofsHandler(); + + /** + * \return true if there was a read error. + */ + bool mkisofsReadError() const; + + protected: + /** + * Initialize the MkisofsHandler. + * This method emits copyright information and an error message in case mkisofs is not installed + * through handleMkisofsInfoMessage. + * + * \return A mkisofs bin object to be used or 0 if mkisofs is not installed. + */ + const K3bExternalBin* initMkisofs(); + + void parseMkisofsOutput( const QString& line ); + + /** + * Used internally by handleMkisofsOutput. + * May be used in case handleMkisofsOutput is not sufficient. + */ + int parseMkisofsProgress( const QString& line ); + + /** + * Called by handleMkisofsOutput + */ + virtual void handleMkisofsProgress( int ) = 0; + + /** + * Called by handleMkisofsOutput + * + * Uses K3bJob::MessageType + */ + virtual void handleMkisofsInfoMessage( const QString&, int ) = 0; + + private: + class Private; + Private* d; +}; + + +#endif diff --git a/libk3b/projects/datacd/k3bmsinfofetcher.cpp b/libk3b/projects/datacd/k3bmsinfofetcher.cpp new file mode 100644 index 0000000..c30d0ff --- /dev/null +++ b/libk3b/projects/datacd/k3bmsinfofetcher.cpp @@ -0,0 +1,243 @@ +/* + * + * $Id: k3bmsinfofetcher.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bmsinfofetcher.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + + +K3bMsInfoFetcher::K3bMsInfoFetcher( K3bJobHandler* jh, QObject* parent, const char* name ) + : K3bJob( jh, parent, name ), + m_process(0), + m_device(0), + m_dvd(false) +{ +} + + +K3bMsInfoFetcher::~K3bMsInfoFetcher() +{ + delete m_process; +} + + +void K3bMsInfoFetcher::start() +{ + jobStarted(); + + emit infoMessage( i18n("Searching previous session"), K3bJob::INFO ); + + if( !k3bcore->externalBinManager()->foundBin( "cdrecord" ) ) { + kdDebug() << "(K3bMsInfoFetcher) could not find cdrecord executable" << endl; + emit infoMessage( i18n("Could not find %1 executable.").arg("cdrecord"), K3bJob::ERROR ); + jobFinished(false); + return; + } + + if( m_device == 0 ) { + kdDebug() << "(K3bMsInfoFetcher) internal error: No device set!" << endl; + jobFinished(false); + return; + } + + // + // first we try to determine if it is a dvd. If so we need to + // read the info on our own + // + + connect( K3bDevice::sendCommand( K3bDevice::DeviceHandler::NG_DISKINFO, m_device ), + SIGNAL(finished(K3bDevice::DeviceHandler*)), + this, + SLOT(slotMediaDetectionFinished(K3bDevice::DeviceHandler*)) ); +} + + +void K3bMsInfoFetcher::getMsInfo() +{ + delete m_process; + m_process = new KProcess(); + + const K3bExternalBin* bin = 0; + if( m_dvd ) { + // already handled + } + else { + bin = k3bcore->externalBinManager()->binObject( "cdrecord" ); + + if( !bin ) { + emit infoMessage( i18n("Could not find %1 executable.").arg( m_dvd ? "dvdrecord" : "cdrecord" ), ERROR ); + jobFinished(false); + return; + } + + *m_process << bin->path; + + // add the device (e.g. /dev/sg1) + *m_process << QString("dev=%1").arg( K3b::externalBinDeviceParameter(m_device, bin) ); + + *m_process << "-msinfo"; + + // additional user parameters from config + const QStringList& params = bin->userParameters(); + for( QStringList::const_iterator it = params.begin(); it != params.end(); ++it ) + *m_process << *it; + + kdDebug() << "***** " << bin->name() << " parameters:\n"; + const QValueList& args = m_process->args(); + QString s; + for( QValueList::const_iterator it = args.begin(); it != args.end(); ++it ) { + s += *it + " "; + } + kdDebug() << s << flush << endl; + emit debuggingOutput( "msinfo command:", s ); + + + // connect( m_process, SIGNAL(receivedStderr(KProcess*, char*, int)), + // this, SLOT(slotCollectOutput(KProcess*, char*, int)) ); + connect( m_process, SIGNAL(receivedStdout(KProcess*, char*, int)), + this, SLOT(slotCollectOutput(KProcess*, char*, int)) ); + connect( m_process, SIGNAL(processExited(KProcess*)), + this, SLOT(slotProcessExited()) ); + + m_msInfo = QString::null; + m_collectedOutput = QString::null; + m_canceled = false; + + if( !m_process->start( KProcess::NotifyOnExit, KProcess::AllOutput ) ) { + emit infoMessage( i18n("Could not start %1.").arg(bin->name()), K3bJob::ERROR ); + jobFinished(false); + } + } +} + + +void K3bMsInfoFetcher::slotMediaDetectionFinished( K3bDevice::DeviceHandler* h ) +{ + if( h->success() ) { + m_dvd = h->diskInfo().isDvdMedia(); + } + else { + // for now we just default to cd and go on with the detecting + m_dvd = false; + } + + if( m_dvd ) { + if( h->diskInfo().mediaType() & (K3bDevice::MEDIA_DVD_PLUS_RW|K3bDevice::MEDIA_DVD_RW_OVWR) ) { + // get info from iso filesystem + K3bIso9660 iso( m_device, h->toc().last().firstSector().lba() ); + if( iso.open() ) { + unsigned long long nextSession = iso.primaryDescriptor().volumeSpaceSize; + // pad to closest 32K boundary + nextSession += 15; + nextSession /= 16; + nextSession *= 16; + m_msInfo.sprintf( "16,%llu", nextSession ); + + jobFinished( true ); + } + else { + emit infoMessage( i18n("Could not open Iso9660 filesystem in %1.") + .arg( m_device->vendor() + " " + m_device->description() ), ERROR ); + jobFinished( false ); + } + } + else { + unsigned int lastSessionStart, nextWritableAdress; + if( m_device->getNextWritableAdress( lastSessionStart, nextWritableAdress ) ) { + m_msInfo.sprintf( "%u,%u", lastSessionStart+16, nextWritableAdress ); + jobFinished( true ); + } + else { + emit infoMessage( i18n("Could not determine next writable address."), ERROR ); + jobFinished( false ); + } + } + } + else // call cdrecord + getMsInfo(); +} + + +void K3bMsInfoFetcher::slotProcessExited() +{ + if( m_canceled ) + return; + + kdDebug() << "(K3bMsInfoFetcher) msinfo fetched" << endl; + + // now parse the output + QString firstLine = m_collectedOutput.left( m_collectedOutput.find("\n") ); + QStringList list = QStringList::split( ",", firstLine ); + if( list.count() == 2 ) { + bool ok1, ok2; + m_lastSessionStart = list.first().toInt( &ok1 ); + m_nextSessionStart = list[1].toInt( &ok2 ); + if( ok1 && ok2 ) + m_msInfo = firstLine.stripWhiteSpace(); + else + m_msInfo = QString::null; + } + else { + m_msInfo = QString::null; + } + + kdDebug() << "(K3bMsInfoFetcher) msinfo parsed: " << m_msInfo << endl; + + if( m_msInfo.isEmpty() ) { + emit infoMessage( i18n("Could not retrieve multisession information from disk."), K3bJob::ERROR ); + emit infoMessage( i18n("The disk is either empty or not appendable."), K3bJob::ERROR ); + jobFinished(false); + } + else { + jobFinished(true); + } +} + + +void K3bMsInfoFetcher::slotCollectOutput( KProcess*, char* output, int len ) +{ + emit debuggingOutput( "msinfo", QString::fromLocal8Bit( output, len ) ); + + m_collectedOutput += QString::fromLocal8Bit( output, len ); +} + + +void K3bMsInfoFetcher::cancel() +{ + // FIXME: this does not work if the devicehandler is running + + if( m_process ) + if( m_process->isRunning() ) { + m_canceled = true; + m_process->kill(); + emit canceled(); + jobFinished(false); + } +} + + +#include "k3bmsinfofetcher.moc" diff --git a/libk3b/projects/datacd/k3bmsinfofetcher.h b/libk3b/projects/datacd/k3bmsinfofetcher.h new file mode 100644 index 0000000..593664f --- /dev/null +++ b/libk3b/projects/datacd/k3bmsinfofetcher.h @@ -0,0 +1,64 @@ +/* + * + * $Id: k3bmsinfofetcher.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef K3B_MSINFO_FETCHER_H +#define K3B_MSINFO_FETCHER_H + +#include + +namespace K3bDevice { + class Device; + class DeviceHandler; +} +class KProcess; + +class K3bMsInfoFetcher : public K3bJob +{ + Q_OBJECT + + public: + K3bMsInfoFetcher( K3bJobHandler*, QObject* parent = 0, const char* name = 0 ); + ~K3bMsInfoFetcher(); + + const QString& msInfo() const { return m_msInfo; } + int lastSessionStart() const { return m_lastSessionStart; } + int nextSessionStart() const { return m_nextSessionStart; } + + public slots: + void start(); + void cancel(); + + void setDevice( K3bDevice::Device* dev ) { m_device = dev; } + + private slots: + void slotProcessExited(); + void slotCollectOutput( KProcess*, char* output, int len ); + void slotMediaDetectionFinished( K3bDevice::DeviceHandler* ); + void getMsInfo(); + + private: + QString m_msInfo; + int m_lastSessionStart; + int m_nextSessionStart; + QString m_collectedOutput; + + KProcess* m_process; + K3bDevice::Device* m_device; + + bool m_canceled; + bool m_dvd; +}; + +#endif diff --git a/libk3b/projects/datacd/k3bsessionimportitem.cpp b/libk3b/projects/datacd/k3bsessionimportitem.cpp new file mode 100644 index 0000000..35f7936 --- /dev/null +++ b/libk3b/projects/datacd/k3bsessionimportitem.cpp @@ -0,0 +1,59 @@ +/* + * + * $Id: k3bsessionimportitem.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bsessionimportitem.h" +#include "k3bfileitem.h" +#include "k3bdiritem.h" + +#include + + +K3bSessionImportItem::K3bSessionImportItem( const K3bIso9660File* isoF, K3bDataDoc* doc, K3bDirItem* dir ) + : K3bDataItem( doc, dir ), + m_replaceItem(0), + m_size( isoF->size() ) + +{ + setK3bName( isoF->name() ); + + // add automagically like a qlistviewitem + if( parent() ) + parent()->addDataItem( this ); +} + + +K3bSessionImportItem::K3bSessionImportItem( const K3bSessionImportItem& item ) + : K3bDataItem( item ), + m_replaceItem( item.m_replaceItem ), + m_size( item.m_size ) +{ +} + + +K3bSessionImportItem::~K3bSessionImportItem() +{ + if( m_replaceItem ) + m_replaceItem->setReplacedItemFromOldSession(0); + + // remove this from parentdir + if( parent() ) + parent()->takeDataItem( this ); +} + + +K3bDataItem* K3bSessionImportItem::copy() const +{ + return new K3bSessionImportItem( *this ); +} diff --git a/libk3b/projects/datacd/k3bsessionimportitem.h b/libk3b/projects/datacd/k3bsessionimportitem.h new file mode 100644 index 0000000..33f8124 --- /dev/null +++ b/libk3b/projects/datacd/k3bsessionimportitem.h @@ -0,0 +1,63 @@ +/* + * + * $Id: k3bsessionimportitem.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_SESSION_IMPORT_ITEM_H_ +#define _K3B_SESSION_IMPORT_ITEM_H_ + + +#include "k3bdataitem.h" + + +class K3bDataDoc; +class K3bFileItem; +class K3bDirItem; +class K3bIso9660File; + + +class K3bSessionImportItem : public K3bDataItem +{ + public: + K3bSessionImportItem( const K3bIso9660File*, K3bDataDoc* doc, K3bDirItem* ); + K3bSessionImportItem( const K3bSessionImportItem& ); + ~K3bSessionImportItem(); + + K3bDataItem* copy() const; + + K3bFileItem* replaceItem() const { return m_replaceItem; } + void setReplaceItem( K3bFileItem* item ) { m_replaceItem = item; } + + bool isFile() const { return false; } + bool isFromOldSession() const { return true; } + + bool isRemoveable() const { return false; } + bool isMoveable() const { return false; } + bool isRenameable() const { return false; } + bool isHideable() const { return false; } + bool writeToCd() const { return false; } + + protected: + // the size of an item from an imported session does not depend + // on the value of followSymlinks + /** + * Normally one does not use this method but K3bDataItem::size() + */ + KIO::filesize_t itemSize( bool ) const { return m_size; } + + private: + K3bFileItem* m_replaceItem; + KIO::filesize_t m_size; +}; + +#endif diff --git a/libk3b/projects/datacd/k3bspecialdataitem.h b/libk3b/projects/datacd/k3bspecialdataitem.h new file mode 100644 index 0000000..05005ed --- /dev/null +++ b/libk3b/projects/datacd/k3bspecialdataitem.h @@ -0,0 +1,76 @@ +/* + * + * $Id: k3bspecialdataitem.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BSPECIALDATAITEM_H +#define K3BSPECIALDATAITEM_H + +#include "k3bdataitem.h" +#include "k3bdiritem.h" + +#include + +/** + * This can be used to create fake items like the boot catalog + * It's mainly a K3bDataItem where everything has to be set manually + */ +class K3bSpecialDataItem : public K3bDataItem +{ + public: + K3bSpecialDataItem( K3bDataDoc* doc, KIO::filesize_t size, K3bDirItem* parent = 0, const QString& k3bName = QString::null ) + : K3bDataItem( doc, parent ), + m_size( size ) + { + setK3bName( k3bName ); + + // add automagically like a qlistviewitem + if( parent ) + parent->addDataItem( this ); + } + + K3bSpecialDataItem( const K3bSpecialDataItem& item ) + : K3bDataItem( item ), + m_mimeType( item.m_mimeType ), + m_size( item.m_size ) { + } + + ~K3bSpecialDataItem() { + // remove this from parentdir + if( parent() ) + parent()->takeDataItem( this ); + } + + K3bDataItem* copy() const { + return new K3bSpecialDataItem( *this ); + } + + void setMimeType( const QString& s ) { m_mimeType = s; } + const QString& mimeType() const { return m_mimeType; } + + bool isSpecialFile() const { return true; } + + protected: + /** + * Normally one does not use this method but K3bDataItem::size() + */ + KIO::filesize_t itemSize( bool ) const { return m_size; } + + private: + QString m_mimeType; + KIO::filesize_t m_size; +}; + +#endif + diff --git a/libk3b/projects/datadvd/Makefile.am b/libk3b/projects/datadvd/Makefile.am new file mode 100644 index 0000000..99ae10c --- /dev/null +++ b/libk3b/projects/datadvd/Makefile.am @@ -0,0 +1,21 @@ +# we need the ../datacd for the uic generated header files +AM_CPPFLAGS= -I$(srcdir)/../../core \ + -I$(srcdir)/../../../libk3bdevice \ + -I$(srcdir)/../../../src \ + -I$(srcdir)/../../tools \ + -I$(srcdir)/../../jobs \ + -I$(srcdir)/../datacd \ + -I$(srcdir)/.. \ + -I../datacd \ + $(all_includes) + +METASOURCES = AUTO + +noinst_LTLIBRARIES = libdvd.la + +libdvd_la_SOURCES = k3bdvddoc.cpp \ + k3bdvdjob.cpp \ + k3bdvdbooktypejob.cpp + +include_HEADERS = k3bdvddoc.h \ + k3bdvdjob.h diff --git a/libk3b/projects/datadvd/k3bdvdbooktypejob.cpp b/libk3b/projects/datadvd/k3bdvdbooktypejob.cpp new file mode 100644 index 0000000..f703452 --- /dev/null +++ b/libk3b/projects/datadvd/k3bdvdbooktypejob.cpp @@ -0,0 +1,350 @@ +/* + * + * $Id: k3bdvdbooktypejob.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bdvdbooktypejob.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + + +class K3bDvdBooktypeJob::Private +{ +public: + Private() + : device(0), + process(0), + dvdBooktypeBin(0), + running(false), + forceNoEject(false) { + } + + K3bDevice::Device* device; + K3bProcess* process; + const K3bExternalBin* dvdBooktypeBin; + + bool success; + bool canceled; + bool running; + + bool forceNoEject; + + int foundMediaType; +}; + + +K3bDvdBooktypeJob::K3bDvdBooktypeJob( K3bJobHandler* jh, QObject* parent, const char* name ) + : K3bJob( jh, parent, name ), + m_action(0) +{ + d = new Private; +} + + +K3bDvdBooktypeJob::~K3bDvdBooktypeJob() +{ + delete d->process; + delete d; +} + + +void K3bDvdBooktypeJob::setForceNoEject( bool b ) +{ + d->forceNoEject = b; +} + + +QString K3bDvdBooktypeJob::jobDescription() const +{ + return i18n("Changing DVD Booktype"); // Changing DVD±R(W) Booktype +} + + +QString K3bDvdBooktypeJob::jobDetails() const +{ + return QString::null; +} + + +void K3bDvdBooktypeJob::start() +{ + d->canceled = false; + d->running = true; + + jobStarted(); + + if( !d->device ) { + emit infoMessage( i18n("No device set"), ERROR ); + jobFinished(false); + d->running = false; + return; + } + + // + // In case we want to change the writers default we do not need to wait for a media + // + if( m_action == SET_MEDIA_DVD_ROM || + m_action == SET_MEDIA_DVD_R_W ) { + emit newSubTask( i18n("Waiting for media") ); + if( waitForMedia( d->device, + K3bDevice::STATE_COMPLETE|K3bDevice::STATE_INCOMPLETE|K3bDevice::STATE_EMPTY, + K3bDevice::MEDIA_DVD_PLUS_RW|K3bDevice::MEDIA_DVD_PLUS_R, + i18n("Please insert an empty DVD+R or a DVD+RW medium into drive

%1 %2 (%3).") + .arg(d->device->vendor()).arg(d->device->description()).arg(d->device->devicename()) ) == -1 ) { + emit canceled(); + jobFinished(false); + d->running = false; + return; + } + + emit infoMessage( i18n("Checking media..."), INFO ); + emit newTask( i18n("Checking media") ); + + connect( K3bDevice::sendCommand( K3bDevice::DeviceHandler::NG_DISKINFO, d->device ), + SIGNAL(finished(K3bDevice::DeviceHandler*)), + this, + SLOT(slotDeviceHandlerFinished(K3bDevice::DeviceHandler*)) ); + } + else { + // change writer defaults + startBooktypeChange(); + } +} + + +void K3bDvdBooktypeJob::start( K3bDevice::DeviceHandler* dh ) +{ + d->canceled = false; + d->running = true; + + jobStarted(); + + slotDeviceHandlerFinished( dh ); +} + + +void K3bDvdBooktypeJob::cancel() +{ + if( d->running ) { + d->canceled = true; + if( d->process ) + d->process->kill(); + } + else { + kdDebug() << "(K3bDvdBooktypeJob) not running." << endl; + } +} + + +void K3bDvdBooktypeJob::setDevice( K3bDevice::Device* dev ) +{ + d->device = dev; +} + + +void K3bDvdBooktypeJob::slotStderrLine( const QString& line ) +{ + emit debuggingOutput( "dvd+rw-booktype", line ); + // FIXME +} + + +void K3bDvdBooktypeJob::slotProcessFinished( KProcess* p ) +{ + if( d->canceled ) { + emit canceled(); + d->success = false; + } + else if( p->normalExit() ) { + if( p->exitStatus() == 0 ) { + emit infoMessage( i18n("Booktype successfully changed"), K3bJob::SUCCESS ); + d->success = true; + } + else { + emit infoMessage( i18n("%1 returned an unknown error (code %2).").arg(d->dvdBooktypeBin->name()).arg(p->exitStatus()), + K3bJob::ERROR ); + emit infoMessage( i18n("Please send me an email with the last output."), K3bJob::ERROR ); + + d->success = false; + } + } + else { + emit infoMessage( i18n("%1 did not exit cleanly.").arg(d->dvdBooktypeBin->name()), + ERROR ); + d->success = false; + } + + // + // No need to eject the media if we changed the writer's default + // + if( m_action == SET_MEDIA_DVD_ROM || + m_action == SET_MEDIA_DVD_R_W ) { + + if( d->forceNoEject || + !k3bcore->globalSettings()->ejectMedia() ) { + d->running = false; + jobFinished(d->success); + } + else { + emit infoMessage( i18n("Ejecting DVD..."), INFO ); + connect( K3bDevice::eject( d->device ), + SIGNAL(finished(K3bDevice::DeviceHandler*)), + this, + SLOT(slotEjectingFinished(K3bDevice::DeviceHandler*)) ); + } + } + else { + d->running = false; + jobFinished(d->success); + } +} + + +void K3bDvdBooktypeJob::slotEjectingFinished( K3bDevice::DeviceHandler* dh ) +{ + if( !dh->success() ) + emit infoMessage( i18n("Unable to eject media."), ERROR ); + + d->running = false; + jobFinished(d->success); +} + + +void K3bDvdBooktypeJob::slotDeviceHandlerFinished( K3bDevice::DeviceHandler* dh ) +{ + if( d->canceled ) { + emit canceled(); + d->running = false; + jobFinished(false); + } + + if( dh->success() ) { + + d->foundMediaType = dh->diskInfo().mediaType(); + if( d->foundMediaType == K3bDevice::MEDIA_DVD_PLUS_R ) { + // the media needs to be empty + if( dh->diskInfo().empty() ) + startBooktypeChange(); + else { + emit infoMessage( i18n("Cannot change booktype on non-empty DVD+R media."), ERROR ); + jobFinished(false); + } + } + else if( d->foundMediaType == K3bDevice::MEDIA_DVD_PLUS_RW ) { + startBooktypeChange(); + } + else { + emit infoMessage( i18n("No DVD+R(W) media found."), ERROR ); + jobFinished(false); + } + } + else { + emit infoMessage( i18n("Unable to determine media state."), ERROR ); + d->running = false; + jobFinished(false); + } +} + + +void K3bDvdBooktypeJob::startBooktypeChange() +{ + delete d->process; + d->process = new K3bProcess(); + d->process->setRunPrivileged(true); + d->process->setSuppressEmptyLines(true); + connect( d->process, SIGNAL(stderrLine(const QString&)), this, SLOT(slotStderrLine(const QString&)) ); + connect( d->process, SIGNAL(processExited(KProcess*)), this, SLOT(slotProcessFinished(KProcess*)) ); + + d->dvdBooktypeBin = k3bcore->externalBinManager()->binObject( "dvd+rw-booktype" ); + if( !d->dvdBooktypeBin ) { + emit infoMessage( i18n("Could not find %1 executable.").arg("dvd+rw-booktype"), ERROR ); + d->running = false; + jobFinished(false); + return; + } + + *d->process << d->dvdBooktypeBin; + + switch( m_action ) { + case SET_MEDIA_DVD_ROM: + *d->process << "-dvd-rom-spec" + << "-media"; + break; + case SET_MEDIA_DVD_R_W: + if( d->foundMediaType == K3bDevice::MEDIA_DVD_PLUS_RW ) + *d->process << "-dvd+rw-spec"; + else + *d->process << "-dvd+r-spec"; + *d->process << "-media"; + break; + case SET_UNIT_DVD_ROM_ON_NEW_DVD_R: + *d->process << "-dvd-rom-spec" + << "-unit+r"; + break; + case SET_UNIT_DVD_ROM_ON_NEW_DVD_RW: + *d->process << "-dvd-rom-spec" + << "-unit+rw"; + break; + case SET_UNIT_DVD_R_ON_NEW_DVD_R: + *d->process << "-dvd+r-spec" + << "-unit+r"; + break; + case SET_UNIT_DVD_RW_ON_NEW_DVD_RW: + *d->process << "-dvd+rw-spec" + << "-unit+rw"; + break; + } + + *d->process << d->device->blockDeviceName(); + + kdDebug() << "***** dvd+rw-booktype parameters:\n"; + const QValueList& args = d->process->args(); + QString s; + for( QValueList::const_iterator it = args.begin(); it != args.end(); ++it ) { + s += *it + " "; + } + kdDebug() << s << endl << flush; + emit debuggingOutput( "dvd+rw-booktype command:", s ); + + + if( !d->process->start( KProcess::NotifyOnExit, KProcess::All ) ) { + // something went wrong when starting the program + // it "should" be the executable + emit infoMessage( i18n("Could not start %1.").arg(d->dvdBooktypeBin->name()), K3bJob::ERROR ); + d->running = false; + jobFinished(false); + } + else { + emit newTask( i18n("Changing Booktype") ); + } +} + +#include "k3bdvdbooktypejob.moc" diff --git a/libk3b/projects/datadvd/k3bdvdbooktypejob.h b/libk3b/projects/datadvd/k3bdvdbooktypejob.h new file mode 100644 index 0000000..b9e7e4b --- /dev/null +++ b/libk3b/projects/datadvd/k3bdvdbooktypejob.h @@ -0,0 +1,99 @@ +/* + * + * $Id: k3bdvdbooktypejob.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_DVD_BOOKTYPE_JOB_H_ +#define _K3B_DVD_BOOKTYPE_JOB_H_ + + +#include + + +class KProcess; +namespace K3bDevice { + class Device; + class DeviceHandler; +} + + +/** + * This job can change the compatibility bit of DVD+R(W) media + * with supported dvd writers. + */ +class K3bDvdBooktypeJob : public K3bJob +{ + Q_OBJECT + + public: + K3bDvdBooktypeJob( K3bJobHandler*, QObject* parent = 0, const char* name = 0 ); + ~K3bDvdBooktypeJob(); + + QString jobDescription() const; + QString jobDetails() const; + + /** + * @list SET_MEDIA_DVD_ROM Change media identification on current media to DVD-ROM. + * @list SET_MEDIA_DVD_R_W Change media identification on current media to DVD+R or DVD+RW. + * @list SET_UNIT_DVD_ROM_ON_NEW_DVD_R Set the drive to write DVD-ROM specification on future written DVD+R discs. + * @list SET_UNIT_DVD_ROM_ON_NEW_DVD_RW Set the drive to write DVD-ROM specification on future written DVD+RW discs. + * @list SET_UNIT_DVD_R_ON_NEW_DVD_R Set the drive to write DVD+R specification on future written DVD+R discs. + * @list SET_UNIT_DVD_RW_ON_NEW_DVD_RW Set the drive to write DVD+RW specification on future written DVD+RW discs. + */ + enum Action { + SET_MEDIA_DVD_ROM, + SET_MEDIA_DVD_R_W, + SET_UNIT_DVD_ROM_ON_NEW_DVD_R, + SET_UNIT_DVD_ROM_ON_NEW_DVD_RW, + SET_UNIT_DVD_R_ON_NEW_DVD_R, + SET_UNIT_DVD_RW_ON_NEW_DVD_RW + }; + + public slots: + void start(); + + /** + * The devicehandler needs to have a valid NgDiskInfo + * Use this to prevent the job from searching a media. + */ + void start( K3bDevice::DeviceHandler* ); + + void cancel(); + + void setDevice( K3bDevice::Device* ); + + void setAction( int a ) { m_action = a; } + + /** + * If set true the job ignores the global K3b setting + * and does not eject the CD-RW after finishing + */ + void setForceNoEject( bool ); + + private slots: + void slotStderrLine( const QString& ); + void slotProcessFinished( KProcess* ); + void slotDeviceHandlerFinished( K3bDevice::DeviceHandler* ); + void slotEjectingFinished( K3bDevice::DeviceHandler* ); + + private: + void startBooktypeChange(); + + int m_action; + + class Private; + Private* d; +}; + + +#endif diff --git a/libk3b/projects/datadvd/k3bdvddoc.cpp b/libk3b/projects/datadvd/k3bdvddoc.cpp new file mode 100644 index 0000000..4ab8b9f --- /dev/null +++ b/libk3b/projects/datadvd/k3bdvddoc.cpp @@ -0,0 +1,39 @@ +/* + * + * $Id: k3bdvddoc.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bdvddoc.h" +#include "k3bdvdjob.h" + +#include + +#include + + +K3bDvdDoc::K3bDvdDoc( QObject* parent ) + : K3bDataDoc( parent ) +{ +} + +K3bDvdDoc::~K3bDvdDoc() +{ +} + +K3bBurnJob* K3bDvdDoc::newBurnJob( K3bJobHandler* hdl, QObject* parent ) +{ + return new K3bDvdJob( this, hdl, parent ); +} + +//#include "k3bdvddoc.moc" diff --git a/libk3b/projects/datadvd/k3bdvddoc.h b/libk3b/projects/datadvd/k3bdvddoc.h new file mode 100644 index 0000000..03b5c3d --- /dev/null +++ b/libk3b/projects/datadvd/k3bdvddoc.h @@ -0,0 +1,37 @@ +/* + * + * $Id: k3bdvddoc.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_DVDDOC_H_ +#define _K3B_DVDDOC_H_ + +#include +#include "k3b_export.h" +class KConfig; + +class LIBK3B_EXPORT K3bDvdDoc : public K3bDataDoc +{ + public: + K3bDvdDoc( QObject* parent = 0 ); + virtual ~K3bDvdDoc(); + + virtual int type() const { return DVD; } + + virtual K3bBurnJob* newBurnJob( K3bJobHandler* hdl, QObject* parent = 0 ); + + protected: + virtual QString typeString() const { return "dvd"; } +}; + +#endif diff --git a/libk3b/projects/datadvd/k3bdvdjob.cpp b/libk3b/projects/datadvd/k3bdvdjob.cpp new file mode 100644 index 0000000..3cd1521 --- /dev/null +++ b/libk3b/projects/datadvd/k3bdvdjob.cpp @@ -0,0 +1,344 @@ +/* + * + * $Id: k3bdvdjob.cpp 690187 2007-07-20 09:18:03Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bdvdjob.h" +#include "k3bdvddoc.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +class K3bDvdJob::Private +{ +public: +}; + + +K3bDvdJob::K3bDvdJob( K3bDataDoc* doc, K3bJobHandler* hdl, QObject* parent ) + : K3bDataJob( doc, hdl, parent ), + m_doc( doc ) +{ + d = new Private(); +} + + +K3bDvdJob::~K3bDvdJob() +{ + delete d; +} + + +void K3bDvdJob::prepareData() +{ +} + + +bool K3bDvdJob::prepareWriterJob() +{ + K3bGrowisofsWriter* writer = new K3bGrowisofsWriter( m_doc->burner(), this, this ); + + // these do only make sense with DVD-R(W) + writer->setSimulate( m_doc->dummy() ); + writer->setBurnSpeed( m_doc->speed() ); + + // Andy said incremental sequential is the default mode and it seems uses have more problems with DAO anyway + // BUT: I also had a report that incremental sequential produced unreadable media! + if( m_doc->writingMode() == K3b::DAO ) +// || ( m_doc->writingMode() == K3b::WRITING_MODE_AUTO && +// usedMultiSessionMode() == K3bDataDoc::NONE ) ) + writer->setWritingMode( K3b::DAO ); + + writer->setMultiSession( usedMultiSessionMode() == K3bDataDoc::CONTINUE || + usedMultiSessionMode() == K3bDataDoc::FINISH ); + + writer->setCloseDvd( usedMultiSessionMode() == K3bDataDoc::NONE || + usedMultiSessionMode() == K3bDataDoc::FINISH ); + + writer->setImageToWrite( QString::null ); // read from stdin + writer->setTrackSize( m_isoImager->size() ); + + if( usedMultiSessionMode() != K3bDataDoc::NONE ) { + // + // growisofs wants a valid -C parameter for multisession, so we get it from the + // K3bMsInfoFetcher (see K3bDataJob::slotMsInfoFetched) + // + writer->setMultiSessionInfo( m_msInfoFetcher->msInfo() ); + } + + setWriterJob( writer ); + + return true; +} + + +void K3bDvdJob::determineMultiSessionMode() +{ + int m = requestMedia( K3bDevice::STATE_INCOMPLETE|K3bDevice::STATE_EMPTY ); + + if( m < 0 ) { + cancel(); + } + else { + connect( K3bDevice::sendCommand( K3bDevice::DeviceHandler::NG_DISKINFO, m_doc->burner() ), + SIGNAL(finished(K3bDevice::DeviceHandler*)), + this, + SLOT(slotDetermineMultiSessionMode(K3bDevice::DeviceHandler*)) ); + } +} + + +K3bDataDoc::MultiSessionMode K3bDvdJob::getMultiSessionMode( const K3bDevice::DiskInfo& info ) +{ + K3bDataDoc::MultiSessionMode mode = K3bDataDoc::NONE; + + if( info.mediaType() & (K3bDevice::MEDIA_DVD_PLUS_RW|K3bDevice::MEDIA_DVD_RW_OVWR) ) { + // + // we need to handle DVD+RW and DVD-RW overwrite media differently since remainingSize() is not valid + // in both cases + // Since one never closes a DVD+RW we only differ between CONTINUE and START + // + + // try to check the filesystem size + K3bIso9660 iso( m_doc->burner() ); + if( iso.open() && info.capacity() - iso.primaryDescriptor().volumeSpaceSize >= m_doc->burningLength() ) { + mode = K3bDataDoc::CONTINUE; + } + else { + mode = K3bDataDoc::START; + } + } + else if( info.appendable() ) { + // + // 3 cases: + // 1. the project does not fit -> no multisession (resulting in asking for another media above) + // 2. the project does fit and fills up the CD (No new sessions after the 4GB boundary) -> finish multisession + // 3. the project does fit and does not fill up the CD -> continue multisession + // + if( m_doc->size() > info.remainingSize().mode1Bytes() && !m_doc->sessionImported() ) + mode = K3bDataDoc::NONE; + else if( info.size() + m_doc->burningLength() + 11400 /* used size + project size + session gap */ > 2097152 /* 4 GB */ ) + mode = K3bDataDoc::FINISH; + else + mode = K3bDataDoc::CONTINUE; + } + else { + // + // We only close the DVD if the project fills it beyond the 4GB boundary + // + if( info.size() + m_doc->burningLength() + 11400 /* used size + project size + session gap */ > 2097152 /* 4 GB */ || + m_doc->writingMode() == K3b::DAO ) + mode = K3bDataDoc::NONE; + else + mode = K3bDataDoc::START; + } + + return mode; +} + + +int K3bDvdJob::requestMedia( int state ) +{ + int mt = 0; + if( m_doc->writingMode() == K3b::WRITING_MODE_RES_OVWR ) // we treat DVD+R(W) as restricted overwrite media + mt = K3bDevice::MEDIA_DVD_RW_OVWR|K3bDevice::MEDIA_DVD_PLUS_RW|K3bDevice::MEDIA_DVD_PLUS_R; + else + mt = K3bDevice::MEDIA_WRITABLE_DVD; + + // double layer media + // in case overburn is enabled we allow some made up max size + // before we force a DL medium + if( m_doc->size() > 4700372992LL ) { + if( !k3bcore->globalSettings()->overburn() || + m_doc->size() > 4900000000LL ) { + mt = K3bDevice::MEDIA_WRITABLE_DVD_DL; + } + } + + return waitForMedia( m_doc->burner(), + state, + mt ); +} + + +bool K3bDvdJob::waitForMedium() +{ + emit infoMessage( i18n("Waiting for media") + "...", INFO ); + + int foundMedium = requestMedia( usedMultiSessionMode() == K3bDataDoc::CONTINUE || + usedMultiSessionMode() == K3bDataDoc::FINISH ? + K3bDevice::STATE_INCOMPLETE : + K3bDevice::STATE_EMPTY ); + + if( foundMedium < 0 || hasBeenCanceled() ) { + return false; + } + + if( foundMedium == 0 ) { + emit infoMessage( i18n("Forced by user. Growisofs will be called without further tests."), INFO ); + } + + else { + // ------------------------------- + // DVD Plus + // ------------------------------- + if( foundMedium & K3bDevice::MEDIA_DVD_PLUS_ALL ) { + if( m_doc->dummy() ) { + if( !questionYesNo( i18n("K3b does not support simulation with DVD+R(W) media. " + "Do you really want to continue? The media will be written " + "for real."), + i18n("No Simulation with DVD+R(W)") ) ) { + return false; + } + + m_doc->setDummy( false ); + emit newTask( i18n("Writing") ); + } + + if( m_doc->writingMode() != K3b::WRITING_MODE_AUTO && m_doc->writingMode() != K3b::WRITING_MODE_RES_OVWR ) + emit infoMessage( i18n("Writing mode ignored when writing DVD+R(W) media."), INFO ); + + if( foundMedium & K3bDevice::MEDIA_DVD_PLUS_RW ) { + if( usedMultiSessionMode() == K3bDataDoc::NONE || + usedMultiSessionMode() == K3bDataDoc::START ) + emit infoMessage( i18n("Writing DVD+RW."), INFO ); + else + emit infoMessage( i18n("Growing ISO9660 filesystem on DVD+RW."), INFO ); + } + else if( foundMedium & K3bDevice::MEDIA_DVD_PLUS_R_DL ) + emit infoMessage( i18n("Writing Double Layer DVD+R."), INFO ); + else + emit infoMessage( i18n("Writing DVD+R."), INFO ); + } + + // ------------------------------- + // DVD Minus + // ------------------------------- + else { + if( m_doc->dummy() && !m_doc->burner()->dvdMinusTestwrite() ) { + if( !questionYesNo( i18n("Your writer (%1 %2) does not support simulation with DVD-R(W) media. " + "Do you really want to continue? The media will be written " + "for real.") + .arg(m_doc->burner()->vendor()) + .arg(m_doc->burner()->description()), + i18n("No Simulation with DVD-R(W)") ) ) { + return false; + } + + m_doc->setDummy( false ); + } + + // RESTRICTED OVERWRITE + // -------------------- + if( foundMedium & K3bDevice::MEDIA_DVD_RW_OVWR ) { + if( usedMultiSessionMode() == K3bDataDoc::NONE || + usedMultiSessionMode() == K3bDataDoc::START ) + emit infoMessage( i18n("Writing DVD-RW in restricted overwrite mode."), INFO ); + else + emit infoMessage( i18n("Growing ISO9660 filesystem on DVD-RW in restricted overwrite mode."), INFO ); + } + + // NORMAL + // ------ + else { + + // FIXME: DVD-R DL jump and stuff + + if( m_doc->writingMode() == K3b::DAO ) + // || ( m_doc->writingMode() == K3b::WRITING_MODE_AUTO && +// usedMultiSessionMode() == K3bDataDoc::NONE ) ) + emit infoMessage( i18n("Writing %1 in DAO mode.").arg( K3bDevice::mediaTypeString(foundMedium, true) ), INFO ); + + else { + // check if the writer supports writing sequential and thus multisession (on -1 the burner cannot handle + // features and we simply ignore it and hope for the best) + if( m_doc->burner()->featureCurrent( K3bDevice::FEATURE_INCREMENTAL_STREAMING_WRITABLE ) == 0 ) { + if( !questionYesNo( i18n("Your writer (%1 %2) does not support Incremental Streaming with %3 " + "media. Multisession will not be possible. Continue anyway?") + .arg(m_doc->burner()->vendor()) + .arg(m_doc->burner()->description()) + .arg( K3bDevice::mediaTypeString(foundMedium, true) ), + i18n("No Incremental Streaming") ) ) { + return false; + } + else { + emit infoMessage( i18n("Writing %1 in DAO mode.").arg( K3bDevice::mediaTypeString(foundMedium, true) ), INFO ); + } + } + else { + if( !(foundMedium & (K3bDevice::MEDIA_DVD_RW|K3bDevice::MEDIA_DVD_RW_OVWR|K3bDevice::MEDIA_DVD_RW_SEQ)) && + m_doc->writingMode() == K3b::WRITING_MODE_RES_OVWR ) + emit infoMessage( i18n("Restricted Overwrite is not possible with DVD-R media."), INFO ); + + emit infoMessage( i18n("Writing %1 in incremental mode.").arg( K3bDevice::mediaTypeString(foundMedium, true) ), INFO ); + } + } + } + } + } + + return true; +} + + +QString K3bDvdJob::jobDescription() const +{ + if( m_doc->onlyCreateImages() ) { + return i18n("Creating Data Image File"); + } + else if( m_doc->multiSessionMode() == K3bDataDoc::NONE || + m_doc->multiSessionMode() == K3bDataDoc::AUTO ) { + return i18n("Writing Data DVD") + + ( m_doc->isoOptions().volumeID().isEmpty() + ? QString::null + : QString( " (%1)" ).arg(m_doc->isoOptions().volumeID()) ); + } + else { + return i18n("Writing Multisession DVD") + + ( m_doc->isoOptions().volumeID().isEmpty() + ? QString::null + : QString( " (%1)" ).arg(m_doc->isoOptions().volumeID()) ); + } +} + + +QString K3bDvdJob::jobDetails() const +{ + if( m_doc->copies() > 1 && + !m_doc->dummy() && + !(m_doc->multiSessionMode() == K3bDataDoc::CONTINUE || + m_doc->multiSessionMode() == K3bDataDoc::FINISH) ) + return i18n("ISO9660 Filesystem (Size: %1) - %n copy", + "ISO9660 Filesystem (Size: %1) - %n copies", + m_doc->copies()) + .arg(KIO::convertSize( m_doc->size() )); + else + return i18n("ISO9660 Filesystem (Size: %1)") + .arg(KIO::convertSize( m_doc->size() )); +} + +#include "k3bdvdjob.moc" diff --git a/libk3b/projects/datadvd/k3bdvdjob.h b/libk3b/projects/datadvd/k3bdvdjob.h new file mode 100644 index 0000000..381bc1d --- /dev/null +++ b/libk3b/projects/datadvd/k3bdvdjob.h @@ -0,0 +1,57 @@ +/* + * + * $Id: k3bdvdjob.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_DVD_JOB_H_ +#define _K3B_DVD_JOB_H_ + +#include + +#include + +class K3bDataDoc; +class K3bGrowisofsWriter; + + +class K3bDvdJob : public K3bDataJob +{ + Q_OBJECT + + public: + /** + * To be more flexible we allow writing of any data doc + */ + K3bDvdJob( K3bDataDoc*, K3bJobHandler*, QObject* parent = 0 ); + virtual ~K3bDvdJob(); + + virtual QString jobDescription() const; + virtual QString jobDetails() const; + + protected: + void prepareData(); + virtual bool prepareWriterJob(); + void determineMultiSessionMode(); + K3bDataDoc::MultiSessionMode getMultiSessionMode( const K3bDevice::DiskInfo& ); + bool waitForMedium(); + int requestMedia( int state ); + + private: + K3bDataDoc* m_doc; + + class Private; + Private* d; +}; + +#endif diff --git a/libk3b/projects/datadvd/k3bdvdview.cpp b/libk3b/projects/datadvd/k3bdvdview.cpp new file mode 100644 index 0000000..512ec4b --- /dev/null +++ b/libk3b/projects/datadvd/k3bdvdview.cpp @@ -0,0 +1,48 @@ +/* + * + * $Id: k3bdvdview.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bdvdview.h" +#include "k3bdvddoc.h" +#include "k3bdvdburndialog.h" +#include +#include + +#include + + +K3bDvdView::K3bDvdView( K3bDvdDoc* doc, QWidget *parent, const char *name ) + : K3bDataView( doc, parent, name ) +{ + m_doc = doc; + + fillStatusDisplay()->showDvdSizes(true); + + m_dataFileView->setNoItemText( i18n("Use drag'n'drop to add files and directories to the project.\n" + "To remove or rename files use the context menu.\n" + "After that press the burn button to write the DVD.") ); +} + + +K3bDvdView::~K3bDvdView() +{ +} + + +K3bProjectBurnDialog* K3bDvdView::newBurnDialog( QWidget* parent, const char* name ) +{ + return new K3bDvdBurnDialog( m_doc, parent, name, true ); +} + +#include "k3bdvdview.moc" diff --git a/libk3b/projects/datadvd/k3bdvdview.h b/libk3b/projects/datadvd/k3bdvdview.h new file mode 100644 index 0000000..d9f30f3 --- /dev/null +++ b/libk3b/projects/datadvd/k3bdvdview.h @@ -0,0 +1,40 @@ +/* + * + * $Id: k3bdvdview.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_DVDVIEW_H_ +#define _K3B_DVDVIEW_H_ + +#include + +class K3bDvdDoc; + + +class K3bDvdView : public K3bDataView +{ + Q_OBJECT + + public: + K3bDvdView( K3bDvdDoc* doc, QWidget *parent = 0, const char *name = 0 ); + ~K3bDvdView(); + + protected: + virtual K3bProjectBurnDialog* newBurnDialog( QWidget* parent = 0, const char* name = 0 ); + + private: + K3bDvdDoc* m_doc; +}; + +#endif diff --git a/libk3b/projects/k3babstractwriter.cpp b/libk3b/projects/k3babstractwriter.cpp new file mode 100644 index 0000000..df22bc3 --- /dev/null +++ b/libk3b/projects/k3babstractwriter.cpp @@ -0,0 +1,96 @@ +/* + * + * $Id: k3babstractwriter.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3babstractwriter.h" + +#include +#include +#include +#include + +#include +#include + + + +K3bAbstractWriter::K3bAbstractWriter( K3bDevice::Device* dev, K3bJobHandler* jh, QObject* parent, const char* name ) + : K3bJob( jh, parent, name ), + m_burnDevice(dev), + m_burnSpeed(1), + m_simulate(false), + m_sourceUnreadable(false) +{ +} + + +K3bAbstractWriter::~K3bAbstractWriter() +{ +} + + +K3bDevice::Device* K3bAbstractWriter::burnDevice() +{ + if( m_burnDevice ) + return m_burnDevice; + else + return k3bcore->deviceManager()->burningDevices().getFirst(); +} + + +void K3bAbstractWriter::cancel() +{ + if( burnDevice() ) { + // we need to unlock the writer because cdrecord locked it while writing + emit infoMessage( i18n("Unlocking drive..."), INFO ); + connect( K3bDevice::unblock( burnDevice() ), SIGNAL(finished(bool)), + this, SLOT(slotUnblockWhileCancellationFinished(bool)) ); + } + else { + emit canceled(); + jobFinished(false); + } +} + + +void K3bAbstractWriter::slotUnblockWhileCancellationFinished( bool success ) +{ + if( !success ) + emit infoMessage( i18n("Could not unlock CD drive."), K3bJob::ERROR ); // FIXME: simply "drive", not "CD drive" + + if( k3bcore->globalSettings()->ejectMedia() ) { + emit newSubTask( i18n("Ejecting CD") ); // FIXME: "media" instead of "CD" + connect( K3bDevice::eject( burnDevice() ), SIGNAL(finished(bool)), + this, SLOT(slotEjectWhileCancellationFinished(bool)) ); + } + else { + emit canceled(); + jobFinished( false ); + } +} + + +void K3bAbstractWriter::slotEjectWhileCancellationFinished( bool success ) +{ + if( !success ) { + emit infoMessage( i18n("Unable to eject media."), K3bJob::ERROR ); + } + + emit canceled(); + jobFinished( false ); +} + + +#include "k3babstractwriter.moc" diff --git a/libk3b/projects/k3babstractwriter.h b/libk3b/projects/k3babstractwriter.h new file mode 100644 index 0000000..3f91ee3 --- /dev/null +++ b/libk3b/projects/k3babstractwriter.h @@ -0,0 +1,92 @@ +/* + * + * $Id: k3babstractwriter.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3B_ABSTRACT_WRITER_H +#define K3B_ABSTRACT_WRITER_H + + +#include "k3bjob.h" + +#include + +class K3bDevice::Device; +class K3bJobHandler; + + +class K3bAbstractWriter : public K3bJob +{ + Q_OBJECT + + public: + virtual ~K3bAbstractWriter(); + + K3bDevice::Device* burnDevice(); + int burnSpeed() const { return m_burnSpeed; } + bool simulate() const { return m_simulate; } + + /** + * This can be used to setup direct streaming between two processes + * for example the cdrecordwriter returnes the stdin fd which can be + * connected to the stdout fd of mkisofs in the isoimager + */ + virtual int fd() const { return -1; } + virtual bool closeFd() { return false; } + + public slots: + /** + * If the burnDevice is set this will try to unlock the drive and + * eject the disk if K3b is configured to do so. + * Will also emit canceled and finished signals. + * may be called by subclasses. + */ + void cancel(); + + void setBurnDevice( K3bDevice::Device* dev ) { m_burnDevice = dev; } + void setBurnSpeed( int s ) { m_burnSpeed = s; } + void setSimulate( bool b ) { m_simulate = b; } + + /** + * Used to inform the writer that the source (especially useful when reading from + * another cd/dvd media) could not be read. + * + * Basically it should be used to make sure no "write an email" message is thrown. + */ + void setSourceUnreadable( bool b = true ) { m_sourceUnreadable = b; } + + signals: + void buffer( int ); + void deviceBuffer( int ); + void writeSpeed( int, int ); + + protected: + K3bAbstractWriter( K3bDevice::Device* dev, K3bJobHandler* hdl, + QObject* parent = 0, const char* name = 0 ); + + bool wasSourceUnreadable() const { return m_sourceUnreadable; } + + protected slots: + void slotUnblockWhileCancellationFinished( bool success ); + void slotEjectWhileCancellationFinished( bool success ); + + private: + K3bDevice::Device* m_burnDevice; + int m_burnSpeed; + bool m_simulate; + bool m_sourceUnreadable; +}; + + +#endif diff --git a/libk3b/projects/k3bcdrdaowriter.cpp b/libk3b/projects/k3bcdrdaowriter.cpp new file mode 100644 index 0000000..c49cb4b --- /dev/null +++ b/libk3b/projects/k3bcdrdaowriter.cpp @@ -0,0 +1,1101 @@ +/* + * + * $Id: k3bcdrdaowriter.cpp 654649 2007-04-16 17:55:50Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * Klaus-Dieter Krannich + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bcdrdaowriter.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + + + +#define PGSMSG_MIN PGSMSG_RCD_ANALYZING +#define PGSMSG_RCD_ANALYZING 1 +#define PGSMSG_RCD_EXTRACTING 2 +#define PGSMSG_WCD_LEADIN 3 +#define PGSMSG_WCD_DATA 4 +#define PGSMSG_WCD_LEADOUT 5 +#define PGSMSG_BLK 6 +#define PGSMSG_MAX PGSMSG_BLK + +struct ProgressMsg { + int status; // see PGSMSG_* constants + int totalTracks; // total number of tracks + int track; // actually written track + int trackProgress; // progress for current track 0..1000 + int totalProgress; // total writing progress 0..1000 + int bufferFillRate; // buffer fill rate 0..100 +}; + +#define PSGMSG_MINSIZE 24 + +struct ProgressMsg2 { + int status; // see PGSMSG_* constants + int totalTracks; // total number of tracks + int track; // actually written track + int trackProgress; // progress for current track 0..1000 + int totalProgress; // total writing progress 0..1000 + int bufferFillRate; // buffer fill rate 0..100 + int writerFillRate; // device write buffer fill rate 0..100 +}; + + +inline bool operator<( const ProgressMsg2& m1, const ProgressMsg2& m2 ) +{ + return m1.track < m2.track + || ( m1.track == m2.track + && m1.trackProgress < m2.trackProgress ) + || m1.totalProgress < m2.totalProgress; +} + + +inline bool operator==( const ProgressMsg2& m1, const ProgressMsg2& m2 ) +{ + return m1.status == m2.status + && m1.track == m2.track + && m1.totalTracks == m2.totalTracks + && m1.trackProgress == m2.trackProgress + && m1.totalProgress == m2.totalProgress + && m1.bufferFillRate == m2.bufferFillRate; +} + +inline bool operator!=( const ProgressMsg2& m1, const ProgressMsg2& m2 ) +{ + return !( m1 == m2 ); +} + + + +class K3bCdrdaoWriter::Private +{ +public: + Private() { + } + + K3bThroughputEstimator* speedEst; + + int usedSpeed; + + ProgressMsg2 oldMsg; + ProgressMsg2 newMsg; + + unsigned int progressMsgSize; +}; + + +K3bCdrdaoWriter::K3bCdrdaoWriter( K3bDevice::Device* dev, K3bJobHandler* hdl, + QObject* parent, const char* name ) + : K3bAbstractWriter( dev, hdl, parent, name ), + m_command(WRITE), + m_blankMode(MINIMAL), + m_sourceDevice(0), + m_readRaw(false), + m_multi(false), + m_force(false), + m_onTheFly(false), + m_fastToc(false), + m_readSubchan(None), + m_taoSource(false), + m_taoSourceAdjust(-1), + m_paranoiaMode(-1), + m_session(-1), + m_process(0), + m_comSock(0), + m_currentTrack(0), + m_forceNoEject(false) +{ + d = new Private(); + d->speedEst = new K3bThroughputEstimator( this ); + connect( d->speedEst, SIGNAL(throughput(int)), + this, SLOT(slotThroughput(int)) ); + + m_eject = k3bcore->globalSettings()->ejectMedia(); + + ::memset( &d->oldMsg, 0, sizeof(ProgressMsg2) ); + ::memset( &d->newMsg, 0, sizeof(ProgressMsg2) ); + + if( socketpair(AF_UNIX,SOCK_STREAM,0,m_cdrdaoComm) ) + { + kdDebug() << "(K3bCdrdaoWriter) could not open socketpair for cdrdao remote messages" << endl; + } + else + { + delete m_comSock; + m_comSock = new QSocket(); + m_comSock->setSocket(m_cdrdaoComm[1]); + m_comSock->socketDevice()->setReceiveBufferSize(49152); + // magic number from Qt documentation + m_comSock->socketDevice()->setBlocking(false); + connect( m_comSock, SIGNAL(readyRead()), + this, SLOT(parseCdrdaoMessage())); + } +} + +K3bCdrdaoWriter::~K3bCdrdaoWriter() +{ + delete d->speedEst; + delete d; + + // close the socket + if( m_comSock ) { + m_comSock->close(); + ::close( m_cdrdaoComm[0] ); + } + delete m_process; + delete m_comSock; +} + + +int K3bCdrdaoWriter::fd() const +{ + if( m_process ) + return m_process->stdinFd(); + else + return -1; +} + + +bool K3bCdrdaoWriter::active() const +{ + return (m_process ? m_process->isRunning() : false); +} + + +void K3bCdrdaoWriter::prepareArgumentList() +{ + + // binary + *m_process << m_cdrdaoBinObject; + + // command + switch ( m_command ) + { + case COPY: + *m_process << "copy"; + setWriteArguments(); + setReadArguments(); + setCopyArguments(); + break; + case WRITE: + *m_process << "write"; + setWriteArguments(); + break; + case READ: + *m_process << "read-cd"; + // source device and source driver + if ( m_sourceDevice ) + *m_process << "--device" + << K3b::externalBinDeviceParameter(m_sourceDevice, m_cdrdaoBinObject); + if ( m_sourceDevice->cdrdaoDriver() != "auto" ) + *m_process << "--driver" << m_sourceDevice->cdrdaoDriver(); + else if( defaultToGenericMMC( m_sourceDevice, false ) ) { + kdDebug() << "(K3bCdrdaoWriter) defaulting to generic-mmc driver for " << m_sourceDevice->blockDeviceName() << endl; + *m_process << "--driver" << "generic-mmc"; + } + setReadArguments(); + break; + case BLANK: + *m_process << "blank"; + setBlankArguments(); + break; + } + + setCommonArguments(); +} + +void K3bCdrdaoWriter::setWriteArguments() +{ + // device and driver + *m_process << "--device" + << K3b::externalBinDeviceParameter(burnDevice(), m_cdrdaoBinObject); + + if( burnDevice()->cdrdaoDriver() != "auto" ) + { + *m_process << "--driver"; + if( burnDevice()->cdTextCapable() == 1 ) + *m_process << QString("%1:0x00000010").arg( burnDevice()->cdrdaoDriver() ); + else + *m_process << burnDevice()->cdrdaoDriver(); + } + else if( defaultToGenericMMC( burnDevice(), true ) ) { + kdDebug() << "(K3bCdrdaoWriter) defaulting to generic-mmc driver for " << burnDevice()->blockDeviceName() << endl; + *m_process << "--driver" << "generic-mmc:0x00000010"; + } + + // burn speed + if( d->usedSpeed != 0 ) + *m_process << "--speed" << QString("%1").arg(d->usedSpeed); + + //simulate + if( simulate() ) + *m_process << "--simulate"; + + // multi + if( m_multi ) + *m_process << "--multi"; + + // force + if( m_force ) + *m_process << "--force"; + + // burnproof + if ( !k3bcore->globalSettings()->burnfree() ) { + if( m_cdrdaoBinObject->hasFeature( "disable-burnproof" ) ) + *m_process << "--buffer-under-run-protection" << "0"; + else + emit infoMessage( i18n("Cdrdao %1 does not support disabling burnfree.").arg(m_cdrdaoBinObject->version), WARNING ); + } + + if( k3bcore->globalSettings()->force() ) { + *m_process << "--force"; + emit infoMessage( i18n("'Force unsafe operations' enabled."), WARNING ); + } + + bool manualBufferSize = + k3bcore->globalSettings()->useManualBufferSize(); + if( manualBufferSize ) { + // + // one buffer in cdrdao holds 1 second of audio data = 75 frames = 75 * 2352 bytes + // + int bufSizeInMb = k3bcore->globalSettings()->bufferSize(); + *m_process << "--buffers" << QString::number( bufSizeInMb*1024*1024/(75*2352) ); + } + + bool overburn = + k3bcore->globalSettings()->overburn(); + if( overburn ) { + if( m_cdrdaoBinObject->hasFeature("overburn") ) + *m_process << "--overburn"; + else + emit infoMessage( i18n("Cdrdao %1 does not support overburning.").arg(m_cdrdaoBinObject->version), WARNING ); + } + +} + +void K3bCdrdaoWriter::setReadArguments() +{ + // readRaw + if ( m_readRaw ) + *m_process << "--read-raw"; + + // subchan + if ( m_readSubchan != None ) + { + *m_process << "--read-subchan"; + switch ( m_readSubchan ) + { + case RW: + *m_process << "rw"; + break; + case RW_RAW: + *m_process << "rw_raw"; + break; + case None: + break; + } + } + + // TAO Source + if ( m_taoSource ) + *m_process << "--tao-source"; + + // TAO Source Adjust + if ( m_taoSourceAdjust != -1 ) + *m_process << "--tao-source-adjust" + << QString("%1").arg(m_taoSourceAdjust); + + // paranoia Mode + if ( m_paranoiaMode != -1 ) + *m_process << "--paranoia-mode" + << QString("%1").arg(m_paranoiaMode); + + // session + if ( m_session != -1 ) + *m_process << "--session" + << QString("%1").arg(m_session); + + // fast TOC + if ( m_fastToc ) + *m_process << "--fast-toc"; + +} + +void K3bCdrdaoWriter::setCopyArguments() +{ + // source device and source driver + *m_process << "--source-device" << K3b::externalBinDeviceParameter(m_sourceDevice, m_cdrdaoBinObject); + if ( m_sourceDevice->cdrdaoDriver() != "auto" ) + *m_process << "--source-driver" << m_sourceDevice->cdrdaoDriver(); + else if( defaultToGenericMMC( m_sourceDevice, false ) ) { + kdDebug() << "(K3bCdrdaoWriter) defaulting to generic-mmc driver for " << m_sourceDevice->blockDeviceName() << endl; + *m_process << "--source-driver" << "generic-mmc"; + } + + // on-the-fly + if ( m_onTheFly ) + *m_process << "--on-the-fly"; +} + +void K3bCdrdaoWriter::setBlankArguments() +{ + // device and driver + *m_process << "--device" + << K3b::externalBinDeviceParameter(burnDevice(), m_cdrdaoBinObject); + + if( burnDevice()->cdrdaoDriver() != "auto" ) + { + *m_process << "--driver"; + if( burnDevice()->cdTextCapable() == 1 ) + *m_process << QString("%1:0x00000010").arg( burnDevice()->cdrdaoDriver() ); + else + *m_process << burnDevice()->cdrdaoDriver(); + } + else if( defaultToGenericMMC( burnDevice(), true ) ) { + kdDebug() << "(K3bCdrdaoWriter) defaulting to generic-mmc driver for " << burnDevice()->blockDeviceName() << endl; + *m_process << "--driver" << "generic-mmc"; + } + + // burn speed + if( d->usedSpeed != 0 ) + *m_process << "--speed" << QString("%1").arg(d->usedSpeed); + + // blank-mode + *m_process << "--blank-mode"; + switch (m_blankMode) + { + case FULL: + *m_process << "full"; + break; + case MINIMAL: + *m_process << "minimal"; + break; + } +} + +void K3bCdrdaoWriter::setCommonArguments() +{ + + // additional user parameters from config + const QStringList& params = m_cdrdaoBinObject->userParameters(); + for( QStringList::const_iterator it = params.begin(); it != params.end(); ++it ) + *m_process << *it; + + + // display debug info + *m_process << "-n" << "-v" << "2"; + + // we have the power to do what ever we want. ;) + *m_process << "--force"; + + // eject + if( m_eject && !m_forceNoEject ) + *m_process << "--eject"; + + // remote + *m_process << "--remote" << QString("%1").arg(m_cdrdaoComm[0]); + + // data File + if ( ! m_dataFile.isEmpty() ) + *m_process << "--datafile" << m_dataFile; + + // BIN/CUE + if ( ! m_cueFileLnk.isEmpty() ) + *m_process << m_cueFileLnk; + // TOC File + else if ( ! m_tocFile.isEmpty() ) + *m_process << m_tocFile; +} + +K3bCdrdaoWriter* K3bCdrdaoWriter::addArgument( const QString& arg ) +{ + *m_process << arg; + return this; +} + + +void K3bCdrdaoWriter::start() +{ + jobStarted(); + + d->speedEst->reset(); + + delete m_process; // kdelibs want this! + m_process = new K3bProcess(); + m_process->setRunPrivileged(true); + m_process->setSplitStdout(false); + m_process->setRawStdin(true); + connect( m_process, SIGNAL(stderrLine(const QString&)), + this, SLOT(slotStdLine(const QString&)) ); + connect( m_process, SIGNAL(processExited(KProcess*)), + this, SLOT(slotProcessExited(KProcess*)) ); + + m_canceled = false; + m_knownError = false; + + m_cdrdaoBinObject = k3bcore->externalBinManager()->binObject("cdrdao"); + + if( !m_cdrdaoBinObject ) { + emit infoMessage( i18n("Could not find %1 executable.").arg("cdrdao"), ERROR ); + jobFinished(false); + return; + } + + emit debuggingOutput( "Used versions", "cdrdao: " + m_cdrdaoBinObject->version ); + + if( !m_cdrdaoBinObject->copyright.isEmpty() ) + emit infoMessage( i18n("Using %1 %2 - Copyright (C) %3").arg(m_cdrdaoBinObject->name()).arg(m_cdrdaoBinObject->version).arg(m_cdrdaoBinObject->copyright), INFO ); + + + // the message size changed in cdrdao 1.1.8) + if( m_cdrdaoBinObject->version >= K3bVersion( 1, 1, 8 ) ) + d->progressMsgSize = sizeof(ProgressMsg2); + else + d->progressMsgSize = sizeof(ProgressMsg); + + // since the --speed parameter is used several times in this code we + // determine the speed in auto once at the beginning + d->usedSpeed = burnSpeed(); + if( d->usedSpeed == 0 ) { + // try to determine the writeSpeed + // if it fails determineMaximalWriteSpeed() will return 0 and + // the choice is left to cdrdao + d->usedSpeed = burnDevice()->determineMaximalWriteSpeed(); + } + d->usedSpeed /= 175; + + switch ( m_command ) + { + case WRITE: + case COPY: + if (!m_tocFile.isEmpty()) + { + + // if tocfile is a cuesheet than create symlinks to *.cue and the binary listed inside the cuesheet. + // now works without the .bin extension too. + if ( !cueSheet() ) { + m_backupTocFile = m_tocFile + ".k3bbak"; + + // workaround, cdrdao deletes the tocfile when --remote parameter is set + if ( !KIO::NetAccess::copy(KURL(m_tocFile),KURL(m_backupTocFile), (QWidget*) 0) ) + { + kdDebug() << "(K3bCdrdaoWriter) could not backup " << m_tocFile << " to " << m_backupTocFile << endl; + emit infoMessage( i18n("Could not backup tocfile."), ERROR ); + jobFinished(false); + return; + } + } + } + break; + case BLANK: + case READ: + break; + } + prepareArgumentList(); + // set working dir to dir part of toc file (to allow rel names in toc-file) + m_process->setWorkingDirectory(QUrl(m_tocFile).dirPath()); + + kdDebug() << "***** cdrdao parameters:\n"; + const QValueList& args = m_process->args(); + QString s; + for( QValueList::const_iterator it = args.begin(); it != args.end(); ++it ) + { + s += *it + " "; + } + kdDebug() << s << flush << endl; + emit debuggingOutput("cdrdao command:", s); + + m_currentTrack = 0; + reinitParser(); + + switch ( m_command ) + { + case READ: + emit newSubTask( i18n("Preparing read process...") ); + break; + case WRITE: + emit newSubTask( i18n("Preparing write process...") ); + break; + case COPY: + emit newSubTask( i18n("Preparing copy process...") ); + break; + case BLANK: + emit newSubTask( i18n("Preparing blanking process...") ); + break; + } + + // FIXME: check the return value + if( K3b::isMounted( burnDevice() ) ) { + emit infoMessage( i18n("Unmounting medium"), INFO ); + K3b::unmount( burnDevice() ); + } + + // block the device (including certain checks) + k3bcore->blockDevice( burnDevice() ); + + // lock the device for good in this process since it will + // be opened in the growisofs process + burnDevice()->close(); + burnDevice()->usageLock(); + + if( !m_process->start( KProcess::NotifyOnExit, KProcess::AllOutput ) ) + { + // something went wrong when starting the program + // it "should" be the executable + kdDebug() << "(K3bCdrdaoWriter) could not start cdrdao" << endl; + emit infoMessage( i18n("Could not start %1.").arg("cdrdao"), K3bJob::ERROR ); + jobFinished(false); + } + else + { + switch ( m_command ) + { + case WRITE: + if( simulate() ) + { + emit infoMessage(i18n("Starting DAO simulation at %1x speed...").arg(d->usedSpeed), + K3bJob::INFO ); + emit newTask( i18n("Simulating") ); + } + else + { + emit infoMessage( i18n("Starting DAO writing at %1x speed...").arg(d->usedSpeed), K3bJob::INFO ); + emit newTask( i18n("Writing") ); + } + break; + case READ: + emit infoMessage(i18n("Starting reading..."), K3bJob::INFO ); + emit newTask( i18n("Reading") ); + break; + case COPY: + if( simulate() ) + { + emit infoMessage(i18n("Starting simulation copy at %1x speed...").arg(d->usedSpeed), K3bJob::INFO ); + emit newTask( i18n("Simulating") ); + } + else + { + emit infoMessage( i18n("Starting copy at %1x speed...").arg(d->usedSpeed), K3bJob::INFO ); + emit newTask( i18n("Copying") ); + } + break; + case BLANK: + emit infoMessage(i18n("Starting blanking..."), K3bJob::INFO ); + emit newTask( i18n("Blanking") ); + } + } +} + + +void K3bCdrdaoWriter::cancel() +{ + m_canceled = true; + + if( m_process ) { + if( m_process->isRunning() ) { + m_process->disconnect(); + m_process->kill(); + + // we need to unlock the device because cdrdao locked it while writing + // + // FIXME: try to determine wheater we are writing or reading and choose + // the device to unblock based on that result. + // + if( m_command == READ ) { + // FIXME: this is a hack + setBurnDevice( m_sourceDevice ); + } + + // this will unblock and eject the drive and emit the finished/canceled signals + K3bAbstractWriter::cancel(); + } + } +} + + +bool K3bCdrdaoWriter::cueSheet() +{ + + // TODO: do this in the K3bCueFileParser + + if ( m_tocFile.lower().endsWith( ".cue" ) ) { + QFile f( m_tocFile ); + if ( f.open( IO_ReadOnly ) ) { + QTextStream ts( &f ); + if ( !ts.eof() ) { + QString line = ts.readLine(); + f.close(); + int pos = line.find( "FILE \"" ); + if( pos < 0 ) + return false; + + pos += 6; + int endPos = line.find( "\" BINARY", pos+1 ); + if( endPos < 0 ) + return false; + + line = line.mid( pos, endPos-pos ); + QFileInfo fi( QFileInfo( m_tocFile ).dirPath() + "/" + QFileInfo( line ).fileName() ); + QString binpath = fi.filePath(); + kdDebug() << QString("K3bCdrdaoWriter::cueSheet() BinFilePath from CueFile: %1").arg( line ) << endl; + kdDebug() << QString("K3bCdrdaoWriter::cueSheet() absolute BinFilePath: %1").arg( binpath ) << endl; + + if ( !fi.exists() ) + return false; + + KTempFile tempF; + QString tempFile = tempF.name(); + tempF.unlink(); + + if ( symlink(QFile::encodeName( binpath ), QFile::encodeName( tempFile + ".bin") ) == -1 ) + return false; + if ( symlink(QFile::encodeName( m_tocFile ), QFile::encodeName( tempFile + ".cue") ) == -1 ) + return false; + + kdDebug() << QString("K3bCdrdaoWriter::cueSheet() symlink BinFileName: %1.bin").arg( tempFile ) << endl; + kdDebug() << QString("K3bCdrdaoWriter::cueSheet() symlink CueFileName: %1.cue").arg( tempFile ) << endl; + m_binFileLnk = tempFile + ".bin"; + m_cueFileLnk = tempFile + ".cue"; + return true; + } + } + } + + return false; +} + +void K3bCdrdaoWriter::slotStdLine( const QString& line ) +{ + parseCdrdaoLine(line); +} + + +void K3bCdrdaoWriter::slotProcessExited( KProcess* p ) +{ + // release the device within this process + burnDevice()->usageUnlock(); + + // unblock the device + k3bcore->unblockDevice( burnDevice() ); + + switch ( m_command ) + { + case WRITE: + case COPY: + if ( !m_binFileLnk.isEmpty() ) { + KIO::NetAccess::del(KURL::fromPathOrURL(m_cueFileLnk), (QWidget*) 0); + KIO::NetAccess::del(KURL::fromPathOrURL(m_binFileLnk), (QWidget*) 0); + } + else if( (!QFile::exists( m_tocFile ) || K3b::filesize( KURL::fromPathOrURL(m_tocFile) ) == 0 ) && !m_onTheFly ) + { + // cdrdao removed the tocfile :( + // we need to recover it + if ( !KIO::NetAccess::copy(KURL::fromPathOrURL(m_backupTocFile), KURL::fromPathOrURL(m_tocFile), (QWidget*) 0) ) + { + kdDebug() << "(K3bCdrdaoWriter) restoring tocfile " << m_tocFile << " failed." << endl; + emit infoMessage( i18n("Due to a bug in cdrdao the toc/cue file %1 has been deleted. " + "K3b was unable to restore it from the backup %2.").arg(m_tocFile).arg(m_backupTocFile), ERROR ); + } + else if ( !KIO::NetAccess::del(KURL::fromPathOrURL(m_backupTocFile), (QWidget*) 0) ) + { + kdDebug() << "(K3bCdrdaoWriter) delete tocfile backkup " << m_backupTocFile << " failed." << endl; + } + } + break; + case BLANK: + case READ: + break; + } + + if( m_canceled ) + return; + + if( p->normalExit() ) + { + switch( p->exitStatus() ) + { + case 0: + if( simulate() ) + emit infoMessage( i18n("Simulation successfully completed"), K3bJob::SUCCESS ); + else + switch ( m_command ) + { + case READ: + emit infoMessage( i18n("Reading successfully completed"), K3bJob::SUCCESS ); + break; + case WRITE: + emit infoMessage( i18n("Writing successfully completed"), K3bJob::SUCCESS ); + break; + case COPY: + emit infoMessage( i18n("Copying successfully completed"), K3bJob::SUCCESS ); + break; + case BLANK: + emit infoMessage( i18n("Blanking successfully completed"), K3bJob::SUCCESS ); + break; + } + + if( m_command == WRITE || m_command == COPY ) { + int s = d->speedEst->average(); + emit infoMessage( i18n("Average overall write speed: %1 KB/s (%2x)").arg(s).arg(KGlobal::locale()->formatNumber((double)s/150.0), 2), INFO ); + } + + jobFinished( true ); + break; + + default: + if( !m_knownError && !wasSourceUnreadable() ) { + emit infoMessage( i18n("%1 returned an unknown error (code %2).").arg(m_cdrdaoBinObject->name()).arg(p->exitStatus()), + K3bJob::ERROR ); + emit infoMessage( i18n("Please include the debugging output in your problem report."), K3bJob::ERROR ); + } + + jobFinished( false ); + break; + } + } + else + { + emit infoMessage( i18n("%1 did not exit cleanly.").arg("cdrdao"), K3bJob::ERROR ); + jobFinished( false ); + } +} + + +void K3bCdrdaoWriter::unknownCdrdaoLine( const QString& line ) +{ + if( line.contains( "at speed" ) ) + { + // parse the speed and inform the user if cdrdao switched it down + int pos = line.find( "at speed" ); + int po2 = line.find( QRegExp("\\D"), pos + 9 ); + int speed = line.mid( pos+9, po2-pos-9 ).toInt(); + if( speed < d->usedSpeed ) + { + emit infoMessage( i18n("Medium or burner do not support writing at %1x speed").arg(d->usedSpeed), K3bJob::WARNING ); + emit infoMessage( i18n("Switching down burn speed to %1x").arg(speed), K3bJob::WARNING ); + } + } +} + + +void K3bCdrdaoWriter::reinitParser() +{ + ::memset( &d->oldMsg, 0, sizeof(ProgressMsg2) ); + ::memset( &d->newMsg, 0, sizeof(ProgressMsg2) ); + + m_currentTrack=0; +} + +void K3bCdrdaoWriter::parseCdrdaoLine( const QString& str ) +{ + emit debuggingOutput( "cdrdao", str ); + // kdDebug() << "(cdrdaoparse)" << str << endl; + // find some messages from cdrdao + // ----------------------------------------------------------------------------------------- + if( (str).startsWith( "Warning" ) || (str).startsWith( "WARNING" ) || (str).startsWith( "ERROR" ) ) + { + parseCdrdaoError( str ); + } + else if( (str).startsWith( "Wrote" ) && !str.contains("blocks") ) + { + parseCdrdaoWrote( str ); + } + else if( (str).startsWith( "Executing power" ) ) + { + emit newSubTask( i18n("Executing Power calibration") ); + } + else if( (str).startsWith( "Power calibration successful" ) ) + { + emit infoMessage( i18n("Power calibration successful"), K3bJob::INFO ); + emit newSubTask( i18n("Preparing burn process...") ); + } + else if( (str).startsWith( "Flushing cache" ) ) + { + emit newSubTask( i18n("Flushing cache") ); + } + else if( (str).startsWith( "Writing CD-TEXT lead" ) ) + { + emit newSubTask( i18n("Writing CD-Text lead-in...") ); + } + else if( (str).startsWith( "Turning BURN-Proof on" ) ) + { + emit infoMessage( i18n("Turning BURN-Proof on"), K3bJob::INFO ); + } + else if( str.startsWith( "Copying" ) ) + { + emit infoMessage( str, K3bJob::INFO ); + } + else if( str.startsWith( "Found ISRC" ) ) + { + emit infoMessage( i18n("Found ISRC code"), K3bJob::INFO ); + } + else if( str.startsWith( "Found pre-gap" ) ) + { + emit infoMessage( i18n("Found pregap: %1").arg( str.mid(str.find(":")+1) ), K3bJob::INFO ); + } + else + unknownCdrdaoLine(str); +} + +void K3bCdrdaoWriter::parseCdrdaoError( const QString& line ) +{ + int pos = -1; + + if( line.contains( "No driver found" ) || + line.contains( "use option --driver" ) ) + { + emit infoMessage( i18n("No cdrdao driver found."), K3bJob::ERROR ); + emit infoMessage( i18n("Please select one manually in the device settings."), K3bJob::ERROR ); + emit infoMessage( i18n("For most current drives this would be 'generic-mmc'."), K3bJob::ERROR ); + m_knownError = true; + } + else if( line.contains( "Cannot setup device" ) ) + { + // no nothing... + } + else if( line.contains( "not ready") ) + { + emit infoMessage( i18n("Device not ready, waiting."),K3bJob::WARNING ); + } + else if( line.contains("Drive does not accept any cue sheet") ) + { + emit infoMessage( i18n("Cue sheet not accepted."), K3bJob::ERROR ); + m_knownError = true; + } + else if( (pos = line.find( "Illegal option" )) > 0 ) { + // ERROR: Illegal option: -wurst + emit infoMessage( i18n("No valid %1 option: %2").arg(m_cdrdaoBinObject->name()).arg(line.mid(pos+16)), + ERROR ); + m_knownError = true; + } + else if( line.contains( "exceeds capacity" ) ) { + emit infoMessage( i18n("Data does not fit on disk."), ERROR ); + if( m_cdrdaoBinObject->hasFeature("overburn") ) + emit infoMessage( i18n("Enable overburning in the advanced K3b settings to burn anyway."), INFO ); + m_knownError = true; + } + // else if( !line.contains( "remote progress message" ) ) +// emit infoMessage( line, K3bJob::ERROR ); +} + +void K3bCdrdaoWriter::parseCdrdaoWrote( const QString& line ) +{ + int pos, po2; + pos = line.find( "Wrote" ); + po2 = line.find( " ", pos + 6 ); + int processed = line.mid( pos+6, po2-pos-6 ).toInt(); + + pos = line.find( "of" ); + po2 = line.find( " ", pos + 3 ); + m_size = line.mid( pos+3, po2-pos-3 ).toInt(); + + d->speedEst->dataWritten( processed*1024 ); + + emit processedSize( processed, m_size ); +} + + +void K3bCdrdaoWriter::parseCdrdaoMessage() +{ + static const char msgSync[] = { 0xff, 0x00, 0xff, 0x00 }; + unsigned int avail = m_comSock->bytesAvailable(); + unsigned int msgs = avail / ( sizeof(msgSync)+d->progressMsgSize ); + unsigned int count = 0; + + if ( msgs < 1 ) + return; + else if ( msgs > 1) { + // move the read-index forward to the beginnig of the most recent message + count = ( msgs-1 ) * ( sizeof(msgSync)+d->progressMsgSize ); + m_comSock->at(count); + kdDebug() << "(K3bCdrdaoParser) " << msgs-1 << " message(s) skipped" << endl; + } + + while( count < avail ) { + + // search for msg sync + int state = 0; + char buf; + while( state < 4 ) { + buf = m_comSock->getch(); + ++count; + if( count == avail ) { + // kdDebug() << "(K3bCdrdaoParser) remote message sync not found (" << count << ")" << endl; + return; + } + + if( buf == msgSync[state] ) + ++state; + else + state = 0; + } + + if( (avail - count) < d->progressMsgSize ) { + kdDebug() << "(K3bCdrdaoParser) could not read complete remote message." << endl; + return; + } + + // read one message (the message size changed in cdrdao 1.1.8) + ::memset( &d->newMsg, 0, d->progressMsgSize ); + int size = m_comSock->readBlock( (char*)&d->newMsg, d->progressMsgSize); + if( size == -1 ) { + kdDebug() << "(K3bCdrdaoParser) read error" << endl; + return; + } + count += size; + + // sometimes the progress takes one step back (on my system when using paranoia-level 3) + // so we just use messages that are greater than the previous or first messages + if( d->oldMsg < d->newMsg + || ( d->newMsg.track == 1 && + d->newMsg.trackProgress <= 10 )) { + + if( d->newMsg.track != m_currentTrack ) { + switch( d->newMsg.status ) { + case PGSMSG_RCD_EXTRACTING: + emit nextTrack( d->newMsg.track, d->newMsg.totalTracks ); + break; + case PGSMSG_WCD_LEADIN: + emit newSubTask( i18n("Writing leadin ") ); + break; + case PGSMSG_WCD_DATA: + emit nextTrack( d->newMsg.track, d->newMsg.totalTracks ); + break; + case PGSMSG_WCD_LEADOUT: + emit newSubTask( i18n("Writing leadout ") ); + break; + } + + m_currentTrack = d->newMsg.track; + } + + if( d->newMsg.status == PGSMSG_WCD_LEADIN || d->newMsg.status == PGSMSG_WCD_LEADOUT ) { + // cdrdao >= 1.1.8 emits progress data when writing the lead-in and lead-out :) + emit subPercent( d->newMsg.totalProgress/10 ); + } + else { + emit subPercent( d->newMsg.trackProgress/10 ); + emit percent( d->newMsg.totalProgress/10 ); + } + + emit buffer(d->newMsg.bufferFillRate); + + if( d->progressMsgSize == (unsigned int)sizeof(ProgressMsg2) ) + emit deviceBuffer( d->newMsg.writerFillRate ); + + ::memcpy( &d->oldMsg, &d->newMsg, d->progressMsgSize ); + } + } +} + + +void K3bCdrdaoWriter::slotThroughput( int t ) +{ + // FIXME: determine sector size + emit writeSpeed( t, 150 ); +} + + +QString K3bCdrdaoWriter::findDriverFile( const K3bExternalBin* bin ) +{ + if( !bin ) + return QString::null; + + // cdrdao normally in (prefix)/bin and driver table in (prefix)/share/cdrdao + QString path = bin->path; + path.truncate( path.findRev("/") ); + path.truncate( path.findRev("/") ); + path += "/share/cdrdao/drivers"; + if( QFile::exists(path) ) + return path; + else { + kdDebug() << "(K3bCdrdaoWriter) could not find cdrdao driver table." << endl; + return QString::null; + } +} + + +// returns true if the driver file could be opened and no driver could be found +// TODO: cache the drivers +bool K3bCdrdaoWriter::defaultToGenericMMC( K3bDevice::Device* dev, bool writer ) +{ + QString driverTable = findDriverFile( m_cdrdaoBinObject ); + if( !driverTable.isEmpty() ) { + QFile f( driverTable ); + if( f.open( IO_ReadOnly ) ) { + // read all drivers + QStringList drivers; + QTextStream fStr( &f ); + while( !fStr.atEnd() ) { + QString line = fStr.readLine(); + if( line.isEmpty() ) + continue; + if( line[0] == '#' ) + continue; + if( line[0] == 'R' && writer ) + continue; + if( line[0] == 'W' && !writer ) + continue; + drivers.append(line); + } + + // search for the driver + for( QStringList::const_iterator it = drivers.begin(); it != drivers.end(); ++it ) { + if( (*it).section( '|', 1, 1 ) == dev->vendor() && + (*it).section( '|', 2, 2 ) == dev->description() ) + return false; + } + + // no driver found + return true; + } + else { + kdDebug() << "(K3bCdrdaoWriter) could not open driver table " << driverTable << endl; + return false; + } + } + else + return false; +} + + +#include "k3bcdrdaowriter.moc" diff --git a/libk3b/projects/k3bcdrdaowriter.h b/libk3b/projects/k3bcdrdaowriter.h new file mode 100644 index 0000000..94a0c9f --- /dev/null +++ b/libk3b/projects/k3bcdrdaowriter.h @@ -0,0 +1,157 @@ +/* + * + * $Id: k3bcdrdaowriter.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * Klaus-Dieter Krannich + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3B_CDRDAO_WRITER_H +#define K3B_CDRDAO_WRITER_H + + +#include "k3babstractwriter.h" + +class K3bExternalBin; +class K3bProcess; +class KProcess; +class K3bDevice::Device; +class QSocket; + + + +class K3bCdrdaoWriter : public K3bAbstractWriter +{ + Q_OBJECT + + public: + + enum Command { WRITE, COPY, READ, BLANK }; + enum BlankMode { FULL, MINIMAL }; + enum SubMode { None, RW, RW_RAW }; + + K3bCdrdaoWriter( K3bDevice::Device* dev, K3bJobHandler*, + QObject* parent = 0, const char* name = 0 ); + ~K3bCdrdaoWriter(); + + /** + * to be used in chain: addArgument(x)->addArgument(y) + */ + K3bCdrdaoWriter* addArgument( const QString& ); + K3bDevice::Device* sourceDevice() { return m_sourceDevice; }; + + int fd() const; + + bool active() const; + + private: + void reinitParser(); + void parseCdrdaoLine( const QString& line ); + void parseCdrdaoWrote( const QString& line ); + void parseCdrdaoError( const QString& line ); + + public slots: + void start(); + void cancel(); + + // options + // --------------------- + void setCommand( int c ) { m_command = c; } + void setBlankMode( int b ) { m_blankMode = b; } + void setMulti( bool b ) { m_multi = b; } + void setForce( bool b ) { m_force = b; } + void setOnTheFly( bool b ) { m_onTheFly = b; } + void setDataFile( const QString& s ) { m_dataFile = s; } + void setTocFile( const QString& s ) { m_tocFile = s; } + + void setSourceDevice( K3bDevice::Device* dev ) { m_sourceDevice = dev; } + void setFastToc( bool b ) { m_fastToc = b; } + void setReadRaw( bool b ) { m_readRaw = b; } + void setReadSubchan(SubMode m) { m_readSubchan=m; }; + void setParanoiaMode( int i ) { m_paranoiaMode = i; } + void setTaoSource(bool b) { m_taoSource=b; }; + void setTaoSourceAdjust(int a) { m_taoSourceAdjust=a; }; + void setSession(int s) { m_session=s; }; + void setEject(bool e) { m_eject=e; }; +// --------------------- + + /** + * If set true the job ignores the global K3b setting + * and does not eject the CD-RW after finishing + */ + void setForceNoEject( bool b ) { m_forceNoEject = b; } + + private slots: + void slotStdLine( const QString& line ); + void slotProcessExited(KProcess*); + void parseCdrdaoMessage(); + void slotThroughput( int t ); + + private: + void unknownCdrdaoLine( const QString& ); + void prepareArgumentList(); + void setWriteArguments(); + void setReadArguments(); + void setCopyArguments(); + void setBlankArguments(); + void setCommonArguments(); + + bool cueSheet(); + + QString findDriverFile( const K3bExternalBin* bin ); + bool defaultToGenericMMC( K3bDevice::Device* dev, bool writer ); + + // options + // --------------------- + int m_command; + int m_blankMode; + K3bDevice::Device* m_sourceDevice; + QString m_dataFile; + QString m_tocFile; + QString m_cueFileLnk; + QString m_binFileLnk; + QString m_backupTocFile; + bool m_readRaw; + bool m_multi; + bool m_force; + bool m_onTheFly; + bool m_fastToc; + SubMode m_readSubchan; + bool m_taoSource; + int m_taoSourceAdjust; + int m_paranoiaMode; + int m_session; + bool m_eject; + // --------------------- + + const K3bExternalBin* m_cdrdaoBinObject; + K3bProcess* m_process; + + int m_cdrdaoComm[2]; + QSocket *m_comSock; + + bool m_canceled; + + bool m_knownError; + +// parser + + int m_size; + int m_currentTrack; + + bool m_forceNoEject; + + class Private; + Private* d; +}; + +#endif diff --git a/libk3b/projects/k3bcdrecordwriter.cpp b/libk3b/projects/k3bcdrecordwriter.cpp new file mode 100644 index 0000000..e87c767 --- /dev/null +++ b/libk3b/projects/k3bcdrecordwriter.cpp @@ -0,0 +1,810 @@ +/* + * + * $Id: k3bcdrecordwriter.cpp 690529 2007-07-21 10:51:47Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include + + +#include "k3bcdrecordwriter.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + + +class K3bCdrecordWriter::Private +{ +public: + Private() + : cdTextFile(0) { + } + + K3bThroughputEstimator* speedEst; + bool canceled; + bool usingBurnfree; + int usedSpeed; + + struct Track { + int size; + bool audio; + }; + + QValueList tracks; + + KTempFile* cdTextFile; +}; + + +K3bCdrecordWriter::K3bCdrecordWriter( K3bDevice::Device* dev, K3bJobHandler* hdl, + QObject* parent, const char* name ) + : K3bAbstractWriter( dev, hdl, parent, name ), + m_clone(false), + m_cue(false), + m_forceNoEject(false) +{ + d = new Private(); + d->speedEst = new K3bThroughputEstimator( this ); + connect( d->speedEst, SIGNAL(throughput(int)), + this, SLOT(slotThroughput(int)) ); + + m_process = 0; + m_writingMode = K3b::TAO; +} + + +K3bCdrecordWriter::~K3bCdrecordWriter() +{ + delete d->cdTextFile; + delete d; + delete m_process; +} + + +bool K3bCdrecordWriter::active() const +{ + return ( m_process && m_process->isRunning() ); +} + + +int K3bCdrecordWriter::fd() const +{ + if( m_process ) + return m_process->stdinFd(); + else + return -1; +} + + +void K3bCdrecordWriter::setDao( bool b ) +{ + m_writingMode = ( b ? K3b::DAO : K3b::TAO ); +} + +void K3bCdrecordWriter::setCueFile( const QString& s) +{ + m_cue = true; + m_cueFile = s; + + // cuefile only works in DAO mode + setWritingMode( K3b::DAO ); +} + +void K3bCdrecordWriter::setClone( bool b ) +{ + m_clone = b; +} + + +void K3bCdrecordWriter::setWritingMode( int mode ) +{ + if( mode == K3b::DAO || + mode == K3b::TAO || + mode == K3b::RAW ) + m_writingMode = mode; + else + kdError() << "(K3bCdrecordWriter) wrong writing mode: " << mode << endl; +} + + +void K3bCdrecordWriter::prepareProcess() +{ + if( m_process ) delete m_process; // kdelibs want this! + m_process = new K3bProcess(); + m_process->setRunPrivileged(true); + // m_process->setPriority( KProcess::PrioHighest ); + m_process->setSplitStdout(true); + m_process->setSuppressEmptyLines(true); + m_process->setRawStdin(true); // we only use stdin when writing on-the-fly + connect( m_process, SIGNAL(stdoutLine(const QString&)), this, SLOT(slotStdLine(const QString&)) ); + connect( m_process, SIGNAL(stderrLine(const QString&)), this, SLOT(slotStdLine(const QString&)) ); + connect( m_process, SIGNAL(processExited(KProcess*)), this, SLOT(slotProcessExited(KProcess*)) ); + + m_cdrecordBinObject = k3bcore->externalBinManager()->binObject("cdrecord"); + + if( !m_cdrecordBinObject ) + return; + + *m_process << m_cdrecordBinObject; + + // display progress + *m_process << "-v"; + + if( m_cdrecordBinObject->hasFeature( "gracetime") ) + *m_process << "gracetime=2"; // 2 is the lowest allowed value (Joerg, why do you do this to us?) + + // Again we assume the device to be set! + *m_process << QString("dev=%1").arg(K3b::externalBinDeviceParameter(burnDevice(), m_cdrecordBinObject)); + + d->usedSpeed = burnSpeed(); + if( d->usedSpeed == 0 ) { + // try to determine the writeSpeed + // if it fails determineMaximalWriteSpeed() will return 0 and + // the choice is left to cdrecord + d->usedSpeed = burnDevice()->determineMaximalWriteSpeed(); + } + d->usedSpeed /= 175; + if( d->usedSpeed != 0 ) + *m_process << QString("speed=%1").arg(d->usedSpeed); + + if( m_writingMode == K3b::DAO || m_cue ) { + if( burnDevice()->dao() ) + *m_process << "-dao"; + else { + if( m_cdrecordBinObject->hasFeature( "tao" ) ) + *m_process << "-tao"; + emit infoMessage( i18n("Writer does not support disk at once (DAO) recording"), WARNING ); + } + } + else if( m_writingMode == K3b::RAW ) { + if( burnDevice()->supportsWritingMode( K3bDevice::RAW_R96R ) ) + *m_process << "-raw96r"; + else if( burnDevice()->supportsWritingMode( K3bDevice::RAW_R16 ) ) + *m_process << "-raw16"; + else if( burnDevice()->supportsWritingMode( K3bDevice::RAW_R96P ) ) + *m_process << "-raw96p"; + else { + emit infoMessage( i18n("Writer does not support raw writing."), WARNING ); + if( m_cdrecordBinObject->hasFeature( "tao" ) ) + *m_process << "-tao"; + } + } + else if( m_cdrecordBinObject->hasFeature( "tao" ) ) + *m_process << "-tao"; + + if( simulate() ) + *m_process << "-dummy"; + + d->usingBurnfree = false; + if( k3bcore->globalSettings()->burnfree() ) { + if( burnDevice()->burnproof() ) { + + d->usingBurnfree = true; + + // with cdrecord 1.11a02 burnproof was renamed to burnfree + if( m_cdrecordBinObject->hasFeature( "burnproof" ) ) + *m_process << "driveropts=burnproof"; + else + *m_process << "driveropts=burnfree"; + } + else + emit infoMessage( i18n("Writer does not support buffer underrun free recording (Burnfree)"), WARNING ); + } + + if( k3bcore->globalSettings()->force() ) { + *m_process << "-force"; + emit infoMessage( i18n("'Force unsafe operations' enabled."), WARNING ); + } + + if( m_cue ) { + m_process->setWorkingDirectory(QUrl(m_cueFile).dirPath()); + *m_process << QString("cuefile=%1").arg( m_cueFile ); + } + + if( m_clone ) + *m_process << "-clone"; + + if( m_rawCdText.size() > 0 ) { + delete d->cdTextFile; + d->cdTextFile = new K3bTempFile( QString::null, ".dat" ); + d->cdTextFile->setAutoDelete(true); + d->cdTextFile->file()->writeBlock( m_rawCdText ); + d->cdTextFile->close(); + + *m_process << "textfile=" + d->cdTextFile->name(); + } + + if( k3bcore->globalSettings()->ejectMedia() && + !m_forceNoEject ) + *m_process << "-eject"; + + bool manualBufferSize = k3bcore->globalSettings()->useManualBufferSize(); + if( manualBufferSize ) { + *m_process << QString("fs=%1m").arg( k3bcore->globalSettings()->bufferSize() ); + } + + bool overburn = k3bcore->globalSettings()->overburn(); + if( overburn ) + if( m_cdrecordBinObject->hasFeature("overburn") ) + *m_process << "-overburn"; + else + emit infoMessage( i18n("Cdrecord %1 does not support overburning.").arg(m_cdrecordBinObject->version), WARNING ); + + // additional user parameters from config + const QStringList& params = m_cdrecordBinObject->userParameters(); + for( QStringList::const_iterator it = params.begin(); it != params.end(); ++it ) + *m_process << *it; + + // add the user parameters + for( QStringList::const_iterator it = m_arguments.begin(); it != m_arguments.end(); ++it ) + *m_process << *it; +} + + +K3bCdrecordWriter* K3bCdrecordWriter::addArgument( const QString& arg ) +{ + m_arguments.append( arg ); + return this; +} + + +void K3bCdrecordWriter::clearArguments() +{ + m_arguments.clear(); +} + + +void K3bCdrecordWriter::start() +{ + jobStarted(); + + d->canceled = false; + d->speedEst->reset(); + + prepareProcess(); + + if( !m_cdrecordBinObject ) { + emit infoMessage( i18n("Could not find %1 executable.").arg("cdrecord"), ERROR ); + jobFinished(false); + return; + } + + emit debuggingOutput( "Used versions", "cdrecord: " + m_cdrecordBinObject->version ); + + if( !m_cdrecordBinObject->copyright.isEmpty() ) + emit infoMessage( i18n("Using %1 %2 - Copyright (C) %3") + .arg(m_cdrecordBinObject->hasFeature( "wodim" ) ? "Wodim" : "Cdrecord" ) + .arg(m_cdrecordBinObject->version) + .arg(m_cdrecordBinObject->copyright), INFO ); + + + kdDebug() << "***** " << m_cdrecordBinObject->name() << " parameters:\n"; + const QValueList& args = m_process->args(); + QString s; + for( QValueList::const_iterator it = args.begin(); it != args.end(); ++it ) { + s += *it + " "; + } + kdDebug() << s << flush << endl; + emit debuggingOutput( m_cdrecordBinObject->name() + " command:", s); + + m_currentTrack = 0; + m_cdrecordError = UNKNOWN; + m_totalTracksParsed = false; + m_alreadyWritten = 0; + d->tracks.clear(); + m_totalSize = 0; + + emit newSubTask( i18n("Preparing write process...") ); + + // FIXME: check the return value + if( K3b::isMounted( burnDevice() ) ) { + emit infoMessage( i18n("Unmounting medium"), INFO ); + K3b::unmount( burnDevice() ); + } + + // block the device (including certain checks) + k3bcore->blockDevice( burnDevice() ); + + // lock the device for good in this process since it will + // be opened in the growisofs process + burnDevice()->close(); + burnDevice()->usageLock(); + + if( !m_process->start( KProcess::NotifyOnExit, KProcess::All ) ) { + // something went wrong when starting the program + // it "should" be the executable + kdDebug() << "(K3bCdrecordWriter) could not start " << m_cdrecordBinObject->name() << endl; + emit infoMessage( i18n("Could not start %1.").arg(m_cdrecordBinObject->name()), K3bJob::ERROR ); + jobFinished(false); + } + else { + if( simulate() ) { + emit newTask( i18n("Simulating") ); + emit infoMessage( i18n("Starting %1 simulation at %2x speed...") + .arg(K3b::writingModeString(m_writingMode)) + .arg(d->usedSpeed), + K3bJob::INFO ); + } + else { + emit newTask( i18n("Writing") ); + emit infoMessage( i18n("Starting %1 writing at %2x speed...") + .arg(K3b::writingModeString(m_writingMode)) + .arg(d->usedSpeed), + K3bJob::INFO ); + } + } +} + + +void K3bCdrecordWriter::cancel() +{ + if( active() ) { + d->canceled = true; + if( m_process && m_process->isRunning() ) + m_process->kill(); + } +} + + +void K3bCdrecordWriter::slotStdLine( const QString& line ) +{ + static QRegExp s_burnfreeCounterRx( "^BURN\\-Free\\swas\\s(\\d+)\\stimes\\sused" ); + static QRegExp s_burnfreeCounterRxPredict( "^Total\\sof\\s(\\d+)\\s\\spossible\\sbuffer\\sunderruns\\spredicted" ); + + // tracknumber: cap(1) + // done: cap(2) + // complete: cap(3) + // fifo: cap(4) (it seems as if some patched cdrecord versions do not emit the fifo info but only the buf... :( + // buffer: cap(5) + static QRegExp s_progressRx( "Track\\s(\\d\\d)\\:\\s*(\\d*)\\sof\\s*(\\d*)\\sMB\\swritten\\s(?:\\(fifo\\s*(\\d*)\\%\\)\\s*)?(?:\\[buf\\s*(\\d*)\\%\\])?.*" ); + + emit debuggingOutput( m_cdrecordBinObject->name(), line ); + + // + // Progress and toc parsing + // + + if( line.startsWith( "Track " ) ) { + if( !m_totalTracksParsed ) { + // this is not the progress display but the list of tracks that will get written + // we always extract the tracknumber to get the highest at last + bool ok; + int tt = line.mid( 6, 2 ).toInt(&ok); + + if( ok ) { + struct Private::Track track; + track.audio = ( line.mid( 10, 5 ) == "audio" ); + + m_totalTracks = tt; + + int sizeStart = line.find( QRegExp("\\d"), 10 ); + int sizeEnd = line.find( "MB", sizeStart ); + track.size = line.mid( sizeStart, sizeEnd-sizeStart ).toInt(&ok); + + if( ok ) { + d->tracks.append(track); + m_totalSize += track.size; + } + else + kdDebug() << "(K3bCdrecordWriter) track number parse error: " + << line.mid( sizeStart, sizeEnd-sizeStart ) << endl; + } + else + kdDebug() << "(K3bCdrecordWriter) track number parse error: " + << line.mid( 6, 2 ) << endl; + } + + else if( s_progressRx.exactMatch( line ) ) { + // int num = s_progressRx.cap(1).toInt(); + int made = s_progressRx.cap(2).toInt(); + int size = s_progressRx.cap(3).toInt(); + int fifo = s_progressRx.cap(4).toInt(); + + emit buffer( fifo ); + m_lastFifoValue = fifo; + + if( s_progressRx.numCaptures() > 4 ) + emit deviceBuffer( s_progressRx.cap(5).toInt() ); + + // + // cdrecord's output sucks a bit. + // we get track sizes that differ from the sizes in the progress + // info since these are dependant on the writing mode. + // so we just use the track sizes and do a bit of math... + // + + if( d->tracks.count() > m_currentTrack-1 && size > 0 ) { + double convV = (double)d->tracks[m_currentTrack-1].size/(double)size; + made = (int)((double)made * convV); + size = d->tracks[m_currentTrack-1].size; + } + else { + kdError() << "(K3bCdrecordWriter) Did not parse all tracks sizes!" << endl; + } + + if( size > 0 ) { + emit processedSubSize( made, size ); + emit subPercent( 100*made/size ); + } + + if( m_totalSize > 0 ) { + emit processedSize( m_alreadyWritten+made, m_totalSize ); + emit percent( 100*(m_alreadyWritten+made)/m_totalSize ); + } + + d->speedEst->dataWritten( (m_alreadyWritten+made)*1024 ); + } + } + + // + // Cdrecord starts all error and warning messages with it's path + // With Debian's script it starts with cdrecord (or /usr/bin/cdrecord or whatever! I hate this script!) + // + + else if( line.startsWith( "cdrecord" ) || + line.startsWith( m_cdrecordBinObject->path ) || + line.startsWith( m_cdrecordBinObject->path.left(m_cdrecordBinObject->path.length()-5) ) ) { + // get rid of the path and the following colon and space + QString errStr = line.mid( line.find(':') + 2 ); + + if( errStr.startsWith( "Drive does not support SAO" ) ) { + emit infoMessage( i18n("DAO (Disk At Once) recording not supported with this writer"), K3bJob::ERROR ); + emit infoMessage( i18n("Please choose TAO (Track At Once) and try again"), K3bJob::ERROR ); + } + else if( errStr.startsWith( "Drive does not support RAW" ) ) { + emit infoMessage( i18n("RAW recording not supported with this writer"), K3bJob::ERROR ); + } + else if( errStr.startsWith("Input/output error.") ) { + emit infoMessage( i18n("Input/output error. Not necessarily serious."), WARNING ); + } + else if( errStr.startsWith("shmget failed") ) { + m_cdrecordError = SHMGET_FAILED; + } + else if( errStr.startsWith("OPC failed") ) { + m_cdrecordError = OPC_FAILED; + } + else if( errStr.startsWith( "Drive needs to reload the media" ) ) { + emit infoMessage( i18n("Reloading of medium required"), K3bJob::INFO ); + } + else if( errStr.startsWith( "The current problem looks like a buffer underrun" ) ) { + if( m_cdrecordError == UNKNOWN ) // it is almost never a buffer underrun these days. + m_cdrecordError = BUFFER_UNDERRUN; + } + else if( errStr.startsWith("WARNING: Data may not fit") ) { + bool overburn = k3bcore->globalSettings()->overburn(); + if( overburn && m_cdrecordBinObject->hasFeature("overburn") ) + emit infoMessage( i18n("Trying to write more than the official disk capacity"), K3bJob::WARNING ); + m_cdrecordError = OVERSIZE; + } + else if( errStr.startsWith("Bad Option") ) { + m_cdrecordError = BAD_OPTION; + // parse option + int pos = line.find( "Bad Option" ) + 13; + int len = line.length() - pos - 1; + emit infoMessage( i18n("No valid %1 option: %2").arg(m_cdrecordBinObject->name()).arg(line.mid(pos, len)), + ERROR ); + } + else if( errStr.startsWith("Cannot set speed/dummy") ) { + m_cdrecordError = CANNOT_SET_SPEED; + } + else if( errStr.startsWith("Cannot open new session") ) { + m_cdrecordError = CANNOT_OPEN_NEW_SESSION; + } + else if( errStr.startsWith("Cannot send CUE sheet") ) { + m_cdrecordError = CANNOT_SEND_CUE_SHEET; + } + else if( errStr.startsWith( "Trying to use ultra high speed" ) || + errStr.startsWith( "Trying to use high speed" ) || + errStr.startsWith( "Probably trying to use ultra high speed" ) || + errStr.startsWith( "You did use a high speed medium on an improper writer" ) || + errStr.startsWith( "You did use a ultra high speed medium on an improper writer" ) ) { + m_cdrecordError = HIGH_SPEED_MEDIUM; + } + else if( errStr.startsWith( "You may have used an ultra low speed medium" ) ) { + m_cdrecordError = LOW_SPEED_MEDIUM; + } + else if( errStr.startsWith( "Permission denied. Cannot open" ) || + errStr.startsWith( "Operation not permitted." ) ) { + m_cdrecordError = PERMISSION_DENIED; + } + else if( errStr.startsWith( "Can only copy session # 1") ) { + emit infoMessage( i18n("Only session 1 will be cloned."), WARNING ); + } + else if( errStr == "Cannot fixate disk." ) { + emit infoMessage( i18n("Unable to fixate the disk."), ERROR ); + if( m_cdrecordError == UNKNOWN ) + m_cdrecordError = CANNOT_FIXATE_DISK; + } + else if( errStr == "A write error occurred." ) { + m_cdrecordError = WRITE_ERROR; + } + else if( errStr.startsWith( "Try again with cdrecord blank=all." ) ) { + m_cdrecordError = BLANK_FAILED; + } + } + + // + // All other messages + // + + else if( line.contains( "at speed" ) ) { + // parse the speed and inform the user if cdrdao switched it down + int pos = line.find( "at speed" ); + int pos2 = line.find( "in", pos+9 ); + int speed = static_cast( line.mid( pos+9, pos2-pos-10 ).toDouble() ); // cdrecord-dvd >= 2.01a25 uses 8.0 and stuff + if( speed != d->usedSpeed ) { + emit infoMessage( i18n("Medium or burner do not support writing at %1x speed").arg(d->usedSpeed), K3bJob::WARNING ); + if( speed > d->usedSpeed ) + emit infoMessage( i18n("Switching burn speed up to %1x").arg(speed), K3bJob::WARNING ); + else + emit infoMessage( i18n("Switching burn speed down to %1x").arg(speed), K3bJob::WARNING ); + } + } + else if( line.startsWith( "Starting new" ) ) { + m_totalTracksParsed = true; + if( m_currentTrack > 0 ) {// nothing has been written at the start of track 1 + if( d->tracks.count() > m_currentTrack-1 ) + m_alreadyWritten += d->tracks[m_currentTrack-1].size; + else + kdError() << "(K3bCdrecordWriter) Did not parse all tracks sizes!" << endl; + } + else + emit infoMessage( i18n("Starting disc write"), INFO ); + + m_currentTrack++; + + if( m_currentTrack > d->tracks.count() ) { + kdDebug() << "(K3bCdrecordWriter) need to add dummy track struct." << endl; + struct Private::Track t; + t.size = 1; + t.audio = false; + d->tracks.append(t); + } + + kdDebug() << "(K3bCdrecordWriter) writing track " << m_currentTrack << " of " << m_totalTracks << " tracks." << endl; + emit nextTrack( m_currentTrack, m_totalTracks ); + } + else if( line.startsWith( "Fixating" ) ) { + emit newSubTask( i18n("Closing Session") ); + } + else if( line.startsWith( "Writing lead-in" ) ) { + m_totalTracksParsed = true; + emit newSubTask( i18n("Writing Leadin") ); + } + else if( line.startsWith( "Writing Leadout") ) { + emit newSubTask( i18n("Writing Leadout") ); + } + else if( line.startsWith( "Writing pregap" ) ) { + emit newSubTask( i18n("Writing pregap") ); + } + else if( line.startsWith( "Performing OPC" ) ) { + emit infoMessage( i18n("Performing Optimum Power Calibration"), K3bJob::INFO ); + } + else if( line.startsWith( "Sending" ) ) { + emit infoMessage( i18n("Sending CUE sheet"), K3bJob::INFO ); + } + else if( line.startsWith( "Turning BURN-Free on" ) || line.startsWith( "BURN-Free is ON") ) { + emit infoMessage( i18n("Enabled Burnfree"), K3bJob::INFO ); + } + else if( line.startsWith( "Turning BURN-Free off" ) ) { + emit infoMessage( i18n("Disabled Burnfree"), K3bJob::WARNING ); + } + else if( line.startsWith( "Re-load disk and hit" ) ) { + // this happens on some notebooks where cdrecord is not able to close the + // tray itself, so we need to ask the user to do so + blockingInformation( i18n("Please reload the medium and press 'ok'"), + i18n("Unable to close the tray") ); + + // now send a to cdrecord + // hopefully this will do it since I have no possibility to test it! + ::write( fd(), "\n", 1 ); + } + else if( s_burnfreeCounterRx.search( line ) ) { + bool ok; + int num = s_burnfreeCounterRx.cap(1).toInt(&ok); + if( ok ) + emit infoMessage( i18n("Burnfree was used 1 time.", "Burnfree was used %n times.", num), INFO ); + } + else if( s_burnfreeCounterRxPredict.search( line ) ) { + bool ok; + int num = s_burnfreeCounterRxPredict.cap(1).toInt(&ok); + if( ok ) + emit infoMessage( i18n("Buffer was low 1 time.", "Buffer was low %n times.", num), INFO ); + } + else if( line.contains("Medium Error") ) { + m_cdrecordError = MEDIUM_ERROR; + } + else if( line.startsWith( "Error trying to open" ) && line.contains( "(Device or resource busy)" ) ) { + m_cdrecordError = DEVICE_BUSY; + } + else { + // debugging + kdDebug() << "(" << m_cdrecordBinObject->name() << ") " << line << endl; + } +} + + +void K3bCdrecordWriter::slotProcessExited( KProcess* p ) +{ + // remove temporary cdtext file + delete d->cdTextFile; + d->cdTextFile = 0; + + // release the device within this process + burnDevice()->usageUnlock(); + + // unblock the device + k3bcore->unblockDevice( burnDevice() ); + + if( d->canceled ) { + // this will unblock and eject the drive and emit the finished/canceled signals + K3bAbstractWriter::cancel(); + return; + } + + + if( p->normalExit() ) { + switch( p->exitStatus() ) { + case 0: + { + if( simulate() ) + emit infoMessage( i18n("Simulation successfully completed"), K3bJob::SUCCESS ); + else + emit infoMessage( i18n("Writing successfully completed"), K3bJob::SUCCESS ); + + int s = d->speedEst->average(); + emit infoMessage( i18n("Average overall write speed: %1 KB/s (%2x)").arg(s).arg(KGlobal::locale()->formatNumber((double)s/150.0), 2), INFO ); + + jobFinished( true ); + } + break; + + default: + kdDebug() << "(K3bCdrecordWriter) error: " << p->exitStatus() << endl; + + if( m_cdrecordError == UNKNOWN && m_lastFifoValue <= 3 ) + m_cdrecordError = BUFFER_UNDERRUN; + + switch( m_cdrecordError ) { + case OVERSIZE: + if( k3bcore->globalSettings()->overburn() && + m_cdrecordBinObject->hasFeature("overburn") ) + emit infoMessage( i18n("Data did not fit on disk."), ERROR ); + else { + emit infoMessage( i18n("Data does not fit on disk."), ERROR ); + if( m_cdrecordBinObject->hasFeature("overburn") ) + emit infoMessage( i18n("Enable overburning in the advanced K3b settings to burn anyway."), INFO ); + } + break; + case BAD_OPTION: + // error message has already been emited earlier since we needed the actual line + break; + case SHMGET_FAILED: + emit infoMessage( i18n("%1 could not reserve shared memory segment of requested size.").arg(m_cdrecordBinObject->name()), ERROR ); + emit infoMessage( i18n("Probably you chose a too large buffer size."), ERROR ); + break; + case OPC_FAILED: + emit infoMessage( i18n("OPC failed. Probably the writer does not like the medium."), ERROR ); + break; + case CANNOT_SET_SPEED: + emit infoMessage( i18n("Unable to set write speed to %1.").arg(d->usedSpeed), ERROR ); + emit infoMessage( i18n("Probably this is lower than your writer's lowest writing speed."), ERROR ); + break; + case CANNOT_SEND_CUE_SHEET: + emit infoMessage( i18n("Unable to send CUE sheet."), ERROR ); + if( m_writingMode == K3b::DAO ) + emit infoMessage( i18n("Sometimes using TAO writing mode solves this issue."), ERROR ); + break; + case CANNOT_OPEN_NEW_SESSION: + emit infoMessage( i18n("Unable to open new session."), ERROR ); + emit infoMessage( i18n("Probably a problem with the medium."), ERROR ); + break; + case CANNOT_FIXATE_DISK: + emit infoMessage( i18n("The disk might still be readable."), ERROR ); + if( m_writingMode == K3b::TAO && burnDevice()->dao() ) + emit infoMessage( i18n("Try DAO writing mode."), ERROR ); + break; + case PERMISSION_DENIED: + emit infoMessage( i18n("%1 has no permission to open the device.").arg("Cdrecord"), ERROR ); +#ifdef HAVE_K3BSETUP + emit infoMessage( i18n("You may use K3bsetup2 to solve this problem."), ERROR ); +#endif + break; + case BUFFER_UNDERRUN: + emit infoMessage( i18n("Probably a buffer underrun occurred."), ERROR ); + if( !d->usingBurnfree && burnDevice()->burnproof() ) + emit infoMessage( i18n("Please enable Burnfree or choose a lower burning speed."), ERROR ); + else + emit infoMessage( i18n("Please choose a lower burning speed."), ERROR ); + break; + case HIGH_SPEED_MEDIUM: + emit infoMessage( i18n("Found a high-speed medium not suitable for the writer being used."), ERROR ); + emit infoMessage( i18n("Use the 'force unsafe operations' option to ignore this."), ERROR ); + break; + case LOW_SPEED_MEDIUM: + emit infoMessage( i18n("Found a low-speed medium not suitable for the writer being used."), ERROR ); + emit infoMessage( i18n("Use the 'force unsafe operations' option to ignore this."), ERROR ); + break; + case MEDIUM_ERROR: + emit infoMessage( i18n("Most likely the burning failed due to low-quality media."), ERROR ); + break; + case DEVICE_BUSY: + emit infoMessage( i18n("Another application is blocking the device (most likely automounting)."), ERROR ); + break; + case WRITE_ERROR: + emit infoMessage( i18n("A write error occurred."), ERROR ); + if( m_writingMode == K3b::DAO ) + emit infoMessage( i18n("Sometimes using TAO writing mode solves this issue."), ERROR ); + break; + case BLANK_FAILED: + emit infoMessage( i18n("Some drives do not support all erase types."), ERROR ); + emit infoMessage( i18n("Try again using 'Complete' erasing."), ERROR ); + break; + case UNKNOWN: + if( p->exitStatus() == 12 && K3b::kernelVersion() >= K3bVersion( 2, 6, 8 ) && m_cdrecordBinObject->hasFeature( "suidroot" ) ) { + emit infoMessage( i18n("Since kernel version 2.6.8 cdrecord cannot use SCSI transport when running suid root anymore."), ERROR ); + emit infoMessage( i18n("You may use K3bSetup to solve this problem or remove the suid bit manually."), ERROR ); + } + else if( !wasSourceUnreadable() ) { + emit infoMessage( i18n("%1 returned an unknown error (code %2).") + .arg(m_cdrecordBinObject->name()).arg(p->exitStatus()), + K3bJob::ERROR ); + + if( p->exitStatus() >= 254 && m_writingMode == K3b::DAO ) { + emit infoMessage( i18n("Sometimes using TAO writing mode solves this issue."), ERROR ); + } + else { + emit infoMessage( i18n("If you are running an unpatched cdrecord version..."), ERROR ); + emit infoMessage( i18n("...and this error also occurs with high quality media..."), ERROR ); + emit infoMessage( i18n("...and the K3b FAQ does not help you..."), ERROR ); + emit infoMessage( i18n("...please include the debugging output in your problem report."), ERROR ); + } + } + break; + } + jobFinished( false ); + } + } + else { + emit infoMessage( i18n("%1 did not exit cleanly.").arg(m_cdrecordBinObject->name()), + ERROR ); + jobFinished( false ); + } +} + + +void K3bCdrecordWriter::slotThroughput( int t ) +{ + emit writeSpeed( t, d->tracks[m_currentTrack-1].audio ? 175 : 150 ); +} + +#include "k3bcdrecordwriter.moc" diff --git a/libk3b/projects/k3bcdrecordwriter.h b/libk3b/projects/k3bcdrecordwriter.h new file mode 100644 index 0000000..9333588 --- /dev/null +++ b/libk3b/projects/k3bcdrecordwriter.h @@ -0,0 +1,123 @@ +/* + * + * $Id: k3bcdrecordwriter.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3B_CDRECORD_WRITER_H +#define K3B_CDRECORD_WRITER_H + + +#include "k3babstractwriter.h" + +#include + +class K3bExternalBin; +class K3bProcess; +class KProcess; +class K3bDevice::Device; + + +class K3bCdrecordWriter : public K3bAbstractWriter +{ + Q_OBJECT + + public: + K3bCdrecordWriter( K3bDevice::Device*, K3bJobHandler* hdl, + QObject* parent = 0, const char* name = 0 ); + ~K3bCdrecordWriter(); + + bool active() const; + + /** + * to be used in chain: addArgument(x)->addArgument(y) + */ + K3bCdrecordWriter* addArgument( const QString& ); + void clearArguments(); + + int fd() const; + + public slots: + void start(); + void cancel(); + + void setDao( bool b ); + void setWritingMode( int ); + void setCueFile( const QString& s); + void setClone( bool b ); + + void setRawCdText( const QByteArray& a ) { m_rawCdText = a; } + + /** + * If set true the job ignores the global K3b setting + * and does not eject the CD-RW after finishing + */ + void setForceNoEject( bool b ) { m_forceNoEject = b; } + + protected slots: + void slotStdLine( const QString& line ); + void slotProcessExited(KProcess*); + void slotThroughput( int t ); + + protected: + virtual void prepareProcess(); + + const K3bExternalBin* m_cdrecordBinObject; + K3bProcess* m_process; + + int m_writingMode; + bool m_totalTracksParsed; + bool m_clone; + bool m_cue; + + QString m_cueFile; + + enum CdrecordError { UNKNOWN, + OVERSIZE, + BAD_OPTION, + SHMGET_FAILED, + OPC_FAILED, + CANNOT_SET_SPEED, + CANNOT_SEND_CUE_SHEET, + CANNOT_OPEN_NEW_SESSION, + CANNOT_FIXATE_DISK, + WRITE_ERROR, + PERMISSION_DENIED, + BUFFER_UNDERRUN, + HIGH_SPEED_MEDIUM, + LOW_SPEED_MEDIUM, + MEDIUM_ERROR, + DEVICE_BUSY, + BLANK_FAILED }; + + QStringList m_arguments; + + private: + unsigned int m_currentTrack; + int m_totalTracks; + int m_totalSize; + int m_alreadyWritten; + + int m_lastFifoValue; + + int m_cdrecordError; + + bool m_forceNoEject; + + QByteArray m_rawCdText; + + class Private; + Private* d; +}; + +#endif diff --git a/libk3b/projects/k3bcuefileparser.cpp b/libk3b/projects/k3bcuefileparser.cpp new file mode 100644 index 0000000..49ca4fc --- /dev/null +++ b/libk3b/projects/k3bcuefileparser.cpp @@ -0,0 +1,461 @@ +/* + * + * $Id: k3bcuefileparser.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bcuefileparser.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + + +// avoid usage of QTextStream since K3b often +// tries to open big files (iso images) in a +// cue file parser to test it. +static QString readLine( QFile* f ) +{ + QString s; + Q_LONG r = f->readLine( s, 1024 ); + if( r >= 0 ) { + // remove the trailing newline + return s.stripWhiteSpace(); + } + else { + // end of file or error + return QString::null; + } +} + + +// TODO: add method: usableByCdrecordDirectly() +// TODO: add Toc with sector sizes + +class K3bCueFileParser::Private +{ +public: + bool inFile; + bool inTrack; + int trackType; + int trackMode; + bool rawData; + bool haveIndex1; + K3b::Msf currentDataPos; + K3b::Msf index0; + + K3bDevice::Toc toc; + int currentParsedTrack; + + K3bDevice::CdText cdText; +}; + + + +K3bCueFileParser::K3bCueFileParser( const QString& filename ) + : K3bImageFileReader() +{ + d = new Private; + openFile( filename ); +} + + +K3bCueFileParser::~K3bCueFileParser() +{ + delete d; +} + + +void K3bCueFileParser::readFile() +{ + setValid(true); + + d->inFile = d->inTrack = d->haveIndex1 = false; + d->trackMode = K3bDevice::Track::UNKNOWN; + d->toc.clear(); + d->cdText.clear(); + d->currentParsedTrack = 0; + + QFile f( filename() ); + if( f.open( IO_ReadOnly ) ) { + QString line = readLine( &f ); + while( !line.isNull() ) { + + if( !parseLine(line) ) { + setValid(false); + break; + } + + line = readLine( &f ); + } + + if( isValid() ) { + // save last parsed track for which we do not have the proper length :( + if( d->currentParsedTrack > 0 ) { + d->toc.append( K3bDevice::Track( d->currentDataPos, + d->currentDataPos, + d->trackType, + d->trackMode ) ); + } + + // debug the toc + kdDebug() << "(K3bCueFileParser) successfully parsed cue file." << endl + << "------------------------------------------------" << endl; + for( unsigned int i = 0; i < d->toc.count(); ++i ) { + K3bDevice::Track& track = d->toc[i]; + kdDebug() << "Track " << (i+1) + << " (" << ( track.type() == K3bDevice::Track::AUDIO ? "audio" : "data" ) << ") " + << track.firstSector().toString() << " - " << track.lastSector().toString() << endl; + } + + kdDebug() << "------------------------------------------------" << endl; + } + } + else { + kdDebug() << "(K3bCueFileParser) could not open file " << filename() << endl; + setValid(false); + } +} + + +bool K3bCueFileParser::parseLine( QString& line ) +{ + // use cap(1) for the filename + static QRegExp fileRx( "FILE\\s\"?([^\"]*)\"?\\s[^\"\\s]*" ); + + // use cap(1) for the flags + static QRegExp flagsRx( "FLAGS(\\s(DCP|4CH|PRE|SCMS)){1,4}" ); + + // use cap(1) for the tracknumber and cap(2) for the datatype + static QRegExp trackRx( "TRACK\\s(\\d{1,2})\\s(AUDIO|CDG|MODE1/2048|MODE1/2352|MODE2/2336|MODE2/2352|CDI/2336|CDI/2352)" ); + + // use cap(1) for the index number, cap(3) for the minutes, cap(4) for the seconds, cap(5) for the frames, + // and cap(2) for the MSF value string + static QRegExp indexRx( "INDEX\\s(\\d{1,2})\\s((\\d+):([0-5]\\d):((?:[0-6]\\d)|(?:7[0-4])))" ); + + // use cap(1) for the MCN + static QRegExp catalogRx( "CATALOG\\s(\\w{13,13})" ); + + // use cap(1) for the ISRC + static QRegExp isrcRx( "ISRC\\s(\\w{5,5}\\d{7,7})" ); + + static QString cdTextRxStr = "\"?([^\"]{0,80})\"?"; + + // use cap(1) for the string + static QRegExp titleRx( "TITLE\\s" + cdTextRxStr ); + static QRegExp performerRx( "PERFORMER\\s" + cdTextRxStr ); + static QRegExp songwriterRx( "SONGWRITER\\s" + cdTextRxStr ); + + + // simplify all white spaces except those in filenames and CD-TEXT + simplifyWhiteSpace( line ); + + // skip comments and empty lines + if( line.startsWith("REM") || line.startsWith("#") || line.isEmpty() ) + return true; + + + // + // FILE + // + if( fileRx.exactMatch( line ) ) { + + setValid( findImageFileName( fileRx.cap(1) ) ); + + if( d->inFile ) { + kdDebug() << "(K3bCueFileParser) only one FILE statement allowed." << endl; + return false; + } + d->inFile = true; + d->inTrack = false; + d->haveIndex1 = false; + return true; + } + + + // + // TRACK + // + else if( trackRx.exactMatch( line ) ) { + if( !d->inFile ) { + kdDebug() << "(K3bCueFileParser) TRACK statement before FILE." << endl; + return false; + } + + // check if we had index1 for the last track + if( d->inTrack && !d->haveIndex1 ) { + kdDebug() << "(K3bCueFileParser) TRACK without INDEX 1." << endl; + return false; + } + + // save last track + // TODO: use d->rawData in some way + if( d->currentParsedTrack > 0 ) { + d->toc.append( K3bDevice::Track( d->currentDataPos, + d->currentDataPos, + d->trackType, + d->trackMode ) ); + } + + d->currentParsedTrack++; + + d->cdText.resize( d->currentParsedTrack ); + + // parse the tracktype + if( trackRx.cap(2) == "AUDIO" ) { + d->trackType = K3bDevice::Track::AUDIO; + d->trackMode = K3bDevice::Track::UNKNOWN; + } + else { + d->trackType = K3bDevice::Track::DATA; + if( trackRx.cap(2).startsWith("MODE1") ) { + d->trackMode = K3bDevice::Track::MODE1; + d->rawData = (trackRx.cap(2) == "MODE1/2352"); + } + else if( trackRx.cap(2).startsWith("MODE2") ) { + d->trackMode = K3bDevice::Track::MODE2; + d->rawData = (trackRx.cap(2) == "MODE2/2352"); + } + else { + kdDebug() << "(K3bCueFileParser) unsupported track type: " << trackRx.cap(2) << endl; + return false; + } + } + + d->haveIndex1 = false; + d->inTrack = true; + d->index0 = 0; + + return true; + } + + + // + // FLAGS + // + else if( flagsRx.exactMatch( line ) ) { + if( !d->inTrack ) { + kdDebug() << "(K3bCueFileParser) FLAGS statement without TRACK." << endl; + return false; + } + + // TODO: save the flags + return true; + } + + + // + // INDEX + // + else if( indexRx.exactMatch( line ) ) { + if( !d->inTrack ) { + kdDebug() << "(K3bCueFileParser) INDEX statement without TRACK." << endl; + return false; + } + + unsigned int indexNumber = indexRx.cap(1).toInt(); + + K3b::Msf indexStart = K3b::Msf::fromString( indexRx.cap(2) ); + + if( indexNumber == 0 ) { + d->index0 = indexStart; + + if( d->currentParsedTrack < 2 && indexStart > 0 ) { + kdDebug() << "(K3bCueFileParser) first track is not allowed to have a pregap > 0." << endl; + return false; + } + } + else if( indexNumber == 1 ) { + d->haveIndex1 = true; + d->currentDataPos = indexStart; + if( d->currentParsedTrack > 1 ) { + d->toc[d->currentParsedTrack-2].setLastSector( indexStart-1 ); + if( d->index0 > 0 && d->index0 < indexStart ) { + d->toc[d->currentParsedTrack-2].setIndex0( d->index0 - d->toc[d->currentParsedTrack-2].firstSector() ); + } + } + } + else { + // TODO: add index > 0 + } + + return true; + } + + + // + // CATALOG + // + if( catalogRx.exactMatch( line ) ) { + // TODO: set the toc's mcn + return true; + } + + + // + // ISRC + // + if( isrcRx.exactMatch( line ) ) { + if( d->inTrack ) { + // TODO: set the track's ISRC + return true; + } + else { + kdDebug() << "(K3bCueFileParser) ISRC without TRACK." << endl; + return false; + } + } + + + // + // CD-TEXT + // TODO: create K3bDevice::TrackCdText entries + // + else if( titleRx.exactMatch( line ) ) { + if( d->inTrack ) + d->cdText[d->currentParsedTrack-1].setTitle( titleRx.cap(1) ); + else + d->cdText.setTitle( titleRx.cap(1) ); + return true; + } + + else if( performerRx.exactMatch( line ) ) { + if( d->inTrack ) + d->cdText[d->currentParsedTrack-1].setPerformer( performerRx.cap(1) ); + else + d->cdText.setPerformer( performerRx.cap(1) ); + return true; + } + + else if( songwriterRx.exactMatch( line ) ) { + if( d->inTrack ) + d->cdText[d->currentParsedTrack-1].setSongwriter( songwriterRx.cap(1) ); + else + d->cdText.setSongwriter( songwriterRx.cap(1) ); + return true; + } + + else { + kdDebug() << "(K3bCueFileParser) unknown Cue line: '" << line << "'" << endl; + return false; + } +} + + +void K3bCueFileParser::simplifyWhiteSpace( QString& s ) +{ + s = s.stripWhiteSpace(); + + unsigned int i = 0; + bool insideQuote = false; + while( i < s.length() ) { + if( !insideQuote ) { + if( s[i].isSpace() && s[i+1].isSpace() ) + s.remove( i, 1 ); + } + + if( s[i] == '"' ) + insideQuote = !insideQuote; + + ++i; + } +} + + +const K3bDevice::Toc& K3bCueFileParser::toc() const +{ + return d->toc; +} + + +const K3bDevice::CdText& K3bCueFileParser::cdText() const +{ + return d->cdText; +} + + +bool K3bCueFileParser::findImageFileName( const QString& dataFile ) +{ + // + // CDRDAO does not use this image filename but replaces the extension from the cue file + // with "bin" to get the image filename, we should take this into account + // + + m_imageFilenameInCue = true; + + // first try filename as a hole (absolut) + if( QFile::exists( dataFile ) ) { + setImageFilename( QFileInfo(dataFile).absFilePath() ); + return true; + } + + // try the filename in the cue's directory + if( QFileInfo( K3b::parentDir(filename()) + dataFile.section( '/', -1 ) ).isFile() ) { + setImageFilename( K3b::parentDir(filename()) + dataFile.section( '/', -1 ) ); + kdDebug() << "(K3bCueFileParser) found image file: " << imageFilename() << endl; + return true; + } + + // try the filename ignoring case + if( QFileInfo( K3b::parentDir(filename()) + dataFile.section( '/', -1 ).lower() ).isFile() ) { + setImageFilename( K3b::parentDir(filename()) + dataFile.section( '/', -1 ).lower() ); + kdDebug() << "(K3bCueFileParser) found image file: " << imageFilename() << endl; + return true; + } + + m_imageFilenameInCue = false; + + // try removing the ending from the cue file (image.bin.cue and image.bin) + if( QFileInfo( filename().left( filename().length()-4 ) ).isFile() ) { + setImageFilename( filename().left( filename().length()-4 ) ); + kdDebug() << "(K3bCueFileParser) found image file: " << imageFilename() << endl; + return true; + } + + // + // we did not find the image specified in the cue. + // Search for another one having the same filename as the cue but a different extension + // + + QDir parentDir( K3b::parentDir(filename()) ); + QString filenamePrefix = filename().section( '/', -1 ); + filenamePrefix.truncate( filenamePrefix.length() - 3 ); // remove cue extension + kdDebug() << "(K3bCueFileParser) checking folder " << parentDir.path() << " for files: " << filenamePrefix << "*" << endl; + + // + // we cannot use the nameFilter in QDir because of the spaces that may occur in filenames + // + QStringList possibleImageFiles = parentDir.entryList( QDir::Files ); + int cnt = 0; + for( QStringList::const_iterator it = possibleImageFiles.constBegin(); it != possibleImageFiles.constEnd(); ++it ) { + if( (*it).lower() == dataFile.section( '/', -1 ).lower() || + (*it).startsWith( filenamePrefix ) && !(*it).endsWith( "cue" ) ) { + ++cnt; + setImageFilename( K3b::parentDir(filename()) + *it ); + } + } + + // + // we only do this if there is one unique file which fits the requirements. + // Otherwise we cannot be certain to have the right file. + // + return ( cnt == 1 && QFileInfo( imageFilename() ).isFile() ); +} diff --git a/libk3b/projects/k3bcuefileparser.h b/libk3b/projects/k3bcuefileparser.h new file mode 100644 index 0000000..41a5ee6 --- /dev/null +++ b/libk3b/projects/k3bcuefileparser.h @@ -0,0 +1,57 @@ +/* + * + * $Id: k3bcuefileparser.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_CUEFILE_PARSER_H_ +#define _K3B_CUEFILE_PARSER_H_ + +#include "k3bimagefilereader.h" + +#include +#include +#include "k3b_export.h" +/** + * Parses a cue file. + * Datatracks have either mode1 or mode2 where the latter contains xa form1/2. + * The last track may not have a proper length! + */ +class LIBK3B_EXPORT K3bCueFileParser : public K3bImageFileReader +{ + public: + K3bCueFileParser( const QString& filename = QString::null ); + ~K3bCueFileParser(); + + /** + * CDRDAO does not use this image filename but replaces the extension from the cue file + * with "bin" to get the image filename. + * So in this case cdrecord won't be able to burn the cue file. That is why we need this hack. + */ + bool imageFilenameInCue() const { return m_imageFilenameInCue; } + + const K3bDevice::Toc& toc() const; + const K3bDevice::CdText& cdText() const; + + private: + void readFile(); + bool parseLine( QString& line ); + void simplifyWhiteSpace( QString& s ); + bool findImageFileName( const QString& fileEntry ); + + bool m_imageFilenameInCue; + + class Private; + Private* d; +}; + +#endif diff --git a/libk3b/projects/k3bdoc.cpp b/libk3b/projects/k3bdoc.cpp new file mode 100644 index 0000000..ac5346d --- /dev/null +++ b/libk3b/projects/k3bdoc.cpp @@ -0,0 +1,221 @@ +/* + * + * $Id: k3bdoc.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +// include files for Qt +#include +#include +#include + +// include files for KDE +#include +#include + +// application specific includes +#include "k3bdoc.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +K3bDoc::K3bDoc( QObject* parent ) + : QObject( parent ), + m_modified(false), + m_view(0) +{ + connect( this, SIGNAL(changed()), this, SLOT(slotChanged()) ); +} + + +K3bDoc::~K3bDoc() +{ +} + + +void K3bDoc::slotChanged() +{ + setModified( true ); + emit changed( this ); +} + + +void K3bDoc::setModified( bool m ) +{ + if( m != m_modified ) { + m_modified = m; + if( m ) + emit changed(); + } +} + + +void K3bDoc::setDummy( bool b ) +{ + m_dummy = b; +} + +void K3bDoc::setSpeed( int speed ) +{ + m_speed = speed; +} + +void K3bDoc::setBurner( K3bDevice::Device* dev ) +{ + m_burner = dev; +} + + +void K3bDoc::addUrl( const KURL& url ) +{ + KURL::List urls(url); + addUrls( urls ); +} + + +void K3bDoc::setURL( const KURL& url ) +{ + doc_url = url; + + emit changed(); +} + +const KURL& K3bDoc::URL() const +{ + return doc_url; +} + + +QString K3bDoc::name() const +{ + return URL().path().section( '/', -1 ); +} + + +bool K3bDoc::newDocument() +{ + setModified( false ); + + m_copies = 1; + m_burner = 0; + m_onTheFly = true; + m_speed = 0; // Auto + m_onlyCreateImages = false; + m_removeImages = true; + m_dummy = false; + m_writingApp = K3b::DEFAULT; + m_writingMode = K3b::WRITING_MODE_AUTO; + m_saved = false; + + return true; +} + + +bool K3bDoc::saveGeneralDocumentData( QDomElement* part ) +{ + QDomDocument doc = part->ownerDocument(); + QDomElement mainElem = doc.createElement( "general" ); + + QDomElement propElem = doc.createElement( "writing_mode" ); + switch( writingMode() ) { + case K3b::DAO: + propElem.appendChild( doc.createTextNode( "dao" ) ); + break; + case K3b::TAO: + propElem.appendChild( doc.createTextNode( "tao" ) ); + break; + case K3b::RAW: + propElem.appendChild( doc.createTextNode( "raw" ) ); + break; + default: + propElem.appendChild( doc.createTextNode( "auto" ) ); + break; + } + mainElem.appendChild( propElem ); + + propElem = doc.createElement( "dummy" ); + propElem.setAttribute( "activated", dummy() ? "yes" : "no" ); + mainElem.appendChild( propElem ); + + propElem = doc.createElement( "on_the_fly" ); + propElem.setAttribute( "activated", onTheFly() ? "yes" : "no" ); + mainElem.appendChild( propElem ); + + propElem = doc.createElement( "only_create_images" ); + propElem.setAttribute( "activated", onlyCreateImages() ? "yes" : "no" ); + mainElem.appendChild( propElem ); + + propElem = doc.createElement( "remove_images" ); + propElem.setAttribute( "activated", removeImages() ? "yes" : "no" ); + mainElem.appendChild( propElem ); + + part->appendChild( mainElem ); + + return true; +} + + +bool K3bDoc::readGeneralDocumentData( const QDomElement& elem ) +{ + if( elem.nodeName() != "general" ) + return false; + + QDomNodeList nodes = elem.childNodes(); + for( uint i = 0; i < nodes.count(); i++ ) { + + QDomElement e = nodes.item(i).toElement(); + if( e.isNull() ) + return false; + + if( e.nodeName() == "writing_mode") { + QString mode = e.text(); + if( mode == "dao" ) + setWritingMode( K3b::DAO ); + else if( mode == "tao" ) + setWritingMode( K3b::TAO ); + else if( mode == "raw" ) + setWritingMode( K3b::RAW ); + else + setWritingMode( K3b::WRITING_MODE_AUTO ); + } + + if( e.nodeName() == "dummy") + setDummy( e.attributeNode( "activated" ).value() == "yes" ); + + if( e.nodeName() == "on_the_fly") + setOnTheFly( e.attributeNode( "activated" ).value() == "yes" ); + + if( e.nodeName() == "only_create_images") + setOnlyCreateImages( e.attributeNode( "activated" ).value() == "yes" ); + + if( e.nodeName() == "remove_images") + setRemoveImages( e.attributeNode( "activated" ).value() == "yes" ); + } + + + return true; +} + + +#include "k3bdoc.moc" diff --git a/libk3b/projects/k3bdoc.h b/libk3b/projects/k3bdoc.h new file mode 100644 index 0000000..f241487 --- /dev/null +++ b/libk3b/projects/k3bdoc.h @@ -0,0 +1,229 @@ +/* + * + * $Id: k3bdoc.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BDOC_H +#define K3BDOC_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +// include files for QT +#include +#include +#include + + +// include files for KDE +#include +#include +#include "k3b_export.h" + +// forward declaration of the K3b classes +class QTimer; +class KTempFile; +class K3bBurnJob; +class QDomDocument; +class QDomElement; +class KConfig; +class KActionCollection; +class K3bJobHandler; + + +namespace K3bDevice { + class Device; +} +namespace K3b { + class Msf; +} + +/** + * K3bDoc is the base document class. + * It handles some general settings. + */ +class LIBK3B_EXPORT K3bDoc : public QObject +{ + Q_OBJECT + + public: + K3bDoc( QObject* = 0 ); + virtual ~K3bDoc(); + + enum DocType { + AUDIO = 1, + DATA, + MIXED, + VCD, + MOVIX, + MOVIX_DVD, + DVD, + VIDEODVD + }; + + virtual int type() const { return m_docType; } + + /** + * \return A name for the project which might for example be used as a suggestion for a file name + * when saving. The default implementation extracts a name from the URL. + */ + virtual QString name() const; + + /** + * \return A string representation of the document type. + */ + virtual QString typeString() const = 0; + + /** + * returns the view widget set with setView() or null if none has been set. + */ + QWidget* view() const { return m_view; } + + /** + * Just for convenience to make an easy mapping from doc to GUI possible. + */ + void setView( QWidget* v ) { m_view = v; } + + /** + * sets the modified flag for the document after a modifying action on the view connected to the document. + */ + virtual void setModified( bool m = true ); + + /** + * returns if the document is modified or not. Use this to determine + * if your document needs saving by the user on closing. + */ + virtual bool isModified() const { return m_modified; } + + /** + * Subclasses should call this when reimplementing. + * Sets some defaults. + */ + virtual bool newDocument(); + + /** + * Load a project from an xml stream. + * + * This is used to load/save k3b projects. + */ + virtual bool loadDocumentData( QDomElement* root ) = 0; + + /** + * Save a project to an xml stream. + * + * This is used to load/save k3b projects. + */ + virtual bool saveDocumentData( QDomElement* docElem ) = 0; + + /** returns the KURL of the document */ + const KURL& URL() const; + /** sets the URL of the document */ + virtual void setURL( const KURL& url ); + + int writingMode() const { return m_writingMode; } + bool dummy() const { return m_dummy; } + bool onTheFly() const { return m_onTheFly; } + bool removeImages() const { return m_removeImages; } + bool onlyCreateImages() const { return m_onlyCreateImages; } + int copies() const { return m_copies; } + int speed() const { return m_speed; } + K3bDevice::Device* burner() const { return m_burner; } + virtual KIO::filesize_t size() const = 0; + virtual K3b::Msf length() const = 0; + + // FIXME: rename this to something like imagePath + const QString& tempDir() const { return m_tempDir; } + + virtual int numOfTracks() const { return 1; } + + /** + * Create a new BurnJob to burn this project. It is not mandatory to use this + * method. You may also just create the BurnJob you need manually. It is just + * easier this way since you don't need to distinguish between the different + * project types. + */ + virtual K3bBurnJob* newBurnJob( K3bJobHandler*, QObject* parent = 0 ) = 0; + + int writingApp() const { return m_writingApp; } + void setWritingApp( int a ) { m_writingApp = a; } + + /** + * @return true if the document has successfully been saved to a file + */ + bool isSaved() const { return m_saved; } + + /** + * Used for session management. Use with care. + */ + void setSaved( bool s ) { m_saved = s; } + + signals: + void changed(); + void changed( K3bDoc* ); + + public slots: + void setDummy( bool d ); + void setWritingMode( int m ) { m_writingMode = m; } + void setOnTheFly( bool b ) { m_onTheFly = b; } + void setSpeed( int speed ); + void setBurner( K3bDevice::Device* dev ); + void setTempDir( const QString& dir ) { m_tempDir = dir; } + void setRemoveImages( bool b ) { m_removeImages = b; } + void setOnlyCreateImages( bool b ) { m_onlyCreateImages = b; } + void setCopies( int c ) { m_copies = c; } + + /** + * the default implementation just calls addUrls with + * list containing the url + */ + virtual void addUrl( const KURL& url ); + virtual void addUrls( const KURL::List& urls ) = 0; + + protected: + int m_docType; + + bool saveGeneralDocumentData( QDomElement* ); + + bool readGeneralDocumentData( const QDomElement& ); + + private slots: + void slotChanged(); + + private: + /** the modified flag of the current document */ + bool m_modified; + KURL doc_url; + + QWidget* m_view; + + QString m_tempDir; + K3bDevice::Device* m_burner; + bool m_dummy; + bool m_onTheFly; + bool m_removeImages; + bool m_onlyCreateImages; + int m_speed; + + /** see k3bglobals.h */ + int m_writingApp; + + int m_writingMode; + + int m_copies; + + bool m_saved; +}; + +#endif // K3BDOC_H diff --git a/libk3b/projects/k3bdvdrecordwriter.cpp b/libk3b/projects/k3bdvdrecordwriter.cpp new file mode 100644 index 0000000..0910d4a --- /dev/null +++ b/libk3b/projects/k3bdvdrecordwriter.cpp @@ -0,0 +1,119 @@ +/* + * + * $Id: k3bdvdrecordwriter.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bdvdrecordwriter.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + + +K3bDvdrecordWriter::K3bDvdrecordWriter( K3bDevice::Device* dev, QObject* parent, const char* name ) + : K3bCdrecordWriter( dev, parent, name ) +{ +} + + +K3bDvdrecordWriter::~K3bDvdrecordWriter() +{ +} + +void K3bDvdrecordWriter::prepareProcess() +{ + if( m_process ) delete m_process; // kdelibs want this! + m_process = new K3bProcess(); + m_process->setRunPrivileged(true); + m_process->setSplitStdout(true); + connect( m_process, SIGNAL(stdoutLine(const QString&)), this, SLOT(slotStdLine(const QString&)) ); + connect( m_process, SIGNAL(stderrLine(const QString&)), this, SLOT(slotStdLine(const QString&)) ); + connect( m_process, SIGNAL(processExited(KProcess*)), this, SLOT(slotProcessExited(KProcess*)) ); + connect( m_process, SIGNAL(wroteStdin(KProcess*)), this, SIGNAL(dataWritten()) ); + +// if( k3bcore->externalBinManager()->binObject("cdrecord")->hasFeature( "dvd-patch" ) ) +// m_cdrecordBinObject = k3bcore->externalBinManager()->binObject("cdrecord"); +// else + m_cdrecordBinObject = k3bcore->externalBinManager()->binObject("dvdrecord"); + + if( !m_cdrecordBinObject ) + return; + + *m_process << m_cdrecordBinObject->path; + + // display progress + *m_process << "-v"; + + if( m_cdrecordBinObject->hasFeature( "delay") ) + *m_process << "-delay" << "0"; + else if( m_cdrecordBinObject->hasFeature( "gracetime") ) + *m_process << "gracetime=2"; // 2 is the lowest allowed value (Joerg, why do you do this to us?) + + // Again we assume the device to be set! + *m_process << QString("dev=%1").arg(K3b::externalBinDeviceParameter(burnDevice(), m_cdrecordBinObject)); + *m_process << QString("speed=%1").arg(burnSpeed()); + + // DVDs are only written in DAO mode (and Packet, but we do not support that since it does not + // make much sense here) + *m_process << "-dao"; + setWritingMode( K3b::DAO ); // just to make sure the CdrecordWriter emits the correct messages + + if( simulate() ) + *m_process << "-dummy"; + + if( burnproof() ) { + if( burnDevice()->burnproof() ) { + // with cdrecord 1.11a02 burnproof was renamed to burnfree + // what about dvdrecord?? + if( m_cdrecordBinObject->version < K3bVersion( "1.11a02" ) ) + *m_process << "driveropts=burnproof"; + else + *m_process << "driveropts=burnfree"; + } + else + emit infoMessage( i18n("Writer does not support buffer underrun free recording (BURNPROOF)"), INFO ); + } + + if( k3bcore->globalSettings()->ejectMedia() ) + *m_process << "-eject"; + + bool manualBufferSize = k3bcore->globalSettings()->manualBufferSize(); + if( manualBufferSize ) { + *m_process << QString("fs=%1m").arg( k3bcore->globalSettings()->writingBuffer() ); + } + + bool overburn = k3bcore->globalSettings()->overburn(); + if( overburn ) + if( m_cdrecordBinObject->hasFeature("overburn") ) + *m_process << "-overburn"; + else + emit infoMessage( i18n("Cdrecord %1 does not support overburning.").arg(m_cdrecordBinObject->version), INFO ); + + // additional user parameters from config + const QStringList& params = m_cdrecordBinObject->userParameters(); + for( QStringList::const_iterator it = params.begin(); it != params.end(); ++it ) + *m_process << *it; + + // add the user parameters + for( QStringList::const_iterator it = m_arguments.begin(); it != m_arguments.end(); ++it ) + *m_process << *it; +} + +#include "k3bdvdrecordwriter.moc" + diff --git a/libk3b/projects/k3bdvdrecordwriter.h b/libk3b/projects/k3bdvdrecordwriter.h new file mode 100644 index 0000000..f9dcf4a --- /dev/null +++ b/libk3b/projects/k3bdvdrecordwriter.h @@ -0,0 +1,40 @@ +/* + * + * $Id: k3bdvdrecordwriter.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_DVDRECORD_WRITER_H_ +#define _K3B_DVDRECORD_WRITER_H_ + +#include "k3bcdrecordwriter.h" + + +class K3bDevice::Device; + +/** + * Basically this is just a wrapper around K3bCdrecordWriter + * which uses another K3bExternalBin and ignores the writingMode setting. + */ +class K3bDvdrecordWriter : public K3bCdrecordWriter +{ + Q_OBJECT + + public: + K3bDvdrecordWriter( K3bDevice::Device*, QObject* parent = 0, const char* name = 0 ); + ~K3bDvdrecordWriter(); + + protected: + void prepareProcess(); +}; + +#endif diff --git a/libk3b/projects/k3bgrowisofshandler.cpp b/libk3b/projects/k3bgrowisofshandler.cpp new file mode 100644 index 0000000..0b582ce --- /dev/null +++ b/libk3b/projects/k3bgrowisofshandler.cpp @@ -0,0 +1,318 @@ +/* + * + * $Id: k3bgrowisofshandler.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bgrowisofshandler.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + + +class K3bGrowisofsHandler::Private +{ +public: + int lastBuffer; + int lastDeviceBuffer; +}; + + +K3bGrowisofsHandler::K3bGrowisofsHandler( QObject* parent, const char* name ) + : QObject( parent, name ) +{ + d = new Private; + reset(); +} + + +K3bGrowisofsHandler::~K3bGrowisofsHandler() +{ + delete d; +} + + +void K3bGrowisofsHandler::reset( K3bDevice::Device* dev, bool dao ) +{ + m_device = dev; + m_error = ERROR_UNKNOWN; + m_dao = dao; + d->lastBuffer = 0; + d->lastDeviceBuffer = 0; +} + + +void K3bGrowisofsHandler::handleStart() +{ +// QTimer::singleShot( 2000, this, SLOT(slotCheckBufferStatus()) ); +} + + +void K3bGrowisofsHandler::handleLine( const QString& line ) +{ + int pos = 0; + + if( line.startsWith( ":-[" ) ) { + // Error + + if( line.contains( "ASC=30h" ) ) + m_error = ERROR_MEDIA; + + // :-[ PERFORM OPC failed with SK=3h/ASC=73h/ASCQ=03h + else if( line.startsWith( ":-[ PERFORM OPC failed" ) ) + emit infoMessage( i18n("OPC failed. Please try writing speed 1x."), K3bJob::ERROR ); + + // :-[ attempt -blank=full or re-run with -dvd-compat -dvd-compat to engage DAO ] + else if( !m_dao && + ( line.contains( "engage DAO" ) || line.contains( "media is not formatted or unsupported" ) ) ) + emit infoMessage( i18n("Please try again with writing mode DAO."), K3bJob::ERROR ); + + else if( line.startsWith( ":-[ Failed to change write speed" ) ) { + m_error = ERROR_SPEED_SET_FAILED; + } + } + else if( line.startsWith( ":-(" ) ) { + if( line.contains( "No space left on device" ) ) + m_error = ERROR_OVERSIZE; + + else if( line.contains( "blocks are free" ) && line.contains( "to be written" ) ) { + m_error = ERROR_OVERSIZE; + if( k3bcore->globalSettings()->overburn() ) + emit infoMessage( i18n("Trying to write more than the official disk capacity"), K3bJob::WARNING ); + } + + else if( line.startsWith( ":-( unable to anonymously mmap" ) ) { + m_error = ERROR_MEMLOCK; + } + + else if( line.startsWith( ":-( write failed" ) ) { + m_error = ERROR_WRITE_FAILED; + } + + else + emit infoMessage( line, K3bJob::ERROR ); + } + else if( line.startsWith( "PERFORM OPC" ) ) { + m_error = ERROR_OPC; + } + else if( line.contains( "flushing cache" ) ) { + // here is where we already should stop queriying the buffer fill + // since the device is only used there so far... + m_device = 0; + + emit flushingCache(); + emit newSubTask( i18n("Flushing Cache") ); + emit infoMessage( i18n("Flushing the cache may take some time."), K3bJob::INFO ); + } + + // FIXME: I think this starts with dev->blockDeviceName() so we could improve parsing with: + // if( line.startsWith( dev->blockDeviceName() ) ) { + // line = line.mid( dev->blockDeviceName().length() ); + // if( line.startsWith( "closing..... + + else if( line.contains( "closing track" ) ) { + emit newSubTask( i18n("Closing Track") ); + } + else if( line.contains( "closing disc" ) ) { + emit newSubTask( i18n("Closing Disk") ); + } + else if( line.contains( "closing session" ) ) { + emit newSubTask( i18n("Closing Session") ); + } + else if( line.contains( "updating RMA" ) ) { + emit newSubTask( i18n("Updating RMA") ); + emit infoMessage( i18n("Updating RMA") + "...", K3bJob::INFO ); + } + else if( line.contains( "closing session" ) ) { + emit newSubTask( i18n("Closing Session") ); + emit infoMessage( i18n("Closing Session") + "...", K3bJob::INFO ); + } + else if( line.contains( "writing lead-out" ) ) { + emit newSubTask( i18n("Writing Lead-out") ); + emit infoMessage( i18n("Writing the lead-out may take some time."), K3bJob::INFO ); + } + else if( line.contains( "Quick Grow" ) ) { + emit infoMessage( i18n("Removing reference to lead-out."), K3bJob::INFO ); + } + else if( line.contains( "copying volume descriptor" ) ) { + emit infoMessage( i18n("Modifying ISO9660 volume descriptor"), K3bJob::INFO ); + } + else if( line.contains( "FEATURE 21h is not on" ) ) { + if( !m_dao ) { + // FIXME: it's not only the writer. It may be the media: something like does not support it with this media + // da war was mit: wenn einmal formattiert, dann geht nur noch dao oder wenn einmal als overwrite + // formattiert, dann nur noch dao oder sowas + emit infoMessage( i18n("Writing mode Incremental Streaming not available"), K3bJob::WARNING ); + emit infoMessage( i18n("Engaging DAO"), K3bJob::WARNING ); + } + } + else if( ( pos = line.find( "Current Write Speed" ) ) > 0 ) { + // parse write speed + // /dev/sr0: "Current Write Speed" is 2.4x1385KBps + + pos += 24; + int endPos = line.find( 'x', pos+1 ); + bool ok = true; + double speed = line.mid( pos, endPos-pos ).toDouble(&ok); + if( ok ) + emit infoMessage( i18n("Writing speed: %1 KB/s (%2x)") + .arg((int)(speed*1385.0)) + .arg(KGlobal::locale()->formatNumber(speed)), K3bJob::INFO ); + else + kdDebug() << "(K3bGrowisofsHandler) parsing error: '" << line.mid( pos, endPos-pos ) << "'" << endl; + } + else if( (pos = line.find( "RBU" )) > 0 ) { + + // FIXME: use QRegExp + + // parse ring buffer fill for growisofs >= 6.0 + pos += 4; + int endPos = line.find( '%', pos+1 ); + bool ok = true; + double val = line.mid( pos, endPos-pos ).toDouble( &ok ); + if( ok ) { + int newBuffer = (int)(val+0.5); + if( newBuffer != d->lastBuffer ) { + d->lastBuffer = newBuffer; + emit buffer( newBuffer ); + } + + // device buffer for growisofs >= 7.0 + pos = line.find( "UBU", pos ); + endPos = line.find( '%', pos+5 ); + if( pos > 0 ) { + pos += 4; + val = line.mid( pos, endPos-pos ).toDouble( &ok ); + if( ok ) { + int newBuffer = (int)(val+0.5); + if( newBuffer != d->lastDeviceBuffer ) { + d->lastDeviceBuffer = newBuffer; + emit deviceBuffer( newBuffer ); + } + } + } + } + else + kdDebug() << "(K3bGrowisofsHandler) failed to parse ring buffer fill from '" << line.mid( pos, endPos-pos ) << "'" << endl; + } + + else { + kdDebug() << "(growisofs) " << line << endl; + } +} + + +void K3bGrowisofsHandler::handleExit( int exitCode ) +{ + switch( m_error ) { + case ERROR_MEDIA: + emit infoMessage( i18n("K3b detected a problem with the media."), K3bJob::ERROR ); + emit infoMessage( i18n("Please try another media brand, preferably one explicitly recommended by your writer's vendor."), K3bJob::ERROR ); + emit infoMessage( i18n("Report the problem if it persists anyway."), K3bJob::ERROR ); + break; + + case ERROR_OVERSIZE: + if( k3bcore->globalSettings()->overburn() ) + emit infoMessage( i18n("Data did not fit on disk."), K3bJob::ERROR ); + else + emit infoMessage( i18n("Data does not fit on disk."), K3bJob::ERROR ); + break; + + case ERROR_SPEED_SET_FAILED: + emit infoMessage( i18n("Unable to set writing speed."), K3bJob::ERROR ); + emit infoMessage( i18n("Please try again with the 'ignore speed' setting."), K3bJob::ERROR ); + break; + + case ERROR_OPC: + emit infoMessage( i18n("Optimum Power Calibration failed."), K3bJob::ERROR ); + emit infoMessage( i18n("Try adding '-use-the-force-luke=noopc' to the " + "growisofs user parameters in the K3b settings."), K3bJob::ERROR ); + break; + + case ERROR_MEMLOCK: + emit infoMessage( i18n("Unable to allocate software buffer."), K3bJob::ERROR ); + emit infoMessage( i18n("This error is caused by the low memorylocked resource limit."), K3bJob::ERROR ); + emit infoMessage( i18n("It can be solved by issuing the command 'ulimit -l unlimited'..."), K3bJob::ERROR ); + emit infoMessage( i18n("...or by lowering the used software buffer size in the advanced K3b settings."), K3bJob::ERROR ); + break; + + case ERROR_WRITE_FAILED: + emit infoMessage( i18n("Write error"), K3bJob::ERROR ); + break; + + default: + + // + // The growisofs error codes: + // + // 128 + errno: fatal error upon program startup + // errno : fatal error during recording + // + + if( exitCode > 128 ) { + // for now we just emit a message with the error + // in the future when I know more about what kinds of errors may occur + // we will enhance this + emit infoMessage( i18n("Fatal error at startup: %1").arg(strerror(exitCode-128)), + K3bJob::ERROR ); + } + else if( exitCode == 1 ) { + // Doku says: warning at exit + // Example: mkisofs error + // unable to reload + // So basically this is just for mkisofs failure since we do not let growisofs reload the media + emit infoMessage( i18n("Warning at exit: (1)"), K3bJob::ERROR ); + emit infoMessage( i18n("Most likely mkisofs failed in some way."), K3bJob::ERROR ); + } + else { + emit infoMessage( i18n("Fatal error during recording: %1").arg(strerror(exitCode)), + K3bJob::ERROR ); + } + } + + reset(); +} + + +void K3bGrowisofsHandler::slotCheckBufferStatus() +{ + connect( K3bDevice::sendCommand( K3bDevice::DeviceHandler::BUFFER_CAPACITY, m_device ), + SIGNAL(finished(K3bDevice::DeviceHandler*)), + this, + SLOT(slotCheckBufferStatusDone(K3bDevice::DeviceHandler*)) ); +} + + +void K3bGrowisofsHandler::slotCheckBufferStatusDone( K3bDevice::DeviceHandler* dh ) +{ + if( dh->success() && dh->bufferCapacity() > 0 ) { + emit deviceBuffer( 100 * (dh->bufferCapacity() - dh->availableBufferCapacity() ) / dh->bufferCapacity() ); + QTimer::singleShot( 500, this, SLOT(slotCheckBufferStatus()) ); + } + else { + kdDebug() << "(K3bGrowisofsHandler) stopping buffer check." << endl; + } +} + +#include "k3bgrowisofshandler.moc" diff --git a/libk3b/projects/k3bgrowisofshandler.h b/libk3b/projects/k3bgrowisofshandler.h new file mode 100644 index 0000000..42fcd2a --- /dev/null +++ b/libk3b/projects/k3bgrowisofshandler.h @@ -0,0 +1,87 @@ +/* + * + * $Id: k3bgrowisofshandler.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_GROWISOFS_HANDLER_H_ +#define _K3B_GROWISOFS_HANDLER_H_ + +#include + +namespace K3bDevice { + class Device; + class DeviceHandler; +} + + +/** + * This class handles the output parsing for growisofs + * We put it in an extra class since we have two classes + * using growisofs: the writer and the imager. + */ +class K3bGrowisofsHandler : public QObject +{ + Q_OBJECT + + public: + K3bGrowisofsHandler( QObject* parent = 0, const char* name = 0 ); + ~K3bGrowisofsHandler(); + + enum ErrorType { + ERROR_UNKNOWN, + ERROR_MEDIA, + ERROR_OVERSIZE, + ERROR_SPEED_SET_FAILED, + ERROR_OPC, + ERROR_MEMLOCK, + ERROR_WRITE_FAILED + }; + + int error() const { return m_error; } + + public slots: + /** + * This will basically reset the error type + * @param dao was growisofs called with DAO? + */ + void reset( K3bDevice::Device* = 0, bool dao = false ); + + void handleStart(); + void handleLine( const QString& ); + void handleExit( int exitCode ); + + signals: + void infoMessage( const QString&, int ); + void newSubTask( const QString& ); + void buffer( int ); + void deviceBuffer( int ); + + /** + * We need this to know when the writing finished to update the progress + */ + void flushingCache(); + + private slots: + void slotCheckBufferStatus(); + void slotCheckBufferStatusDone( K3bDevice::DeviceHandler* ); + + private: + class Private; + Private* d; + + int m_error; + bool m_dao; + K3bDevice::Device* m_device; +}; + +#endif diff --git a/libk3b/projects/k3bgrowisofswriter.cpp b/libk3b/projects/k3bgrowisofswriter.cpp new file mode 100644 index 0000000..3144547 --- /dev/null +++ b/libk3b/projects/k3bgrowisofswriter.cpp @@ -0,0 +1,630 @@ +/* + * + * $Id: k3bgrowisofswriter.cpp 731898 2007-11-02 08:22:18Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bgrowisofswriter.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "k3bgrowisofshandler.h" +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + + +class K3bGrowisofsWriter::Private +{ +public: + Private() + : writingMode( 0 ), + closeDvd(false), + multiSession(false), + process( 0 ), + growisofsBin( 0 ), + trackSize(-1), + layerBreak(0), + usingRingBuffer(false), + ringBuffer(0), + forceNoEject( false ) { + } + + int writingMode; + bool closeDvd; + bool multiSession; + K3bProcess* process; + const K3bExternalBin* growisofsBin; + QString image; + + bool success; + bool canceled; + bool finished; + + QTime lastSpeedCalculationTime; + int lastSpeedCalculationBytes; + int lastProgress; + unsigned int lastProgressed; + double lastWritingSpeed; + + bool writingStarted; + + K3bThroughputEstimator* speedEst; + K3bGrowisofsHandler* gh; + + // used in DAO with growisofs >= 5.15 + long trackSize; + + long layerBreak; + + unsigned long long overallSizeFromOutput; + long long firstSizeFromOutput; + + QFile inputFile; + + bool usingRingBuffer; + K3bPipeBuffer* ringBuffer; + + QString multiSessionInfo; + + bool forceNoEject; +}; + + +K3bGrowisofsWriter::K3bGrowisofsWriter( K3bDevice::Device* dev, K3bJobHandler* hdl, + QObject* parent, const char* name ) + : K3bAbstractWriter( dev, hdl, parent, name ) +{ + d = new Private; + d->speedEst = new K3bThroughputEstimator( this ); + connect( d->speedEst, SIGNAL(throughput(int)), + this, SLOT(slotThroughput(int)) ); + + d->gh = new K3bGrowisofsHandler( this ); + connect( d->gh, SIGNAL(infoMessage(const QString&, int)), + this,SIGNAL(infoMessage(const QString&, int)) ); + connect( d->gh, SIGNAL(newSubTask(const QString&)), + this, SIGNAL(newSubTask(const QString&)) ); + connect( d->gh, SIGNAL(buffer(int)), + this, SIGNAL(buffer(int)) ); + connect( d->gh, SIGNAL(deviceBuffer(int)), + this, SIGNAL(deviceBuffer(int)) ); + connect( d->gh, SIGNAL(flushingCache()), + this, SLOT(slotFlushingCache()) ); +} + + +K3bGrowisofsWriter::~K3bGrowisofsWriter() +{ + delete d->process; + delete d; +} + + +bool K3bGrowisofsWriter::active() const +{ + return (d->process ? d->process->isRunning() : false); +} + + +int K3bGrowisofsWriter::fd() const +{ + if( d->process ) { + if( d->usingRingBuffer ) + return d->ringBuffer->inFd(); + else + return d->process->stdinFd(); + } + else + return -1; +} + + +bool K3bGrowisofsWriter::closeFd() +{ + return ( !::close( fd() ) ); +} + + +bool K3bGrowisofsWriter::prepareProcess() +{ + d->growisofsBin = k3bcore->externalBinManager()->binObject( "growisofs" ); + if( !d->growisofsBin ) { + emit infoMessage( i18n("Could not find %1 executable.").arg("growisofs"), ERROR ); + return false; + } + + if( d->growisofsBin->version < K3bVersion( 5, 10 ) ) { + emit infoMessage( i18n("Growisofs version %1 is too old. " + "K3b needs at least version 5.10.").arg(d->growisofsBin->version), + ERROR ); + return false; + } + + emit debuggingOutput( "Used versions", "growisofs: " + d->growisofsBin->version ); + + if( !d->growisofsBin->copyright.isEmpty() ) + emit infoMessage( i18n("Using %1 %2 - Copyright (C) %3").arg("growisofs") + .arg(d->growisofsBin->version).arg(d->growisofsBin->copyright), INFO ); + + + // + // The growisofs bin is ready. Now we add the parameters + // + delete d->process; + d->process = new K3bProcess(); + d->process->setRunPrivileged(true); + // d->process->setPriority( KProcess::PrioHighest ); + d->process->setSplitStdout(true); + d->process->setRawStdin(true); + connect( d->process, SIGNAL(stderrLine(const QString&)), this, SLOT(slotReceivedStderr(const QString&)) ); + connect( d->process, SIGNAL(stdoutLine(const QString&)), this, SLOT(slotReceivedStderr(const QString&)) ); + connect( d->process, SIGNAL(processExited(KProcess*)), this, SLOT(slotProcessExited(KProcess*)) ); + + + // + // growisofs < 5.20 wants the tracksize to be a multiple of 16 (1 ECC block: 16*2048 bytes) + // we simply pad ourselves. + // + // But since the writer itself properly pads or writes a longer lead-out we don't really need + // to write zeros. We just tell growisofs to reserve a multiple of 16 blocks. + // This is only releveant in DAO mode anyway. + // + // FIXME: seems as we also need this for double layer writing. Better make it the default and + // actually write the pad bytes. The only possibility I see right now is to add a padding option + // to the pipebuffer. + int trackSizePadding = 0; + if( d->trackSize > 0 && d->growisofsBin->version < K3bVersion( 5, 20 ) ) { + if( d->trackSize % 16 ) { + trackSizePadding = (16 - d->trackSize%16); + kdDebug() << "(K3bGrowisofsWriter) need to pad " << trackSizePadding << " blocks." << endl; + } + } + + + *d->process << d->growisofsBin; + + // set this var to true to enable the ringbuffer + d->usingRingBuffer = ( d->growisofsBin->version < K3bVersion( 6, 0 ) ); + + QString s = burnDevice()->blockDeviceName() + "="; + if( d->usingRingBuffer || d->image.isEmpty() ) { + // we always read from stdin since the ringbuffer does the actual reading from the source + s += "/dev/fd/0"; + } + else + s += d->image; + + if( d->multiSession && !d->multiSessionInfo.isEmpty() ) + *d->process << "-C" << d->multiSessionInfo; + + if( d->multiSession ) + *d->process << "-M"; + else + *d->process << "-Z"; + *d->process << s; + + + if( !d->image.isEmpty() && d->usingRingBuffer ) { + d->inputFile.setName( d->image ); + d->trackSize = (K3b::filesize( d->image ) + 1024) / 2048; + if( !d->inputFile.open( IO_ReadOnly ) ) { + emit infoMessage( i18n("Could not open file %1.").arg(d->image), ERROR ); + return false; + } + } + + // now we use the force (luke ;) do not reload the dvd, K3b does that. + *d->process << "-use-the-force-luke=notray"; + + // we check for existing filesystems ourselves, so we always force the overwrite... + *d->process << "-use-the-force-luke=tty"; + + bool dvdCompat = d->closeDvd; + + // DL writing with forced layer break + if( d->layerBreak > 0 ) { + *d->process << "-use-the-force-luke=break:" + QString::number(d->layerBreak); + dvdCompat = true; + } + + // the tracksize parameter takes priority over the dao:tracksize parameter since growisofs 5.18 + else if( d->growisofsBin->version > K3bVersion( 5, 17 ) && d->trackSize > 0 ) + *d->process << "-use-the-force-luke=tracksize:" + QString::number(d->trackSize + trackSizePadding); + + if( simulate() ) + *d->process << "-use-the-force-luke=dummy"; + + if( d->writingMode == K3b::DAO ) { + dvdCompat = true; + if( d->growisofsBin->version >= K3bVersion( 5, 15 ) && d->trackSize > 0 ) + *d->process << "-use-the-force-luke=dao:" + QString::number(d->trackSize + trackSizePadding); + else + *d->process << "-use-the-force-luke=dao"; + d->gh->reset( burnDevice(), true ); + } + else + d->gh->reset( burnDevice(), false ); + + // + // Never use the -dvd-compat parameter with DVD+RW media + // because the only thing it does is creating problems. + // Normally this should be done in growisofs + // + int mediaType = burnDevice()->mediaType(); + if( dvdCompat && + mediaType != K3bDevice::MEDIA_DVD_PLUS_RW && + mediaType != K3bDevice::MEDIA_DVD_RW_OVWR ) + *d->process << "-dvd-compat"; + + // + // Some DVD writers do not allow changing the writing speed so we allow + // the user to ignore the speed setting + // + int speed = burnSpeed(); + if( speed >= 0 ) { + if( speed == 0 ) { + // try to determine the writeSpeed + // if it fails determineOptimalWriteSpeed() will return 0 and + // the choice is left to growisofs which means that the choice is + // really left to the drive since growisofs does not change the speed + // if no option is given + speed = burnDevice()->determineMaximalWriteSpeed(); + } + + // speed may be a float number. example: DVD+R(W): 2.4x + if( speed != 0 ) + *d->process << QString("-speed=%1").arg( speed%1385 > 0 + ? QString::number( (float)speed/1385.0, 'f', 1 ) + : QString::number( speed/1385 ) ); + } + + if( k3bcore->globalSettings()->overburn() ) + *d->process << "-overburn"; + + if( !d->usingRingBuffer && d->growisofsBin->version >= K3bVersion( 6, 0 ) ) { + bool manualBufferSize = k3bcore->globalSettings()->useManualBufferSize(); + int bufSize = ( manualBufferSize ? k3bcore->globalSettings()->bufferSize() : 32 ); + *d->process << QString("-use-the-force-luke=bufsize:%1m").arg(bufSize); + } + + // additional user parameters from config + const QStringList& params = d->growisofsBin->userParameters(); + for( QStringList::const_iterator it = params.begin(); it != params.end(); ++it ) + *d->process << *it; + + emit debuggingOutput( "Burned media", K3bDevice::mediaTypeString(mediaType) ); + + return true; +} + + +void K3bGrowisofsWriter::start() +{ + jobStarted(); + + d->lastWritingSpeed = 0; + d->lastProgressed = 0; + d->lastProgress = 0; + d->firstSizeFromOutput = -1; + d->lastSpeedCalculationTime = QTime::currentTime(); + d->lastSpeedCalculationBytes = 0; + d->writingStarted = false; + d->canceled = false; + d->speedEst->reset(); + d->finished = false; + + if( !prepareProcess() ) { + jobFinished( false ); + } + else { + + kdDebug() << "***** " << d->growisofsBin->name() << " parameters:\n"; + const QValueList& args = d->process->args(); + QString s; + for( QValueList::const_iterator it = args.begin(); it != args.end(); ++it ) { + s += *it + " "; + } + kdDebug() << s << flush << endl; + emit debuggingOutput( d->growisofsBin->name() + " command:", s); + + + emit newSubTask( i18n("Preparing write process...") ); + + // FIXME: check the return value + if( K3b::isMounted( burnDevice() ) ) { + emit infoMessage( i18n("Unmounting medium"), INFO ); + K3b::unmount( burnDevice() ); + } + + // block the device (including certain checks) + k3bcore->blockDevice( burnDevice() ); + + // lock the device for good in this process since it will + // be opened in the growisofs process + burnDevice()->close(); + burnDevice()->usageLock(); + + if( !d->process->start( KProcess::NotifyOnExit, KProcess::All ) ) { + // something went wrong when starting the program + // it "should" be the executable + kdDebug() << "(K3bGrowisofsWriter) could not start " << d->growisofsBin->path << endl; + emit infoMessage( i18n("Could not start %1.").arg(d->growisofsBin->name()), K3bJob::ERROR ); + jobFinished(false); + } + else { + if( simulate() ) { + emit newTask( i18n("Simulating") ); + emit infoMessage( i18n("Starting simulation..."), + K3bJob::INFO ); + } + else { + emit newTask( i18n("Writing") ); + emit infoMessage( i18n("Starting disc write..."), K3bJob::INFO ); + } + + d->gh->handleStart(); + + // create the ring buffer + if( d->usingRingBuffer ) { + if( !d->ringBuffer ) { + d->ringBuffer = new K3bPipeBuffer( this, this ); + connect( d->ringBuffer, SIGNAL(percent(int)), this, SIGNAL(buffer(int)) ); + connect( d->ringBuffer, SIGNAL(finished(bool)), this, SLOT(slotRingBufferFinished(bool)) ); + } + + d->ringBuffer->writeToFd( d->process->stdinFd() ); + bool manualBufferSize = k3bcore->globalSettings()->useManualBufferSize(); + int bufSize = ( manualBufferSize ? k3bcore->globalSettings()->bufferSize() : 20 ); + d->ringBuffer->setBufferSize( bufSize ); + + if( !d->image.isEmpty() ) + d->ringBuffer->readFromFd( d->inputFile.handle() ); + + d->ringBuffer->start(); + } + } + } +} + + +void K3bGrowisofsWriter::cancel() +{ + if( active() ) { + d->canceled = true; + closeFd(); + if( d->usingRingBuffer && d->ringBuffer ) + d->ringBuffer->cancel(); + d->process->kill(); + } +} + + +void K3bGrowisofsWriter::setWritingMode( int m ) +{ + d->writingMode = m; +} + + +void K3bGrowisofsWriter::setTrackSize( long size ) +{ + d->trackSize = size; +} + + +void K3bGrowisofsWriter::setLayerBreak( long lb ) +{ + d->layerBreak = lb; +} + + +void K3bGrowisofsWriter::setCloseDvd( bool b ) +{ + d->closeDvd = b; +} + + +void K3bGrowisofsWriter::setMultiSession( bool b ) +{ + d->multiSession = b; +} + + +void K3bGrowisofsWriter::setImageToWrite( const QString& filename ) +{ + d->image = filename; +} + + +void K3bGrowisofsWriter::slotReceivedStderr( const QString& line ) +{ + emit debuggingOutput( d->growisofsBin->name(), line ); + + if( line.contains( "remaining" ) ) { + + if( !d->writingStarted ) { + d->writingStarted = true; + emit newSubTask( i18n("Writing data") ); + } + + // parse progress + int pos = line.find( "/" ); + unsigned long long done = line.left( pos ).toULongLong(); + bool ok = true; + d->overallSizeFromOutput = line.mid( pos+1, line.find( "(", pos ) - pos - 1 ).toULongLong( &ok ); + if( d->firstSizeFromOutput == -1 ) + d->firstSizeFromOutput = done; + done -= d->firstSizeFromOutput; + d->overallSizeFromOutput -= d->firstSizeFromOutput; + if( ok ) { + int p = (int)(100 * done / d->overallSizeFromOutput); + if( p > d->lastProgress ) { + emit percent( p ); + emit subPercent( p ); + d->lastProgress = p; + } + if( (unsigned int)(done/1024/1024) > d->lastProgressed ) { + d->lastProgressed = (unsigned int)(done/1024/1024); + emit processedSize( d->lastProgressed, (int)(d->overallSizeFromOutput/1024/1024) ); + emit processedSubSize( d->lastProgressed, (int)(d->overallSizeFromOutput/1024/1024) ); + } + + // try parsing write speed (since growisofs 5.11) + pos = line.find( '@' ); + if( pos != -1 ) { + pos += 1; + double speed = line.mid( pos, line.find( 'x', pos ) - pos ).toDouble(&ok); + if( ok ) { + if( d->lastWritingSpeed != speed ) + emit writeSpeed( (int)(speed*1385.0), 1385 ); + d->lastWritingSpeed = speed; + } + else + kdDebug() << "(K3bGrowisofsWriter) speed parsing failed: '" + << line.mid( pos, line.find( 'x', pos ) - pos ) << "'" << endl; + } + else { + d->speedEst->dataWritten( done/1024 ); + } + } + else + kdDebug() << "(K3bGrowisofsWriter) progress parsing failed: '" + << line.mid( pos+1, line.find( "(", pos ) - pos - 1 ).stripWhiteSpace() << "'" << endl; + } + + // else + // to be able to parse the ring buffer fill in growisofs 6.0 we need to do this all the time + // FIXME: get rid of the K3bGrowisofsHandler once it is sure that we do not need the K3bGrowisofsImager anymore + d->gh->handleLine( line ); +} + + +void K3bGrowisofsWriter::slotProcessExited( KProcess* p ) +{ + d->inputFile.close(); + + // release the device within this process + burnDevice()->usageUnlock(); + + // unblock the device + k3bcore->unblockDevice( burnDevice() ); + + if( d->canceled ) { + if( !d->finished ) { + d->finished = true; + // this will unblock and eject the drive and emit the finished/canceled signals + K3bAbstractWriter::cancel(); + } + return; + } + + d->finished = true; + + // it seems that growisofs sometimes exits with a valid exit code while a write error occured + if( p->exitStatus() == 0 && d->gh->error() != K3bGrowisofsHandler::ERROR_WRITE_FAILED ) { + + int s = d->speedEst->average(); + if( s > 0 ) + emit infoMessage( i18n("Average overall write speed: %1 KB/s (%2x)") + .arg(s).arg(KGlobal::locale()->formatNumber((double)s/1385.0), 2), INFO ); + + if( simulate() ) + emit infoMessage( i18n("Simulation successfully completed"), K3bJob::SUCCESS ); + else + emit infoMessage( i18n("Writing successfully completed"), K3bJob::SUCCESS ); + + d->success = true; + } + else { + if( !wasSourceUnreadable() ) + d->gh->handleExit( p->exitStatus() ); + d->success = false; + } + + if( !k3bcore->globalSettings()->ejectMedia() || d->forceNoEject ) + jobFinished(d->success); + else { + emit newSubTask( i18n("Ejecting DVD") ); + connect( K3bDevice::eject( burnDevice() ), + SIGNAL(finished(K3bDevice::DeviceHandler*)), + this, + SLOT(slotEjectingFinished(K3bDevice::DeviceHandler*)) ); + } +} + + +void K3bGrowisofsWriter::slotRingBufferFinished( bool ) +{ + if( !d->finished ) { + d->finished = true; + // this will unblock and eject the drive and emit the finished/canceled signals + K3bAbstractWriter::cancel(); + } +} + + +void K3bGrowisofsWriter::slotEjectingFinished( K3bDevice::DeviceHandler* dh ) +{ + if( !dh->success() ) + emit infoMessage( i18n("Unable to eject media."), ERROR ); + + jobFinished(d->success); +} + + +void K3bGrowisofsWriter::slotThroughput( int t ) +{ + emit writeSpeed( t, 1385 ); +} + + +void K3bGrowisofsWriter::slotFlushingCache() +{ + if( !d->canceled ) { + // + // growisofs's progress output stops before 100%, so we do it manually + // + emit percent( 100 ); + emit processedSize( d->overallSizeFromOutput/1024/1024, + d->overallSizeFromOutput/1024/1024 ); + } +} + + +void K3bGrowisofsWriter::setMultiSessionInfo( const QString& info ) +{ + d->multiSessionInfo = info; +} + + +void K3bGrowisofsWriter::setForceNoEject( bool b ) +{ + d->forceNoEject = b; +} + +#include "k3bgrowisofswriter.moc" diff --git a/libk3b/projects/k3bgrowisofswriter.h b/libk3b/projects/k3bgrowisofswriter.h new file mode 100644 index 0000000..ed69923 --- /dev/null +++ b/libk3b/projects/k3bgrowisofswriter.h @@ -0,0 +1,106 @@ +/* + * + * $Id: k3bgrowisofswriter.h 679276 2007-06-23 13:25:21Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_GROWISOFS_WRITER_H_ +#define _K3B_GROWISOFS_WRITER_H_ + +#include "k3babstractwriter.h" + + +namespace K3bDevice { + class Device; + class DeviceHandler; +} +class KProcess; + + + +class K3bGrowisofsWriter : public K3bAbstractWriter +{ + Q_OBJECT + + public: + K3bGrowisofsWriter( K3bDevice::Device*, K3bJobHandler*, + QObject* parent = 0, const char* name = 0 ); + ~K3bGrowisofsWriter(); + + bool active() const; + + int fd() const; + bool closeFd(); + + public slots: + void start(); + void cancel(); + + void setWritingMode( int ); + + /** + * If true the growisofs parameter -M is used in favor of -Z. + */ + void setMultiSession( bool b ); + + /** + * Only used in DAO mode and only supported with growisofs >= 5.15 + * @param size size in blocks + */ + void setTrackSize( long size ); + + /** + * Use this in combination with setTrackSize when writing double layer media. + * @param lb The number of data sectors in the first layer. It needs to be less or equal + * to tracksize/2. The writer will pad the second layer with zeros if + * break < tracksize/2. + * If set to 0 this setting will be ignored. + */ + void setLayerBreak( long lb ); + + /** + * Close the DVD to enable max DVD compatibility (uses the growisofs --dvd-compat parameter) + * This will also be used in DAO mode and when the layerBreak has been set. + */ + void setCloseDvd( bool ); + + /** + * set this to QString::null or an empty string to let the writer + * read it's data from fd() + */ + void setImageToWrite( const QString& ); + + /** + * While reading the image from stdin growisofs needs + * a valid -C parameter for multisession. + */ + void setMultiSessionInfo( const QString& ); + + void setForceNoEject( bool ); + + protected: + bool prepareProcess(); + + protected slots: + void slotReceivedStderr( const QString& ); + void slotProcessExited( KProcess* ); + void slotEjectingFinished( K3bDevice::DeviceHandler* dh ); + void slotThroughput( int t ); + void slotFlushingCache(); + void slotRingBufferFinished( bool ); + + private: + class Private; + Private* d; +}; + +#endif diff --git a/libk3b/projects/k3bimagefilereader.cpp b/libk3b/projects/k3bimagefilereader.cpp new file mode 100644 index 0000000..70ece16 --- /dev/null +++ b/libk3b/projects/k3bimagefilereader.cpp @@ -0,0 +1,88 @@ +/* + * + * $Id: k3bimagefilereader.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bimagefilereader.h" + +#include +#include + +#include + + + +class K3bImageFileReader::Private +{ +public: + Private() + : isValid(false) { + } + + QString filename; + QString imageFilename; + bool isValid; +}; + + +K3bImageFileReader::K3bImageFileReader() +{ + d = new Private(); +} + + +K3bImageFileReader::~K3bImageFileReader() +{ + delete d; +} + + +void K3bImageFileReader::openFile( const QString& filename ) +{ + d->filename = filename; + d->imageFilename = QString::null; + setValid(false); + + if( !filename.isEmpty() ) + readFile(); +} + + +void K3bImageFileReader::setValid( bool b ) +{ + d->isValid = b; +} + + +void K3bImageFileReader::setImageFilename( const QString& filename ) +{ + d->imageFilename = filename; +} + + +bool K3bImageFileReader::isValid() const +{ + return d->isValid; +} + + +const QString& K3bImageFileReader::filename() const +{ + return d->filename; +} + + +const QString& K3bImageFileReader::imageFilename() const +{ + return d->imageFilename; +} diff --git a/libk3b/projects/k3bimagefilereader.h b/libk3b/projects/k3bimagefilereader.h new file mode 100644 index 0000000..2bf727e --- /dev/null +++ b/libk3b/projects/k3bimagefilereader.h @@ -0,0 +1,55 @@ +/* + * + * $Id: k3bimagefilereader.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_IMAGE_FILE_READER_H_ +#define _K3B_IMAGE_FILE_READER_H_ + +#include +#include "k3b_export.h" + +class LIBK3B_EXPORT K3bImageFileReader +{ + public: + K3bImageFileReader(); + virtual ~K3bImageFileReader(); + + /** + * Open a file. In most cases the TOC file + */ + void openFile( const QString& filename ); + + virtual bool isValid() const; + + /** + * Return the current set filename; + */ + const QString& filename() const; + + /** + * returns the name of the corresponding image file. + */ + virtual const QString& imageFilename() const; + + protected: + virtual void readFile() = 0; + void setValid( bool ); + void setImageFilename( const QString& ); + + private: + class Private; + Private* d; +}; + +#endif diff --git a/libk3b/projects/k3binffilewriter.cpp b/libk3b/projects/k3binffilewriter.cpp new file mode 100644 index 0000000..9395b2a --- /dev/null +++ b/libk3b/projects/k3binffilewriter.cpp @@ -0,0 +1,186 @@ +/* + * + * $Id: k3binffilewriter.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3binffilewriter.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + + + +K3bInfFileWriter::K3bInfFileWriter() + : m_index0(-1), + m_trackNumber(1), + m_trackStart(0), + m_trackLength(0), + m_preEmphasis(false), + m_copyPermitted(true), + m_bigEndian(false) +{ +} + + +bool K3bInfFileWriter::save( const QString& filename ) +{ + QFile f( filename ); + + if( !f.open( IO_WriteOnly ) ) { + kdDebug() << "(K3bInfFileWriter) could not open file " << f.name() << endl; + return false; + } + + QTextStream s( &f ); + + return save( s ); +} + + +bool K3bInfFileWriter::save( QTextStream& s ) +{ + // now write the inf data + // ---------------------- + // header + s << "# Cdrecord-Inf-File written by K3b " << k3bcore->version() + << ", " << QDateTime::currentDateTime().toString() << endl + << "#" << endl; + + s << "ISRC=\t\t" << m_isrc << endl; + s << "MCN=\t\t" << m_mcn << endl; + + // CD-Text + s << "Albumperformer=\t" << "'" << m_albumPerformer << "'" << endl; + s << "Albumtitle=\t" << "'" << m_albumTitle << "'" << endl; + + s << "Performer=\t" << "'" << m_trackPerformer << "'" << endl; + s << "Songwriter=\t" << "'" << m_trackSongwriter << "'" << endl; + s << "Composer=\t" << "'" << m_trackComposer << "'" << endl; + s << "Arranger=\t" << "'" << m_trackArranger << "'" << endl; + s << "Message=\t" << "'" << m_trackMessage << "'" << endl; + + s << "Tracktitle=\t" << "'" << m_trackTitle << "'" << endl; + + s << "Tracknumber=\t" << m_trackNumber << endl; + + // track start + s << "Trackstart=\t" << m_trackStart.lba() << endl; + + // track length + s << "# Tracklength: " << m_trackLength.toString() << endl; + s << "Tracklength=\t" << m_trackLength.totalFrames() << ", 0" << endl; + + // pre-emphasis + s << "Pre-emphasis=\t"; + if( m_preEmphasis ) + s << "yes"; + else + s << "no"; + s << endl; + + // channels (always 2) + s << "Channels=\t2" << endl; + + // copy-permitted + // TODO: not sure about this! + // there are three options: yes, no, once + // but using "once" gives the same result as with cdrdao + // and that's important. + s << "Copy_permitted=\t"; + if( m_copyPermitted ) + s << "yes"; + else + s << "once"; + s << endl; + + // endianess - wav is little -> onthefly: big, with images: little + s << "Endianess=\t"; + if( m_bigEndian ) + s << "big"; + else + s << "little"; + s << endl; + + // write indices + // the current tracks' data contains the pregap of the next track + // if the pregap has length 0 we need no index 0 + if( m_indices.isEmpty() ) + s << "Index=\t\t0" << endl; + else { + for( unsigned int i = 0; i < m_indices.count(); ++i ) + s << "Index=\t\t" << m_indices[i] << endl; + } + + s << "Index0=\t\t" << m_index0 << endl; + + return ( s.device()->status() == IO_Ok ); +} + + +void K3bInfFileWriter::setTrack( const K3bDevice::Track& track ) +{ + m_indices.clear(); + + // the first index always has to be a zero (cdrecord manpage) + m_indices.append( 0 ); + + const QValueVector& indexList = track.indices(); + for( unsigned int i = 0; i < indexList.count(); ++i ) + m_indices.append( indexList[i].lba() ); + + if( track.index0() > 0 ) + m_index0 = track.index0().lba(); + else + m_index0 = -1; + + setPreEmphasis( track.preEmphasis() ); + setCopyPermitted( track.copyPermitted() ); + + setTrackStart( track.firstSector() ); + setTrackLength( track.length() ); + + setIsrc( track.isrc() ); + + setBigEndian( true ); +} + + +void K3bInfFileWriter::addIndex( long i ) +{ + m_indices.append( i ); +} + + +void K3bInfFileWriter::setTrackCdText( const K3bDevice::TrackCdText& cdtext ) +{ + setTrackTitle( cdtext.title() ); + setTrackPerformer( cdtext.performer() ); + setTrackSongwriter( cdtext.songwriter() ); + setTrackComposer( cdtext.composer() ); + setTrackArranger( cdtext.arranger() ); + setTrackMessage( cdtext.message() ); +} + + +void K3bInfFileWriter::setCdText( const K3bDevice::CdText& cdtext ) +{ + setAlbumTitle( cdtext.title() ); + setAlbumPerformer( cdtext.performer() ); +} diff --git a/libk3b/projects/k3binffilewriter.h b/libk3b/projects/k3binffilewriter.h new file mode 100644 index 0000000..74e23e4 --- /dev/null +++ b/libk3b/projects/k3binffilewriter.h @@ -0,0 +1,119 @@ +/* + * + * $Id: k3binffilewriter.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_INF_FILE_WRITER_H_ +#define _K3B_INF_FILE_WRITER_H_ + +#include +#include + +#include + + +namespace K3bDevice { + class Track; + class TrackCdText; + class CdText; +} + + +class K3bInfFileWriter +{ + public: + K3bInfFileWriter(); + + bool save( QTextStream& ); + bool save( const QString& filename ); + + /** + * Use this to set: + * @li trackStart + * @li trackLength + * @li index0 + * @li all indices + * @li preemphasis + * @li copyPermitted + * @li ISRC + * + * Endianess is set to big. + * + * Tracknumber needs to be set manually. + */ + void setTrack( const K3bDevice::Track& ); + + void clearIndices() { m_indices.clear(); } + + /** + * This is relative to the track start + */ + void setIndex0( int i ) { m_index0 = i; } + void addIndex( long i ); + + void setTrackNumber( int i ) { m_trackNumber = i; } + + void setTrackStart( const K3b::Msf& i ) { m_trackStart = i; } + void setTrackLength( const K3b::Msf& i ) { m_trackLength = i; } + + void setPreEmphasis( bool b ) { m_preEmphasis = b; } + void setCopyPermitted( bool b ) { m_copyPermitted = b; } + + /** + * Cdrecord seems to ignore this anyway and always expect big endian + * data on stdin and wavs are little endian anyway. + */ + void setBigEndian( bool b ) { m_bigEndian = b; } + + void setTrackCdText( const K3bDevice::TrackCdText& ); + void setTrackTitle( const QString& s ) { m_trackTitle = s; } + void setTrackPerformer( const QString& s ) { m_trackPerformer = s; } + void setTrackSongwriter( const QString& s ) { m_trackSongwriter = s; } + void setTrackComposer( const QString& s ) { m_trackComposer = s; } + void setTrackArranger( const QString& s ) { m_trackArranger = s; } + void setTrackMessage( const QString& s ) { m_trackMessage = s; } + + void setCdText( const K3bDevice::CdText& ); + void setAlbumTitle( const QString& s ) { m_albumTitle = s; } + void setAlbumPerformer( const QString& s ) { m_albumPerformer = s; } + + void setIsrc( const QCString& s ) { m_isrc = s; } + void setMcn( const QCString& s ) { m_mcn = s; } + + private: + long m_index0; + + QValueVector m_indices; + + int m_trackNumber; + K3b::Msf m_trackStart; + K3b::Msf m_trackLength; + bool m_preEmphasis; + bool m_copyPermitted; + bool m_bigEndian; + + QString m_trackTitle; + QString m_trackPerformer; + QString m_trackSongwriter; + QString m_trackComposer; + QString m_trackArranger; + QString m_trackMessage; + + QString m_albumTitle; + QString m_albumPerformer; + + QCString m_isrc; + QCString m_mcn; +}; + +#endif diff --git a/libk3b/projects/k3bpipebuffer.cpp b/libk3b/projects/k3bpipebuffer.cpp new file mode 100644 index 0000000..3b61116 --- /dev/null +++ b/libk3b/projects/k3bpipebuffer.cpp @@ -0,0 +1,281 @@ +/* + * + * $Id: k3bpipebuffer.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bpipebuffer.h" + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +// +// This one is based on the little pipebuf2 program by Peter Osterlund +// + + +class K3bPipeBuffer::WorkThread : public K3bThread +{ +public: + WorkThread() + : K3bThread(), + buffer(0), + bufSize(4*1024*1024), + canceled(false) { + outFd = inFd = -1; + inFdPair[0] = inFdPair[1] = -1; + } + + ~WorkThread() { + delete [] buffer; + } + + bool initFds() { + if( inFd == -1 ) { + if( ::socketpair(AF_UNIX, SOCK_STREAM, 0, inFdPair) ) { + // if( ::pipe( inFdPair ) ) { + kdDebug() << "(K3bPipeBuffer::WorkThread) unable to create socketpair" << endl; + inFdPair[0] = inFdPair[1] = -1; + return false; + } + else { + ::fcntl(inFdPair[0], F_SETFL, O_NONBLOCK); + ::fcntl(outFd, F_SETFL, O_NONBLOCK); + } + } + else { + ::fcntl(inFd, F_SETFL, O_NONBLOCK); + } + + delete [] buffer; + buffer = new char[bufSize]; + + return (buffer != 0); + } + + void run() { + emitStarted(); + + int usedInFd = -1; + if( inFd > 0 ) + usedInFd = inFd; + else + usedInFd = inFdPair[0]; + + kdDebug() << "(K3bPipeBuffer::WorkThread) reading from " << usedInFd + << " and writing to " << outFd << endl; + kdDebug() << "(K3bPipeBuffer::WorkThread) using buffer size of " << bufSize << endl; + + // start the buffering + unsigned int bufPos = 0; + unsigned int dataLen = 0; + bool eof = false; + bool error = false; + canceled = false; + int oldPercent = 0; + + static const unsigned int MAX_BUFFER_READ = 2048*3; + + while( !canceled && !error && (!eof || dataLen > 0) ) { + // + // create two fd sets + // + fd_set readFds, writeFds; + FD_ZERO(&readFds); + FD_ZERO(&writeFds); + + // + // fill the fd sets + // + if( !eof && dataLen < bufSize ) + FD_SET(usedInFd, &readFds); + if( dataLen > 0 ) + FD_SET(outFd, &writeFds); + + // + // wait for data + // + int ret = select( QMAX(usedInFd, outFd) + 1, &readFds, &writeFds, NULL, NULL); + + // + // Do the buffering + // + if( !canceled && ret > 0 ) { + + int percent = -1; + + // + // Read from the buffer and write to the output + // + if( FD_ISSET(outFd, &writeFds) ) { + unsigned int maxLen = QMIN(bufSize - bufPos, dataLen); + + ret = ::write( outFd, &buffer[bufPos], maxLen ); + + if( ret < 0 ) { + if( (errno != EINTR) && (errno != EAGAIN) ) { + kdDebug() << "(K3bPipeBuffer::WorkThread) error while writing to " << outFd << endl; + error = true; + } + } + else { + // + // we always emit before the reading from the buffer since + // it makes way more sense to show the buffer before the reading. + // + percent = (int)((double)dataLen*100.0/(double)bufSize); + + bufPos = (bufPos + ret) % bufSize; + dataLen -= ret; + } + } + + // + // Read into the buffer + // + else if( FD_ISSET(usedInFd, &readFds) ) { + unsigned int readPos = (bufPos + dataLen) % bufSize; + unsigned int maxLen = QMIN(bufSize - readPos, bufSize - dataLen); + // + // never read more than xxx bytes + // This is some tuning to prevent the reading from blocking the whole thread + // + if( maxLen > MAX_BUFFER_READ ) // some dummy value below 1 MB + maxLen = MAX_BUFFER_READ; + ret = ::read( usedInFd, &buffer[readPos], maxLen ); + if( ret < 0 ) { + if( (errno != EINTR) && (errno != EAGAIN) ) { + kdDebug() << "(K3bPipeBuffer::WorkThread) error while reading from " << usedInFd << endl; + error = true; + } + } + else if( ret == 0 ) { + kdDebug() << "(K3bPipeBuffer::WorkThread) end of input." << endl; + eof = true; + } + else { + dataLen += ret; + + percent = (int)((double)dataLen*100.0/(double)bufSize); + } + } + + // A little hack to keep the buffer display from flickering + if( percent == 99 ) + percent = 100; + + if( percent != -1 && percent != oldPercent ) { + emitPercent( percent ); + oldPercent = percent; + } + } + else if( !canceled ) { + error = true; + kdDebug() << "(K3bPipeBuffer::WorkThread) select: " << ::strerror(errno) << endl; + } + } + + if( inFd == -1 ) { + ::close( inFdPair[0] ); + ::close( inFdPair[1] ); + inFdPair[0] = inFdPair[1] = -1; + } + + // + // close the fd we are writing to (this is need to make growisofs happy + // TODO: perhaps make this configurable + // + ::close( outFd ); + + if( canceled ) + emitCanceled(); + emitFinished( !error && !canceled ); + } + + char* buffer; + size_t bufSize; + int outFd; + int inFd; + int inFdPair[2]; + bool canceled; +}; + + +K3bPipeBuffer::K3bPipeBuffer( K3bJobHandler* jh, QObject* parent, const char* name ) + : K3bThreadJob( jh, parent, name ) +{ + m_thread = new WorkThread(); + setThread( m_thread ); +} + + +K3bPipeBuffer::~K3bPipeBuffer() +{ + delete m_thread; +} + + +void K3bPipeBuffer::start() +{ + // + // Create the socketpair in the gui thread to be sure it's available after + // this method returns. + // + if( !m_thread->initFds() ) + jobFinished(false); + else + K3bThreadJob::start(); +} + + +void K3bPipeBuffer::cancel() +{ + m_thread->canceled = true; +} + + +void K3bPipeBuffer::setBufferSize( int mb ) +{ + m_thread->bufSize = mb * 1024 * 1024; +} + + +void K3bPipeBuffer::readFromFd( int fd ) +{ + m_thread->inFd = fd; +} + + +void K3bPipeBuffer::writeToFd( int fd ) +{ + m_thread->outFd = fd; +} + + +int K3bPipeBuffer::inFd() const +{ + if( m_thread->inFd == -1 ) + return m_thread->inFdPair[1]; + else + return m_thread->inFd; +} diff --git a/libk3b/projects/k3bpipebuffer.h b/libk3b/projects/k3bpipebuffer.h new file mode 100644 index 0000000..6aae368 --- /dev/null +++ b/libk3b/projects/k3bpipebuffer.h @@ -0,0 +1,59 @@ +/* + * + * $Id: k3bpipebuffer.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_PIPE_BUFFER_H_ +#define _K3B_PIPE_BUFFER_H_ + + +#include + +/** + * the pipebuffer uses the signal percent to show it's status. + */ +class K3bPipeBuffer : public K3bThreadJob +{ + public: + K3bPipeBuffer( K3bJobHandler*, QObject* parent = 0, const char* name = 0 ); + ~K3bPipeBuffer(); + + /** + * Set the buffer size in MB. The default value is 4 MB. + */ + void setBufferSize( int ); + + /** + * If this is set to -1 (which is the default) the pipebuffer + * will create a fd pair which can be obtained by inFd() after + * the buffer has been started. + */ + void readFromFd( int fd ); + void writeToFd( int fd ); + + /** + * This is only valid after the piepbuffer has been started and no fd + * has been set with readFromFd. + */ + int inFd() const; + + public slots: + void start(); + void cancel(); + + private: + class WorkThread; + WorkThread* m_thread; +}; + +#endif diff --git a/libk3b/projects/k3btocfilewriter.cpp b/libk3b/projects/k3btocfilewriter.cpp new file mode 100644 index 0000000..77662d6 --- /dev/null +++ b/libk3b/projects/k3btocfilewriter.cpp @@ -0,0 +1,356 @@ +/* + * + * $Id: k3btocfilewriter.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3btocfilewriter.h" + +#include +#include +#include +#include + +#include +#include +#include + + +K3bTocFileWriter::K3bTocFileWriter() + : m_hideFirstTrack(false), + m_sessionToWrite(1) +{ +} + + +bool K3bTocFileWriter::save( const QString& filename ) +{ + QFile f( filename ); + + if( !f.open( IO_WriteOnly ) ) { + kdDebug() << "(K3bCueFileWriter) could not open file " << f.name() << endl; + return false; + } + + QTextStream s( &f ); + + return save( s ); +} + + +bool K3bTocFileWriter::save( QTextStream& t ) +{ + writeHeader(t); + + if( !m_cdText.isEmpty() ) + writeGlobalCdText(t); + + // + // see if we have multiple sessions + // + int sessions = 1; + for( K3bDevice::Toc::iterator it = m_toc.begin(); it != m_toc.end(); ++it ) { + if( (*it).session() > 1 ) + sessions = (*it).session(); + } + + if( m_sessionToWrite > sessions ) + m_sessionToWrite = 1; + + // + // We can only hide the first track if both the first and the second track are + // audio tracks. + // We also can only hide the first track in the first session. + // + bool hideFirstTrack = m_hideFirstTrack; + if( m_toc.count() < 2 || + m_toc[0].type() != K3bDevice::Track::AUDIO || + m_toc[1].type() != K3bDevice::Track::AUDIO || + (sessions > 1 && m_sessionToWrite != 1 ) ) + hideFirstTrack = false; + + + // the dataStart will be the offset in case we do not write the first session + K3b::Msf dataStart; + + unsigned int trackIndex = 0; + if( hideFirstTrack ) { + const K3bDevice::Track& hiddenTrack = m_toc[0]; + const K3bDevice::Track& track = m_toc[1]; + + t << "// Track number 1 (hidden) and track number 2 (as track 1)" << endl; + t << "TRACK AUDIO" << endl; + + if( track.copyPermitted() ) + t << "COPY" << endl; + else + t << "NO COPY" << endl; + + if( track.preEmphasis() ) + t << "PRE_EMPHASIS" << endl; + else + t << "NO PRE_EMPHASIS" << endl; + + if( !m_cdText.isEmpty() ) + writeTrackCdText( m_cdText[0], t ); + + // the "hidden" file will be used as pregap for the "first" track + t << "AUDIOFILE "; + writeDataSource( 0, t ); + if( readFromStdin() ) + t << hiddenTrack.firstSector().toString(); + else + t << " 0"; + t << " " << hiddenTrack.length().toString() << endl; + t << "START" << endl; // use the whole hidden file as pregap + + // now comes the "real" first track + t << "AUDIOFILE "; + writeDataSource( 1, t ); + if( readFromStdin() ) + t << track.firstSector().toString() << " "; + else + t << "0 "; + // no index 0 for the last track. Or should we allow this??? + if( m_toc.count() == 2 ) + t << track.length().toString(); + else + t << track.realAudioLength().toString(); + t << endl << endl; + + trackIndex+=2; + } + else { + // + // Seek to the first track to write. + // In case we hid the first track above it was the first track anyway. + // + while( m_toc[trackIndex].session() < m_sessionToWrite && + m_toc[trackIndex].session() > 0 ) + ++trackIndex; + + dataStart = m_toc[trackIndex].firstSector(); + } + + kdDebug() << "(K3bTocFileWriter) using offset of: " << dataStart.toString() << endl; + + while( trackIndex < m_toc.count() ) { + if( m_toc[trackIndex].session() == 0 || m_toc[trackIndex].session() == m_sessionToWrite ) + writeTrack( trackIndex, dataStart, t ); + trackIndex++; + } + + return ( t.device()->status() == IO_Ok ); +} + + +void K3bTocFileWriter::writeHeader( QTextStream& t ) +{ + // little comment + t << "// TOC-file to use with cdrdao created by K3b " << k3bcore->version() + << ", " << QDateTime::currentDateTime().toString() << endl << endl; + + t << "// " << m_toc.count() << " tracks" << endl; + if( m_toc.back().session() > 0 ) { + t << "// " << m_toc.back().session() << " sessions" << endl + << "// this is session number " << m_sessionToWrite << endl; + } + t << endl; + + // check the cd type + if( m_toc.contentType() == K3bDevice::AUDIO ) { + t << "CD_DA"; + } + else { + bool hasMode2Tracks = false; + for( K3bDevice::Toc::iterator it = m_toc.begin(); it != m_toc.end(); ++it ) { + const K3bDevice::Track& track = *it; + if( track.type() == K3bDevice::Track::DATA && + (track.mode() == K3bDevice::Track::MODE2 || + track.mode() == K3bDevice::Track::XA_FORM1 || + track.mode() == K3bDevice::Track::XA_FORM2 ) ) { + hasMode2Tracks = true; + break; + } + } + + if( hasMode2Tracks ) + t << "CD_ROM_XA"; + else + t << "CD_ROM"; + } + + t << endl << endl; +} + + +void K3bTocFileWriter::writeTrack( unsigned int index, const K3b::Msf& offset, QTextStream& t ) +{ + const K3bDevice::Track& track = m_toc[index]; + + t << "// Track number " << (index+1) << endl; + + if( track.type() == K3bDevice::Track::AUDIO ) { + t << "TRACK AUDIO" << endl; + + if( track.copyPermitted() ) + t << "COPY" << endl; + else + t << "NO COPY" << endl; + + if( track.preEmphasis() ) + t << "PRE_EMPHASIS" << endl; + else + t << "NO PRE_EMPHASIS" << endl; + + if( !m_cdText.isEmpty() ) + writeTrackCdText( m_cdText[index], t ); + + // + // cdrdao sees the pregap as part of the current track and not as part of + // the previous like it really is. + // + + if( index == 0 ) { + if( (track.firstSector()-offset) > 0 ) { + // + // the first track is the only track K3b does not generate null-pregap data for + // since cdrecord does not allow this. So We just do it here the same way and tell + // cdrdao to create the first pregap for us + // + + t << "PREGAP " + << (track.firstSector()-offset).toString() << endl; + } + } + else { + const K3bDevice::Track& lastTrack = m_toc[index-1]; + + // + // the pregap data + // + if( lastTrack.index0() > 0 ) { + t << "AUDIOFILE "; + writeDataSource( index-1, t ); + if( readFromStdin() ) + t << (lastTrack.firstSector() + lastTrack.index0() - offset).toString(); + else + t << (lastTrack.index0() - offset).toString(); + t << " " + << (lastTrack.length() - lastTrack.index0()).toString() + << endl + << "START" << endl; + } + } + + // + // The track data + // + t << "AUDIOFILE "; + writeDataSource( index, t ); + if( readFromStdin() ) + t << (track.firstSector() - offset).toString() << " "; + else + t << "0 "; + // no index 0 for the last track. Or should we allow this??? + if( index == m_toc.count()-1 ) + t << track.length().toString(); + else + t << track.realAudioLength().toString(); + t << endl; + } + else { + if( track.mode() == K3bDevice::Track::XA_FORM1 ) + t << "TRACK MODE2_FORM1" << endl; + else if( track.mode() == K3bDevice::Track::XA_FORM2 ) + t << "TRACK MODE2_FORM2" << endl; + else + t << "TRACK MODE1" << endl; + + if( !m_cdText.isEmpty() && !m_toc.contentType() != K3bDevice::DATA ) { + // + // insert fake cdtext + // cdrdao does not work without it and it seems not to do any harm. + // + t << "CD_TEXT {" << endl + << " LANGUAGE 0 {" << endl + << " TITLE " << "\"\"" << endl + << " PERFORMER " << "\"\"" << endl + << " ISRC " << "\"\"" << endl + << " ARRANGER " << "\"\"" << endl + << " SONGWRITER " << "\"\"" << endl + << " COMPOSER " << "\"\"" << endl + << " MESSAGE " << "\"\"" << endl + << " }" << endl + << "}" << endl; + } + + if( readFromStdin() ) + t << "DATAFILE \"-\" " << track.length().toString() << endl; + else + t << "DATAFILE \"" << m_filenames[index] << "\"" << endl; + t << endl; + } + + t << endl; +} + + +void K3bTocFileWriter::writeGlobalCdText( QTextStream& t ) +{ + t << "CD_TEXT {" << endl; + t << " LANGUAGE_MAP { 0: EN }" << endl; + t << " LANGUAGE 0 {" << endl; + t << " TITLE " << "\"" << m_cdText.title() << "\"" << endl; + t << " PERFORMER " << "\"" << m_cdText.performer() << "\"" << endl; + t << " DISC_ID " << "\"" << m_cdText.discId() << "\"" << endl; + t << " UPC_EAN " << "\"" << m_cdText.upcEan() << "\"" << endl; + t << endl; + t << " ARRANGER " << "\"" << m_cdText.arranger() << "\"" << endl; + t << " SONGWRITER " << "\"" << m_cdText.songwriter() << "\"" << endl; + t << " COMPOSER " << "\"" << m_cdText.composer() << "\"" << endl; + t << " MESSAGE " << "\"" << m_cdText.message() << "\"" << endl; + t << " }" << endl; + t << "}" << endl; + t << endl; +} + + +void K3bTocFileWriter::writeTrackCdText( const K3bDevice::TrackCdText& track, QTextStream& t ) +{ + t << "CD_TEXT {" << endl; + t << " LANGUAGE 0 {" << endl; + t << " TITLE " << "\"" << track.title() << "\"" << endl; + t << " PERFORMER " << "\"" << track.performer() << "\"" << endl; + t << " ISRC " << "\"" << track.isrc() << "\"" << endl; + t << " ARRANGER " << "\"" << track.arranger() << "\"" << endl; + t << " SONGWRITER " << "\"" << track.songwriter() << "\"" << endl; + t << " COMPOSER " << "\"" << track.composer() << "\"" << endl; + t << " MESSAGE " << "\"" << track.message() << "\"" << endl; + t << " }" << endl; + t << "}" << endl; +} + + +void K3bTocFileWriter::writeDataSource( unsigned int trackIndex, QTextStream& t ) +{ + if( readFromStdin() ) + t << "\"-\" "; + else + t << "\"" << m_filenames[trackIndex] << "\" "; +} + + +bool K3bTocFileWriter::readFromStdin() const +{ + return ( m_toc.count() > m_filenames.count() ); +} diff --git a/libk3b/projects/k3btocfilewriter.h b/libk3b/projects/k3btocfilewriter.h new file mode 100644 index 0000000..1c1da47 --- /dev/null +++ b/libk3b/projects/k3btocfilewriter.h @@ -0,0 +1,62 @@ +/* + * + * $Id: k3btocfilewriter.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_TOC_FILE_WRITER_H_ +#define _K3B_TOC_FILE_WRITER_H_ + +#include +#include + +#include +#include + +namespace K3bDevice { + class TrackCdText; +} + +class K3bTocFileWriter +{ + public: + K3bTocFileWriter(); + + bool save( QTextStream& ); + bool save( const QString& filename ); + + void setData( const K3bDevice::Toc& toc ) { m_toc = toc; } + void setCdText( const K3bDevice::CdText& text ) { m_cdText = text; } + void setFilenames( const QStringList& names ) { m_filenames = names; } + void setHideFirstTrack( bool b ) { m_hideFirstTrack = b; } + + /** + * The default is 1. + */ + void setSession( int s ) { m_sessionToWrite = s; } + + private: + void writeHeader( QTextStream& t ); + void writeGlobalCdText( QTextStream& t ); + void writeTrackCdText( const K3bDevice::TrackCdText& track, QTextStream& t ); + void writeTrack( unsigned int index, const K3b::Msf& offset, QTextStream& t ); + void writeDataSource( unsigned int trackNumber, QTextStream& t ); + bool readFromStdin() const; + + K3bDevice::Toc m_toc; + K3bDevice::CdText m_cdText; + QStringList m_filenames; + bool m_hideFirstTrack; + int m_sessionToWrite; +}; + +#endif diff --git a/libk3b/projects/mixedcd/Makefile.am b/libk3b/projects/mixedcd/Makefile.am new file mode 100644 index 0000000..fb5f44c --- /dev/null +++ b/libk3b/projects/mixedcd/Makefile.am @@ -0,0 +1,23 @@ +# we need the ../datacd and ../audiocd for the uic generated header files +AM_CPPFLAGS= -I$(srcdir)/../../core \ + -I$(srcdir)/../../plugin \ + -I$(srcdir)/../../../libk3bdevice \ + -I$(srcdir)/../../../src \ + -I$(srcdir)/../../tools \ + -I$(srcdir)/.. \ + -I$(srcdir)/../datacd \ + -I$(srcdir)/../audiocd \ + -I$(srcdir)/../../plugin \ + -I../datacd \ + -I../audiocd \ + $(all_includes) + +METASOURCES = AUTO + +noinst_LTLIBRARIES = libmixed.la + +libmixed_la_SOURCES = k3bmixeddoc.cpp \ + k3bmixedjob.cpp + +include_HEADERS = k3bmixeddoc.h \ + k3bmixedjob.h diff --git a/libk3b/projects/mixedcd/k3bmixeddoc.cpp b/libk3b/projects/mixedcd/k3bmixeddoc.cpp new file mode 100644 index 0000000..a2c76b0 --- /dev/null +++ b/libk3b/projects/mixedcd/k3bmixeddoc.cpp @@ -0,0 +1,249 @@ +/* + * + * $Id: k3bmixeddoc.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bmixeddoc.h" +#include "k3bmixedjob.h" + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + + + +K3bMixedDoc::K3bMixedDoc( QObject* parent ) + : K3bDoc( parent ) +{ + m_dataDoc = new K3bDataDoc( this ); + m_audioDoc = new K3bAudioDoc( this ); + + connect( m_dataDoc, SIGNAL(changed()), + this, SIGNAL(changed()) ); + connect( m_audioDoc, SIGNAL(changed()), + this, SIGNAL(changed()) ); +} + + +K3bMixedDoc::~K3bMixedDoc() +{ +} + + +bool K3bMixedDoc::newDocument() +{ + m_dataDoc->newDocument(); + m_audioDoc->newDocument(); + + return K3bDoc::newDocument(); +} + + +QString K3bMixedDoc::name() const +{ + return m_dataDoc->name(); +} + + +void K3bMixedDoc::setURL( const KURL& url ) +{ + K3bDoc::setURL( url ); + m_audioDoc->setURL( url ); + m_dataDoc->setURL( url ); +} + + +void K3bMixedDoc::setModified( bool m ) +{ + m_audioDoc->setModified( m ); + m_dataDoc->setModified( m ); +} + + +bool K3bMixedDoc::isModified() const +{ + return ( m_audioDoc->isModified() || m_dataDoc->isModified() ); +} + + +KIO::filesize_t K3bMixedDoc::size() const +{ + return m_dataDoc->size() + m_audioDoc->size(); +} + +K3b::Msf K3bMixedDoc::length() const +{ + return m_dataDoc->length() + m_audioDoc->length(); +} + + +int K3bMixedDoc::numOfTracks() const +{ + return m_audioDoc->numOfTracks() + 1; +} + + +K3bBurnJob* K3bMixedDoc::newBurnJob( K3bJobHandler* hdl, QObject* parent ) +{ + return new K3bMixedJob( this, hdl, parent ); +} + + +void K3bMixedDoc::addUrls( const KURL::List& urls ) +{ + dataDoc()->addUrls( urls ); +} + + +bool K3bMixedDoc::loadDocumentData( QDomElement* rootElem ) +{ + QDomNodeList nodes = rootElem->childNodes(); + + if( nodes.length() < 4 ) + return false; + + if( nodes.item(0).nodeName() != "general" ) + return false; + if( !readGeneralDocumentData( nodes.item(0).toElement() ) ) + return false; + + if( nodes.item(1).nodeName() != "audio" ) + return false; + QDomElement audioElem = nodes.item(1).toElement(); + if( !m_audioDoc->loadDocumentData( &audioElem ) ) + return false; + + if( nodes.item(2).nodeName() != "data" ) + return false; + QDomElement dataElem = nodes.item(2).toElement(); + if( !m_dataDoc->loadDocumentData( &dataElem ) ) + return false; + + if( nodes.item(3).nodeName() != "mixed" ) + return false; + + QDomNodeList optionList = nodes.item(3).childNodes(); + for( uint i = 0; i < optionList.count(); i++ ) { + + QDomElement e = optionList.item(i).toElement(); + if( e.isNull() ) + return false; + + if( e.nodeName() == "remove_buffer_files" ) + setRemoveImages( e.toElement().text() == "yes" ); + else if( e.nodeName() == "image_path" ) + setTempDir( e.toElement().text() ); + else if( e.nodeName() == "mixed_type" ) { + QString mt = e.toElement().text(); + if( mt == "last_track" ) + setMixedType( DATA_LAST_TRACK ); + else if( mt == "second_session" ) + setMixedType( DATA_SECOND_SESSION ); + else + setMixedType( DATA_FIRST_TRACK ); + } + } + + return true; +} + + +bool K3bMixedDoc::saveDocumentData( QDomElement* docElem ) +{ + QDomDocument doc = docElem->ownerDocument(); + saveGeneralDocumentData( docElem ); + + QDomElement audioElem = doc.createElement( "audio" ); + m_audioDoc->saveDocumentData( &audioElem ); + docElem->appendChild( audioElem ); + + QDomElement dataElem = doc.createElement( "data" ); + m_dataDoc->saveDocumentData( &dataElem ); + docElem->appendChild( dataElem ); + + QDomElement mixedElem = doc.createElement( "mixed" ); + docElem->appendChild( mixedElem ); + + QDomElement bufferFilesElem = doc.createElement( "remove_buffer_files" ); + bufferFilesElem.appendChild( doc.createTextNode( removeImages() ? "yes" : "no" ) ); + mixedElem.appendChild( bufferFilesElem ); + + QDomElement imagePathElem = doc.createElement( "image_path" ); + imagePathElem.appendChild( doc.createTextNode( tempDir() ) ); + mixedElem.appendChild( imagePathElem ); + + QDomElement mixedTypeElem = doc.createElement( "mixed_type" ); + switch( mixedType() ) { + case DATA_FIRST_TRACK: + mixedTypeElem.appendChild( doc.createTextNode( "first_track" ) ); + break; + case DATA_LAST_TRACK: + mixedTypeElem.appendChild( doc.createTextNode( "last_track" ) ); + break; + case DATA_SECOND_SESSION: + mixedTypeElem.appendChild( doc.createTextNode( "second_session" ) ); + break; + } + mixedElem.appendChild( mixedTypeElem ); + + setModified( false ); + + return true; +} + + +K3bDevice::Toc K3bMixedDoc::toToc( int dataMode, const K3b::Msf& dataTrackLength ) const +{ + // !inaccurate datatrack size! + K3bDevice::Track dataTrack( 0, dataTrackLength > 0 ? dataTrackLength-1 : m_dataDoc->length()-1, + K3bDevice::Track::DATA, dataMode ); + K3bDevice::Toc toc = audioDoc()->toToc(); + if( mixedType() == DATA_FIRST_TRACK ) { + // fix the audio tracks' sectors + for( K3bDevice::Toc::iterator it = toc.begin(); it != toc.end(); ++it ) { + (*it).setLastSector( (*it).lastSector() + dataTrack.length() ); + (*it).setFirstSector( (*it).firstSector() + dataTrack.length() ); + } + toc.insert( toc.begin(), dataTrack ); + } + else { + // fix the datatrack's sectors + dataTrack.setLastSector( dataTrack.lastSector() + toc.back().lastSector()+1 ); + dataTrack.setFirstSector( toc.back().lastSector()+1 ); + toc.append( dataTrack ); + + if( mixedType() == DATA_SECOND_SESSION ) { + // fix the session numbers + for( K3bDevice::Toc::iterator it = toc.begin(); it != toc.end(); ++it ) { + if( (*it).type() == K3bDevice::Track::DATA ) + (*it).setSession( 2 ); + else + (*it).setSession( 1 ); + } + } + } + + return toc; +} + +#include "k3bmixeddoc.moc" + diff --git a/libk3b/projects/mixedcd/k3bmixeddoc.h b/libk3b/projects/mixedcd/k3bmixeddoc.h new file mode 100644 index 0000000..7d71b39 --- /dev/null +++ b/libk3b/projects/mixedcd/k3bmixeddoc.h @@ -0,0 +1,95 @@ +/* + * + * $Id: k3bmixeddoc.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef K3B_MIXED_DOC_H +#define K3B_MIXED_DOC_H + +#include +#include +#include + +#include +#include "k3b_export.h" +class QDomDocument; +class QDomElement; +class K3bBurnJob; +//class K3bView; +class QWidget; +class KConfig; + + +class LIBK3B_EXPORT K3bMixedDoc : public K3bDoc +{ + Q_OBJECT + + public: + K3bMixedDoc( QObject* parent = 0 ); + ~K3bMixedDoc(); + + QString name() const; + + bool newDocument(); + + void setModified( bool m = true ); + bool isModified() const; + + KIO::filesize_t size() const; + K3b::Msf length() const; + + int numOfTracks() const; + + K3bBurnJob* newBurnJob( K3bJobHandler*, QObject* parent = 0 ); + + K3bAudioDoc* audioDoc() const { return m_audioDoc; } + K3bDataDoc* dataDoc() const { return m_dataDoc; } + + enum MixedType { DATA_FIRST_TRACK, + DATA_LAST_TRACK, + DATA_SECOND_SESSION }; + + int mixedType() const { return m_mixedType; } + int type() const { return MIXED; } + + void setURL( const KURL& url ); + + /** + * Represent the structure of the doc as CD Table of Contents. + * Be aware that the length of the data track is just an estimate + * and needs to be corrected if not specified here. + * + * @param dataMode mode of the data track (MODE1 or XA_FORM1) + * @param dataTrackLength exact length of the dataTrack + */ + + K3bDevice::Toc toToc( int dataMode, const K3b::Msf& dataTrackLength = 0 ) const; + + public slots: + void setMixedType( MixedType t ) { m_mixedType = t; } + void addUrls( const KURL::List& urls ); + + protected: + bool loadDocumentData( QDomElement* ); + bool saveDocumentData( QDomElement* ); + QString typeString() const { return "mixed"; } + + private: + K3bDataDoc* m_dataDoc; + K3bAudioDoc* m_audioDoc; + + int m_mixedType; +}; + + +#endif diff --git a/libk3b/projects/mixedcd/k3bmixedjob.cpp b/libk3b/projects/mixedcd/k3bmixedjob.cpp new file mode 100644 index 0000000..a4be92c --- /dev/null +++ b/libk3b/projects/mixedcd/k3bmixedjob.cpp @@ -0,0 +1,1339 @@ +/* + * + * $Id: k3bmixedjob.cpp 690212 2007-07-20 11:02:13Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + + + +#include "k3bmixedjob.h" +#include "k3bmixeddoc.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +static QString createNonExistingFilesString( const QValueList& items, unsigned int max ) +{ + QString s; + unsigned int cnt = 0; + for( QValueList::const_iterator it = items.begin(); + it != items.end(); ++it ) { + + s += KStringHandler::csqueeze( (*it)->filename(), 60 ); + + ++cnt; + if( cnt >= max || it == items.end() ) + break; + + s += "
"; + } + + if( items.count() > max ) + s += "..."; + + return s; +} + + + +class K3bMixedJob::Private +{ +public: + Private() + : maxSpeedJob(0) { + } + + + int copies; + int copiesDone; + + K3bAudioMaxSpeedJob* maxSpeedJob; + bool maxSpeed; +}; + + +K3bMixedJob::K3bMixedJob( K3bMixedDoc* doc, K3bJobHandler* hdl, QObject* parent ) + : K3bBurnJob( hdl, parent ), + m_doc( doc ), + m_normalizeJob(0) +{ + d = new Private; + + m_isoImager = new K3bIsoImager( doc->dataDoc(), this, this ); + connect( m_isoImager, SIGNAL(infoMessage(const QString&, int)), this, SIGNAL(infoMessage(const QString&, int)) ); + connect( m_isoImager, SIGNAL(percent(int)), this, SLOT(slotIsoImagerPercent(int)) ); + connect( m_isoImager, SIGNAL(finished(bool)), this, SLOT(slotIsoImagerFinished(bool)) ); + connect( m_isoImager, SIGNAL(debuggingOutput(const QString&, const QString&)), + this, SIGNAL(debuggingOutput(const QString&, const QString&)) ); + + m_audioImager = new K3bAudioImager( doc->audioDoc(), this, this ); + connect( m_audioImager, SIGNAL(infoMessage(const QString&, int)), + this, SIGNAL(infoMessage(const QString&, int)) ); + connect( m_audioImager, SIGNAL(percent(int)), this, SLOT(slotAudioDecoderPercent(int)) ); + connect( m_audioImager, SIGNAL(subPercent(int)), this, SLOT(slotAudioDecoderSubPercent(int)) ); + connect( m_audioImager, SIGNAL(finished(bool)), this, SLOT(slotAudioDecoderFinished(bool)) ); + connect( m_audioImager, SIGNAL(nextTrack(int, int)), this, SLOT(slotAudioDecoderNextTrack(int, int)) ); + + m_msInfoFetcher = new K3bMsInfoFetcher( this, this ); + connect( m_msInfoFetcher, SIGNAL(finished(bool)), this, SLOT(slotMsInfoFetched(bool)) ); + connect( m_msInfoFetcher, SIGNAL(infoMessage(const QString&, int)), this, SIGNAL(infoMessage(const QString&, int)) ); + + m_writer = 0; + m_tocFile = 0; + m_tempData = new K3bAudioJobTempData( m_doc->audioDoc(), this ); +} + + +K3bMixedJob::~K3bMixedJob() +{ + delete m_tocFile; + delete d; +} + + +K3bDevice::Device* K3bMixedJob::writer() const +{ + if( m_doc->onlyCreateImages() ) + return 0; + else + return m_doc->burner(); +} + + +K3bDoc* K3bMixedJob::doc() const +{ + return m_doc; +} + + +void K3bMixedJob::start() +{ + jobStarted(); + + m_canceled = false; + m_errorOccuredAndAlreadyReported = false; + d->copiesDone = 0; + d->copies = m_doc->copies(); + m_currentAction = PREPARING_DATA; + d->maxSpeed = false; + + if( m_doc->dummy() ) + d->copies = 1; + + prepareProgressInformation(); + + // + // Check if all files exist + // + QValueList nonExistingFiles; + K3bAudioTrack* track = m_doc->audioDoc()->firstTrack(); + while( track ) { + K3bAudioDataSource* source = track->firstSource(); + while( source ) { + if( K3bAudioFile* file = dynamic_cast( source ) ) { + if( !QFile::exists( file->filename() ) ) + nonExistingFiles.append( file ); + } + source = source->next(); + } + track = track->next(); + } + if( !nonExistingFiles.isEmpty() ) { + if( questionYesNo( "

" + i18n("The following files could not be found. Do you want to remove them from the " + "project and continue without adding them to the image?") + + "

" + createNonExistingFilesString( nonExistingFiles, 10 ), + i18n("Warning"), + i18n("Remove missing files and continue"), + i18n("Cancel and go back") ) ) { + for( QValueList::const_iterator it = nonExistingFiles.begin(); + it != nonExistingFiles.end(); ++it ) { + delete *it; + } + } + else { + m_canceled = true; + emit canceled(); + jobFinished(false); + return; + } + } + + // + // Make sure the project is not empty + // + if( m_doc->audioDoc()->numOfTracks() == 0 ) { + emit infoMessage( i18n("Please add files to your project first."), ERROR ); + jobFinished(false); + return; + } + + + // set some flags that are needed + m_doc->audioDoc()->setOnTheFly( m_doc->onTheFly() ); // for the toc writer + m_doc->audioDoc()->setHideFirstTrack( false ); // unsupported + m_doc->dataDoc()->setBurner( m_doc->burner() ); // so the isoImager can read ms data + + emit newTask( i18n("Preparing data") ); + + determineWritingMode(); + + // + // First we make sure the data portion is valid + // + + // we do not have msinfo yet + m_currentAction = INITIALIZING_IMAGER; + m_isoImager->setMultiSessionInfo( QString::null ); + m_isoImager->init(); +} + + +void K3bMixedJob::startFirstCopy() +{ + // + // if not onthefly create the iso image and then the wavs + // and write then + // if onthefly calculate the iso size + // + if( m_doc->onTheFly() ) { + if( m_doc->speed() == 0 ) { + emit newSubTask( i18n("Determining maximum writing speed") ); + + // + // try to determine the max possible speed + // no need to check the data track's max speed. Most current systems are able + // to handle the maxium possible + // + if( !d->maxSpeedJob ) { + // the maxspeed job gets the device from the doc: + m_doc->audioDoc()->setBurner( m_doc->burner() ); + d->maxSpeedJob = new K3bAudioMaxSpeedJob( m_doc->audioDoc(), this, this ); + connect( d->maxSpeedJob, SIGNAL(percent(int)), + this, SIGNAL(subPercent(int)) ); + connect( d->maxSpeedJob, SIGNAL(finished(bool)), + this, SLOT(slotMaxSpeedJobFinished(bool)) ); + } + d->maxSpeedJob->start(); + } + else if( m_doc->mixedType() != K3bMixedDoc::DATA_SECOND_SESSION ) { + m_currentAction = PREPARING_DATA; + m_isoImager->calculateSize(); + } + else { + // we cannot calculate the size since we don't have the msinfo yet + // so first write the audio session + writeNextCopy(); + } + } + else { + emit burning(false); + + emit infoMessage( i18n("Creating audio image files in %1").arg(m_doc->tempDir()), INFO ); + + m_tempFilePrefix = K3b::findUniqueFilePrefix( ( !m_doc->audioDoc()->title().isEmpty() + ? m_doc->audioDoc()->title() + : m_doc->dataDoc()->isoOptions().volumeID() ), + m_doc->tempDir() ); + + m_tempData->prepareTempFileNames( m_doc->tempDir() ); + QStringList filenames; + for( K3bAudioTrack* track = m_doc->audioDoc()->firstTrack(); track; track = track->next() ) + filenames += m_tempData->bufferFileName( track ); + m_audioImager->setImageFilenames( filenames ); + + if( m_doc->mixedType() != K3bMixedDoc::DATA_SECOND_SESSION ) { + createIsoImage(); + } + else { + emit newTask( i18n("Creating audio image files") ); + m_currentAction = CREATING_AUDIO_IMAGE; + m_audioImager->start(); + } + } +} + + +void K3bMixedJob::slotMaxSpeedJobFinished( bool success ) +{ + d->maxSpeed = success; + if( !success ) + emit infoMessage( i18n("Unable to determine maximum speed for some reason. Ignoring."), WARNING ); + + if( m_doc->mixedType() != K3bMixedDoc::DATA_SECOND_SESSION ) { + m_currentAction = PREPARING_DATA; + m_isoImager->calculateSize(); + } + else { + // we cannot calculate the size since we don't have the msinfo yet + // so first write the audio session + writeNextCopy(); + } +} + + +void K3bMixedJob::writeNextCopy() +{ + if( m_doc->mixedType() == K3bMixedDoc::DATA_SECOND_SESSION ) { + m_currentAction = WRITING_AUDIO_IMAGE; + if( !prepareWriter() || !startWriting() ) { + cleanupAfterError(); + jobFinished(false); + } + else if( m_doc->onTheFly() ) + m_audioImager->start(); + } + else { + // the prepareWriter method needs the action to be set + if( m_doc->mixedType() == K3bMixedDoc::DATA_LAST_TRACK ) + m_currentAction = WRITING_AUDIO_IMAGE; + else + m_currentAction = WRITING_ISO_IMAGE; + + if( !prepareWriter() || !startWriting() ) { + cleanupAfterError(); + jobFinished(false); + } + else if( m_doc->onTheFly() ) { + if( m_doc->mixedType() == K3bMixedDoc::DATA_LAST_TRACK ) + m_audioImager->start(); + else + m_isoImager->start(); + } + } +} + + +void K3bMixedJob::cancel() +{ + m_canceled = true; + + if( d->maxSpeedJob ) + d->maxSpeedJob->cancel(); + + if( m_writer ) + m_writer->cancel(); + m_isoImager->cancel(); + m_audioImager->cancel(); + m_msInfoFetcher->cancel(); + emit infoMessage( i18n("Writing canceled."), K3bJob::ERROR ); + removeBufferFiles(); + emit canceled(); + jobFinished(false); +} + + +void K3bMixedJob::slotMsInfoFetched( bool success ) +{ + if( m_canceled || m_errorOccuredAndAlreadyReported ) + return; + + if( success ) { + if( m_usedDataWritingApp == K3b::CDRECORD ) + m_isoImager->setMultiSessionInfo( m_msInfoFetcher->msInfo() ); + else // cdrdao seems to write a 150 blocks pregap that is not used by cdrecord + m_isoImager->setMultiSessionInfo( QString("%1,%2") + .arg(m_msInfoFetcher->lastSessionStart()) + .arg(m_msInfoFetcher->nextSessionStart()+150) ); + + if( m_doc->onTheFly() ) { + m_currentAction = PREPARING_DATA; + m_isoImager->calculateSize(); + } + else { + createIsoImage(); + } + } + else { + // the MsInfoFetcher already emitted failure info + cleanupAfterError(); + jobFinished(false); + } +} + + +void K3bMixedJob::slotIsoImagerFinished( bool success ) +{ + if( m_canceled || m_errorOccuredAndAlreadyReported ) + return; + + // + // Initializing imager before the first copy + // + if( m_currentAction == INITIALIZING_IMAGER ) { + if( success ) { + m_currentAction = PREPARING_DATA; + + // check the size + m_projectSize = m_isoImager->size() + m_doc->audioDoc()->length(); + if( m_doc->mixedType() == K3bMixedDoc::DATA_SECOND_SESSION ) + m_projectSize += 11400; // the session gap + + startFirstCopy(); + } + else { + cleanupAfterError(); + jobFinished( false ); + } + } + + // + // Recalculated iso image size + // + else if( m_currentAction == PREPARING_DATA ) { + if( success ) { + // 1. data in first track: + // start isoimager and writer + // when isoimager finishes start audiodecoder + + // 2. data in last track + // start audiodecoder and writer + // when audiodecoder finishes start isoimager + + // 3. data in second session + // start audiodecoder and writer + // start isoimager and writer + + if( m_doc->mixedType() == K3bMixedDoc::DATA_SECOND_SESSION ) { + m_currentAction = WRITING_ISO_IMAGE; + if( !prepareWriter() || !startWriting() ) { + cleanupAfterError(); + jobFinished(false); + } + else + m_isoImager->start(); + } + else + writeNextCopy(); + } + else { + cleanupAfterError(); + jobFinished( false ); + } + } + + // + // Image creation finished + // + else { + if( !success ) { + emit infoMessage( i18n("Error while creating ISO image."), ERROR ); + cleanupAfterError(); + + jobFinished( false ); + return; + } + + if( m_doc->onTheFly() ) { + if( m_doc->mixedType() == K3bMixedDoc::DATA_FIRST_TRACK ) { + m_currentAction = WRITING_AUDIO_IMAGE; + m_audioImager->start(); + } + } + else { + emit infoMessage( i18n("ISO image successfully created."), SUCCESS ); + + if( m_doc->mixedType() == K3bMixedDoc::DATA_SECOND_SESSION ) { + m_currentAction = WRITING_ISO_IMAGE; + + if( !prepareWriter() || !startWriting() ) { + cleanupAfterError(); + jobFinished(false); + } + } + else { + emit newTask( i18n("Creating audio image files") ); + m_currentAction = CREATING_AUDIO_IMAGE; + m_audioImager->start(); + } + } + } +} + + +void K3bMixedJob::slotWriterFinished( bool success ) +{ + if( m_canceled || m_errorOccuredAndAlreadyReported ) + return; + + if( !success ) { + cleanupAfterError(); + jobFinished(false); + return; + } + + emit burning(false); + + if( m_doc->mixedType() == K3bMixedDoc::DATA_SECOND_SESSION && m_currentAction == WRITING_AUDIO_IMAGE ) { + // reload the media (as a subtask so the user does not see the "Flushing cache" or "Fixating" messages while + // doing so + emit newSubTask( i18n("Reloading the medium") ); + connect( K3bDevice::reload( m_doc->burner() ), SIGNAL(finished(bool)), + this, SLOT(slotMediaReloadedForSecondSession(bool)) ); + } + else { + d->copiesDone++; + if( d->copiesDone < d->copies ) { + K3bDevice::eject( m_doc->burner() ); + writeNextCopy(); + } + else { + if( !m_doc->onTheFly() && m_doc->removeImages() ) + removeBufferFiles(); + + if( k3bcore->globalSettings()->ejectMedia() ) + K3bDevice::eject( m_doc->burner() ); + + jobFinished(true); + } + } +} + + +void K3bMixedJob::slotMediaReloadedForSecondSession( bool success ) +{ + if( !success ) + blockingInformation( i18n("Please reload the medium and press 'ok'"), + i18n("Unable to close the tray") ); + + // start the next session + m_currentAction = WRITING_ISO_IMAGE; + if( d->copiesDone > 0 ) { + // we only create the image once. This should not be a problem??? + if( !prepareWriter() || !startWriting() ) { + cleanupAfterError(); + jobFinished(false); + } + else if( m_doc->onTheFly() ) { + m_isoImager->start(); + } + } + else if( m_doc->dummy() ) { + // do not try to get ms info in simulation mode since the cd is empty! + if( m_doc->onTheFly() ) { + m_currentAction = PREPARING_DATA; + m_isoImager->calculateSize(); + } + else + createIsoImage(); + } + else { + m_currentAction = FETCHING_MSINFO; + m_msInfoFetcher->setDevice( m_doc->burner() ); + m_msInfoFetcher->start(); + } +} + + +void K3bMixedJob::slotAudioDecoderFinished( bool success ) +{ + if( m_canceled || m_errorOccuredAndAlreadyReported ) + return; + + if( !success ) { + emit infoMessage( i18n("Error while decoding audio tracks."), ERROR ); + cleanupAfterError(); + jobFinished(false); + return; + } + + if( m_doc->onTheFly() ) { + if( m_doc->mixedType() == K3bMixedDoc::DATA_LAST_TRACK ) { + m_currentAction = WRITING_ISO_IMAGE; + m_isoImager->start(); + } + } + else { + emit infoMessage( i18n("Audio images successfully created."), SUCCESS ); + + if( m_doc->audioDoc()->normalize() ) { + normalizeFiles(); + } + else { + if( m_doc->mixedType() == K3bMixedDoc::DATA_FIRST_TRACK ) + m_currentAction = WRITING_ISO_IMAGE; + else + m_currentAction = WRITING_AUDIO_IMAGE; + + if( !prepareWriter() || !startWriting() ) { + cleanupAfterError(); + jobFinished(false); + } + } + } +} + + +void K3bMixedJob::slotAudioDecoderNextTrack( int t, int tt ) +{ + if( m_doc->onlyCreateImages() || !m_doc->onTheFly() ) { + K3bAudioTrack* track = m_doc->audioDoc()->getTrack(t); + emit newSubTask( i18n("Decoding audio track %1 of %2%3") + .arg(t) + .arg(tt) + .arg( track->title().isEmpty() || track->artist().isEmpty() + ? QString::null + : " (" + track->artist() + " - " + track->title() + ")" ) ); + } +} + + +bool K3bMixedJob::prepareWriter() +{ + if( m_writer ) delete m_writer; + + if( ( m_currentAction == WRITING_ISO_IMAGE && m_usedDataWritingApp == K3b::CDRECORD ) || + ( m_currentAction == WRITING_AUDIO_IMAGE && m_usedAudioWritingApp == K3b::CDRECORD ) ) { + + if( !writeInfFiles() ) { + kdDebug() << "(K3bMixedJob) could not write inf-files." << endl; + emit infoMessage( i18n("IO Error"), ERROR ); + + return false; + } + + K3bCdrecordWriter* writer = new K3bCdrecordWriter( m_doc->burner(), this, this ); + + // only write the audio tracks in DAO mode + if( m_currentAction == WRITING_ISO_IMAGE ) + writer->setWritingMode( m_usedDataWritingMode ); + else + writer->setWritingMode( m_usedAudioWritingMode ); + + writer->setSimulate( m_doc->dummy() ); + writer->setBurnSpeed( m_doc->speed() ); + + if( m_doc->mixedType() == K3bMixedDoc::DATA_SECOND_SESSION ) { + if( m_currentAction == WRITING_ISO_IMAGE ) { + if( m_doc->onTheFly() ) + writer->addArgument("-waiti"); + + addDataTrack( writer ); + } + else { + writer->addArgument("-multi"); + addAudioTracks( writer ); + } + } + else { + if( m_doc->mixedType() == K3bMixedDoc::DATA_FIRST_TRACK ) + addDataTrack( writer ); + addAudioTracks( writer ); + if( m_doc->mixedType() == K3bMixedDoc::DATA_LAST_TRACK ) + addDataTrack( writer ); + } + + m_writer = writer; + } + else { + if( !writeTocFile() ) { + kdDebug() << "(K3bDataJob) could not write tocfile." << endl; + emit infoMessage( i18n("IO Error"), ERROR ); + + return false; + } + + // create the writer + // create cdrdao job + K3bCdrdaoWriter* writer = new K3bCdrdaoWriter( m_doc->burner(), this, this ); + writer->setSimulate( m_doc->dummy() ); + writer->setBurnSpeed( m_doc->speed() ); + + // multisession only for the first session + writer->setMulti( m_doc->mixedType() == K3bMixedDoc::DATA_SECOND_SESSION + && m_currentAction == WRITING_AUDIO_IMAGE ); + + writer->setTocFile( m_tocFile->name() ); + + m_writer = writer; + } + + connect( m_writer, SIGNAL(infoMessage(const QString&, int)), this, SIGNAL(infoMessage(const QString&, int)) ); + connect( m_writer, SIGNAL(percent(int)), this, SLOT(slotWriterJobPercent(int)) ); + connect( m_writer, SIGNAL(processedSize(int, int)), this, SIGNAL(processedSize(int, int)) ); + connect( m_writer, SIGNAL(subPercent(int)), this, SIGNAL(subPercent(int)) ); + connect( m_writer, SIGNAL(processedSubSize(int, int)), this, SIGNAL(processedSubSize(int, int)) ); + connect( m_writer, SIGNAL(nextTrack(int, int)), this, SLOT(slotWriterNextTrack(int, int)) ); + connect( m_writer, SIGNAL(buffer(int)), this, SIGNAL(bufferStatus(int)) ); + connect( m_writer, SIGNAL(deviceBuffer(int)), this, SIGNAL(deviceBuffer(int)) ); + connect( m_writer, SIGNAL(writeSpeed(int, int)), this, SIGNAL(writeSpeed(int, int)) ); + connect( m_writer, SIGNAL(finished(bool)), this, SLOT(slotWriterFinished(bool)) ); + // connect( m_writer, SIGNAL(newTask(const QString&)), this, SIGNAL(newTask(const QString&)) ); + connect( m_writer, SIGNAL(newSubTask(const QString&)), this, SIGNAL(newSubTask(const QString&)) ); + connect( m_writer, SIGNAL(debuggingOutput(const QString&, const QString&)), + this, SIGNAL(debuggingOutput(const QString&, const QString&)) ); + + return true; +} + + +bool K3bMixedJob::writeInfFiles() +{ + K3bInfFileWriter infFileWriter; + K3bAudioTrack* track = m_doc->audioDoc()->firstTrack(); + while( track ) { + + infFileWriter.setTrack( track->toCdTrack() ); + infFileWriter.setTrackNumber( track->trackNumber() ); + if( !m_doc->onTheFly() ) + infFileWriter.setBigEndian( false ); + + if( !infFileWriter.save( m_tempData->infFileName(track) ) ) + return false; + + track = track->next(); + } + return true; +} + + +bool K3bMixedJob::writeTocFile() +{ + // FIXME: create the tocfile in the same directory like all the other files. + + if( m_tocFile ) delete m_tocFile; + m_tocFile = new KTempFile( QString::null, "toc" ); + m_tocFile->setAutoDelete(true); + + // write the toc-file + if( QTextStream* s = m_tocFile->textStream() ) { + + K3bTocFileWriter tocFileWriter; + + // + // TOC + // + tocFileWriter.setData( m_doc->toToc( m_usedDataMode == K3b::MODE2 + ? K3bDevice::Track::XA_FORM1 + : K3bDevice::Track::MODE1, + m_doc->onTheFly() + ? m_isoImager->size() + : m_doc->dataDoc()->length() ) ); + + // + // CD-Text + // + if( m_doc->audioDoc()->cdText() ) { + K3bDevice::CdText text = m_doc->audioDoc()->cdTextData(); + // if data in first track we need to add a dummy cdtext + if( m_doc->mixedType() == K3bMixedDoc::DATA_FIRST_TRACK ) + text.insert( text.begin(), K3bDevice::TrackCdText() ); + + tocFileWriter.setCdText( text ); + } + + // + // Session to write + // + tocFileWriter.setSession( m_doc->mixedType() == K3bMixedDoc::DATA_SECOND_SESSION && + m_currentAction == WRITING_ISO_IMAGE ? 2 : 1 ); + + // + // image filenames + // + if( !m_doc->onTheFly() ) { + QStringList files; + K3bAudioTrack* track = m_doc->audioDoc()->firstTrack(); + while( track ) { + files += m_tempData->bufferFileName( track ); + track = track->next(); + } + if( m_doc->mixedType() == K3bMixedDoc::DATA_FIRST_TRACK ) + files.prepend( m_isoImageFilePath ); + else + files.append( m_isoImageFilePath ); + + tocFileWriter.setFilenames( files ); + } + + bool success = tocFileWriter.save( *s ); + + m_tocFile->close(); + + // backup for debugging +// KIO::NetAccess::del("/tmp/trueg/tocfile_debug_backup.toc",0L); +// KIO::NetAccess::copy( m_tocFile->name(), "/tmp/trueg/tocfile_debug_backup.toc",0L ); + + return success; + } + else + return false; +} + + +void K3bMixedJob::addAudioTracks( K3bCdrecordWriter* writer ) +{ + writer->addArgument( "-useinfo" ); + + // add raw cdtext data + if( m_doc->audioDoc()->cdText() ) { + writer->setRawCdText( m_doc->audioDoc()->cdTextData().rawPackData() ); + } + + writer->addArgument( "-audio" ); + + // we always pad because although K3b makes sure all tracks' length are multiples of 2352 + // it seems that normalize sometimes corrupts these lengths + // FIXME: see K3bAudioJob for the whole less4secs and zeroPregap handling + writer->addArgument( "-pad" ); + + // Allow tracks shorter than 4 seconds + writer->addArgument( "-shorttrack" ); + + // add all the audio tracks + K3bAudioTrack* track = m_doc->audioDoc()->firstTrack(); + while( track ) { + if( m_doc->onTheFly() ) { + // this is only supported by cdrecord versions >= 2.01a13 + writer->addArgument( QFile::encodeName( m_tempData->infFileName( track ) ) ); + } + else { + writer->addArgument( QFile::encodeName( m_tempData->bufferFileName( track ) ) ); + } + track = track->next(); + } +} + +void K3bMixedJob::addDataTrack( K3bCdrecordWriter* writer ) +{ + // add data track + if( m_usedDataMode == K3b::MODE2 ) { + if( k3bcore->externalBinManager()->binObject("cdrecord") && + k3bcore->externalBinManager()->binObject("cdrecord")->hasFeature( "xamix" ) ) + writer->addArgument( "-xa" ); + else + writer->addArgument( "-xa1" ); + } + else + writer->addArgument( "-data" ); + + if( m_doc->onTheFly() ) + writer->addArgument( QString("-tsize=%1s").arg(m_isoImager->size()) )->addArgument("-"); + else + writer->addArgument( m_isoImageFilePath ); +} + + +void K3bMixedJob::slotWriterNextTrack( int t, int ) +{ + K3bAudioTrack* track = 0; + + if( m_doc->mixedType() == K3bMixedDoc::DATA_FIRST_TRACK ) { + if( t > 1 ) + track = m_doc->audioDoc()->getTrack(t-1); + } + else if( m_doc->mixedType() == K3bMixedDoc::DATA_LAST_TRACK ) { + if( t < m_doc->audioDoc()->numOfTracks()+1 ) + track = m_doc->audioDoc()->getTrack(t); + } + else if( m_currentAction == WRITING_AUDIO_IMAGE ) + track = m_doc->audioDoc()->getTrack(t); + else + t = m_doc->numOfTracks(); + + if( track ) + emit newSubTask( i18n("Writing track %1 of %2%3") + .arg(t) + .arg(m_doc->numOfTracks()) + .arg( track->title().isEmpty() || track->artist().isEmpty() + ? QString::null + : " (" + track->artist() + " - " + track->title() + ")" ) ); + else + emit newSubTask( i18n("Writing track %1 of %2 (%3)").arg(t).arg(m_doc->numOfTracks()).arg(i18n("ISO9660 data")) ); +} + + +void K3bMixedJob::slotWriterJobPercent( int p ) +{ + double totalTasks = d->copies; + double tasksDone = d->copiesDone; + if( m_doc->audioDoc()->normalize() ) { + totalTasks+=1.0; + tasksDone+=1.0; + } + if( !m_doc->onTheFly() ) { + totalTasks+=1.0; + } + + if( m_doc->mixedType() == K3bMixedDoc::DATA_SECOND_SESSION ) { + if( m_currentAction == WRITING_AUDIO_IMAGE ) { + // the audio imager has finished in all cases + // the iso imager only if this is not the first copy + if( d->copiesDone > 0 ) + tasksDone += 1.0; + else if( !m_doc->onTheFly() ) + tasksDone += m_audioDocPartOfProcess; + + p = (int)((double)p*m_audioDocPartOfProcess); + } + else { + // all images have been created + if( !m_doc->onTheFly() ) + tasksDone += 1.0; + + p = (int)(100.0*m_audioDocPartOfProcess + (double)p*(1.0-m_audioDocPartOfProcess)); + } + } + else if( !m_doc->onTheFly() ) + tasksDone += 1.0; + + emit percent( (int)((100.0*tasksDone + (double)p) / totalTasks) ); +} + + +void K3bMixedJob::slotAudioDecoderPercent( int p ) +{ + // the only thing finished here might be the isoimager which is part of this task + if( !m_doc->onTheFly() ) { + double totalTasks = d->copies+1; + if( m_doc->audioDoc()->normalize() ) + totalTasks+=1.0; + + if( m_doc->mixedType() == K3bMixedDoc::DATA_SECOND_SESSION ) + p = (int)((double)p*m_audioDocPartOfProcess); + else + p = (int)(100.0*(1.0-m_audioDocPartOfProcess) + (double)p*m_audioDocPartOfProcess); + + emit percent( (int)((double)p / totalTasks) ); + } +} + + +void K3bMixedJob::slotAudioDecoderSubPercent( int p ) +{ + if( !m_doc->onTheFly() ) { + emit subPercent( p ); + } +} + + +void K3bMixedJob::slotIsoImagerPercent( int p ) +{ + if( !m_doc->onTheFly() ) { + emit subPercent( p ); + if( m_doc->mixedType() == K3bMixedDoc::DATA_SECOND_SESSION ) { + + double totalTasks = d->copies+1.0; + double tasksDone = d->copiesDone; + if( m_doc->audioDoc()->normalize() ) { + totalTasks+=1.0; + // the normalizer finished + tasksDone+=1.0; + } + + // the writing of the audio part finished + tasksDone += m_audioDocPartOfProcess; + + // the audio decoder finished (which is part of this task in terms of progress) + p = (int)(100.0*m_audioDocPartOfProcess + (double)p*(1.0-m_audioDocPartOfProcess)); + + emit percent( (int)((100.0*tasksDone + (double)p) / totalTasks) ); + } + else { + double totalTasks = d->copies+1.0; + if( m_doc->audioDoc()->normalize() ) + totalTasks+=1.0; + + emit percent( (int)((double)(p*(1.0-m_audioDocPartOfProcess)) / totalTasks) ); + } + } +} + + +bool K3bMixedJob::startWriting() +{ + if( m_doc->mixedType() == K3bMixedDoc::DATA_SECOND_SESSION ) { + if( m_currentAction == WRITING_ISO_IMAGE) { + if( m_doc->dummy() ) + emit newTask( i18n("Simulating second session") ); + else if( d->copies > 1 ) + emit newTask( i18n("Writing second session of copy %1").arg(d->copiesDone+1) ); + else + emit newTask( i18n("Writing second session") ); + } + else { + if( m_doc->dummy() ) + emit newTask( i18n("Simulating first session") ); + else if( d->copies > 1 ) + emit newTask( i18n("Writing first session of copy %1").arg(d->copiesDone+1) ); + else + emit newTask( i18n("Writing first session") ); + } + } + else if( m_doc->dummy() ) + emit newTask( i18n("Simulating") ); + else + emit newTask( i18n("Writing Copy %1").arg(d->copiesDone+1) ); + + + // if we append the second session the cd is already in the drive + if( !(m_doc->mixedType() == K3bMixedDoc::DATA_SECOND_SESSION + && m_currentAction == WRITING_ISO_IMAGE) ) { + + emit newSubTask( i18n("Waiting for media") ); + if( waitForMedia( m_doc->burner() ) < 0 ) { + cancel(); + return false; + } + + // just to be sure we did not get canceled during the async discWaiting + if( m_canceled ) + return false; + + // check if the project will fit on the CD + if( m_doc->mixedType() == K3bMixedDoc::DATA_SECOND_SESSION ) { + // the media is in and has been checked so this should be fast (hopefully) + K3b::Msf mediaSize = m_doc->burner()->diskInfo().capacity(); + if( mediaSize < m_projectSize ) { + if( k3bcore->globalSettings()->overburn() ) { + emit infoMessage( i18n("Trying to write more than the official disk capacity"), K3bJob::WARNING ); + } + else { + emit infoMessage( i18n("Data does not fit on disk."), ERROR ); + return false; + } + } + } + } + + // in case we determined the max possible writing speed we have to reset the speed on the writer job + // here since an inserted media is necessary + // the Max speed job will compare the max speed value with the supported values of the writer + if( d->maxSpeed ) + m_writer->setBurnSpeed( d->maxSpeedJob->maxSpeed() ); + + emit burning(true); + m_writer->start(); + + if( m_doc->onTheFly() ) { + // now the writer is running and we can get it's stdin + // we only use this method when writing on-the-fly since + // we cannot easily change the audioDecode fd while it's working + // which we would need to do since we write into several + // image files. + m_audioImager->writeToFd( m_writer->fd() ); + m_isoImager->writeToFd( m_writer->fd() ); + } + + return true; +} + + +void K3bMixedJob::createIsoImage() +{ + m_currentAction = CREATING_ISO_IMAGE; + + // prepare iso image file + m_isoImageFilePath = m_tempFilePrefix + "_datatrack.iso"; + + if( !m_doc->onTheFly() ) + emit newTask( i18n("Creating ISO image file") ); + emit newSubTask( i18n("Creating ISO image in %1").arg(m_isoImageFilePath) ); + emit infoMessage( i18n("Creating ISO image in %1").arg(m_isoImageFilePath), INFO ); + + m_isoImager->writeToImageFile( m_isoImageFilePath ); + m_isoImager->start(); +} + + +void K3bMixedJob::cleanupAfterError() +{ + m_errorOccuredAndAlreadyReported = true; + // m_audioImager->cancel(); + m_isoImager->cancel(); + if( m_writer ) + m_writer->cancel(); + + if( m_tocFile ) delete m_tocFile; + m_tocFile = 0; + + // remove the temp files + removeBufferFiles(); +} + + +void K3bMixedJob::removeBufferFiles() +{ + if ( !m_doc->onTheFly() ) { + emit infoMessage( i18n("Removing buffer files."), INFO ); + } + + if( QFile::exists( m_isoImageFilePath ) ) + if( !QFile::remove( m_isoImageFilePath ) ) + emit infoMessage( i18n("Could not delete file %1.").arg(m_isoImageFilePath), ERROR ); + + // removes buffer images and temp toc or inf files + m_tempData->cleanup(); +} + + +void K3bMixedJob::determineWritingMode() +{ + // we don't need this when only creating image and it is possible + // that the burn device is null + if( m_doc->onlyCreateImages() ) + return; + + // at first we determine the data mode + // -------------------------------------------------------------- + if( m_doc->dataDoc()->dataMode() == K3b::DATA_MODE_AUTO ) { + if( m_doc->mixedType() == K3bMixedDoc::DATA_SECOND_SESSION ) + m_usedDataMode = K3b::MODE2; + else + m_usedDataMode = K3b::MODE1; + } + else + m_usedDataMode = m_doc->dataDoc()->dataMode(); + + + // we try to use cdrecord if possible + bool cdrecordOnTheFly = false; + bool cdrecordCdText = false; + bool cdrecordUsable = false; + + if( k3bcore->externalBinManager()->binObject("cdrecord") ) { + cdrecordOnTheFly = + k3bcore->externalBinManager()->binObject("cdrecord")->hasFeature( "audio-stdin" ); + cdrecordCdText = + k3bcore->externalBinManager()->binObject("cdrecord")->hasFeature( "cdtext" ); + cdrecordUsable = + !( !cdrecordOnTheFly && m_doc->onTheFly() ) && + !( m_doc->audioDoc()->cdText() && !cdrecordCdText ); + } + + // Writing Application + // -------------------------------------------------------------- + // cdrecord seems to have problems writing xa 1 disks in dao mode? At least on my system! + if( writingApp() == K3b::DEFAULT ) { + if( m_doc->mixedType() == K3bMixedDoc::DATA_SECOND_SESSION ) { + if( m_doc->writingMode() == K3b::DAO || + ( m_doc->writingMode() == K3b::WRITING_MODE_AUTO && !cdrecordUsable ) ) { + m_usedAudioWritingApp = K3b::CDRDAO; + m_usedDataWritingApp = K3b::CDRDAO; + } + else { + m_usedAudioWritingApp = K3b::CDRECORD; + m_usedDataWritingApp = K3b::CDRECORD; + } + } + else { + if( cdrecordUsable ) { + m_usedAudioWritingApp = K3b::CDRECORD; + m_usedDataWritingApp = K3b::CDRECORD; + } + else { + m_usedAudioWritingApp = K3b::CDRDAO; + m_usedDataWritingApp = K3b::CDRDAO; + } + } + } + else { + m_usedAudioWritingApp = writingApp(); + m_usedDataWritingApp = writingApp(); + } + + // TODO: use K3bExceptions::brokenDaoAudio + + // Writing Mode (TAO/DAO/RAW) + // -------------------------------------------------------------- + if( m_doc->writingMode() == K3b::WRITING_MODE_AUTO ) { + + if( m_doc->mixedType() == K3bMixedDoc::DATA_SECOND_SESSION ) { + if( m_usedDataWritingApp == K3b::CDRECORD ) + m_usedDataWritingMode = K3b::TAO; + else + m_usedDataWritingMode = K3b::DAO; + + // default to Session at once for the audio part + m_usedAudioWritingMode = K3b::DAO; + } + else if( writer()->dao() ) { + m_usedDataWritingMode = K3b::DAO; + m_usedAudioWritingMode = K3b::DAO; + } + else { + m_usedDataWritingMode = K3b::TAO; + m_usedAudioWritingMode = K3b::TAO; + } + } + else { + m_usedAudioWritingMode = m_doc->writingMode(); + m_usedDataWritingMode = m_doc->writingMode(); + } + + + if( m_usedDataWritingApp == K3b::CDRECORD ) { + if( !cdrecordOnTheFly && m_doc->onTheFly() ) { + m_doc->setOnTheFly( false ); + emit infoMessage( i18n("On-the-fly writing with cdrecord < 2.01a13 not supported."), ERROR ); + } + + if( m_doc->audioDoc()->cdText() ) { + if( !cdrecordCdText ) { + m_doc->audioDoc()->writeCdText( false ); + emit infoMessage( i18n("Cdrecord %1 does not support CD-Text writing.").arg(k3bcore->externalBinManager()->binObject("cdrecord")->version), ERROR ); + } + else if( m_usedAudioWritingMode == K3b::TAO ) { + emit infoMessage( i18n("It is not possible to write CD-Text in TAO mode. Try DAO or RAW."), WARNING ); + } + } + } +} + + +void K3bMixedJob::normalizeFiles() +{ + if( !m_normalizeJob ) { + m_normalizeJob = new K3bAudioNormalizeJob( this, this ); + + connect( m_normalizeJob, SIGNAL(infoMessage(const QString&, int)), + this, SIGNAL(infoMessage(const QString&, int)) ); + connect( m_normalizeJob, SIGNAL(percent(int)), this, SLOT(slotNormalizeProgress(int)) ); + connect( m_normalizeJob, SIGNAL(subPercent(int)), this, SLOT(slotNormalizeSubProgress(int)) ); + connect( m_normalizeJob, SIGNAL(finished(bool)), this, SLOT(slotNormalizeJobFinished(bool)) ); + connect( m_normalizeJob, SIGNAL(newTask(const QString&)), this, SIGNAL(newSubTask(const QString&)) ); + connect( m_normalizeJob, SIGNAL(debuggingOutput(const QString&, const QString&)), + this, SIGNAL(debuggingOutput(const QString&, const QString&)) ); + } + + // add all the files + QValueVector files; + K3bAudioTrack* track = m_doc->audioDoc()->firstTrack(); + while( track ) { + files.append( m_tempData->bufferFileName(track) ); + track = track->next(); + } + + m_normalizeJob->setFilesToNormalize( files ); + + emit newTask( i18n("Normalizing volume levels") ); + m_normalizeJob->start(); +} + +void K3bMixedJob::slotNormalizeJobFinished( bool success ) +{ + if( m_canceled || m_errorOccuredAndAlreadyReported ) + return; + + if( success ) { + if( m_doc->mixedType() == K3bMixedDoc::DATA_FIRST_TRACK ) + m_currentAction = WRITING_ISO_IMAGE; + else + m_currentAction = WRITING_AUDIO_IMAGE; + + if( !prepareWriter() || !startWriting() ) { + cleanupAfterError(); + jobFinished(false); + } + } + else { + cleanupAfterError(); + jobFinished(false); + } +} + +void K3bMixedJob::slotNormalizeProgress( int p ) +{ + double totalTasks = d->copies+2.0; + double tasksDone = 0; + + if( m_doc->mixedType() == K3bMixedDoc::DATA_SECOND_SESSION ) { + // the audio imager finished (m_audioDocPartOfProcess*1 task) + // plus the normalize progress + tasksDone = m_audioDocPartOfProcess; + } + else { + // the iso and audio imagers already finished (one task) + // plus the normalize progress + tasksDone = 1.0; + } + + emit percent( (int)((100.0*tasksDone + (double)p) / totalTasks) ); +} + + +void K3bMixedJob::slotNormalizeSubProgress( int p ) +{ + emit subPercent( p ); +} + + +void K3bMixedJob::prepareProgressInformation() +{ + // calculate percentage of audio and data + // this is also used in on-the-fly mode + double ds = (double)m_doc->dataDoc()->length().totalFrames(); + double as = (double)m_doc->audioDoc()->length().totalFrames(); + m_audioDocPartOfProcess = as/(ds+as); +} + + +QString K3bMixedJob::jobDescription() const +{ + if( m_doc->mixedType() == K3bMixedDoc::DATA_SECOND_SESSION ) + return i18n("Writing Enhanced Audio CD") + + ( m_doc->audioDoc()->title().isEmpty() + ? QString::null + : QString( " (%1)" ).arg(m_doc->audioDoc()->title()) ); + else + return i18n("Writing Mixed Mode CD") + + ( m_doc->audioDoc()->title().isEmpty() + ? QString::null + : QString( " (%1)" ).arg(m_doc->audioDoc()->title()) ); +} + + +QString K3bMixedJob::jobDetails() const +{ + return ( i18n("%1 tracks (%2 minutes audio data, %3 ISO9660 data)") + .arg(m_doc->numOfTracks()) + .arg(m_doc->audioDoc()->length().toString()) + .arg(KIO::convertSize(m_doc->dataDoc()->size())) + + ( m_doc->copies() > 1 && !m_doc->dummy() + ? i18n(" - %n copy", " - %n copies", m_doc->copies()) + : QString::null ) ); +} + +#include "k3bmixedjob.moc" diff --git a/libk3b/projects/mixedcd/k3bmixedjob.h b/libk3b/projects/mixedcd/k3bmixedjob.h new file mode 100644 index 0000000..50a1dc7 --- /dev/null +++ b/libk3b/projects/mixedcd/k3bmixedjob.h @@ -0,0 +1,144 @@ +/* + * + * $Id: k3bmixedjob.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BMIXEDJOB_H +#define K3BMIXEDJOB_H + +#include + + +class K3bMixedDoc; +class K3bIsoImager; +class K3bAudioImager; +class QFile; +class QDataStream; +class K3bAbstractWriter; +class K3bWaveFileWriter; +class KTempFile; +class K3bCdrecordWriter; +class K3bMsInfoFetcher; +class K3bAudioNormalizeJob; +class K3bAudioJobTempData; +class K3bDevice::Device; + +/** + *@author Sebastian Trueg + */ +class K3bMixedJob : public K3bBurnJob +{ + Q_OBJECT + + public: + K3bMixedJob( K3bMixedDoc*, K3bJobHandler*, QObject* parent = 0 ); + ~K3bMixedJob(); + + K3bDoc* doc() const; + K3bDevice::Device* writer() const; + + QString jobDescription() const; + QString jobDetails() const; + + public slots: + void cancel(); + void start(); + + protected slots: + // iso imager slots + void slotIsoImagerFinished( bool success ); + void slotIsoImagerPercent(int); + + // ms info fetcher slots + void slotMsInfoFetched(bool); + + // audio decoder slots + void slotAudioDecoderFinished( bool ); + void slotAudioDecoderNextTrack( int, int ); + void slotAudioDecoderPercent(int); + void slotAudioDecoderSubPercent( int ); + + // writer slots + void slotWriterFinished( bool success ); + void slotWriterNextTrack(int, int); + void slotWriterJobPercent(int); + + // normalizing slots + void slotNormalizeJobFinished( bool ); + void slotNormalizeProgress( int ); + void slotNormalizeSubProgress( int ); + + // misc slots + void slotMediaReloadedForSecondSession( bool ); + void slotMaxSpeedJobFinished( bool ); + + private: + bool prepareWriter(); + bool writeTocFile(); + bool writeInfFiles(); + bool startWriting(); + void startFirstCopy(); + void addAudioTracks( K3bCdrecordWriter* writer ); + void addDataTrack( K3bCdrecordWriter* writer ); + void cleanupAfterError(); + void removeBufferFiles(); + void createIsoImage(); + void determineWritingMode(); + void normalizeFiles(); + void prepareProgressInformation(); + void writeNextCopy(); + void determinePreliminaryDataImageSize(); + + K3bMixedDoc* m_doc; + K3bIsoImager* m_isoImager; + K3bAudioImager* m_audioImager; + K3bAudioJobTempData* m_tempData; + K3bWaveFileWriter* m_waveFileWriter; + K3bAbstractWriter* m_writer; + K3bMsInfoFetcher* m_msInfoFetcher; + K3bAudioNormalizeJob* m_normalizeJob; + + QString m_isoImageFilePath; + + KTempFile* m_tocFile; + + enum Action { INITIALIZING_IMAGER, + PREPARING_DATA, + CREATING_ISO_IMAGE, + CREATING_AUDIO_IMAGE, + WRITING_ISO_IMAGE, + WRITING_AUDIO_IMAGE, + FETCHING_MSINFO }; + + int m_currentAction; + double m_audioDocPartOfProcess; + + bool m_canceled; + bool m_errorOccuredAndAlreadyReported; + + int m_usedDataMode; + int m_usedDataWritingApp; + int m_usedAudioWritingApp; + int m_usedDataWritingMode; + int m_usedAudioWritingMode; + + QString m_tempFilePrefix; + + K3b::Msf m_projectSize; + + class Private; + Private* d; +}; + +#endif diff --git a/libk3b/projects/movixcd/Makefile.am b/libk3b/projects/movixcd/Makefile.am new file mode 100644 index 0000000..d1b4f5d --- /dev/null +++ b/libk3b/projects/movixcd/Makefile.am @@ -0,0 +1,23 @@ +# we need the ../datacd for the uic generated header files +AM_CPPFLAGS= -I$(srcdir)/../../core \ + -I$(srcdir)/../../../libk3bdevice \ + -I$(srcdir)/../../../src \ + -I$(srcdir)/../../tools \ + -I$(srcdir)/../datacd \ + -I$(srcdir)/.. \ + -I../datacd \ + $(all_includes) + +METASOURCES = AUTO + +noinst_LTLIBRARIES = libmovix.la + +libmovix_la_SOURCES = k3bmovixprogram.cpp \ + k3bmovixdoc.cpp \ + k3bmovixjob.cpp \ + k3bmovixfileitem.cpp \ + k3bmovixdocpreparer.cpp + +include_HEADERS = k3bmovixdoc.h \ + k3bmovixjob.h \ + k3bmovixfileitem.h diff --git a/libk3b/projects/movixcd/k3bmovixdoc.cpp b/libk3b/projects/movixcd/k3bmovixdoc.cpp new file mode 100644 index 0000000..f7b2198 --- /dev/null +++ b/libk3b/projects/movixcd/k3bmovixdoc.cpp @@ -0,0 +1,445 @@ +/* + * + * $Id: k3bmovixdoc.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bmovixdoc.h" +#include "k3bmovixjob.h" +#include "k3bmovixfileitem.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +K3bMovixDoc::K3bMovixDoc( QObject* parent ) + : K3bDataDoc( parent ) +{ + connect( this, SIGNAL(itemRemoved(K3bDataItem*)), + this, SLOT(slotDataItemRemoved(K3bDataItem*)) ); +} + + +K3bMovixDoc::~K3bMovixDoc() +{ +} + + +K3bBurnJob* K3bMovixDoc::newBurnJob( K3bJobHandler* hdl, QObject* parent ) +{ + return new K3bMovixJob( this, hdl, parent ); +} + + +bool K3bMovixDoc::newDocument() +{ + m_loopPlaylist = 1; + m_ejectDisk = false; + m_reboot = false; + m_shutdown = false; + m_randomPlay = false; + + return K3bDataDoc::newDocument(); +} + + +void K3bMovixDoc::addUrls( const KURL::List& urls ) +{ + for( KURL::List::ConstIterator it = urls.begin(); it != urls.end(); ++it ) { + addMovixFile( *it ); + } + + emit newMovixFileItems(); +} + + +void K3bMovixDoc::addMovixFile( const KURL& _url, int pos ) +{ + KURL url = K3b::convertToLocalUrl( _url ); + + QFileInfo f( url.path() ); + if( !f.isFile() || !url.isLocalFile() ) + return; + + QString newName = f.fileName(); + if( nameAlreadyInDir( newName, root() ) ) { + kapp->config()->setGroup("Data project settings"); + bool dropDoubles = kapp->config()->readBoolEntry( "Drop doubles", false ); + if( dropDoubles ) + return; + + bool ok = true; + do { + newName = KInputDialog::getText( i18n("Enter New Filename"), + i18n("A file with that name already exists. Please enter a new name:"), + newName, &ok, 0 ); + } while( ok && nameAlreadyInDir( newName, root() ) ); + + if( !ok ) + return; + } + + K3bMovixFileItem* newK3bItem = new K3bMovixFileItem( f.absFilePath(), this, root(), newName ); + if( pos < 0 || pos > (int)m_movixFiles.count() ) + pos = m_movixFiles.count(); + + m_movixFiles.insert( pos, newK3bItem ); + + emit newMovixFileItems(); + + setModified(true); +} + + +bool K3bMovixDoc::loadDocumentData( QDomElement* rootElem ) +{ + if( !root() ) + newDocument(); + + QDomNodeList nodes = rootElem->childNodes(); + + if( nodes.item(0).nodeName() != "general" ) { + kdDebug() << "(K3bMovixDoc) could not find 'general' section." << endl; + return false; + } + if( !readGeneralDocumentData( nodes.item(0).toElement() ) ) + return false; + + + // parse options + // ----------------------------------------------------------------- + if( nodes.item(1).nodeName() != "data_options" ) { + kdDebug() << "(K3bMovixDoc) could not find 'data_options' section." << endl; + return false; + } + if( !loadDocumentDataOptions( nodes.item(1).toElement() ) ) + return false; + // ----------------------------------------------------------------- + + + + // parse header + // ----------------------------------------------------------------- + if( nodes.item(2).nodeName() != "data_header" ) { + kdDebug() << "(K3bMovixDoc) could not find 'data_header' section." << endl; + return false; + } + if( !loadDocumentDataHeader( nodes.item(2).toElement() ) ) + return false; + // ----------------------------------------------------------------- + + + + // parse movix options + // ----------------------------------------------------------------- + if( nodes.item(3).nodeName() != "movix_options" ) { + kdDebug() << "(K3bMovixDoc) could not find 'movix_options' section." << endl; + return false; + } + + // load the options + QDomNodeList optionList = nodes.item(3).childNodes(); + for( uint i = 0; i < optionList.count(); i++ ) { + + QDomElement e = optionList.item(i).toElement(); + if( e.isNull() ) + return false; + + if( e.nodeName() == "shutdown") + setShutdown( e.attributeNode( "activated" ).value() == "yes" ); + else if( e.nodeName() == "reboot") + setReboot( e.attributeNode( "activated" ).value() == "yes" ); + else if( e.nodeName() == "eject_disk") + setEjectDisk( e.attributeNode( "activated" ).value() == "yes" ); + else if( e.nodeName() == "random_play") + setRandomPlay( e.attributeNode( "activated" ).value() == "yes" ); + else if( e.nodeName() == "no_dma") + setNoDma( e.attributeNode( "activated" ).value() == "yes" ); + else if( e.nodeName() == "subtitle_fontset") + setSubtitleFontset( e.text() ); + else if( e.nodeName() == "boot_message_language") + setBootMessageLanguage( e.text() ); + else if( e.nodeName() == "audio_background") + setAudioBackground( e.text() ); + else if( e.nodeName() == "keyboard_language") + setKeyboardLayout( e.text() ); + else if( e.nodeName() == "codecs") + setCodecs( QStringList::split( ',', e.text() ) ); + else if( e.nodeName() == "default_boot_label") + setDefaultBootLabel( e.text() ); + else if( e.nodeName() == "additional_mplayer_options") + setAdditionalMPlayerOptions( e.text() ); + else if( e.nodeName() == "unwanted_mplayer_options") + setUnwantedMPlayerOptions( e.text() ); + else if( e.nodeName() == "loop_playlist") + setLoopPlaylist( e.text().toInt() ); + else + kdDebug() << "(K3bMovixDoc) unknown movix option: " << e.nodeName() << endl; + } + // ----------------------------------------------------------------- + + // parse files + // ----------------------------------------------------------------- + if( nodes.item(4).nodeName() != "movix_files" ) { + kdDebug() << "(K3bMovixDoc) could not find 'movix_files' section." << endl; + return false; + } + + // load file items + QDomNodeList fileList = nodes.item(4).childNodes(); + for( uint i = 0; i < fileList.count(); i++ ) { + + QDomElement e = fileList.item(i).toElement(); + if( e.isNull() ) + return false; + + if( e.nodeName() == "file" ) { + if( !e.hasAttribute( "name" ) ) { + kdDebug() << "(K3bMovixDoc) found file tag without name attribute." << endl; + return false; + } + + QDomElement urlElem = e.firstChild().toElement(); + if( urlElem.isNull() ) { + kdDebug() << "(K3bMovixDoc) found file tag without url child." << endl; + return false; + } + + // create the item + K3bMovixFileItem* newK3bItem = new K3bMovixFileItem( urlElem.text(), + this, + root(), + e.attributeNode("name").value() ); + m_movixFiles.append( newK3bItem ); + + // subtitle file? + QDomElement subTitleElem = e.childNodes().item(1).toElement(); + if( !subTitleElem.isNull() && subTitleElem.nodeName() == "subtitle_file" ) { + urlElem = subTitleElem.firstChild().toElement(); + if( urlElem.isNull() ) { + kdDebug() << "(K3bMovixDoc) found subtitle_file tag without url child." << endl; + return false; + } + + QString name = K3bMovixFileItem::subTitleFileName( newK3bItem->k3bName() ); + K3bFileItem* subItem = new K3bFileItem( urlElem.text(), this, root(), name ); + newK3bItem->setSubTitleItem( subItem ); + } + } + else { + kdDebug() << "(K3bMovixDoc) found " << e.nodeName() << " node where 'file' was expected." << endl; + return false; + } + } + // ----------------------------------------------------------------- + + + emit newMovixFileItems(); + + return true; +} + + +bool K3bMovixDoc::saveDocumentData( QDomElement* docElem ) +{ + QDomDocument doc = docElem->ownerDocument(); + + saveGeneralDocumentData( docElem ); + + QDomElement optionsElem = doc.createElement( "data_options" ); + saveDocumentDataOptions( optionsElem ); + + QDomElement headerElem = doc.createElement( "data_header" ); + saveDocumentDataHeader( headerElem ); + + QDomElement movixOptElem = doc.createElement( "movix_options" ); + QDomElement movixFilesElem = doc.createElement( "movix_files" ); + + + // save the movix options + QDomElement propElem = doc.createElement( "shutdown" ); + propElem.setAttribute( "activated", shutdown() ? "yes" : "no" ); + movixOptElem.appendChild( propElem ); + + propElem = doc.createElement( "reboot" ); + propElem.setAttribute( "activated", reboot() ? "yes" : "no" ); + movixOptElem.appendChild( propElem ); + + propElem = doc.createElement( "eject_disk" ); + propElem.setAttribute( "activated", ejectDisk() ? "yes" : "no" ); + movixOptElem.appendChild( propElem ); + + propElem = doc.createElement( "random_play" ); + propElem.setAttribute( "activated", randomPlay() ? "yes" : "no" ); + movixOptElem.appendChild( propElem ); + + propElem = doc.createElement( "no_dma" ); + propElem.setAttribute( "activated", noDma() ? "yes" : "no" ); + movixOptElem.appendChild( propElem ); + + propElem = doc.createElement( "subtitle_fontset" ); + propElem.appendChild( doc.createTextNode( subtitleFontset() ) ); + movixOptElem.appendChild( propElem ); + + propElem = doc.createElement( "boot_message_language" ); + propElem.appendChild( doc.createTextNode( bootMessageLanguage() ) ); + movixOptElem.appendChild( propElem ); + + propElem = doc.createElement( "audio_background" ); + propElem.appendChild( doc.createTextNode( audioBackground() ) ); + movixOptElem.appendChild( propElem ); + + propElem = doc.createElement( "keyboard_language" ); + propElem.appendChild( doc.createTextNode( keyboardLayout() ) ); + movixOptElem.appendChild( propElem ); + + propElem = doc.createElement( "codecs" ); + propElem.appendChild( doc.createTextNode( codecs().join(",") ) ); + movixOptElem.appendChild( propElem ); + + propElem = doc.createElement( "default_boot_label" ); + propElem.appendChild( doc.createTextNode( defaultBootLabel() ) ); + movixOptElem.appendChild( propElem ); + + propElem = doc.createElement( "additional_mplayer_options" ); + propElem.appendChild( doc.createTextNode( additionalMPlayerOptions() ) ); + movixOptElem.appendChild( propElem ); + + propElem = doc.createElement( "unwanted_mplayer_options" ); + propElem.appendChild( doc.createTextNode( unwantedMPlayerOptions() ) ); + movixOptElem.appendChild( propElem ); + + propElem = doc.createElement( "loop_playlist" ); + propElem.appendChild( doc.createTextNode( QString::number(loopPlaylist()) ) ); + movixOptElem.appendChild( propElem ); + + + // save the movix items + for( QPtrListIterator it( m_movixFiles ); + *it; ++it ) { + K3bMovixFileItem* item = *it; + + QDomElement topElem = doc.createElement( "file" ); + topElem.setAttribute( "name", item->k3bName() ); + QDomElement urlElem = doc.createElement( "url" ); + urlElem.appendChild( doc.createTextNode( item->localPath() ) ); + topElem.appendChild( urlElem ); + if( item->subTitleItem() ) { + QDomElement subElem = doc.createElement( "subtitle_file" ); + urlElem = doc.createElement( "url" ); + urlElem.appendChild( doc.createTextNode( item->subTitleItem()->localPath() ) ); + subElem.appendChild( urlElem ); + topElem.appendChild( subElem ); + } + + movixFilesElem.appendChild( topElem ); + } + + docElem->appendChild( optionsElem ); + docElem->appendChild( headerElem ); + docElem->appendChild( movixOptElem ); + docElem->appendChild( movixFilesElem ); + + return true; +} + + +void K3bMovixDoc::slotDataItemRemoved( K3bDataItem* item ) +{ + // check if it's a movix item + if( K3bMovixFileItem* fi = dynamic_cast(item) ) + if( m_movixFiles.containsRef( fi ) ) { + emit movixItemRemoved( fi ); + m_movixFiles.removeRef( fi ); + setModified(true); + } +} + + +int K3bMovixDoc::indexOf( K3bMovixFileItem* item ) +{ + return m_movixFiles.findRef(item)+1; +} + + +void K3bMovixDoc::moveMovixItem( K3bMovixFileItem* item, K3bMovixFileItem* itemAfter ) +{ + if( item == itemAfter ) + return; + + // set the current item to track + m_movixFiles.findRef( item ); + // take the current item + item = m_movixFiles.take(); + + // if after == 0 findRef returnes -1 + int pos = m_movixFiles.findRef( itemAfter ); + m_movixFiles.insert( pos+1, item ); + + emit newMovixFileItems(); + + setModified(true); +} + + +void K3bMovixDoc::addSubTitleItem( K3bMovixFileItem* item, const KURL& url ) +{ + if( item->subTitleItem() ) + removeSubTitleItem( item ); + + QFileInfo f( url.path() ); + if( !f.isFile() || !url.isLocalFile() ) + return; + + // check if there already is a file named like we want to name the subTitle file + QString name = K3bMovixFileItem::subTitleFileName( item->k3bName() ); + + if( nameAlreadyInDir( name, root() ) ) { + KMessageBox::error( 0, i18n("Could not rename subtitle file. File with requested name %1 already exists.").arg(name) ); + return; + } + + K3bFileItem* subItem = new K3bFileItem( f.absFilePath(), this, root(), name ); + item->setSubTitleItem( subItem ); + + emit newMovixFileItems(); + + setModified(true); +} + + +void K3bMovixDoc::removeSubTitleItem( K3bMovixFileItem* item ) +{ + if( item->subTitleItem() ) { + emit subTitleItemRemoved( item ); + + delete item->subTitleItem(); + item->setSubTitleItem(0); + + setModified(true); + } +} + +#include "k3bmovixdoc.moc" diff --git a/libk3b/projects/movixcd/k3bmovixdoc.h b/libk3b/projects/movixcd/k3bmovixdoc.h new file mode 100644 index 0000000..53debfc --- /dev/null +++ b/libk3b/projects/movixcd/k3bmovixdoc.h @@ -0,0 +1,125 @@ +/* + * + * $Id: k3bmovixdoc.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_MOVIX_DOC_H_ +#define _K3B_MOVIX_DOC_H_ + + +#include + +#include +#include "k3b_export.h" +//class K3bView; +class KURL; +class QDomElement; +class K3bFileItem; +class K3bMovixFileItem; +class K3bDataItem; +class KConfig; + + +class LIBK3B_EXPORT K3bMovixDoc : public K3bDataDoc +{ + Q_OBJECT + + public: + K3bMovixDoc( QObject* parent = 0 ); + virtual ~K3bMovixDoc(); + + virtual int type() const { return MOVIX; } + + virtual K3bBurnJob* newBurnJob( K3bJobHandler* hdl, QObject* parent ); + + bool newDocument(); + + const QPtrList& movixFileItems() const { return m_movixFiles; } + + int indexOf( K3bMovixFileItem* ); + + + bool shutdown() const { return m_shutdown; } + bool reboot() const { return m_reboot; } + bool ejectDisk() const { return m_ejectDisk; } + bool randomPlay() const { return m_randomPlay; } + const QString& subtitleFontset() const { return m_subtitleFontset; } + const QString& bootMessageLanguage() const { return m_bootMessageLanguage; } + const QString& audioBackground() const { return m_audioBackground; } + const QString& keyboardLayout() const { return m_keyboardLayout; } + const QStringList& codecs() const { return m_codecs; } + const QString& defaultBootLabel() const { return m_defaultBootLabel; } + const QString& additionalMPlayerOptions() const { return m_additionalMPlayerOptions; } + const QString& unwantedMPlayerOptions() const { return m_unwantedMPlayerOptions; } + int loopPlaylist() const { return m_loopPlaylist; } + bool noDma() const { return m_noDma; } + + void setShutdown( bool v ) { m_shutdown = v; } + void setReboot( bool v ) { m_reboot = v; } + void setEjectDisk( bool v ) { m_ejectDisk = v; } + void setRandomPlay( bool v ) { m_randomPlay = v; } + void setSubtitleFontset( const QString& v ) { m_subtitleFontset = v; } + void setBootMessageLanguage( const QString& v ) { m_bootMessageLanguage = v; } + void setAudioBackground( const QString& b ) { m_audioBackground = b; } + void setKeyboardLayout( const QString& l ) { m_keyboardLayout = l; } + void setCodecs( const QStringList& c ) { m_codecs = c; } + void setDefaultBootLabel( const QString& v ) { m_defaultBootLabel = v; } + void setAdditionalMPlayerOptions( const QString& v ) { m_additionalMPlayerOptions = v; } + void setUnwantedMPlayerOptions( const QString& v ) { m_unwantedMPlayerOptions = v; } + void setLoopPlaylist( int v ) { m_loopPlaylist = v; } + void setNoDma( bool b ) { m_noDma = b; } + + signals: + void newMovixFileItems(); + void movixItemRemoved( K3bMovixFileItem* ); + void subTitleItemRemoved( K3bMovixFileItem* ); + + public slots: + void addUrls( const KURL::List& urls ); + void addMovixFile( const KURL& url, int pos = -1 ); + void moveMovixItem( K3bMovixFileItem* item, K3bMovixFileItem* itemAfter ); + void addSubTitleItem( K3bMovixFileItem*, const KURL& ); + void removeSubTitleItem( K3bMovixFileItem* ); + + protected: + /** reimplemented from K3bDoc */ + bool loadDocumentData( QDomElement* root ); + /** reimplemented from K3bDoc */ + bool saveDocumentData( QDomElement* ); + + virtual QString typeString() const { return "movix"; } + + private slots: + void slotDataItemRemoved( K3bDataItem* ); + + private: + QPtrList m_movixFiles; + + bool m_shutdown; + bool m_reboot; + bool m_ejectDisk; + bool m_randomPlay; + QString m_subtitleFontset; + QString m_bootMessageLanguage; + QString m_audioBackground; + QString m_keyboardLayout; + QStringList m_codecs; + QString m_defaultBootLabel; + QString m_additionalMPlayerOptions; + QString m_unwantedMPlayerOptions; + int m_loopPlaylist; + bool m_noDma; +}; + +#endif diff --git a/libk3b/projects/movixcd/k3bmovixdocpreparer.cpp b/libk3b/projects/movixcd/k3bmovixdocpreparer.cpp new file mode 100644 index 0000000..57e18af --- /dev/null +++ b/libk3b/projects/movixcd/k3bmovixdocpreparer.cpp @@ -0,0 +1,490 @@ +/* + * + * $Id: k3bmovixdocpreparer.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bmovixdocpreparer.h" +#include "k3bmovixdoc.h" +#include "k3bmovixprogram.h" +#include "k3bmovixfileitem.h" + + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + + +class K3bMovixDocPreparer::Private +{ +public: + Private() + : doc(0), + playlistFile(0), + isolinuxConfigFile(0), + movixRcFile(0), + isolinuxDir(0), + movixDir(0), + mplayerDir(0), + playlistFileItem(0), + structuresCreated(false) { + } + + K3bMovixDoc* doc; + const K3bMovixBin* eMovixBin; + + KTempFile* playlistFile; + KTempFile* isolinuxConfigFile; + KTempFile* movixRcFile; + + K3bDirItem* isolinuxDir; + K3bDirItem* movixDir; + K3bDirItem* mplayerDir; + K3bFileItem* playlistFileItem; + + QPtrList newMovixItems; + + bool structuresCreated; +}; + + +K3bMovixDocPreparer::K3bMovixDocPreparer( K3bMovixDoc* doc, K3bJobHandler* jh, QObject* parent, const char* name ) + : K3bJob( jh, parent, name ) +{ + d = new Private(); + d->doc = doc; +} + + +K3bMovixDocPreparer::~K3bMovixDocPreparer() +{ + removeMovixStructures(); + delete d; +} + + +K3bMovixDoc* K3bMovixDocPreparer::doc() const +{ + return d->doc; +} + + +void K3bMovixDocPreparer::start() +{ + kdDebug() << k_funcinfo << endl; + jobStarted(); + + bool success = true; + if( d->structuresCreated ) + removeMovixStructures(); + else + success = createMovixStructures(); + + jobFinished(success); +} + + +void K3bMovixDocPreparer::cancel() +{ + // do nothing... +} + + +bool K3bMovixDocPreparer::createMovixStructures() +{ + kdDebug() << k_funcinfo << endl; + removeMovixStructures(); + + if( doc() ) { + doc()->setMultiSessionMode( K3bDataDoc::NONE ); + doc()->prepareFilenames(); + } + + d->eMovixBin = dynamic_cast( k3bcore->externalBinManager()->binObject("eMovix") ); + if( d->eMovixBin ) { + bool success = false; + if( d->eMovixBin->version >= K3bVersion( 0, 9, 0 ) ) + success = addMovixFilesNew(); + else + success = addMovixFiles(); + + d->structuresCreated = success; + return success; + } + else { + emit infoMessage( i18n("Could not find a valid eMovix installation."), ERROR ); + return false; + } +} + + +void K3bMovixDocPreparer::removeMovixStructures() +{ + kdDebug() << k_funcinfo << endl; + // remove movix files from doc + // the dataitems do the cleanup in the doc + delete d->movixDir; + delete d->isolinuxDir; + delete d->mplayerDir; + delete d->playlistFileItem; + + d->movixDir = 0; + d->isolinuxDir = 0; + d->mplayerDir = 0; + d->playlistFileItem = 0; + + d->newMovixItems.setAutoDelete( true ); + d->newMovixItems.clear(); + + // remove all the temp files + delete d->playlistFile; + delete d->isolinuxConfigFile; + delete d->movixRcFile; + + d->playlistFile = 0; + d->isolinuxConfigFile = 0; + d->movixRcFile = 0; + + d->structuresCreated = false; +} + + +bool K3bMovixDocPreparer::writePlaylistFile() +{ + delete d->playlistFile; + d->playlistFile = new KTempFile(); + d->playlistFile->setAutoDelete(true); + + if( QTextStream* s = d->playlistFile->textStream() ) { + + const QPtrList& movixFileItems = d->doc->movixFileItems(); + + for( QPtrListIterator it( movixFileItems ); + *it; ++it ) { + *s << "/cdrom/"; + *s << it.current()->writtenName(); + *s << endl; + } + + d->playlistFile->close(); + return true; + } + else { + emit infoMessage( i18n("Could not write to temporary file %1").arg(d->playlistFile->name()), ERROR ); + return false; + } +} + + +bool K3bMovixDocPreparer::writeIsolinuxConfigFile( const QString& originalPath ) +{ + delete d->isolinuxConfigFile; + d->isolinuxConfigFile = new KTempFile(); + d->isolinuxConfigFile->setAutoDelete(true); + + if( QTextStream* s = d->isolinuxConfigFile->textStream() ) { + + // now open the default isolinux.cfg and copy everything except the first line which contains + // the default boot label + QFile f( originalPath ); + if( f.open( IO_ReadOnly ) ) { + + QTextStream isolinuxConfigOrig( &f ); + + if( d->doc->defaultBootLabel() != i18n("default") ) { + isolinuxConfigOrig.readLine(); // skip first line + *s << "default " << d->doc->defaultBootLabel() << endl; + } + + QString line = isolinuxConfigOrig.readLine(); + while( !line.isNull() ) { + *s << line << endl; + line = isolinuxConfigOrig.readLine(); + } + + d->isolinuxConfigFile->close(); + return true; + } + else + return false; + } + else { + emit infoMessage( i18n("Could not write to temporary file %1").arg(d->isolinuxConfigFile->name()), ERROR ); + return false; + } +} + + +bool K3bMovixDocPreparer::writeMovixRcFile() +{ + delete d->movixRcFile; + d->movixRcFile = new KTempFile(); + d->movixRcFile->setAutoDelete(true); + + if( QTextStream* s = d->movixRcFile->textStream() ) { + + if( !d->doc->additionalMPlayerOptions().isEmpty() ) + *s << "extra-mplayer-options=" << d->doc->additionalMPlayerOptions() << endl; + if( !d->doc->unwantedMPlayerOptions().isEmpty() ) + *s << "unwanted-mplayer-options=" << d->doc->unwantedMPlayerOptions() << endl; + *s << "loop=" << d->doc->loopPlaylist() << endl; + if( d->doc->shutdown() ) + *s << "shut=y" << endl; + if( d->doc->reboot() ) + *s << "reboot=y" << endl; + if( d->doc->ejectDisk() ) + *s << "eject=y" << endl; + if( d->doc->randomPlay() ) + *s << "random=y" << endl; + if( d->doc->noDma() ) + *s << "dma=n" << endl; + + d->movixRcFile->close(); + return true; + } + else { + emit infoMessage( i18n("Could not write to temporary file %1").arg(d->movixRcFile->name()), ERROR ); + return false; + } +} + + +bool K3bMovixDocPreparer::addMovixFiles() +{ + // first of all we create the directories + d->isolinuxDir = new K3bDirItem( "isolinux", d->doc, d->doc->root() ); + d->movixDir = new K3bDirItem( "movix", d->doc, d->doc->root() ); + K3bDirItem* kernelDir = d->doc->addEmptyDir( "kernel", d->isolinuxDir ); + + // add the linux kernel + (void)new K3bFileItem( d->eMovixBin->path + "/isolinux/kernel/vmlinuz", d->doc, kernelDir ); + + // add the boot image + K3bBootItem* bootItem = d->doc->createBootItem( d->eMovixBin->path + "/isolinux/isolinux.bin", + d->isolinuxDir ); + bootItem->setImageType( K3bBootItem::NONE ); + bootItem->setLoadSize( 4 ); + bootItem->setBootInfoTable(true); + + // some sort weights as defined in isolinux + d->isolinuxDir->setSortWeight( 100 ); + kernelDir->setSortWeight( 50 ); + bootItem->setSortWeight( 200 ); + + // rename the boot catalog file + d->doc->bootCataloge()->setK3bName( "isolinux.boot" ); + + // the following sucks! Redesign it! + + // add all the isolinux files + QStringList isolinuxFiles = d->eMovixBin->isolinuxFiles(); + isolinuxFiles.remove( "isolinux.bin" ); + isolinuxFiles.remove( "isolinux.cfg" ); + isolinuxFiles.remove( "kernel/vmlinuz" ); + for( QStringList::const_iterator it = isolinuxFiles.begin(); + it != isolinuxFiles.end(); ++it ) { + QString path = d->eMovixBin->path + "/isolinux/" + *it; + (void)new K3bFileItem( path, d->doc, d->isolinuxDir ); + } + + const QStringList& movixFiles = d->eMovixBin->movixFiles(); + for( QStringList::const_iterator it = movixFiles.begin(); + it != movixFiles.end(); ++it ) { + QString path = d->eMovixBin->path + "/movix/" + *it; + (void)new K3bFileItem( path, d->doc, d->movixDir ); + } + + // add doku files + QString path = d->eMovixBin->languageDir( d->doc->bootMessageLanguage() ); + QDir dir(path); + QStringList helpFiles = dir.entryList(QDir::Files); + for( QStringList::const_iterator it = helpFiles.begin(); + it != helpFiles.end(); ++it ) { + // some emovix installations include backup-files, no one's perfect ;) + if( !(*it).endsWith( "~" ) ) + (void)new K3bFileItem( path + "/" + *it, d->doc, d->isolinuxDir ); + } + + + // add subtitle font dir + if( !d->doc->subtitleFontset().isEmpty() && + d->doc->subtitleFontset() != i18n("none") ) { + d->mplayerDir = new K3bDirItem( "mplayer", d->doc, d->doc->root() ); + + QString fontPath = d->eMovixBin->subtitleFontDir( d->doc->subtitleFontset() ); + QFileInfo fontType( fontPath ); + if( fontType.isDir() ) { + K3bDirItem* fontDir = new K3bDirItem( "font", d->doc, d->mplayerDir ); + QDir dir( fontPath ); + QStringList fontFiles = dir.entryList( QDir::Files ); + for( QStringList::const_iterator it = fontFiles.begin(); + it != fontFiles.end(); ++it ) { + (void)new K3bFileItem( fontPath + "/" + *it, d->doc, fontDir ); + } + } + else { + // just a ttf file + // needs to be named: subfont.ttf and needs to be placed in mplayer/ + // instead of mplayer/font + (void)new K3bFileItem( fontPath, + d->doc, + d->mplayerDir, + "subfont.ttf" ); + } + } + + + // add movix-config-file and boot-config file + if( writeMovixRcFile() && + writeIsolinuxConfigFile( d->eMovixBin->path + "/isolinux/isolinux.cfg" ) && + writePlaylistFile() ) { + + (void)new K3bFileItem( d->movixRcFile->name(), d->doc, d->movixDir, "movixrc" ); + (void)new K3bFileItem( d->isolinuxConfigFile->name(), d->doc, d->isolinuxDir, "isolinux.cfg" ); + d->playlistFileItem = new K3bFileItem( d->playlistFile->name(), d->doc, d->doc->root(), "movix.list" ); + + return true; + } + else + return false; +} + + +bool K3bMovixDocPreparer::addMovixFilesNew() +{ + // 1. get a list of files from the movixbin + // 2. create file items (replace isolinux.cfg with the one created above) + // 3. add movixrc and movix.list files + // 4. set weights for isolinux files + + // FIXME: use the settings from the doc + QStringList files = d->eMovixBin->files( d->doc->keyboardLayout(), + d->doc->subtitleFontset(), + d->doc->audioBackground(), + d->doc->bootMessageLanguage(), + "all" /*d->doc->codecs()*/ ); // for now we simply don't allow selection + + for( QStringList::iterator it = files.begin(); it != files.end(); ++it ) { + QString docPath = (*it).section( ' ', 0, 0 ); + QString filePath = (*it).section( ' ', 1, 1 ); + QString fileName = filePath.section( '/', -1 ); + + if( fileName == "isolinux.cfg" ) { + // replace the local file with our modified one + if( writeIsolinuxConfigFile( filePath ) ) + createItem( d->isolinuxConfigFile->name(), docPath )->setK3bName( "isolinux.cfg" ); + else + return false; + } + else if( fileName == "isolinux.bin" ) { + // create boot item (no need to remember this since it's in a dir which will be removed + // anyway) + K3bBootItem* bootItem = d->doc->createBootItem( filePath, createDir(docPath) ); + bootItem->setImageType( K3bBootItem::NONE ); + bootItem->setLoadSize( 4 ); + bootItem->setBootInfoTable(true); + + // set the proper sort weight + bootItem->setSortWeight( 200 ); + bootItem->parent()->setSortWeight( 100 ); + } + else if( fileName != "movixrc" ) { // we create our own movixrc + K3bFileItem* item = createItem( filePath, docPath ); + + // Truetype subtitle fonts needs to be named subfont.ttf + if( fileName == d->doc->subtitleFontset() + ".ttf" ) { + item->setK3bName( "subfont.ttf" ); + } + else if( fileName == "vmlinuz" ) + item->setSortWeight( 50 ); + } + } + + // Some distributions (such as Gentoo for example) do use the win32codecs package instead of the + // eMovix supplied codecs. These codecs are not picked up by the movix-conf script + K3bDirItem* codecDir = dynamic_cast( d->doc->root()->findByPath( "/eMoviX/codecs" ) ); + if( !codecDir || codecDir->isEmpty() ) { + QDir localCodecDir( d->eMovixBin->movixDataDir() + "/codecs" ); + if( localCodecDir.exists() ) { + QStringList codecFiles = localCodecDir.entryList( QDir::Files ); + for( QStringList::const_iterator it = codecFiles.begin(); it != codecFiles.end(); ++it ) + createItem( localCodecDir.path() + '/' + *it, "/eMoviX/codecs" ); + } + } + + if( writePlaylistFile() && writeMovixRcFile() ) { + // add the two items that are not listed by the script + createItem( d->movixRcFile->name(), "/eMoviX/movix" )->setK3bName( "movixrc" ); + createItem( d->playlistFile->name(), "/" )->setK3bName( "movix.list" ); + return true; + } + else + return false; +} + + +K3bFileItem* K3bMovixDocPreparer::createItem( const QString& localPath, const QString& docPath ) +{ + // make sure the path in the doc exists + K3bDirItem* dir = createDir( docPath ); + + // create the file in dir + K3bFileItem* item = new K3bFileItem( localPath, d->doc, dir ); + + // remember the item to remove it becasue the dir cannot be removed + if( dir == d->doc->root() ) + d->newMovixItems.append( item ); + + return item; +} + + +K3bDirItem* K3bMovixDocPreparer::createDir( const QString& docPath ) +{ + QStringList docPathSections = QStringList::split( '/', docPath ); + K3bDirItem* dir = d->doc->root(); + for( QStringList::iterator it = docPathSections.begin(); it != docPathSections.end(); ++it ) { + K3bDataItem* next = dir->find( *it ); + if( !next ) + dir = new K3bDirItem( *it, d->doc, dir ); + else if( next->isDir() ) + dir = static_cast( next ); + else { + kdError() << "(K3bMovixDocPreparer) found non-dir item where a dir was needed." << endl; + return 0; + } + } + + // remember the dir to remove it + if( dir != d->doc->root() ) { + K3bDirItem* delDir = dir; + while( delDir->parent() != d->doc->root() ) + delDir = delDir->parent(); + if( d->newMovixItems.findRef( delDir ) == -1 ) + d->newMovixItems.append( delDir ); + } + + return dir; +} + +#include "k3bmovixdocpreparer.moc" diff --git a/libk3b/projects/movixcd/k3bmovixdocpreparer.h b/libk3b/projects/movixcd/k3bmovixdocpreparer.h new file mode 100644 index 0000000..3844eae --- /dev/null +++ b/libk3b/projects/movixcd/k3bmovixdocpreparer.h @@ -0,0 +1,67 @@ +/* + * + * $Id: k3bmovixdocpreparer.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_MOVIX_DOC_PREPARER_H_ +#define _K3B_MOVIX_DOC_PREPARER_H_ + +#include + +class K3bMovixDoc; +class K3bFileItem; +class K3bDirItem; + + +/** + * This class creates the needed eMovix structures in an eMovix doc + * and removes them after creating the image. + */ +class K3bMovixDocPreparer : public K3bJob +{ + Q_OBJECT + + public: + explicit K3bMovixDocPreparer( K3bMovixDoc* doc, K3bJobHandler*, QObject* parent = 0, const char* name = 0 ); + ~K3bMovixDocPreparer(); + + K3bMovixDoc* doc() const; + + bool createMovixStructures(); + void removeMovixStructures(); + + public slots: + /** + * use createMovixStructures and removeMovixStructures instead. + */ + void start(); + + /** + * Useless since this job works syncronously + */ + void cancel(); + + private: + bool writePlaylistFile(); + bool writeIsolinuxConfigFile( const QString& ); + bool writeMovixRcFile(); + bool addMovixFiles(); + bool addMovixFilesNew(); + K3bFileItem* createItem( const QString& localPath, const QString& docPath ); + K3bDirItem* createDir( const QString& docPath ); + + class Private; + Private* d; +}; + +#endif diff --git a/libk3b/projects/movixcd/k3bmovixfileitem.cpp b/libk3b/projects/movixcd/k3bmovixfileitem.cpp new file mode 100644 index 0000000..12803a2 --- /dev/null +++ b/libk3b/projects/movixcd/k3bmovixfileitem.cpp @@ -0,0 +1,68 @@ +/* + * + * $Id: k3bmovixfileitem.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bmovixfileitem.h" +#include "k3bmovixdoc.h" + +#include + + +K3bMovixFileItem::K3bMovixFileItem( const QString& fileName, + K3bMovixDoc* doc, + K3bDirItem* dir, + const QString& k3bName ) + : K3bFileItem( fileName, doc, dir, k3bName ), + m_doc(doc), + m_subTitleItem(0) +{ +} + + +K3bMovixFileItem::~K3bMovixFileItem() +{ + if( m_subTitleItem ) + m_doc->removeSubTitleItem( this ); + + // remove this from parentdir + // it is important to do it here and not + // rely on the K3bFileItem destructor becasue + // otherwise the doc is not informed early enough + if( parent() ) + parent()->takeDataItem( this ); +} + + +void K3bMovixFileItem::setK3bName( const QString& newName ) +{ + K3bFileItem::setK3bName( newName ); + + // take care of the subTitle file + if( m_subTitleItem ) { + m_subTitleItem->setK3bName( subTitleFileName(k3bName()) ); + } +} + + +QString K3bMovixFileItem::subTitleFileName( const QString& name ) +{ + // remove ending from k3bName + QString subName = name; + int pos = subName.findRev("."); + if( pos > 0 ) + subName.truncate( pos ); + subName += ".sub"; + return subName; +} diff --git a/libk3b/projects/movixcd/k3bmovixfileitem.h b/libk3b/projects/movixcd/k3bmovixfileitem.h new file mode 100644 index 0000000..343f00b --- /dev/null +++ b/libk3b/projects/movixcd/k3bmovixfileitem.h @@ -0,0 +1,52 @@ +/* + * + * $Id: k3bmovixfileitem.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_MOVIX_FILEITEM_H_ +#define _K3B_MOVIX_FILEITEM_H_ + +#include + +class K3bMovixDoc; + + +class K3bMovixFileItem : public K3bFileItem +{ + public: + K3bMovixFileItem( const QString& fileName, K3bMovixDoc* doc, K3bDirItem* dir, const QString& k3bName = 0 ); + ~K3bMovixFileItem(); + + K3bFileItem* subTitleItem() const { return m_subTitleItem; } + void setSubTitleItem( K3bFileItem* i ) { m_subTitleItem = i; } + + /** + * reimplemented from K3bDataItem + * also renames the subTitleItem + */ + void setK3bName( const QString& ); + + /** + * returnes the name that the subtitle file must have in + * order to work with mplayer + */ + static QString subTitleFileName( const QString& ); + + private: + K3bMovixDoc* m_doc; + + K3bFileItem* m_subTitleItem; +}; + +#endif diff --git a/libk3b/projects/movixcd/k3bmovixjob.cpp b/libk3b/projects/movixcd/k3bmovixjob.cpp new file mode 100644 index 0000000..2579453 --- /dev/null +++ b/libk3b/projects/movixcd/k3bmovixjob.cpp @@ -0,0 +1,132 @@ +/* + * + * $Id: k3bmovixjob.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bmovixjob.h" +#include "k3bmovixdoc.h" +#include "k3bmovixfileitem.h" +#include "k3bmovixdocpreparer.h" + +#include +#include +#include + +#include +#include + + +K3bMovixJob::K3bMovixJob( K3bMovixDoc* doc, K3bJobHandler* jh, QObject* parent ) + : K3bBurnJob( jh, parent ), + m_doc(doc) +{ + m_dataJob = new K3bDataJob( doc, this, this ); + m_movixDocPreparer = new K3bMovixDocPreparer( doc, this, this ); + + // pipe signals + connect( m_dataJob, SIGNAL(percent(int)), this, SIGNAL(percent(int)) ); + connect( m_dataJob, SIGNAL(subPercent(int)), this, SIGNAL(subPercent(int)) ); + connect( m_dataJob, SIGNAL(processedSubSize(int, int)), this, SIGNAL(processedSubSize(int, int)) ); + connect( m_dataJob, SIGNAL(processedSize(int, int)), this, SIGNAL(processedSize(int, int)) ); + connect( m_dataJob, SIGNAL(bufferStatus(int)), this, SIGNAL(bufferStatus(int)) ); + connect( m_dataJob, SIGNAL(deviceBuffer(int)), this, SIGNAL(deviceBuffer(int)) ); + connect( m_dataJob, SIGNAL(writeSpeed(int, int)), this, SIGNAL(writeSpeed(int, int)) ); + connect( m_dataJob, SIGNAL(newTask(const QString&)), this, SIGNAL(newTask(const QString&)) ); + connect( m_dataJob, SIGNAL(newSubTask(const QString&)), this, SIGNAL(newSubTask(const QString&)) ); + connect( m_dataJob, SIGNAL(debuggingOutput(const QString&, const QString&)), + this, SIGNAL(debuggingOutput(const QString&, const QString&)) ); + connect( m_dataJob, SIGNAL(infoMessage(const QString&, int)), + this, SIGNAL(infoMessage(const QString&, int)) ); + connect( m_dataJob, SIGNAL(burning(bool)), this, SIGNAL(burning(bool)) ); + + // we need to clean up here + connect( m_dataJob, SIGNAL(finished(bool)), this, SLOT(slotDataJobFinished(bool)) ); + + connect( m_movixDocPreparer, SIGNAL(infoMessage(const QString&, int)), + this, SIGNAL(infoMessage(const QString&, int)) ); +} + + +K3bMovixJob::~K3bMovixJob() +{ +} + + +K3bDevice::Device* K3bMovixJob::writer() const +{ + return m_dataJob->writer(); +} + + +K3bDoc* K3bMovixJob::doc() const +{ + return m_doc; +} + + +void K3bMovixJob::start() +{ + jobStarted(); + + m_canceled = false; + m_dataJob->setWritingApp( writingApp() ); + + if( m_movixDocPreparer->createMovixStructures() ) { + m_dataJob->start(); + } + else { + m_movixDocPreparer->removeMovixStructures(); + jobFinished(false); + } +} + + +void K3bMovixJob::cancel() +{ + m_canceled = true; + m_dataJob->cancel(); +} + + +void K3bMovixJob::slotDataJobFinished( bool success ) +{ + m_movixDocPreparer->removeMovixStructures(); + + if( m_canceled || m_dataJob->hasBeenCanceled() ) + emit canceled(); + + jobFinished( success ); +} + + +QString K3bMovixJob::jobDescription() const +{ + if( m_doc->isoOptions().volumeID().isEmpty() ) + return i18n("Writing eMovix CD"); + else + return i18n("Writing eMovix CD (%1)").arg(m_doc->isoOptions().volumeID()); +} + + +QString K3bMovixJob::jobDetails() const +{ + return ( i18n("1 file (%1) and about 8 MB eMovix data", + "%n files (%1) and about 8 MB eMovix data", + m_doc->movixFileItems().count()).arg(KIO::convertSize(m_doc->size())) + + ( m_doc->copies() > 1 + ? i18n(" - %n copy", " - %n copies", m_doc->copies()) + : QString::null ) ); +} + +#include "k3bmovixjob.moc" diff --git a/libk3b/projects/movixcd/k3bmovixjob.h b/libk3b/projects/movixcd/k3bmovixjob.h new file mode 100644 index 0000000..81dea8e --- /dev/null +++ b/libk3b/projects/movixcd/k3bmovixjob.h @@ -0,0 +1,60 @@ +/* + * + * $Id: k3bmovixjob.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_MOVIX_JOB_H_ +#define _K3B_MOVIX_JOB_H_ + +#include + +class K3bMovixDoc; +class K3bDevice::Device; +class K3bDataJob; +class KTempFile; +class K3bMovixInstallation; +class K3bMovixDocPreparer; +class K3bDirItem; +class K3bFileItem; + +class K3bMovixJob : public K3bBurnJob +{ + Q_OBJECT + + public: + K3bMovixJob( K3bMovixDoc* doc, K3bJobHandler*, QObject* parent = 0 ); + ~K3bMovixJob(); + + K3bDoc* doc() const; + K3bDevice::Device* writer() const; + + QString jobDescription() const; + QString jobDetails() const; + + public slots: + void start(); + void cancel(); + + private slots: + void slotDataJobFinished( bool ); + + private: + K3bMovixDoc* m_doc; + K3bDataJob* m_dataJob; + K3bMovixDocPreparer* m_movixDocPreparer; + + bool m_canceled; +}; + +#endif diff --git a/libk3b/projects/movixcd/k3bmovixprogram.cpp b/libk3b/projects/movixcd/k3bmovixprogram.cpp new file mode 100644 index 0000000..8720e8d --- /dev/null +++ b/libk3b/projects/movixcd/k3bmovixprogram.cpp @@ -0,0 +1,339 @@ +/* + * + * $Id: k3bmovixprogram.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bmovixprogram.h" + +#include + +#include +#include + +#include +#include +#include + + +K3bMovixProgram::K3bMovixProgram() + : K3bExternalProgram( "eMovix" ) +{ +} + +bool K3bMovixProgram::scan( const QString& p ) +{ + if( p.isEmpty() ) + return false; + + QString path = p; + if( path[path.length()-1] != '/' ) + path.append("/"); + + // first test if we have a version info (eMovix >= 0.8.0pre3) + if( !QFile::exists( path + "movix-version" ) ) + return false; + + K3bMovixBin* bin = 0; + + // + // probe version and data dir + // + KProcess vp, dp; + vp << path + "movix-version"; + dp << path + "movix-conf"; + K3bProcessOutputCollector vout( &vp ), dout( &dp ); + if( vp.start( KProcess::Block, KProcess::AllOutput ) && dp.start( KProcess::Block, KProcess::AllOutput ) ) { + // movix-version just gives us the version number on stdout + if( !vout.output().isEmpty() && !dout.output().isEmpty() ) { + bin = new K3bMovixBin( this ); + bin->version = vout.output().stripWhiteSpace(); + bin->path = path; + bin->m_movixPath = dout.output().stripWhiteSpace(); + } + } + else { + kdDebug() << "(K3bMovixProgram) could not start " << path << "movix-version" << endl; + return false; + } + + if( bin->version >= K3bVersion( 0, 9, 0 ) ) + return scanNewEMovix( bin, path ); + else + return scanOldEMovix( bin, path ); +} + + +bool K3bMovixProgram::scanNewEMovix( K3bMovixBin* bin, const QString& path ) +{ + QStringList files = bin->files(); + for( QStringList::iterator it = files.begin(); + it != files.end(); ++it ) { + if( (*it).contains( "isolinux.cfg" ) ) { + bin->m_supportedBootLabels = determineSupportedBootLabels( QStringList::split( " ", *it )[1] ); + break; + } + } + + // here we simply check for the movix-conf program + if( QFile::exists( path + "movix-conf" ) ) { + bin->addFeature( "newfiles" ); + addBin(bin); + return true; + } + else { + delete bin; + return false; + } +} + + +bool K3bMovixProgram::scanOldEMovix( K3bMovixBin* bin, const QString& path ) +{ + // + // first check if all necessary directories are present + // + QDir dir( bin->movixDataDir() ); + QStringList subdirs = dir.entryList( QDir::Dirs ); + if( !subdirs.contains( "boot-messages" ) ) { + kdDebug() << "(K3bMovixProgram) could not find subdir 'boot-messages'" << endl; + delete bin; + return false; + } + if( !subdirs.contains( "isolinux" ) ) { + kdDebug() << "(K3bMovixProgram) could not find subdir 'isolinux'" << endl; + delete bin; + return false; + } + if( !subdirs.contains( "movix" ) ) { + kdDebug() << "(K3bMovixProgram) could not find subdir 'movix'" << endl; + delete bin; + return false; + } + if( !subdirs.contains( "mplayer-fonts" ) ) { + kdDebug() << "(K3bMovixProgram) could not find subdir 'mplayer-fonts'" << endl; + delete bin; + return false; + } + + + // + // check if we have a version of eMovix which contains the movix-files script + // + if( QFile::exists( path + "movix-files" ) ) { + bin->addFeature( "files" ); + + KProcess p; + K3bProcessOutputCollector out( &p ); + p << bin->path + "movix-files"; + if( p.start( KProcess::Block, KProcess::AllOutput ) ) { + bin->m_movixFiles = QStringList::split( "\n", out.output() ); + } + } + + // + // fallback: to be compatible with 0.8.0rc2 we just add all files in the movix directory + // + if( bin->m_movixFiles.isEmpty() ) { + QDir dir( bin->movixDataDir() + "/movix" ); + bin->m_movixFiles = dir.entryList(QDir::Files); + } + + // + // these files are fixed. That should not be a problem + // since Isolinux is quite stable as far as I know. + // + bin->m_isolinuxFiles.append( "initrd.gz" ); + bin->m_isolinuxFiles.append( "isolinux.bin" ); + bin->m_isolinuxFiles.append( "isolinux.cfg" ); + bin->m_isolinuxFiles.append( "kernel/vmlinuz" ); + bin->m_isolinuxFiles.append( "movix.lss" ); + bin->m_isolinuxFiles.append( "movix.msg" ); + + + // + // check every single necessary file :( + // + for( QStringList::const_iterator it = bin->m_isolinuxFiles.begin(); + it != bin->m_isolinuxFiles.end(); ++it ) { + if( !QFile::exists( bin->movixDataDir() + "/isolinux/" + *it ) ) { + kdDebug() << "(K3bMovixProgram) Could not find file " << *it << endl; + delete bin; + return false; + } + } + + // + // now check the boot-messages languages + // + dir.cd( "boot-messages" ); + bin->m_supportedLanguages = dir.entryList(QDir::Dirs); + bin->m_supportedLanguages.remove("."); + bin->m_supportedLanguages.remove(".."); + bin->m_supportedLanguages.remove("CVS"); // the eMovix makefile stuff seems not perfect ;) + bin->m_supportedLanguages.prepend( i18n("default") ); + dir.cdUp(); + + // + // now check the supported mplayer-fontsets + // FIXME: every font dir needs to contain the "font.desc" file! + // + dir.cd( "mplayer-fonts" ); + bin->m_supportedSubtitleFonts = dir.entryList( QDir::Dirs ); + bin->m_supportedSubtitleFonts.remove("."); + bin->m_supportedSubtitleFonts.remove(".."); + bin->m_supportedSubtitleFonts.remove("CVS"); // the eMovix makefile stuff seems not perfect ;) + // new ttf fonts in 0.8.0rc2 + bin->m_supportedSubtitleFonts += dir.entryList( "*.ttf", QDir::Files ); + bin->m_supportedSubtitleFonts.prepend( i18n("none") ); + dir.cdUp(); + + // + // now check the supported boot labels + // + dir.cd( "isolinux" ); + bin->m_supportedBootLabels = determineSupportedBootLabels( dir.filePath("isolinux.cfg") ); + + // + // This seems to be a valid eMovix installation. :) + // + + addBin(bin); + return true; +} + + +QStringList K3bMovixProgram::determineSupportedBootLabels( const QString& isoConfigFile ) const +{ + QStringList list( i18n("default") ); + + QFile f( isoConfigFile ); + if( !f.open( IO_ReadOnly ) ) { + kdDebug() << "(K3bMovixProgram) could not open file '" << f.name() << "'" << endl; + } + else { + QTextStream fs( &f ); + QString line = fs.readLine(); + while( !line.isNull() ) { + if( line.startsWith( "label" ) ) + list.append( line.mid( 5 ).stripWhiteSpace() ); + + line = fs.readLine(); + } + f.close(); + } + + return list; +} + + +QString K3bMovixBin::subtitleFontDir( const QString& font ) const +{ + if( font == i18n("none" ) ) + return ""; + else if( m_supportedSubtitleFonts.contains( font ) ) + return path + "/mplayer-fonts/" + font; + else + return ""; +} + + +QString K3bMovixBin::languageDir( const QString& lang ) const +{ + if( lang == i18n("default") ) + return languageDir( "en" ); + else if( m_supportedLanguages.contains( lang ) ) + return path + "/boot-messages/" + lang; + else + return ""; +} + + +QStringList K3bMovixBin::supportedSubtitleFonts() const +{ + if( version >= K3bVersion( 0, 9, 0 ) ) + return QStringList( i18n("default") ) += supported( "font" ); + else + return m_supportedSubtitleFonts; +} + + +QStringList K3bMovixBin::supportedLanguages() const +{ + if( version >= K3bVersion( 0, 9, 0 ) ) + return QStringList( i18n("default") ) += supported( "lang" ); + else + return m_supportedLanguages; +} + + +// only used for eMovix >= 0.9.0 +QStringList K3bMovixBin::supportedKbdLayouts() const +{ + return QStringList( i18n("default") ) += supported( "kbd" ); +} + + +// only used for eMovix >= 0.9.0 +QStringList K3bMovixBin::supportedBackgrounds() const +{ + return QStringList( i18n("default") ) += supported( "background" ); +} + + +// only used for eMovix >= 0.9.0 +QStringList K3bMovixBin::supportedCodecs() const +{ + return supported( "codecs" ); +} + + +QStringList K3bMovixBin::supported( const QString& type ) const +{ + KProcess p; + K3bProcessOutputCollector out( &p ); + p << path + "movix-conf" << "--supported=" + type; + if( p.start( KProcess::Block, KProcess::AllOutput ) ) + return QStringList::split( "\n", out.output() ); + else + return QStringList(); +} + + +QStringList K3bMovixBin::files( const QString& kbd, + const QString& font, + const QString& bg, + const QString& lang, + const QStringList& codecs ) const +{ + KProcess p; + K3bProcessOutputCollector out( &p ); + p << path + "movix-conf" << "--files"; + + + if( !kbd.isEmpty() && kbd != i18n("default") ) + p << "--kbd" << kbd; + if( !font.isEmpty() && font != i18n("default") ) + p << "--font" << font; + if( !bg.isEmpty() && bg != i18n("default") ) + p << "--background" << bg; + if( !lang.isEmpty() && lang != i18n("default") ) + p << "--lang" << lang; + if( !codecs.isEmpty() ) + p << "--codecs" << codecs.join( "," ); + + if( p.start( KProcess::Block, KProcess::AllOutput ) ) + return QStringList::split( "\n", out.output() ); + else + return QStringList(); +} diff --git a/libk3b/projects/movixcd/k3bmovixprogram.h b/libk3b/projects/movixcd/k3bmovixprogram.h new file mode 100644 index 0000000..a6a9ac0 --- /dev/null +++ b/libk3b/projects/movixcd/k3bmovixprogram.h @@ -0,0 +1,103 @@ +/* + * + * $Id: k3bmovixprogram.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_MOVIX_PROGRAM_H_ +#define _K3B_MOVIX_PROGRAM_H_ + +#include +#include "k3b_export.h" + +class LIBK3B_EXPORT K3bMovixBin : public K3bExternalBin +{ + public: + K3bMovixBin( K3bExternalProgram* p ) + : K3bExternalBin( p ) { + } + + const QString& movixDataDir() const { return m_movixPath; } + + const QStringList& supportedBootLabels() const { return m_supportedBootLabels; } + QStringList supportedSubtitleFonts() const; + QStringList supportedLanguages() const; + QStringList supportedKbdLayouts() const; + QStringList supportedBackgrounds() const; + QStringList supportedCodecs() const; + + /* + * Unused for eMovix versions 0.9.0 and above + */ + const QStringList& movixFiles() const { return m_movixFiles; } + + /* + * Unused for eMovix versions 0.9.0 and above + */ + const QStringList& isolinuxFiles() const { return m_isolinuxFiles; } + + /** + * returnes empty string if font was not found + * + * Unused for eMovix versions 0.9.0 and above + */ + QString subtitleFontDir( const QString& font ) const; + + /** + * returnes empty string if lang was not found + * + * Unused for eMovix versions 0.9.0 and above + */ + QString languageDir( const QString& lang ) const; + + /** + * Interface for the movix-conf --files interface for + * versions >= 0.9.0 + */ + QStringList files( const QString& kbd = QString::null, + const QString& font = QString::null, + const QString& bg = QString::null, + const QString& lang = QString::null, + const QStringList& codecs = QStringList() ) const; + + private: + QStringList supported( const QString& ) const; + + QString m_movixPath; + QStringList m_movixFiles; + QStringList m_isolinuxFiles; + QStringList m_supportedBootLabels; + QStringList m_supportedSubtitleFonts; + QStringList m_supportedLanguages; + + friend class K3bMovixProgram; +}; + + +class LIBK3B_EXPORT K3bMovixProgram : public K3bExternalProgram +{ + public: + K3bMovixProgram(); + + bool scan( const QString& ); + + bool supportsUserParameters() const { return false; } + + private: + bool scanNewEMovix( K3bMovixBin* bin, const QString& ); + bool scanOldEMovix( K3bMovixBin* bin, const QString& ); + QStringList determineSupportedBootLabels( const QString& ) const; +}; + + + +#endif diff --git a/libk3b/projects/movixdvd/Makefile.am b/libk3b/projects/movixdvd/Makefile.am new file mode 100644 index 0000000..7af7283 --- /dev/null +++ b/libk3b/projects/movixdvd/Makefile.am @@ -0,0 +1,21 @@ +# we need the ../datacd and ../movixcd for the uic generated header files +AM_CPPFLAGS= -I$(srcdir)/../../core \ + -I$(srcdir)/../../../libk3bdevice \ + -I$(srcdir)/../../../src \ + -I$(srcdir)/../../tools \ + -I$(srcdir)/../datadvd \ + -I$(srcdir)/../movixcd \ + -I$(srcdir)/../datacd \ + -I$(srcdir)/.. \ + -I../datacd \ + -I../movixcd \ + $(all_includes) + +METASOURCES = AUTO + +noinst_LTLIBRARIES = libmovixdvd.la + +libmovixdvd_la_SOURCES = k3bmovixdvddoc.cpp k3bmovixdvdjob.cpp + +include_HEADERS = k3bmovixdvddoc.h \ + k3bmovixdvdjob.h diff --git a/libk3b/projects/movixdvd/k3bmovixdvddoc.cpp b/libk3b/projects/movixdvd/k3bmovixdvddoc.cpp new file mode 100644 index 0000000..80b8ec2 --- /dev/null +++ b/libk3b/projects/movixdvd/k3bmovixdvddoc.cpp @@ -0,0 +1,36 @@ +/* + * + * $Id: k3bmovixdvddoc.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bmovixdvddoc.h" +#include "k3bmovixdvdjob.h" + +#include + + +K3bMovixDvdDoc::K3bMovixDvdDoc( QObject* parent ) + : K3bMovixDoc( parent ) +{ +} + +K3bMovixDvdDoc::~K3bMovixDvdDoc() +{ +} + +K3bBurnJob* K3bMovixDvdDoc::newBurnJob( K3bJobHandler* hdl, QObject* parent ) +{ + return new K3bMovixDvdJob( this, hdl, parent ); +} + +#include "k3bmovixdvddoc.moc" diff --git a/libk3b/projects/movixdvd/k3bmovixdvddoc.h b/libk3b/projects/movixdvd/k3bmovixdvddoc.h new file mode 100644 index 0000000..85943f0 --- /dev/null +++ b/libk3b/projects/movixdvd/k3bmovixdvddoc.h @@ -0,0 +1,40 @@ +/* + * + * $Id: k3bmovixdvddoc.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_MOVIX_DVD_DOC_H_ +#define _K3B_MOVIX_DVD_DOC_H_ + +#include +#include "k3b_export.h" +class KConfig; + + +class LIBK3B_EXPORT K3bMovixDvdDoc : public K3bMovixDoc +{ + Q_OBJECT + + public: + K3bMovixDvdDoc( QObject* parent = 0 ); + ~K3bMovixDvdDoc(); + + int type() const { return MOVIX_DVD; } + + K3bBurnJob* newBurnJob( K3bJobHandler* hdl, QObject* parent ); + + protected: + QString typeString() const { return "movixdvd"; } +}; + +#endif diff --git a/libk3b/projects/movixdvd/k3bmovixdvdjob.cpp b/libk3b/projects/movixdvd/k3bmovixdvdjob.cpp new file mode 100644 index 0000000..b556997 --- /dev/null +++ b/libk3b/projects/movixdvd/k3bmovixdvdjob.cpp @@ -0,0 +1,131 @@ +/* + * + * $Id: k3bmovixdvdjob.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bmovixdvdjob.h" +#include "k3bmovixdvddoc.h" +#include "k3bmovixfileitem.h" +#include "k3bmovixdocpreparer.h" + +#include +#include +#include + +#include +#include + + +K3bMovixDvdJob::K3bMovixDvdJob( K3bMovixDvdDoc* doc, K3bJobHandler* jh, QObject* parent ) + : K3bBurnJob( jh, parent ), + m_doc(doc) +{ + m_dvdJob = new K3bDvdJob( doc, this, this ); + m_movixDocPreparer = new K3bMovixDocPreparer( doc, this, this ); + + // pipe signals + connect( m_dvdJob, SIGNAL(percent(int)), this, SIGNAL(percent(int)) ); + connect( m_dvdJob, SIGNAL(subPercent(int)), this, SIGNAL(subPercent(int)) ); + connect( m_dvdJob, SIGNAL(processedSubSize(int, int)), this, SIGNAL(processedSubSize(int, int)) ); + connect( m_dvdJob, SIGNAL(processedSize(int, int)), this, SIGNAL(processedSize(int, int)) ); + connect( m_dvdJob, SIGNAL(bufferStatus(int)), this, SIGNAL(bufferStatus(int)) ); + connect( m_dvdJob, SIGNAL(writeSpeed(int, int)), this, SIGNAL(writeSpeed(int, int)) ); + connect( m_dvdJob, SIGNAL(newTask(const QString&)), this, SIGNAL(newTask(const QString&)) ); + connect( m_dvdJob, SIGNAL(newSubTask(const QString&)), this, SIGNAL(newSubTask(const QString&)) ); + connect( m_dvdJob, SIGNAL(debuggingOutput(const QString&, const QString&)), + this, SIGNAL(debuggingOutput(const QString&, const QString&)) ); + connect( m_dvdJob, SIGNAL(infoMessage(const QString&, int)), + this, SIGNAL(infoMessage(const QString&, int)) ); + connect( m_dvdJob, SIGNAL(burning(bool)), this, SIGNAL(burning(bool)) ); + + // we need to clean up here + connect( m_dvdJob, SIGNAL(finished(bool)), this, SLOT(slotDvdJobFinished(bool)) ); + + connect( m_movixDocPreparer, SIGNAL(infoMessage(const QString&, int)), + this, SIGNAL(infoMessage(const QString&, int)) ); +} + + +K3bMovixDvdJob::~K3bMovixDvdJob() +{ +} + + +K3bDevice::Device* K3bMovixDvdJob::writer() const +{ + return m_dvdJob->writer(); +} + + +K3bDoc* K3bMovixDvdJob::doc() const +{ + return m_doc; +} + + +void K3bMovixDvdJob::start() +{ + jobStarted(); + + m_canceled = false; + m_dvdJob->setWritingApp( writingApp() ); + + if( m_movixDocPreparer->createMovixStructures() ) { + m_dvdJob->start(); + } + else { + m_movixDocPreparer->removeMovixStructures(); + jobFinished(false); + } +} + + +void K3bMovixDvdJob::cancel() +{ + m_canceled = true; + m_dvdJob->cancel(); +} + + +void K3bMovixDvdJob::slotDvdJobFinished( bool success ) +{ + m_movixDocPreparer->removeMovixStructures(); + + if( m_canceled || m_dvdJob->hasBeenCanceled() ) + emit canceled(); + + jobFinished( success ); +} + + +QString K3bMovixDvdJob::jobDescription() const +{ + if( m_doc->isoOptions().volumeID().isEmpty() ) + return i18n("Writing eMovix DVD"); + else + return i18n("Writing eMovix DVD (%1)").arg(m_doc->isoOptions().volumeID()); +} + + +QString K3bMovixDvdJob::jobDetails() const +{ + return ( i18n("1 file (%1) and about 8 MB eMovix data", + "%n files (%1) and about 8 MB eMovix data", + m_doc->movixFileItems().count()).arg(KIO::convertSize(m_doc->size())) + + ( m_doc->copies() > 1 + ? i18n(" - %n copy", " - %n copies", m_doc->copies()) + : QString::null ) ); +} + +#include "k3bmovixdvdjob.moc" diff --git a/libk3b/projects/movixdvd/k3bmovixdvdjob.h b/libk3b/projects/movixdvd/k3bmovixdvdjob.h new file mode 100644 index 0000000..2b9ce10 --- /dev/null +++ b/libk3b/projects/movixdvd/k3bmovixdvdjob.h @@ -0,0 +1,60 @@ +/* + * + * $Id: k3bmovixdvdjob.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_MOVIX_DVD_JOB_H_ +#define _K3B_MOVIX_DVD_JOB_H_ + +#include + +class K3bMovixDvdDoc; +class K3bDevice::Device; +class K3bDvdJob; +class KTempFile; +class K3bMovixInstallation; +class K3bMovixDocPreparer; +class K3bDirItem; +class K3bFileItem; + +class K3bMovixDvdJob : public K3bBurnJob +{ + Q_OBJECT + + public: + K3bMovixDvdJob( K3bMovixDvdDoc* doc, K3bJobHandler*, QObject* parent = 0 ); + ~K3bMovixDvdJob(); + + K3bDoc* doc() const; + K3bDevice::Device* writer() const; + + QString jobDescription() const; + QString jobDetails() const; + + public slots: + void start(); + void cancel(); + + private slots: + void slotDvdJobFinished( bool ); + + private: + K3bMovixDvdDoc* m_doc; + K3bDvdJob* m_dvdJob; + K3bMovixDocPreparer* m_movixDocPreparer; + + bool m_canceled; +}; + +#endif diff --git a/libk3b/projects/videocd/Makefile.am b/libk3b/projects/videocd/Makefile.am new file mode 100644 index 0000000..1e18d02 --- /dev/null +++ b/libk3b/projects/videocd/Makefile.am @@ -0,0 +1,20 @@ +AM_CPPFLAGS= -I$(srcdir)/../../core \ + -I$(srcdir)/../../../src \ + -I$(srcdir)/../../../libk3bdevice \ + -I$(srcdir)/../../tools \ + -I$(srcdir)/.. \ + $(all_includes) + +METASOURCES = AUTO + +noinst_LTLIBRARIES = libvcd.la + +libvcd_la_SOURCES = k3bvcddoc.cpp k3bvcdtrack.cpp k3bvcdjob.cpp k3bvcdoptions.cpp k3bvcdxmlview.cpp + +libvcd_la_LIBADD = mpeginfo/libmpeginfo.la + +SUBDIRS = cdi extra mpeginfo + +include_HEADERS = k3bvcdjob.h \ + k3bvcddoc.h \ + k3bvcdoptions.h diff --git a/libk3b/projects/videocd/cdi/Makefile.am b/libk3b/projects/videocd/cdi/Makefile.am new file mode 100644 index 0000000..e487acc --- /dev/null +++ b/libk3b/projects/videocd/cdi/Makefile.am @@ -0,0 +1,5 @@ + +cdidir = $(kde_datadir)/k3b/cdi +cdi_DATA = cdi_imag.rtf cdi_text.fnt cdi_vcd.app cdi_vcd.cfg vcd_on_cdi_41.pdf icdia.htm + +EXTRA_DIST = $(cdi_DATA) diff --git a/libk3b/projects/videocd/cdi/cdi_imag.rtf b/libk3b/projects/videocd/cdi/cdi_imag.rtf new file mode 100644 index 0000000..809145f Binary files /dev/null and b/libk3b/projects/videocd/cdi/cdi_imag.rtf differ diff --git a/libk3b/projects/videocd/cdi/cdi_text.fnt b/libk3b/projects/videocd/cdi/cdi_text.fnt new file mode 100644 index 0000000..0dd0e15 Binary files /dev/null and b/libk3b/projects/videocd/cdi/cdi_text.fnt differ diff --git a/libk3b/projects/videocd/cdi/cdi_vcd.app b/libk3b/projects/videocd/cdi/cdi_vcd.app new file mode 100644 index 0000000..ceb31fc Binary files /dev/null and b/libk3b/projects/videocd/cdi/cdi_vcd.app differ diff --git a/libk3b/projects/videocd/cdi/cdi_vcd.cfg b/libk3b/projects/videocd/cdi/cdi_vcd.cfg new file mode 100644 index 0000000..4aed0eb --- /dev/null +++ b/libk3b/projects/videocd/cdi/cdi_vcd.cfg @@ -0,0 +1,12 @@ +CONTROLS=ALL +CURCOL=YELLOW +PSDCURCOL=RED +PSDCURSHAPE=ARROW +CENTRTRACK=2 +AUTOPLAY=AUTO_ON +DUALCHAN=DUAL_ON +TIMECODE_X=64 +TIMECODE_Y=100 +LOTID_X=64 +LOTID_Y=64 +ALBUM=STANDARD \ No newline at end of file diff --git a/libk3b/projects/videocd/cdi/icdia.htm b/libk3b/projects/videocd/cdi/icdia.htm new file mode 100644 index 0000000..cd6c47b --- /dev/null +++ b/libk3b/projects/videocd/cdi/icdia.htm @@ -0,0 +1,12 @@ + + + + +The New International CD-i Association + + + +The New International CD-i Association - http://www.icdia.org + + + diff --git a/libk3b/projects/videocd/cdi/vcd_on_cdi_41.pdf b/libk3b/projects/videocd/cdi/vcd_on_cdi_41.pdf new file mode 100644 index 0000000..cdf4fed Binary files /dev/null and b/libk3b/projects/videocd/cdi/vcd_on_cdi_41.pdf differ diff --git a/libk3b/projects/videocd/extra/Makefile.am b/libk3b/projects/videocd/extra/Makefile.am new file mode 100644 index 0000000..717fa99 --- /dev/null +++ b/libk3b/projects/videocd/extra/Makefile.am @@ -0,0 +1,5 @@ + +extradir = $(kde_datadir)/k3b/extra +extra_DATA = k3bphotovcd.mpg k3bphotosvcd.mpg + +EXTRA_DIST = $(extra_DATA) diff --git a/libk3b/projects/videocd/extra/k3bphotosvcd.mpg b/libk3b/projects/videocd/extra/k3bphotosvcd.mpg new file mode 100644 index 0000000..50156d7 Binary files /dev/null and b/libk3b/projects/videocd/extra/k3bphotosvcd.mpg differ diff --git a/libk3b/projects/videocd/extra/k3bphotovcd.mpg b/libk3b/projects/videocd/extra/k3bphotovcd.mpg new file mode 100644 index 0000000..2ddb69e Binary files /dev/null and b/libk3b/projects/videocd/extra/k3bphotovcd.mpg differ diff --git a/libk3b/projects/videocd/k3bvcddoc.cpp b/libk3b/projects/videocd/k3bvcddoc.cpp new file mode 100644 index 0000000..462aea3 --- /dev/null +++ b/libk3b/projects/videocd/k3bvcddoc.cpp @@ -0,0 +1,894 @@ +/* +* +* $Id: k3bvcddoc.cpp 619556 2007-01-03 17:38:12Z trueg $ +* Copyright (C) 2003-2005 Christian Kvasny +* +* This file is part of the K3b project. +* Copyright (C) 1998-2007 Sebastian Trueg +* +* 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 2 of the License, or +* (at your option) any later version. +* See the file "COPYING" for the exact licensing terms. +*/ + +// QT-includes +#include +#include +#include +#include +#include +#include +#include +#include + +// KDE-includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// K3b-includes +#include "k3bvcddoc.h" +#include "k3bvcdtrack.h" +#include "k3bvcdjob.h" +#include +#include + + +bool desperate_mode = false; +bool preserve_header = false; +bool print_progress = true; +bool aspect_correction = false; +byte forced_sequence_header = 0; + +K3bVcdDoc::K3bVcdDoc( QObject* parent ) + : K3bDoc( parent ) +{ + m_tracks = 0L; + m_vcdOptions = new K3bVcdOptions(); + + m_docType = VCD; + m_vcdType = NONE; + + m_urlAddingTimer = new QTimer( this ); + connect( m_urlAddingTimer, SIGNAL( timeout() ), this, SLOT( slotWorkUrlQueue() ) ); + + // FIXME: remove the newTracks() signal and replace it with the changed signal + connect( this, SIGNAL( newTracks() ), this, SIGNAL( changed() ) ); + connect( this, SIGNAL( trackRemoved( K3bVcdTrack* ) ), this, SIGNAL( changed() ) ); +} + +K3bVcdDoc::~K3bVcdDoc() +{ + if ( m_tracks ) { + m_tracks->setAutoDelete( true ); + delete m_tracks; + } + + delete m_vcdOptions; +} + +bool K3bVcdDoc::newDocument() +{ + if ( m_tracks ) + while ( m_tracks->first() ) + removeTrack( m_tracks->first() ); + else + m_tracks = new QPtrList; + m_tracks->setAutoDelete( false ); + + return K3bDoc::newDocument(); +} + + +QString K3bVcdDoc::name() const +{ + return m_vcdOptions->volumeId(); +} + + +KIO::filesize_t K3bVcdDoc::calcTotalSize() const +{ + unsigned long long sum = 0; + if ( m_tracks ) { + for ( K3bVcdTrack * track = m_tracks->first(); track; track = m_tracks->next() ) { + sum += track->size(); + } + } + return sum; +} + +KIO::filesize_t K3bVcdDoc::size() const +{ + // mode2 -> mode1 int(( n+2047 ) / 2048) * 2352 + // mode1 -> mode2 int(( n+2351 ) / 2352) * 2048 + long tracksize = long( ( calcTotalSize() + 2351 ) / 2352 ) * 2048; + return tracksize + ISOsize(); +} + +KIO::filesize_t K3bVcdDoc::ISOsize() const +{ + // 136000b for vcd iso reseved + long long iso_size = 136000; + if ( vcdOptions() ->CdiSupport() ) { + iso_size += vcdOptions() ->CDIsize(); + } + + return iso_size; +} + +K3b::Msf K3bVcdDoc::length() const +{ + return K3b::Msf( size() / 2048 ); +} + + +bool K3bVcdDoc::isImage( const KURL& url ) +{ + QImage p; + return p.load( QFile::encodeName( url.path() ) ); +} + +void K3bVcdDoc::addUrls( const KURL::List& urls ) +{ + // make sure we add them at the end even if urls are in the queue + addTracks( urls, 99 ); +} + +void K3bVcdDoc::addTracks( const KURL::List& urls, uint position ) +{ + KURL::List::ConstIterator end( urls.end() ); + for ( KURL::List::ConstIterator it = urls.begin(); it != end; ++it ) { + urlsToAdd.enqueue( new PrivateUrlToAdd( K3b::convertToLocalUrl(*it), position++ ) ); + } + + m_urlAddingTimer->start( 0 ); +} + +void K3bVcdDoc::slotWorkUrlQueue() +{ + if ( !urlsToAdd.isEmpty() ) { + PrivateUrlToAdd * item = urlsToAdd.dequeue(); + lastAddedPosition = item->position; + + // append at the end by default + if ( lastAddedPosition > m_tracks->count() ) + lastAddedPosition = m_tracks->count(); + + if ( !item->url.isLocalFile() ) { + kdDebug() << item->url.path() << " no local file" << endl; + return ; + } + + if ( !QFile::exists( item->url.path() ) ) { + kdDebug() << "(K3bVcdDoc) file not found: " << item->url.path() << endl; + m_notFoundFiles.append( item->url.path() ); + return ; + } + + if ( K3bVcdTrack * newTrack = createTrack( item->url ) ) + addTrack( newTrack, lastAddedPosition ); + + delete item; + + emit newTracks(); + } else { + m_urlAddingTimer->stop(); + + emit newTracks(); + + // reorder pbc tracks + setPbcTracks(); + + informAboutNotFoundFiles(); + } +} + +K3bVcdTrack* K3bVcdDoc::createTrack( const KURL& url ) +{ + char filename[ 255 ]; + QString error_string = ""; + strcpy( filename, QFile::encodeName( url.path() ) ); + K3bMpegInfo* Mpeg = new K3bMpegInfo( filename ); + + if ( Mpeg ) { + int mpegVersion = Mpeg->version(); + if ( mpegVersion > 0 ) { + + if ( vcdType() == NONE && mpegVersion < 2 ) { + m_urlAddingTimer->stop(); + setVcdType( vcdTypes( mpegVersion ) ); + vcdOptions() ->setMpegVersion( mpegVersion ); + KMessageBox::information( kapp->mainWidget(), + i18n( "K3b will create a %1 image from the given MPEG " + "files, but these files must already be in %2 " + "format. K3b does not yet resample MPEG files." ) + .arg( i18n( "VCD" ) ) + .arg( i18n( "VCD" ) ), + i18n( "Information" ) ); + m_urlAddingTimer->start( 0 ); + } else if ( vcdType() == NONE ) { + m_urlAddingTimer->stop(); + vcdOptions() ->setMpegVersion( mpegVersion ); + bool force = false; + force = ( KMessageBox::questionYesNo( kapp->mainWidget(), + i18n( "K3b will create a %1 image from the given MPEG " + "files, but these files must already be in %2 " + "format. K3b does not yet resample MPEG files." ) + .arg( i18n( "SVCD" ) ) + .arg( i18n( "SVCD" ) ) + + "\n\n" + + i18n( "Note: Forcing MPEG2 as VCD is not supported by " + "some standalone DVD players." ), + i18n( "Information" ), + KStdGuiItem::ok().text(), + i18n( "Forcing VCD" ) ) == KMessageBox::No ); + if ( force ) { + setVcdType( vcdTypes( 1 ) ); + vcdOptions() ->setAutoDetect( false ); + } else + setVcdType( vcdTypes( mpegVersion ) ); + + m_urlAddingTimer->start( 0 ); + } + + + if ( numOfTracks() > 0 && vcdOptions() ->mpegVersion() != mpegVersion ) { + KMessageBox::error( kapp->mainWidget(), "(" + url.path() + ")\n" + + i18n( "You cannot mix MPEG1 and MPEG2 video files.\nPlease start a new Project for this filetype.\nResample not implemented in K3b yet." ), + i18n( "Wrong File Type for This Project" ) ); + + delete Mpeg; + return 0; + } + + K3bVcdTrack* newTrack = new K3bVcdTrack( m_tracks, url.path() ); + *( newTrack->mpeg_info ) = *( Mpeg->mpeg_info ); + + if ( newTrack->isSegment() && !vcdOptions()->PbcEnabled() ) { + KMessageBox::information( kapp->mainWidget(), + i18n( "PBC (Playback control) enabled.\n" + "Videoplayers can not reach Segments (Mpeg Still Pictures) without Playback control ." ) , + i18n( "Information" ) ); + + vcdOptions()->setPbcEnabled( true ); + } + + // set defaults; + newTrack->setPlayTime( vcdOptions() ->PbcPlayTime() ); + newTrack->setWaitTime( vcdOptions() ->PbcWaitTime() ); + newTrack->setPbcNumKeys( vcdOptions() ->PbcNumkeysEnabled() ); + delete Mpeg; + + // debugging output + newTrack->PrintInfo(); + + return newTrack; + } + } else if ( isImage( url ) ) { // image track + // woking on ... + // for future use + // photoalbum starts here + // return here the new photoalbum track + } + + if ( Mpeg ) { + error_string = Mpeg->error_string(); + delete Mpeg; + } + + // error (unsupported files) + KMessageBox::error( kapp->mainWidget(), "(" + url.path() + ")\n" + + i18n( "Only MPEG1 and MPEG2 video files are supported.\n" ) + error_string , + i18n( "Wrong File Format" ) ); + + + return 0; +} + +void K3bVcdDoc::addTrack( const KURL& url, uint position ) +{ + urlsToAdd.enqueue( new PrivateUrlToAdd( url, position ) ); + + m_urlAddingTimer->start( 0 ); +} + + +void K3bVcdDoc::addTrack( K3bVcdTrack* track, uint position ) +{ + if ( m_tracks->count() >= 98 ) { + kdDebug() << "(K3bVcdDoc) VCD Green Book only allows 98 tracks." << endl; + // TODO: show some messagebox + delete track; + return ; + } + + lastAddedPosition = position; + + if ( !m_tracks->insert( position, track ) ) { + lastAddedPosition = m_tracks->count(); + m_tracks->insert( m_tracks->count(), track ); + } + + if ( track->isSegment() ) + vcdOptions() ->increaseSegments( ); + else + vcdOptions() ->increaseSequence( ); + + emit newTracks(); + + setModified( true ); +} + + +void K3bVcdDoc::removeTrack( K3bVcdTrack* track ) +{ + if ( !track ) { + return ; + } + + // set the current item to track + if ( m_tracks->findRef( track ) >= 0 ) { + // take the current item + track = m_tracks->take(); + + // remove all pbc references to us? + if ( track->hasRevRef() ) + track->delRefToUs(); + + // remove all pbc references from us? + track->delRefFromUs(); + + // emit signal before deleting the track to avoid crashes + // when the view tries to call some of the tracks' methods + emit trackRemoved( track ); + + if ( track->isSegment() ) + vcdOptions() ->decreaseSegments( ); + else + vcdOptions() ->decreaseSequence( ); + + delete track; + + if ( numOfTracks() == 0 ) { + setVcdType( NONE ); + vcdOptions() ->setAutoDetect( true ); + } + + // reorder pbc tracks + setPbcTracks(); + } +} + +void K3bVcdDoc::moveTrack( const K3bVcdTrack* track, const K3bVcdTrack* after ) +{ + if ( track == after ) + return ; + + // set the current item to track + m_tracks->findRef( track ); + // take the current item + track = m_tracks->take(); + + // if after == 0 findRef returnes -1 + int pos = m_tracks->findRef( after ); + m_tracks->insert( pos + 1, track ); + + // reorder pbc tracks + setPbcTracks(); + + emit changed(); +} + + +QString K3bVcdDoc::typeString() const +{ + return "vcd"; +} + + +K3bBurnJob* K3bVcdDoc::newBurnJob( K3bJobHandler* hdl, QObject* parent ) +{ + return new K3bVcdJob( this, hdl, parent ); +} + +void K3bVcdDoc::informAboutNotFoundFiles() +{ + if ( !m_notFoundFiles.isEmpty() ) { + KMessageBox::informationList( view(), i18n( "Could not find the following files:" ), + m_notFoundFiles, i18n( "Not Found" ) ); + + m_notFoundFiles.clear(); + } +} + +void K3bVcdDoc::setVcdType( int type ) +{ + m_vcdType = type; + switch ( type ) { + case 0: + //vcd 1.1 + vcdOptions() ->setVcdClass( "vcd" ); + vcdOptions() ->setVcdVersion( "1.1" ); + break; + case 1: + //vcd 2.0 + vcdOptions() ->setVcdClass( "vcd" ); + vcdOptions() ->setVcdVersion( "2.0" ); + break; + case 2: + //svcd 1.0 + vcdOptions() ->setVcdClass( "svcd" ); + vcdOptions() ->setVcdVersion( "1.0" ); + break; + case 3: + //hqvcd 1.0 + vcdOptions() ->setVcdClass( "hqvcd" ); + vcdOptions() ->setVcdVersion( "1.0" ); + break; + + } +} + +void K3bVcdDoc::setPbcTracks() +{ + // reorder pbc tracks + /* + if ( !vcdOptions()->PbcEnabled() ) + return; + */ + + if ( m_tracks ) { + int count = m_tracks->count(); + kdDebug() << QString( "K3bVcdDoc::setPbcTracks() - we have %1 tracks in list." ).arg( count ) << endl; + + QPtrListIterator iterTrack( *m_tracks ); + K3bVcdTrack* track; + while ( ( track = iterTrack.current() ) != 0 ) { + ++iterTrack; + for ( int i = 0; i < K3bVcdTrack::_maxPbcTracks; i++ ) { + // do not change userdefined tracks + if ( !track->isPbcUserDefined( i ) ) { + if ( track->getPbcTrack( i ) ) + track->getPbcTrack( i ) ->delFromRevRefList( track ); + + K3bVcdTrack* t = 0L; + int index = track->index(); + + // we are the last track + if ( index == count - 1 ) { + switch ( i ) { + case K3bVcdTrack::PREVIOUS: + // we are not alone :) + if ( count > 1 ) { + t = at( index - 1 ); + t->addToRevRefList( track ); + track->setPbcTrack( i, t ); + } else { + track->setPbcTrack( i ); + track->setPbcNonTrack( i, K3bVcdTrack::VIDEOEND ); + } + break; + case K3bVcdTrack::AFTERTIMEOUT: + case K3bVcdTrack::NEXT: + track->setPbcTrack( i ); + track->setPbcNonTrack( i, K3bVcdTrack::VIDEOEND ); + break; + case K3bVcdTrack::RETURN: + track->setPbcTrack( i ); + track->setPbcNonTrack( i, K3bVcdTrack::VIDEOEND ); + break; + case K3bVcdTrack::DEFAULT: + track->setPbcTrack( i ); + track->setPbcNonTrack( i, K3bVcdTrack::DISABLED ); + break; + } + } + // we are the first track + else if ( index == 0 ) { + switch ( i ) { + case K3bVcdTrack::PREVIOUS: + track->setPbcTrack( i ); + track->setPbcNonTrack( i, K3bVcdTrack::VIDEOEND ); + break; + case K3bVcdTrack::AFTERTIMEOUT: + case K3bVcdTrack::NEXT: + t = at( index + 1 ); + t->addToRevRefList( track ); + track->setPbcTrack( i, t ); + break; + case K3bVcdTrack::RETURN: + track->setPbcTrack( i ); + track->setPbcNonTrack( i, K3bVcdTrack::VIDEOEND ); + break; + case K3bVcdTrack::DEFAULT: + track->setPbcTrack( i ); + track->setPbcNonTrack( i, K3bVcdTrack::DISABLED ); + break; + } + } + // we are one of the other tracks and have PREVIOUS and NEXT Track + else { + switch ( i ) { + case K3bVcdTrack::PREVIOUS: + t = at( index - 1 ); + t->addToRevRefList( track ); + track->setPbcTrack( i, t ); + break; + case K3bVcdTrack::AFTERTIMEOUT: + case K3bVcdTrack::NEXT: + t = at( index + 1 ); + t->addToRevRefList( track ); + track->setPbcTrack( i, t ); + break; + case K3bVcdTrack::RETURN: + track->setPbcTrack( i ); + track->setPbcNonTrack( i, K3bVcdTrack::VIDEOEND ); + break; + case K3bVcdTrack::DEFAULT: + track->setPbcTrack( i ); + track->setPbcNonTrack( i, K3bVcdTrack::DISABLED ); + break; + } + } + } + } + } + } +} + + +bool K3bVcdDoc::loadDocumentData( QDomElement* root ) +{ + newDocument(); + + QDomNodeList nodes = root->childNodes(); + + if ( nodes.length() < 3 ) + return false; + + if ( nodes.item( 0 ).nodeName() != "general" ) + return false; + if ( !readGeneralDocumentData( nodes.item( 0 ).toElement() ) ) + return false; + + if ( nodes.item( 1 ).nodeName() != "vcd" ) + return false; + + if ( nodes.item( 2 ).nodeName() != "contents" ) + return false; + + + // vcd Label + QDomNodeList vcdNodes = nodes.item( 1 ).childNodes(); + + for ( uint i = 0; i < vcdNodes.count(); i++ ) { + QDomNode item = vcdNodes.item( i ); + QString name = item.nodeName(); + + kdDebug() << QString( "(K3bVcdDoc::loadDocumentData) nodeName = '%1'" ).arg( name ) << endl; + + if ( name == "volumeId" ) + vcdOptions() ->setVolumeId( item.toElement().text() ); + else if ( name == "albumId" ) + vcdOptions() ->setAlbumId( item.toElement().text() ); + else if ( name == "volumeSetId" ) + vcdOptions() ->setVolumeSetId( item.toElement().text() ); + else if ( name == "preparer" ) + vcdOptions() ->setPreparer( item.toElement().text() ); + else if ( name == "publisher" ) + vcdOptions() ->setPublisher( item.toElement().text() ); + else if ( name == "vcdType" ) + setVcdType( vcdTypes( item.toElement().text().toInt() ) ); + else if ( name == "mpegVersion" ) + vcdOptions() ->setMpegVersion( item.toElement().text().toInt() ); + else if ( name == "PreGapLeadout" ) + vcdOptions() ->setPreGapLeadout( item.toElement().text().toInt() ); + else if ( name == "PreGapTrack" ) + vcdOptions() ->setPreGapTrack( item.toElement().text().toInt() ); + else if ( name == "FrontMarginTrack" ) + vcdOptions() ->setFrontMarginTrack( item.toElement().text().toInt() ); + else if ( name == "RearMarginTrack" ) + vcdOptions() ->setRearMarginTrack( item.toElement().text().toInt() ); + else if ( name == "FrontMarginTrackSVCD" ) + vcdOptions() ->setFrontMarginTrackSVCD( item.toElement().text().toInt() ); + else if ( name == "RearMarginTrackSVCD" ) + vcdOptions() ->setRearMarginTrackSVCD( item.toElement().text().toInt() ); + else if ( name == "volumeCount" ) + vcdOptions() ->setVolumeCount( item.toElement().text().toInt() ); + else if ( name == "volumeNumber" ) + vcdOptions() ->setVolumeNumber( item.toElement().text().toInt() ); + else if ( name == "AutoDetect" ) + vcdOptions() ->setAutoDetect( item.toElement().text().toInt() ); + else if ( name == "CdiSupport" ) + vcdOptions() ->setCdiSupport( item.toElement().text().toInt() ); + else if ( name == "NonCompliantMode" ) + vcdOptions() ->setNonCompliantMode( item.toElement().text().toInt() ); + else if ( name == "Sector2336" ) + vcdOptions() ->setSector2336( item.toElement().text().toInt() ); + else if ( name == "UpdateScanOffsets" ) + vcdOptions() ->setUpdateScanOffsets( item.toElement().text().toInt() ); + else if ( name == "RelaxedAps" ) + vcdOptions() ->setRelaxedAps( item.toElement().text().toInt() ); + else if ( name == "UseGaps" ) + vcdOptions() ->setUseGaps( item.toElement().text().toInt() ); + else if ( name == "PbcEnabled" ) + vcdOptions() ->setPbcEnabled( item.toElement().text().toInt() ); + else if ( name == "SegmentFolder" ) + vcdOptions() ->setSegmentFolder( item.toElement().text().toInt() ); + else if ( name == "Restriction" ) + vcdOptions() ->setRestriction( item.toElement().text().toInt() ); + } + + // vcd Tracks + QDomNodeList trackNodes = nodes.item( 2 ).childNodes(); + + for ( uint i = 0; i < trackNodes.length(); i++ ) { + + // check if url is available + QDomElement trackElem = trackNodes.item( i ).toElement(); + QString url = trackElem.attributeNode( "url" ).value(); + if ( !QFile::exists( url ) ) + m_notFoundFiles.append( url ); + else { + KURL k; + k.setPath( url ); + if ( K3bVcdTrack * track = createTrack( k ) ) { + track ->setPlayTime( trackElem.attribute( "playtime", "1" ).toInt() ); + track ->setWaitTime( trackElem.attribute( "waittime", "2" ).toInt() ); + track ->setReactivity( trackElem.attribute( "reactivity", "0" ).toInt() ); + track -> setPbcNumKeys( ( trackElem.attribute( "numkeys", "yes" ).contains( "yes" ) ) ? true : false ); + track -> setPbcNumKeysUserdefined( ( trackElem.attribute( "userdefinednumkeys", "no" ).contains( "yes" ) ) ? true : false ); + + addTrack( track, m_tracks->count() ); + } + } + } + + emit newTracks(); + + // do not add saved pbcTrack links when one ore more files missing. + // TODO: add info message to informAboutNotFoundFiles(); + if ( m_notFoundFiles.isEmpty() ) { + int type; + int val; + bool pbctrack; + for ( uint trackId = 0; trackId < trackNodes.length(); trackId++ ) { + QDomElement trackElem = trackNodes.item( trackId ).toElement(); + QDomNodeList trackNodes = trackElem.childNodes(); + for ( uint i = 0; i < trackNodes.length(); i++ ) { + QDomElement trackElem = trackNodes.item( i ).toElement(); + QString name = trackElem.tagName(); + if ( name.contains( "pbc" ) ) { + if ( trackElem.hasAttribute ( "type" ) ) { + type = trackElem.attribute ( "type" ).toInt(); + if ( trackElem.hasAttribute ( "pbctrack" ) ) { + pbctrack = ( trackElem.attribute ( "pbctrack" ) == "yes" ); + if ( trackElem.hasAttribute ( "val" ) ) { + val = trackElem.attribute ( "val" ).toInt(); + K3bVcdTrack* track = m_tracks->at( trackId ); + K3bVcdTrack* pbcTrack = m_tracks->at( val ); + if ( pbctrack ) { + pbcTrack->addToRevRefList( track ); + track->setPbcTrack( type, pbcTrack ); + track->setUserDefined( type, true ); + } else { + track->setPbcTrack( type ); + track->setPbcNonTrack( type, val ); + track->setUserDefined( type, true ); + } + } + } + } + } else if ( name.contains( "numkeys" ) ) { + if ( trackElem.hasAttribute ( "key" ) ) { + int key = trackElem.attribute ( "key" ).toInt(); + if ( trackElem.hasAttribute ( "val" ) ) { + int val = trackElem.attribute ( "val" ).toInt() - 1; + K3bVcdTrack* track = m_tracks->at( trackId ); + if ( val >= 0 ) { + K3bVcdTrack * numkeyTrack = m_tracks->at( val ); + track->setDefinedNumKey( key, numkeyTrack ); + } else { + track->setDefinedNumKey( key, 0L ); + } + } + } + } + + } + + } + setPbcTracks(); + setModified( false ); + } + + informAboutNotFoundFiles(); + return true; +} + + + +bool K3bVcdDoc::saveDocumentData( QDomElement * docElem ) +{ + QDomDocument doc = docElem->ownerDocument(); + saveGeneralDocumentData( docElem ); + + // save Vcd Label + QDomElement vcdMain = doc.createElement( "vcd" ); + + QDomElement vcdElem = doc.createElement( "volumeId" ); + vcdElem.appendChild( doc.createTextNode( vcdOptions() ->volumeId() ) ); + vcdMain.appendChild( vcdElem ); + + vcdElem = doc.createElement( "albumId" ); + vcdElem.appendChild( doc.createTextNode( vcdOptions() ->albumId() ) ); + vcdMain.appendChild( vcdElem ); + + vcdElem = doc.createElement( "volumeSetId" ); + vcdElem.appendChild( doc.createTextNode( vcdOptions() ->volumeSetId() ) ); + vcdMain.appendChild( vcdElem ); + + vcdElem = doc.createElement( "preparer" ); + vcdElem.appendChild( doc.createTextNode( vcdOptions() ->preparer() ) ); + vcdMain.appendChild( vcdElem ); + + vcdElem = doc.createElement( "publisher" ); + vcdElem.appendChild( doc.createTextNode( vcdOptions() ->publisher() ) ); + vcdMain.appendChild( vcdElem ); + + // applicationId() + // systemId() + + vcdElem = doc.createElement( "vcdType" ); + vcdElem.appendChild( doc.createTextNode( QString::number( vcdType() ) ) ); + vcdMain.appendChild( vcdElem ); + + vcdElem = doc.createElement( "mpegVersion" ); + vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->mpegVersion() ) ) ); + vcdMain.appendChild( vcdElem ); + + vcdElem = doc.createElement( "PreGapLeadout" ); + vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->PreGapLeadout() ) ) ); + vcdMain.appendChild( vcdElem ); + + vcdElem = doc.createElement( "PreGapTrack" ); + vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->PreGapTrack() ) ) ); + vcdMain.appendChild( vcdElem ); + + vcdElem = doc.createElement( "FrontMarginTrack" ); + vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->FrontMarginTrack() ) ) ); + vcdMain.appendChild( vcdElem ); + + vcdElem = doc.createElement( "RearMarginTrack" ); + vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->RearMarginTrack() ) ) ); + vcdMain.appendChild( vcdElem ); + + vcdElem = doc.createElement( "FrontMarginTrackSVCD" ); + vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->FrontMarginTrackSVCD() ) ) ); + vcdMain.appendChild( vcdElem ); + + vcdElem = doc.createElement( "RearMarginTrackSVCD" ); + vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->RearMarginTrackSVCD() ) ) ); + vcdMain.appendChild( vcdElem ); + + vcdElem = doc.createElement( "volumeCount" ); + vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->volumeCount() ) ) ); + vcdMain.appendChild( vcdElem ); + + vcdElem = doc.createElement( "volumeNumber" ); + vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->volumeNumber() ) ) ); + vcdMain.appendChild( vcdElem ); + + vcdElem = doc.createElement( "AutoDetect" ); + vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->AutoDetect() ) ) ); + vcdMain.appendChild( vcdElem ); + + vcdElem = doc.createElement( "CdiSupport" ); + vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->CdiSupport() ) ) ); + vcdMain.appendChild( vcdElem ); + + vcdElem = doc.createElement( "NonCompliantMode" ); + vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->NonCompliantMode() ) ) ); + vcdMain.appendChild( vcdElem ); + + vcdElem = doc.createElement( "Sector2336" ); + vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->Sector2336() ) ) ); + vcdMain.appendChild( vcdElem ); + + vcdElem = doc.createElement( "UpdateScanOffsets" ); + vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->UpdateScanOffsets() ) ) ); + vcdMain.appendChild( vcdElem ); + + vcdElem = doc.createElement( "RelaxedAps" ); + vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->RelaxedAps() ) ) ); + vcdMain.appendChild( vcdElem ); + + vcdElem = doc.createElement( "UseGaps" ); + vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->UseGaps() ) ) ); + vcdMain.appendChild( vcdElem ); + + vcdElem = doc.createElement( "PbcEnabled" ); + vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->PbcEnabled() ) ) ); + vcdMain.appendChild( vcdElem ); + + vcdElem = doc.createElement( "SegmentFolder" ); + vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->SegmentFolder() ) ) ); + vcdMain.appendChild( vcdElem ); + + vcdElem = doc.createElement( "Restriction" ); + vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->Restriction() ) ) ); + vcdMain.appendChild( vcdElem ); + + docElem->appendChild( vcdMain ); + + // save the tracks + // ------------------------------------------------------------- + QDomElement contentsElem = doc.createElement( "contents" ); + + QPtrListIterator iterTrack( *m_tracks ); + K3bVcdTrack* track; + + while ( ( track = iterTrack.current() ) != 0 ) { + ++iterTrack; + + QDomElement trackElem = doc.createElement( "track" ); + trackElem.setAttribute( "url", KIO::decodeFileName( track->absPath() ) ); + trackElem.setAttribute( "playtime", track->getPlayTime() ); + trackElem.setAttribute( "waittime", track->getWaitTime() ); + trackElem.setAttribute( "reactivity", track->Reactivity() ); + trackElem.setAttribute( "numkeys", ( track->PbcNumKeys() ) ? "yes" : "no" ); + trackElem.setAttribute( "userdefinednumkeys", ( track->PbcNumKeysUserdefined() ) ? "yes" : "no" ); + + for ( int i = 0; + i < K3bVcdTrack::_maxPbcTracks; + i++ ) { + if ( track->isPbcUserDefined( i ) ) { + // save pbcTracks + QDomElement pbcElem = doc.createElement( "pbc" ); + pbcElem.setAttribute( "type", i ); + if ( track->getPbcTrack( i ) ) { + pbcElem.setAttribute( "pbctrack", "yes" ); + pbcElem.setAttribute( "val", track->getPbcTrack( i ) ->index() ); + } else { + pbcElem.setAttribute( "pbctrack", "no" ); + pbcElem.setAttribute( "val", track->getNonPbcTrack( i ) ); + } + trackElem.appendChild( pbcElem ); + } + } + QMap numKeyMap = track->DefinedNumKey(); + QMap::const_iterator trackIt; + + for ( trackIt = numKeyMap.begin(); + trackIt != numKeyMap.end(); + ++trackIt ) { + QDomElement numElem = doc.createElement( "numkeys" ); + if ( trackIt.data() ) { + numElem.setAttribute( "key", trackIt.key() ); + numElem.setAttribute( "val", trackIt.data() ->index() + 1 ); + } else { + numElem.setAttribute( "key", trackIt.key() ); + numElem.setAttribute( "val", 0 ); + } + trackElem.appendChild( numElem ); + } + + contentsElem.appendChild( trackElem ); + } + // ------------------------------------------------------------- + + docElem->appendChild( contentsElem ); + + return true; +} + +#include "k3bvcddoc.moc" diff --git a/libk3b/projects/videocd/k3bvcddoc.h b/libk3b/projects/videocd/k3bvcddoc.h new file mode 100644 index 0000000..8b10837 --- /dev/null +++ b/libk3b/projects/videocd/k3bvcddoc.h @@ -0,0 +1,192 @@ +/* +* +* $Id: k3bvcddoc.h 619556 2007-01-03 17:38:12Z trueg $ +* Copyright (C) 2003-2004 Christian Kvasny +* +* This file is part of the K3b project. +* Copyright (C) 1998-2007 Sebastian Trueg +* +* 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 2 of the License, or +* (at your option) any later version. +* See the file "COPYING" for the exact licensing terms. +*/ + +#ifndef K3BVCDDOC_H +#define K3BVCDDOC_H + +// Qt Includes +#include +#include +#include +#include +#include +#include +#include + +// Kde Includes +#include + +// K3b Includes +#include "k3bvcdoptions.h" +#include "mpeginfo/k3bmpeginfo.h" +#include +#include "k3b_export.h" +class K3bApp; +class K3bVcdTrack; +class K3bVcdJob; +//class K3bView; +class QWidget; +class QTimer; +class QDomDocument; +class QDomElement; +class KConfig; + + + +class LIBK3B_EXPORT K3bVcdDoc : public K3bDoc +{ + Q_OBJECT + + public: + K3bVcdDoc( QObject* ); + ~K3bVcdDoc(); + + int type() const { return VCD; } + + QString name() const; + + enum vcdTypes { VCD11, VCD20, SVCD10, HQVCD, NONE}; + + bool newDocument(); + int numOfTracks() const + { + return m_tracks->count(); + } + + const QString& vcdImage() const + { + return m_vcdImage; + } + void setVcdImage( const QString& s ) + { + m_vcdImage = s; + } + + K3bVcdTrack* first() + { + return m_tracks->first(); + } + K3bVcdTrack* current() const + { + return m_tracks->current(); + } + K3bVcdTrack* next() + { + return m_tracks->next(); + } + K3bVcdTrack* prev() + { + return m_tracks->prev(); + } + K3bVcdTrack* at( uint i ) + { + return m_tracks->at( i ); + } + K3bVcdTrack* take( uint i ) + { + return m_tracks->take( i ); + } + + const QPtrList* tracks() const + { + return m_tracks; + } + + /** get the current size of the project */ + KIO::filesize_t size() const; + K3b::Msf length() const; + + K3bBurnJob* newBurnJob( K3bJobHandler* hdl, QObject* parent ); + K3bVcdOptions* vcdOptions() const + { + return m_vcdOptions; + } + + int vcdType() const + { + return m_vcdType; + } + void setVcdType( int type ); + void setPbcTracks(); + + public slots: + /** + * will test the file and add it to the project. + * connect to at least result() to know when + * the process is finished and check error() + * to know about the result. + **/ + void addUrls( const KURL::List& ); + void addTrack( const KURL&, uint ); + void addTracks( const KURL::List&, uint ); + /** adds a track without any testing */ + void addTrack( K3bVcdTrack* track, uint position = 0 ); + + // --- TODO: this should read: removeTrack( K3bVcdTrack* ) + void removeTrack( K3bVcdTrack* ); + void moveTrack( const K3bVcdTrack* track, const K3bVcdTrack* after ); + + protected slots: + /** processes queue "urlsToAdd" **/ + void slotWorkUrlQueue(); + + signals: + void newTracks(); + + void trackRemoved( K3bVcdTrack* ); + + protected: + /** reimplemented from K3bDoc */ + bool loadDocumentData( QDomElement* root ); + /** reimplemented from K3bDoc */ + bool saveDocumentData( QDomElement* ); + + QString typeString() const; + + private: + K3bVcdTrack* createTrack( const KURL& url ); + void informAboutNotFoundFiles(); + + QStringList m_notFoundFiles; + QString m_vcdImage; + + class PrivateUrlToAdd + { + public: + PrivateUrlToAdd( const KURL& u, int _pos ) + : url( u ), position( _pos ) + {} + KURL url; + int position; + }; + + /** Holds all the urls that have to be added to the list of tracks. **/ + QPtrQueue urlsToAdd; + QTimer* m_urlAddingTimer; + + QPtrList* m_tracks; + KIO::filesize_t calcTotalSize() const; + KIO::filesize_t ISOsize() const; + + bool isImage( const KURL& url ); + + K3bVcdTrack* m_lastAddedTrack; + K3bVcdOptions* m_vcdOptions; + + int m_vcdType; + uint lastAddedPosition; +}; + +#endif diff --git a/libk3b/projects/videocd/k3bvcdjob.cpp b/libk3b/projects/videocd/k3bvcdjob.cpp new file mode 100644 index 0000000..a1b347a --- /dev/null +++ b/libk3b/projects/videocd/k3bvcdjob.cpp @@ -0,0 +1,567 @@ +/* +* +* $Id: k3bvcdjob.cpp 619556 2007-01-03 17:38:12Z trueg $ +* Copyright (C) 2003-2004 Christian Kvasny +* +* This file is part of the K3b project. +* Copyright (C) 1998-2007 Sebastian Trueg +* +* 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 2 of the License, or +* (at your option) any later version. +* See the file "COPYING" for the exact licensing terms. +*/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "k3bvcdjob.h" + +// K3b Includes +#include "k3bvcddoc.h" +#include "k3bvcdtrack.h" +#include "k3bvcdxmlview.h" +#include +#include +#include +#include +#include +#include +#include +#include + +K3bVcdJob::K3bVcdJob( K3bVcdDoc* doc, K3bJobHandler* jh, QObject* parent, const char* name ) + : K3bBurnJob( jh, parent, name ) +{ + m_doc = doc; + m_doc->setCopies( m_doc->dummy() || m_doc->onlyCreateImages() ? 1 : m_doc->copies() ); + m_process = 0; + m_currentWrittenTrackNumber = 0; + m_bytesFinishedTracks = 0; + m_writerJob = 0; + // m_createimageonlypercent = 33.3; + m_createimageonlypercent = 100 / ( m_doc->copies() + 2 ); + m_currentcopy = 1; + m_imageFinished = false; +} + + +K3bVcdJob::~K3bVcdJob() +{ + delete m_process; + + if ( m_writerJob ) + delete m_writerJob; +} + + +K3bDoc* K3bVcdJob::doc() const +{ + return m_doc; +} + + +K3bDevice::Device* K3bVcdJob::writer() const +{ + if( doc()->onlyCreateImages() ) + return 0; + else + return doc() ->burner(); +} + +void K3bVcdJob::cancel() +{ + cancelAll(); + + emit canceled(); + jobFinished( false ); +} + + +void K3bVcdJob::cancelAll() +{ + m_canceled = true; + + if ( m_writerJob ) + m_writerJob->cancel(); + + if ( m_process->isRunning() ) { + m_process->disconnect( this ); + m_process->kill(); + } + + // remove bin-file if it is unfinished or the user selected to remove image + if ( QFile::exists( m_doc->vcdImage() ) ) { + if ( !m_doc->onTheFly() && m_doc->removeImages() || !m_imageFinished ) { + emit infoMessage( i18n( "Removing Binary file %1" ).arg( m_doc->vcdImage() ), K3bJob::SUCCESS ); + QFile::remove + ( m_doc->vcdImage() ); + m_doc->setVcdImage( "" ); + } + } + + // remove cue-file if it is unfinished or the user selected to remove image + if ( QFile::exists( m_cueFile ) ) { + if ( !m_doc->onTheFly() && m_doc->removeImages() || !m_imageFinished ) { + emit infoMessage( i18n( "Removing Cue file %1" ).arg( m_cueFile ), K3bJob::SUCCESS ); + QFile::remove + ( m_cueFile ); + m_cueFile = ""; + } + } +} + + +void K3bVcdJob::start() +{ + kdDebug() << "(K3bVcdJob) starting job" << endl; + + jobStarted(); + emit burning( false ); + m_canceled = false; + + int pos = QString( m_doc->vcdImage() ).find( ".bin", QString( m_doc->vcdImage() ).length() - 4 ); + if ( pos > 0 ) { + m_cueFile = m_doc->vcdImage().left( pos ) + ".cue"; + } else { + m_cueFile = m_doc->vcdImage() + ".cue"; + m_doc->setVcdImage( m_doc->vcdImage() + ".bin" ); + } + + if ( vcdDoc() ->onlyCreateImages() ) + m_createimageonlypercent = 50.0; + + // vcdxGen(); + xmlGen(); +} + +void K3bVcdJob::xmlGen() +{ + + KTempFile tempF; + m_xmlFile = tempF.name(); + tempF.unlink(); + + K3bVcdXmlView xmlView( m_doc ); + + if ( !xmlView.write( m_xmlFile ) ) { + kdDebug() << "(K3bVcdJob) could not write xmlfile." << endl; + emit infoMessage( i18n( "Could not write correct XML-file." ), K3bJob::ERROR ); + cancelAll(); + jobFinished( false ); + } + + // emit infoMessage( i18n( "XML-file successfully created" ), K3bJob::SUCCESS ); + emit debuggingOutput( "K3bVcdXml:", xmlView.xmlString() ); + + vcdxBuild(); + +} + +void K3bVcdJob::vcdxBuild() +{ + emit newTask( i18n( "Creating image files" ) ); + + m_stage = stageUnknown; + firstTrack = true; + delete m_process; + m_process = new K3bProcess(); + + emit infoMessage( i18n( "Creating Cue/Bin files ..." ), K3bJob::INFO ); + const K3bExternalBin* bin = k3bcore ->externalBinManager() ->binObject( "vcdxbuild" ); + if ( !bin ) { + kdDebug() << "(K3bVcdJob) could not find vcdxbuild executable" << endl; + emit infoMessage( i18n( "Could not find %1 executable." ).arg( "vcdxbuild" ), K3bJob::ERROR ); + emit infoMessage( i18n( "To create VideoCDs you must install VcdImager Version %1." ).arg( ">= 0.7.12" ), K3bJob::INFO ); + emit infoMessage( i18n( "You can find this on your distribution disks or download it from http://www.vcdimager.org" ), K3bJob::INFO ); + cancelAll(); + jobFinished( false ); + return ; + } + + if ( bin->version < K3bVersion( "0.7.12" ) ) { + kdDebug() << "(K3bVcdJob) vcdxbuild executable too old!" << endl; + emit infoMessage( i18n( "%1 executable too old: need version %2 or greater." ).arg( "Vcdxbuild" ).arg( "0.7.12" ), K3bJob::ERROR ); + emit infoMessage( i18n( "You can find this on your distribution disks or download it from http://www.vcdimager.org" ), K3bJob::INFO ); + cancelAll(); + jobFinished( false ); + return ; + } + + if ( !bin->copyright.isEmpty() ) + emit infoMessage( i18n( "Using %1 %2 - Copyright (C) %3" ).arg( bin->name() ).arg( bin->version ).arg( bin->copyright ), INFO ); + + *m_process << bin; + + // additional user parameters from config + const QStringList& params = k3bcore->externalBinManager() ->program( "vcdxbuild" ) ->userParameters(); + for ( QStringList::const_iterator it = params.begin(); it != params.end(); ++it ) + *m_process << *it; + + + if ( vcdDoc() ->vcdOptions() ->Sector2336() ) { + kdDebug() << "(K3bVcdJob) Write 2336 Sectors = on" << endl; + *m_process << "--sector-2336"; + } + + *m_process << "--progress" << "--gui"; + + *m_process << QString( "--cue-file=%1" ).arg( m_cueFile ); + + *m_process << QString( "--bin-file=%1" ).arg( m_doc->vcdImage() ); + + *m_process << QString( "%1" ).arg( QFile::encodeName( m_xmlFile ) ); + + connect( m_process, SIGNAL( receivedStderr( KProcess*, char*, int ) ), + this, SLOT( slotParseVcdxBuildOutput( KProcess*, char*, int ) ) ); + connect( m_process, SIGNAL( receivedStdout( KProcess*, char*, int ) ), + this, SLOT( slotParseVcdxBuildOutput( KProcess*, char*, int ) ) ); + connect( m_process, SIGNAL( processExited( KProcess* ) ), + this, SLOT( slotVcdxBuildFinished() ) ); + + // vcdxbuild commandline parameters + kdDebug() << "***** vcdxbuild parameters:" << endl; + ; + const QValueList& args = m_process->args(); + QString s; + for ( QValueList::const_iterator it = args.begin(); it != args.end(); ++it ) { + s += *it + " "; + } + kdDebug() << s << flush << endl; + emit debuggingOutput( "vcdxbuild command:", s ); + + if ( !m_process->start( KProcess::NotifyOnExit, KProcess::AllOutput ) ) { + kdDebug() << "(K3bVcdJob) could not start vcdxbuild" << endl; + emit infoMessage( i18n( "Could not start %1." ).arg( "vcdxbuild" ), K3bJob::ERROR ); + cancelAll(); + jobFinished( false ); + } +} + +void K3bVcdJob::slotParseVcdxBuildOutput( KProcess*, char* output, int len ) +{ + QString buffer = QString::fromLocal8Bit( output, len ); + + // split to lines + QStringList lines = QStringList::split( "\n", buffer ); + + QDomDocument xml_doc; + QDomElement xml_root; + + // do every line + for ( QStringList::Iterator str = lines.begin(); str != lines.end(); ++str ) { + *str = ( *str ).stripWhiteSpace(); + + emit debuggingOutput( "vcdxbuild", *str ); + + xml_doc.setContent( QString( "" ) + *str + "" ); + + xml_root = xml_doc.documentElement(); + + // There should be only one... but ... + for ( QDomNode node = xml_root.firstChild(); !node.isNull(); node = node.nextSibling() ) { + QDomElement el = node.toElement(); + if ( el.isNull() ) + continue; + + const QString tagName = el.tagName().lower(); + + if ( tagName == "progress" ) { + const QString oper = el.attribute( "operation" ).lower(); + const unsigned long long pos = el.attribute( "position" ).toLong(); + const long long size = el.attribute( "size" ).toLong(); + + if ( oper == "scan" ) { + // Scan Video Files + if ( m_stage == stageUnknown || pos < m_bytesFinished ) { + const uint index = el.attribute( "id" ).replace( QRegExp( "sequence-" ), "" ).toUInt(); + + m_currentWrittenTrack = m_doc->at( m_currentWrittenTrackNumber ); + emit newSubTask( i18n( "Scanning video file %1 of %2 (%3)" ).arg( index + 1 ).arg( doc() ->numOfTracks() ).arg( m_currentWrittenTrack->fileName() ) ); + m_bytesFinished = 0; + + if ( !firstTrack ) { + m_bytesFinishedTracks += m_doc->at( m_currentWrittenTrackNumber ) ->size(); + m_currentWrittenTrackNumber++; + } else + firstTrack = false; + } + emit subPercent( ( int ) ( 100.0 * ( double ) pos / ( double ) size ) ); + emit processedSubSize( pos / 1024 / 1024, size / 1024 / 1024 ); + + // this is the first of three processes. + double relOverallWritten = ( ( double ) m_bytesFinishedTracks + ( double ) pos ) / ( double ) doc() ->size(); + emit percent( ( int ) ( m_createimageonlypercent * relOverallWritten ) ); + + m_bytesFinished = pos; + m_stage = stageScan; + + } else if ( oper == "write" ) { + emit subPercent( ( int ) ( 100.0 * ( double ) pos / ( double ) size ) ); + emit processedSubSize( ( pos * 2048 ) / 1024 / 1024, ( size * 2048 ) / 1024 / 1024 ); + emit percent( ( int ) ( m_createimageonlypercent + ( m_createimageonlypercent * ( double ) pos / ( double ) size ) ) ); + + m_stage = stageWrite; + } else { + return ; + } + } else if ( tagName == "log" ) { + QDomText tel = el.firstChild().toText(); + const QString level = el.attribute( "level" ).lower(); + if ( tel.isText() ) { + const QString text = tel.data(); + if ( m_stage == stageWrite && level == "information" ) + kdDebug() << QString( "(K3bVcdJob) VcdxBuild information, %1" ).arg( text ) << endl; + if ( ( text ).startsWith( "writing track" ) ) + emit newSubTask( i18n( "Creating Image for track %1" ).arg( ( text ).mid( 14 ) ) ); + else { + if ( level != "error" ) { + kdDebug() << QString( "(K3bVcdJob) vcdxbuild warning, %1" ).arg( text ) << endl; + parseInformation( text ); + } else { + kdDebug() << QString( "(K3bVcdJob) vcdxbuild error, %1" ).arg( text ) << endl; + emit infoMessage( text, K3bJob::ERROR ); + } + } + } + } + } + } +} + + +void K3bVcdJob::slotVcdxBuildFinished() +{ + if ( m_process->normalExit() ) { + // TODO: check the process' exitStatus() + switch ( m_process->exitStatus() ) { + case 0: + emit infoMessage( i18n( "Cue/Bin files successfully created." ), K3bJob::SUCCESS ); + m_imageFinished = true; + break; + default: + emit infoMessage( i18n( "%1 returned an unknown error (code %2)." ).arg( "vcdxbuild" ).arg( m_process->exitStatus() ), + K3bJob::ERROR ); + emit infoMessage( i18n( "Please send me an email with the last output." ), K3bJob::ERROR ); + cancelAll(); + jobFinished( false ); + return ; + } + } else { + emit infoMessage( i18n( "%1 did not exit cleanly." ).arg( "Vcdxbuild" ), K3bJob::ERROR ); + cancelAll(); + jobFinished( false ); + return ; + } + + //remove xml-file + if ( QFile::exists( m_xmlFile ) ) + QFile::remove + ( m_xmlFile ); + + kdDebug() << QString( "(K3bVcdJob) create only image: %1" ).arg( vcdDoc() ->onlyCreateImages() ) << endl; + if ( !vcdDoc() ->onlyCreateImages() ) + startWriterjob(); + else + jobFinished( true ); +} + +void K3bVcdJob::startWriterjob() +{ + kdDebug() << QString( "(K3bVcdJob) writing copy %1 of %2" ).arg( m_currentcopy ).arg( m_doc->copies() ) << endl; + if ( prepareWriterJob() ) { + if ( waitForMedia( m_doc->burner() ) < 0 ) { + cancel(); + return ; + } + // just to be sure we did not get canceled during the async discWaiting + if ( m_canceled ) + return ; + + if ( m_doc->copies() > 1 ) + emit newTask( i18n( "Writing Copy %1 of %2" ).arg( m_currentcopy ).arg( m_doc->copies() ) ); + + emit burning( true ); + m_writerJob->start(); + } +} + +bool K3bVcdJob::prepareWriterJob() +{ + if ( m_writerJob ) + delete m_writerJob; + + const K3bExternalBin* cdrecordBin = k3bcore->externalBinManager() ->binObject( "cdrecord" ); + if ( writingApp() == K3b::DEFAULT && cdrecordBin->hasFeature( "cuefile" ) && m_doc->burner() ->dao() ) + setWritingApp( K3b::CDRECORD ); + + if ( writingApp() == K3b::CDRDAO || writingApp() == K3b::DEFAULT ) { + K3bCdrdaoWriter * writer = new K3bCdrdaoWriter( m_doc->burner(), this, this ); + // create cdrdao job + writer->setCommand( K3bCdrdaoWriter::WRITE ); + writer->setSimulate( m_doc->dummy() ); + writer->setBurnSpeed( m_doc->speed() ); + + writer->setTocFile( m_cueFile ); + + m_writerJob = writer; + + } else if ( writingApp() == K3b::CDRECORD ) { + K3bCdrecordWriter * writer = new K3bCdrecordWriter( m_doc->burner(), this, this ); + // create cdrecord job + + writer->setSimulate( m_doc->dummy() ); + writer->setBurnSpeed( m_doc->speed() ); + writer->setDao( true ); + writer->setCueFile( m_cueFile ); + + m_writerJob = writer; + + } + + connect( m_writerJob, SIGNAL( infoMessage( const QString&, int ) ), this, SIGNAL( infoMessage( const QString&, int ) ) ); + connect( m_writerJob, SIGNAL( percent( int ) ), this, SLOT( slotWriterJobPercent( int ) ) ); + connect( m_writerJob, SIGNAL( processedSize( int, int ) ), this, SLOT( slotProcessedSize( int, int ) ) ); + connect( m_writerJob, SIGNAL( subPercent( int ) ), this, SIGNAL( subPercent( int ) ) ); + connect( m_writerJob, SIGNAL( processedSubSize( int, int ) ), this, SIGNAL( processedSubSize( int, int ) ) ); + connect( m_writerJob, SIGNAL( nextTrack( int, int ) ), this, SLOT( slotWriterNextTrack( int, int ) ) ); + connect( m_writerJob, SIGNAL( buffer( int ) ), this, SIGNAL( bufferStatus( int ) ) ); + connect( m_writerJob, SIGNAL( deviceBuffer( int ) ), this, SIGNAL( deviceBuffer( int ) ) ); + connect( m_writerJob, SIGNAL( writeSpeed( int, int ) ), this, SIGNAL( writeSpeed( int, int ) ) ); + connect( m_writerJob, SIGNAL( finished( bool ) ), this, SLOT( slotWriterJobFinished( bool ) ) ); + connect( m_writerJob, SIGNAL( newTask( const QString& ) ), this, SIGNAL( newTask( const QString& ) ) ); + connect( m_writerJob, SIGNAL( newSubTask( const QString& ) ), this, SIGNAL( newSubTask( const QString& ) ) ); + connect( m_writerJob, SIGNAL( debuggingOutput( const QString&, const QString& ) ), this, SIGNAL( debuggingOutput( const QString&, const QString& ) ) ); + + return true; +} + +void K3bVcdJob::slotWriterJobPercent( int p ) +{ + emit percent( ( int ) ( ( m_createimageonlypercent * ( m_currentcopy + 1 ) ) + p / ( m_doc->copies() + 2 ) ) ); +} + +void K3bVcdJob::slotProcessedSize( int cs, int ts ) +{ + emit processedSize( cs + ( ts * ( m_currentcopy - 1 ) ) , ts * m_doc->copies() ); +} + +void K3bVcdJob::slotWriterNextTrack( int t, int tt ) +{ + emit newSubTask( i18n( "Writing Track %1 of %2" ).arg( t ).arg( tt ) ); +} + +void K3bVcdJob::slotWriterJobFinished( bool success ) +{ + if ( m_canceled ) + return ; + + if ( m_currentcopy >= m_doc->copies() ) { + // remove bin-file if it is unfinished or the user selected to remove image + if ( QFile::exists( m_doc->vcdImage() ) ) { + if ( !m_doc->onTheFly() && m_doc->removeImages() || !m_imageFinished ) { + emit infoMessage( i18n( "Removing Binary file %1" ).arg( m_doc->vcdImage() ), K3bJob::SUCCESS ); + QFile::remove + ( m_doc->vcdImage() ); + m_doc->setVcdImage( "" ); + } + } + + // remove cue-file if it is unfinished or the user selected to remove image + if ( QFile::exists( m_cueFile ) ) { + if ( !m_doc->onTheFly() && m_doc->removeImages() || !m_imageFinished ) { + emit infoMessage( i18n( "Removing Cue file %1" ).arg( m_cueFile ), K3bJob::SUCCESS ); + QFile::remove + ( m_cueFile ); + m_cueFile = ""; + } + } + } + + if ( success ) { + // allright + // the writerJob should have emited the "simulation/writing successful" signal + if ( m_currentcopy >= m_doc->copies() ) { + jobFinished( true ); + } else { + m_currentcopy++; + startWriterjob(); + } + } else { + cancelAll(); + jobFinished( false ); + } +} + +void K3bVcdJob::parseInformation( const QString &text ) +{ + // parse warning + if ( text.contains( "mpeg user scan data: one or more BCD fields out of range for" ) ) { + int index = text.find( " for" ); + + emit infoMessage( i18n( "One or more BCD fields out of range for %1" ).arg( text.mid( index + 4 ).stripWhiteSpace() ), K3bJob::WARNING ); + + } else if ( text.contains( "mpeg user scan data: from now on, scan information data errors will not be reported anymore" ) ) { + emit infoMessage( i18n( "From now on, scan information data errors will not be reported anymore" ), K3bJob::INFO ); + emit infoMessage( i18n( "Consider enabling the 'update scan offsets' option, if it is not enabled already." ), K3bJob::INFO ); + + } else if ( text.contains( "APS' pts seems out of order (actual pts" ) ) { + int index = text.find( "(actual pts" ); + int index2 = text.find( ", last seen pts" ); + int index3 = text.find( ") -- ignoring this aps" ); + + emit infoMessage( i18n( "APS' pts seems out of order (actual pts %1, last seen pts %2)" ).arg( text.mid( index + 12, index2 - index - 12 ).stripWhiteSpace() ).arg( text.mid( index2 + 14, index3 - index2 - 14 ).stripWhiteSpace() ), K3bJob::WARNING ); + emit infoMessage( i18n( "Ignoring this aps" ), K3bJob::INFO ); + + } else if ( text.contains( "bad packet at packet" ) ) { + int index = text.find( "at packet #" ); + int index2 = text.find( "(stream byte offset" ); + int index3 = text.find( ") -- remaining " ); + int index4 = text.find( "bytes of stream will be ignored" ); + + emit infoMessage( i18n( "Bad packet at packet #%1 (stream byte offset %2)" ).arg( text.mid( index + 11, index2 - index - 11 ).stripWhiteSpace() ).arg( text.mid( index2 + 19, index3 - index2 - 19 ).stripWhiteSpace() ), K3bJob::WARNING ); + emit infoMessage( i18n( "Remaining %1 bytes of stream will be ignored." ).arg( text.mid( index3 + 15, index4 - index3 - 15 ).stripWhiteSpace() ), K3bJob::WARNING ); + } +} + +QString K3bVcdJob::jobDescription() const +{ + switch ( m_doc->vcdType() ) { + case K3bVcdDoc::VCD11: + return i18n( "Writing Video CD (Version 1.1)" ); + case K3bVcdDoc::VCD20: + return i18n( "Writing Video CD (Version 2.0)" ); + case K3bVcdDoc::SVCD10: + return i18n( "Writing Super Video CD" ); + case K3bVcdDoc::HQVCD: + return i18n( "Writing High-Quality Video CD" ); + default: + return i18n( "Writing Video CD" ); + } +} + + +QString K3bVcdJob::jobDetails() const +{ + return ( i18n( "1 MPEG (%1)", + "%n MPEGs (%1)", + m_doc->tracks() ->count() ).arg( KIO::convertSize( m_doc->size() ) ) + + ( m_doc->copies() > 1 + ? i18n( " - %n copy", " - %n copies", m_doc->copies() ) + : QString::null ) ); +} + +#include "k3bvcdjob.moc" diff --git a/libk3b/projects/videocd/k3bvcdjob.h b/libk3b/projects/videocd/k3bvcdjob.h new file mode 100644 index 0000000..917c8b1 --- /dev/null +++ b/libk3b/projects/videocd/k3bvcdjob.h @@ -0,0 +1,115 @@ +/* +* +* $Id: k3bvcdjob.h 619556 2007-01-03 17:38:12Z trueg $ +* Copyright (C) 2003-2004 Christian Kvasny +* +* This file is part of the K3b project. +* Copyright (C) 1998-2007 Sebastian Trueg +* +* 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 2 of the License, or +* (at your option) any later version. +* See the file "COPYING" for the exact licensing terms. +*/ + +#ifndef K3BVCDJOB_H +#define K3BVCDJOB_H + +#include + +class K3bVcdDoc; +class K3bVcdTrack; +class QString; +class K3bProcess; +class KProcess; +class QDataStream; +class K3bAbstractWriter; +class K3bDevice::Device; + + +class K3bVcdJob : public K3bBurnJob +{ + Q_OBJECT + + public: + K3bVcdJob( K3bVcdDoc*, K3bJobHandler*, QObject* parent = 0, const char* name = 0 ); + ~K3bVcdJob(); + + K3bDoc* doc() const; + K3bVcdDoc* vcdDoc() const + { + return m_doc; + } + K3bDevice::Device* writer() const; + + QString jobDescription() const; + QString jobDetails() const; + + public slots: + void start(); + void cancel(); + + private slots: + void cancelAll(); + + protected slots: + void slotVcdxBuildFinished(); + void slotParseVcdxBuildOutput( KProcess*, char* output, int len ); + + void slotWriterJobPercent( int p ); + void slotProcessedSize( int cs, int ts ); + void slotWriterNextTrack( int t, int tt ); + void slotWriterJobFinished( bool success ); + + + private: + bool prepareWriterJob(); + + void xmlGen(); + void vcdxBuild(); + void parseInformation( const QString& ); + void startWriterjob(); + + int m_copies; + int m_finishedCopies; + + unsigned long m_blocksToCopy; + unsigned long m_bytesFinishedTracks; + unsigned long m_bytesFinished; + + enum { stageUnknown, stageScan, stageWrite, _stage_max }; + + K3bVcdDoc* m_doc; + K3bDevice::Device* m_writer; + K3bDevice::Device* m_reader; + K3bVcdTrack* m_currentWrittenTrack; + + int m_speed; + int m_stage; + int m_currentcopy; + int m_currentWrittenTrackNumber; + + double m_createimageonlypercent; + + bool firstTrack; + bool m_burnProof; + bool m_keepImage; + bool m_onlyCreateImage; + bool m_onTheFly; + bool m_dummy; + bool m_fastToc; + bool m_readRaw; + bool m_imageFinished; + bool m_canceled; + + QString m_tempPath; + QString m_cueFile; + QString m_xmlFile; + QString m_collectedOutput; + + K3bAbstractWriter* m_writerJob; + K3bProcess* m_process; +}; + +#endif diff --git a/libk3b/projects/videocd/k3bvcdoptions.cpp b/libk3b/projects/videocd/k3bvcdoptions.cpp new file mode 100644 index 0000000..6009a4a --- /dev/null +++ b/libk3b/projects/videocd/k3bvcdoptions.cpp @@ -0,0 +1,146 @@ +/* +* +* $Id: k3bvcdoptions.cpp 619556 2007-01-03 17:38:12Z trueg $ +* Copyright (C) 2003-2004 Christian Kvasny +* +* This file is part of the K3b project. +* Copyright (C) 1998-2007 Sebastian Trueg +* +* 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 2 of the License, or +* (at your option) any later version. +* See the file "COPYING" for the exact licensing terms. +*/ + +// Kde Includes +#include +#include +#include +#include +#include + +// Qt Includes +#include +#include + +// K3b Includes +#include "k3bvcdoptions.h" +#include + +K3bVcdOptions::K3bVcdOptions() + : m_restriction( 0 ), + m_segment( 0 ), + m_sequence( 0 ), + m_pbcenabled( PbcEnabled() ), + m_pbcnumkeysenabled( PbcNumkeysEnabled() ), + m_volumeID( "VIDEOCD" ), + m_albumID( "" ), + m_volumeSetId( "" ), + m_publisher( QString( "K3b - Version %1" ).arg( k3bcore->version() ) ), + m_applicationId( "CDI/CDI_VCD.APP;1" ), + m_systemId( "CD-RTOS CD-BRIDGE" ), + m_vcdclass( "vcd" ), + m_vcdversion( "2.0" ), + m_pregapleadout( 150 ), + m_pregaptrack( 150 ), + m_frontmargintrack( 30 ), + m_rearmargintrack( 45 ), + m_frontmargintrackSVCD( 0 ), + m_rearmargintrackSVCD( 0 ), + m_mpegversion( 1 ), + m_volumeCount( 1 ), + m_volumeNumber( 1 ), + m_autodetect( true ), + m_cdisupport( false ), + m_brokensvcdmode( false ), + m_VCD30interpretation( false ), + m_sector2336( false ), + m_updatescanoffsets( false ), + m_relaxedaps( false ), + m_segmentfolder( true ), + m_usegaps( false ) +{} + +bool K3bVcdOptions::checkCdiFiles() +{ + m_cdisize = 0; + if ( !QFile::exists( locate( "data", "k3b/cdi/cdi_imag.rtf" ) ) ) + return false; + if ( !QFile::exists( locate( "data", "k3b/cdi/cdi_text.fnt" ) ) ) + return false; + if ( !QFile::exists( locate( "data", "k3b/cdi/cdi_vcd.app" ) ) ) + return false; + if ( !QFile::exists( locate( "data", "k3b/cdi/cdi_vcd.cfg" ) ) ) + return false; + + m_cdisize += QFile( locate( "data", "k3b/cdi/cdi_imag.rtf" ) ).size(); + m_cdisize += QFile( locate( "data", "k3b/cdi/cdi_text.fnt" ) ).size(); + m_cdisize += QFile( locate( "data", "k3b/cdi/cdi_vcd.app" ) ).size(); + m_cdisize += QFile( locate( "data", "k3b/cdi/cdi_vcd.cfg" ) ).size(); + + return true; +} + +void K3bVcdOptions::save( KConfigBase* c ) +{ + c->writeEntry( "volume_id", m_volumeID ); + c->writeEntry( "album_id", m_albumID ); + c->writeEntry( "volume_set_id", m_volumeSetId ); + c->writeEntry( "preparer", m_preparer ); + c->writeEntry( "publisher", m_publisher ); + c->writeEntry( "volume_count", m_volumeCount ); + c->writeEntry( "volume_number", m_volumeNumber ); + c->writeEntry( "autodetect", m_autodetect ); + c->writeEntry( "cdi_support", m_cdisupport ); + c->writeEntry( "broken_svcd_mode", m_brokensvcdmode ); + c->writeEntry( "VCD30interpretation", m_VCD30interpretation ); + c->writeEntry( "2336_sectors", m_sector2336 ); + c->writeEntry( "UpdateScanOffsets", m_updatescanoffsets ); + c->writeEntry( "RelaxedAps", m_relaxedaps ); + c->writeEntry( "PbcEnabled", m_pbcenabled ); + c->writeEntry( "SegmentFolder", m_segmentfolder ); + c->writeEntry( "Restriction", m_restriction ); + c->writeEntry( "PreGapLeadout", m_pregapleadout ); + c->writeEntry( "PreGapTrack", m_pregaptrack ); + c->writeEntry( "FrontMarginTrack", m_frontmargintrack ); + c->writeEntry( "RearMarginTrack", m_rearmargintrack ); + c->writeEntry( "UseGaps", m_usegaps ); +} + + +K3bVcdOptions K3bVcdOptions::load( KConfigBase* c ) +{ + K3bVcdOptions options; + + options.setVolumeId( c->readEntry( "volume_id", options.volumeId() ) ); + options.setAlbumId( c->readEntry( "album_id", options.albumId() ) ); + options.setVolumeSetId( c->readEntry( "volume_set_id", options.volumeSetId() ) ); + options.setPreparer( c->readEntry( "preparer", options.preparer() ) ); + options.setPublisher( c->readEntry( "publisher", options.publisher() ) ); + options.setVolumeCount( c->readNumEntry( "volume_count", options.volumeCount() ) ); + options.setVolumeNumber( c->readNumEntry( "volume_number", options.volumeNumber() ) ); + options.setAutoDetect( c->readBoolEntry( "autodetect", options.AutoDetect() ) ); + options.setCdiSupport( c->readBoolEntry( "cdi_support", options.CdiSupport() ) ); + options.setNonCompliantMode( c->readBoolEntry( "broken_svcd_mode", options.NonCompliantMode() ) ); + options.setVCD30interpretation( c->readBoolEntry( "VCD30interpretation", options.VCD30interpretation() ) ); + options.setSector2336( c->readBoolEntry( "2336_sectors", options.Sector2336() ) ); + options.setUpdateScanOffsets( c->readBoolEntry( "UpdateScanOffsets", options.UpdateScanOffsets() ) ); + options.setRelaxedAps( c->readBoolEntry( "RelaxedAps", options.RelaxedAps() ) ); + options.setPbcEnabled( c->readBoolEntry( "PbcEnabled", options.PbcEnabled() ) ); + options.setSegmentFolder( c->readBoolEntry( "SegmentFolder", options.SegmentFolder() ) ); + options.setRestriction( c->readNumEntry( "Restriction", options.Restriction() ) ); + options.setPreGapLeadout( c->readNumEntry( "PreGapLeadout", options.PreGapLeadout() ) ); + options.setPreGapTrack( c->readNumEntry( "PreGapTrack", options.PreGapTrack() ) ); + options.setFrontMarginTrack( c->readNumEntry( "FrontMarginTrack", options.FrontMarginTrack() ) ); + options.setRearMarginTrack( c->readNumEntry( "RearMarginTrack", options.RearMarginTrack() ) ); + options.setUseGaps( c->readBoolEntry( "UseGaps", options.UseGaps() ) ); + + return options; +} + +K3bVcdOptions K3bVcdOptions::defaults() +{ + // let the constructor create defaults + return K3bVcdOptions(); +} diff --git a/libk3b/projects/videocd/k3bvcdoptions.h b/libk3b/projects/videocd/k3bvcdoptions.h new file mode 100644 index 0000000..aa5fed2 --- /dev/null +++ b/libk3b/projects/videocd/k3bvcdoptions.h @@ -0,0 +1,377 @@ +/* +* +* $Id: k3bvcdoptions.h 619556 2007-01-03 17:38:12Z trueg $ +* Copyright (C) 2003-2004 Christian Kvasny +* +* This file is part of the K3b project. +* Copyright (C) 1998-2007 Sebastian Trueg +* +* 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 2 of the License, or +* (at your option) any later version. +* See the file "COPYING" for the exact licensing terms. +*/ + +#ifndef K3B_VCD_OPTIONS_H +#define K3B_VCD_OPTIONS_H + +#include +#include "k3b_export.h" + +class KConfigBase; + +class LIBK3B_EXPORT K3bVcdOptions +{ + public: + K3bVcdOptions(); + const QString& volumeId() const + { + return m_volumeID; + } + const QString& albumId() const + { + return m_albumID; + } + const QString& volumeSetId() const + { + return m_volumeSetId; + } + const QString& preparer() const + { + return m_preparer; + } + const QString& publisher() const + { + return m_publisher; + } + + const QString& applicationId() const + { + return m_applicationId; + } + const QString& systemId() const + { + return m_systemId; + } + + const QString& vcdClass() const + { + return m_vcdclass; + } + const QString& vcdVersion() const + { + return m_vcdversion; + } + + const int PreGapLeadout() + { + return m_pregapleadout; + } + const int PreGapTrack() + { + return m_pregaptrack; + } + const int FrontMarginTrack() + { + return m_frontmargintrack; + } + const int RearMarginTrack() + { + return m_rearmargintrack; + } + const int FrontMarginTrackSVCD() + { + return m_frontmargintrackSVCD; + } + const int RearMarginTrackSVCD() + { + return m_rearmargintrackSVCD; + } + + const int mpegVersion() const + { + return m_mpegversion; + } + + const int volumeCount() const + { + return m_volumeCount; + } + const int volumeNumber() const + { + return m_volumeNumber; + } + + const bool AutoDetect() const + { + return m_autodetect; + } + const bool CdiSupport() const + { + return m_cdisupport; + } + const bool NonCompliantMode() const + { + return m_brokensvcdmode; + } + const bool VCD30interpretation() const + { + return m_VCD30interpretation; + } + const bool Sector2336() const + { + return m_sector2336; + } + const bool UpdateScanOffsets() const + { + return m_updatescanoffsets; + } + const bool RelaxedAps() const + { + return m_relaxedaps; + } + const bool UseGaps() const + { + return m_usegaps; + } + const unsigned long long CDIsize() const + { + return m_cdisize; + } + + void setAlbumId( const QString& s ) + { + m_albumID = s; + } + void setVolumeId( const QString& s ) + { + m_volumeID = s; + } + void setVolumeSetId( const QString& s ) + { + m_volumeSetId = s; + } + void setPreparer( const QString& s ) + { + m_preparer = s; + } + void setPublisher( const QString& s ) + { + m_publisher = s; + } + + void setVcdClass( const QString& s ) + { + m_vcdclass = s; + } + void setVcdVersion( const QString& s ) + { + m_vcdversion = s; + } + + void setPreGapLeadout( const int i ) + { + m_pregapleadout = i; + } + void setPreGapTrack( const int i ) + { + m_pregaptrack = i; + } + void setFrontMarginTrack( const int i ) + { + m_frontmargintrack = i; + } + void setRearMarginTrack( const int i ) + { + m_rearmargintrack = i; + } + void setFrontMarginTrackSVCD( const int i ) + { + m_frontmargintrackSVCD = i; + } + void setRearMarginTrackSVCD( const int i ) + { + m_rearmargintrackSVCD = i; + } + + void setMpegVersion( const int v ) + { + m_mpegversion = v; + } + void setVolumeCount( const int c ) + { + m_volumeCount = c; + } + void setVolumeNumber( const int n ) + { + m_volumeNumber = n; + } + + void setAutoDetect( const bool& b ) + { + m_autodetect = b; + } + void setCdiSupport( const bool& b ) + { + m_cdisupport = b; + } + void setNonCompliantMode( const bool& b ) + { + m_brokensvcdmode = b; + } + void setVCD30interpretation( const bool& b ) + { + m_VCD30interpretation = b; + } + void setSector2336( const bool& b ) + { + m_sector2336 = b; + } + void setUpdateScanOffsets( const bool& b ) + { + m_updatescanoffsets = b; + } + void setRelaxedAps( const bool& b ) + { + m_relaxedaps = b; + } + void setUseGaps( const bool& b ) + { + m_usegaps = b; + } + + bool checkCdiFiles(); + void save( KConfigBase* c ); + + static K3bVcdOptions load( KConfigBase* c ); + static K3bVcdOptions defaults(); + + void setPbcEnabled( const bool& b ) + { + m_pbcenabled = b; + } + bool PbcEnabled() const + { + return m_pbcenabled; + }; + void setPbcNumkeysEnabled( const bool& b ) + { + m_pbcnumkeysenabled = b; + } + bool PbcNumkeysEnabled() const + { + return m_pbcnumkeysenabled; + }; + + void setPbcPlayTime( const int i ) + { + m_def_pbcplaytime = i; + } + int PbcPlayTime( ) + { + return m_def_pbcplaytime; + } + + void setPbcWaitTime( const int i ) + { + m_def_pbcwaittime = i; + } + int PbcWaitTime( ) + { + return m_def_pbcwaittime; + } + + void setSegmentFolder( const bool& b ) + { + m_segmentfolder = b; + } + bool SegmentFolder() const + { + return m_segmentfolder; + }; + + void setRestriction( const int i ) + { + m_restriction = i; + } + int Restriction() const + { + return m_restriction; + }; + void increaseSegments( ) + { + m_segment += 1; + } + void decreaseSegments( ) + { + m_segment -= 1; + } + bool haveSegments() const + { + return m_segment > 0; + }; + void increaseSequence( ) + { + m_sequence += 1; + } + void decreaseSequence( ) + { + m_sequence -= 1; + } + + bool haveSequence() const + { + return m_sequence > 0; + }; + + private: + int m_restriction; + int m_segment; + int m_sequence; + + // pbc + bool m_pbcenabled; + bool m_pbcnumkeysenabled; + + // volume descriptor + QString m_volumeID; + QString m_albumID; + QString m_volumeSetId; + + QString m_preparer; + QString m_publisher; + + QString m_applicationId; + QString m_systemId; + + QString m_vcdclass; + QString m_vcdversion; + + int m_pregapleadout; + int m_pregaptrack; + int m_frontmargintrack; + int m_rearmargintrack; + int m_frontmargintrackSVCD; + int m_rearmargintrackSVCD; + + int m_mpegversion; + int m_volumeCount; + int m_volumeNumber; + + bool m_autodetect; + bool m_cdisupport; + bool m_brokensvcdmode; + bool m_VCD30interpretation; + bool m_sector2336; + bool m_updatescanoffsets; + bool m_relaxedaps; + bool m_segmentfolder; + bool m_usegaps; + + int m_def_pbcplaytime; + int m_def_pbcwaittime; + unsigned long long m_cdisize; +}; + +#endif diff --git a/libk3b/projects/videocd/k3bvcdtrack.cpp b/libk3b/projects/videocd/k3bvcdtrack.cpp new file mode 100644 index 0000000..7f0043f --- /dev/null +++ b/libk3b/projects/videocd/k3bvcdtrack.cpp @@ -0,0 +1,456 @@ +/* +* +* $Id: k3bvcdtrack.cpp 619556 2007-01-03 17:38:12Z trueg $ +* Copyright (C) 2003-2004 Christian Kvasny +* +* This file is part of the K3b project. +* Copyright (C) 1998-2007 Sebastian Trueg +* +* 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 2 of the License, or +* (at your option) any later version. +* See the file "COPYING" for the exact licensing terms. +*/ + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +// K3b Includes +#include "k3bvcdtrack.h" +#include + +K3bVcdTrack::K3bVcdTrack( QPtrList* parent, const QString& filename ) + : m_pbcnumkeys( true ), + m_pbcnumkeysuserdefined( false ), + m_file( filename ) +{ + m_parent = parent; + m_title = QFileInfo( m_file ).baseName( true ); + + m_revreflist = new QPtrList; + + for ( int i = 0; i < K3bVcdTrack::_maxPbcTracks; i++ ) { + m_pbctrackmap.insert( i, 0L ); + m_pbcnontrackmap.insert( i, K3bVcdTrack::DISABLED ); + m_pbcusrdefmap.insert( i, false ); + } + + m_reactivity = false; + + m_definedkeysmap.clear(); + + mpeg_info = new Mpeginfo(); +} + + +K3bVcdTrack::~K3bVcdTrack() +{} + + +KIO::filesize_t K3bVcdTrack::size() const +{ + return m_file.size(); +} + +int K3bVcdTrack::index() const +{ + int i = m_parent->find( this ); + if ( i < 0 ) + kdDebug() << "(K3bVcdTrack) I'm not part of my parent!" << endl; + return i; +} + +void K3bVcdTrack::addToRevRefList( K3bVcdTrack* revreftrack ) +{ + kdDebug() << "K3bVcdTrack::addToRevRefList: track = " << revreftrack << endl; + + m_revreflist->append( revreftrack ); + + kdDebug() << "K3bVcdTrack::hasRevRef count = " << m_revreflist->count() << " empty = " << m_revreflist->isEmpty() << endl; +} + +void K3bVcdTrack::delFromRevRefList( K3bVcdTrack* revreftrack ) +{ + if ( !m_revreflist->isEmpty() ) { + m_revreflist->remove + ( revreftrack ); + } +} + +bool K3bVcdTrack::hasRevRef() +{ + return !m_revreflist->isEmpty() ; +} + +void K3bVcdTrack::delRefToUs() +{ + for ( K3bVcdTrack * track = m_revreflist->first(); track; track = m_revreflist->next() ) { + for ( int i = 0; i < K3bVcdTrack::_maxPbcTracks; i++ ) { + kdDebug() << "K3bVcdTrack::delRefToUs count = " << m_revreflist->count() << " empty = " << m_revreflist->isEmpty() << " track = " << track << " this = " << this << endl; + if ( this == track->getPbcTrack( i ) ) { + track->setPbcTrack( i ); + track->setUserDefined( i, false ); + track->delFromRevRefList( this ); + } + } + } +} + +void K3bVcdTrack::delRefFromUs() +{ + for ( int i = 0; i < K3bVcdTrack::_maxPbcTracks; i++ ) { + if ( this->getPbcTrack( i ) ) { + this->getPbcTrack( i ) ->delFromRevRefList( this ); + } + } +} + +void K3bVcdTrack::setPbcTrack( int which, K3bVcdTrack* pbctrack ) +{ + kdDebug() << "K3bVcdTrack::setPbcTrack " << which << ", " << pbctrack << endl; + m_pbctrackmap.replace( which, pbctrack ); +} + +void K3bVcdTrack::setPbcNonTrack( int which, int type ) +{ + kdDebug() << "K3bVcdTrack::setNonPbcTrack " << which << ", " << type << endl; + m_pbcnontrackmap.replace( which, type ); +} + +void K3bVcdTrack::setUserDefined( int which, bool ud ) +{ + m_pbcusrdefmap.replace( which, ud ); +} + +K3bVcdTrack* K3bVcdTrack::getPbcTrack( const int& which ) +{ + if ( m_pbctrackmap.find( which ) == m_pbctrackmap.end() ) + return 0; + else + return m_pbctrackmap[ which ]; +} + +int K3bVcdTrack::getNonPbcTrack( const int& which ) +{ + if ( m_pbcnontrackmap.find( which ) == m_pbcnontrackmap.end() ) + return 0; + else + return m_pbcnontrackmap[ which ]; +} + +bool K3bVcdTrack::isPbcUserDefined( int which ) +{ + return m_pbcusrdefmap[ which ]; +} + +const QString K3bVcdTrack::resolution() +{ + if ( mpeg_info->has_video ) { + for ( int i = 0; i < 2; i++ ) { + if ( mpeg_info->video[ i ].seen ) { + return QString( "%1 x %2" ).arg( mpeg_info->video[ i ].hsize ).arg( mpeg_info->video[ i ].vsize ); + } + } + } + + return i18n( "n/a" ); +} + +const QString K3bVcdTrack::highresolution() +{ + if ( mpeg_info->has_video ) { + if ( mpeg_info->video[ 2 ].seen ) { + return QString( "%1 x %2" ).arg( mpeg_info->video[ 2 ].hsize ).arg( mpeg_info->video[ 2 ].vsize ); + } + } + return i18n( "n/a" ); +} + +const QString K3bVcdTrack::video_frate() +{ + if ( mpeg_info->has_video ) { + for ( int i = 0; i < 2; i++ ) { + if ( mpeg_info->video[ i ].seen ) { + return QString::number( mpeg_info->video[ i ].frate ); + } + } + } + + return i18n( "n/a" ); +} + +const QString K3bVcdTrack::video_bitrate() +{ + if ( mpeg_info->has_video ) { + for ( int i = 0; i < 2; i++ ) { + if ( mpeg_info->video[ i ].seen ) { + return i18n( "%1 bit/s" ).arg( mpeg_info->video[ i ].bitrate ) ; + } + } + } + + return i18n( "n/a" ); +} + + + +const QString K3bVcdTrack::video_format() +{ + if ( mpeg_info->has_video ) { + for ( int i = 0; i < 2; i++ ) { + if ( mpeg_info->video[ i ].seen ) { + switch ( mpeg_info->video[ i ].video_format ) { + case 0 : + return i18n( "Component" ); + break; + case 1 : + return "PAL"; + break; + case 2 : + return "NTSC"; + break; + case 3 : + return "SECAM"; + break; + case 4 : + return "MAC"; + break; + case 5 : + default: + return i18n( "Unspecified" ); + kdDebug() << "K3bVcdTrack::video_format() :" << mpeg_info->video[ i ].video_format << endl; + break; + } + } + } + } + return i18n( "n/a" ); +} + +const QString K3bVcdTrack::video_chroma() +{ + if ( mpeg_info->has_video ) { + // MPEG1 only supports 4:2:0 Format + if ( version() == K3bMpegInfo::MPEG_VERS_MPEG1 ) + return QString( "4:2:0" ); + + for ( int i = 0; i < 2; i++ ) { + if ( mpeg_info->video[ i ].seen ) { + switch ( mpeg_info->video[ i ].chroma_format ) { + case 1 : + return QString( "4:2:0" ); + break; + case 2 : + return QString( "4:2:2" ); + break; + case 3 : + return QString( "4:4:4" ); + break; + + } + } + } + } + + return i18n( "n/a" ); +} + +const QString K3bVcdTrack::audio_layer() +{ + if ( mpeg_info->has_audio ) { + for ( int i = 0; i < 2; i++ ) { + if ( mpeg_info->audio[ i ].seen ) { + return QString::number( mpeg_info->audio[ i ].layer ); + } + } + } + + return i18n( "n/a" ); +} + +const QString K3bVcdTrack::audio_bitrate() +{ + if ( mpeg_info->has_audio ) { + for ( int i = 0; i < 2; i++ ) { + if ( mpeg_info->audio[ i ].seen ) { + return i18n( "%1 bit/s" ).arg( mpeg_info->audio[ i ].bitrate ) ; + } + } + } + + return i18n( "n/a" ); +} + +const QString K3bVcdTrack::audio_sampfreq() +{ + if ( mpeg_info->has_audio ) { + for ( int i = 0; i < 2; i++ ) { + if ( mpeg_info->audio[ i ].seen ) { + return i18n( "%1 Hz" ).arg( mpeg_info->audio[ i ].sampfreq ) ; + } + } + } + + return i18n( "n/a" ); +} + +const QString K3bVcdTrack::audio_mode( ) +{ + if ( mpeg_info->has_audio ) { + for ( int i = 2; i >= 0; i-- ) + if ( mpeg_info->audio[ i ].seen ) + return QString( audio_type2str( mpeg_info->audio[ i ].version, mpeg_info->audio[ i ].mode, i ) ); + + } + + return i18n( "n/a" ); +} + +const QString K3bVcdTrack::audio_copyright( ) +{ + if ( mpeg_info->has_audio ) { + for ( int i = 2; i >= 0; i-- ) + if ( mpeg_info->audio[ i ].seen ) + if ( mpeg_info->audio[ i ].copyright ) + return QString( "(c) " ) + ( mpeg_info->audio[ i ].original ? i18n( "original" ) : i18n( "duplicate" ) ); + else + return ( mpeg_info->audio[ i ].original ? i18n( "original" ) : i18n( "duplicate" ) ); + } + + return i18n( "n/a" ); +} + +const QString K3bVcdTrack::mpegTypeS( bool audio ) +{ + if ( mpeg_info->has_video && !audio ) { + for ( int i = 0; i < 3; i++ ) + if ( mpeg_info->video[ i ].seen ) { + if ( i == 0 ) { + return QString( "MPEG%1 " ).arg( mpeg_info->version ) + i18n( "Motion Picture" ); + } else { + return QString( "MPEG%1 " ).arg( mpeg_info->version ) + i18n( "Still Picture" ); + } + } + } + if ( mpeg_info->has_audio && audio ) { + for ( int i = 0; i < 3; i++ ) + if ( mpeg_info->audio[ i ].seen ) { + return QString( "MPEG%1 " ).arg( mpeg_info->audio[ i ].version ) + i18n( "Layer %1" ).arg( mpeg_info->audio[ i ].layer ); + } + } + + return i18n( "n/a" ); +} + +const int K3bVcdTrack::mpegType( ) +{ + if ( mpeg_info->has_video ) { + for ( int i = 0; i < 3; i++ ) + if ( mpeg_info->video[ i ].seen ) { + if ( i == 0 ) { + return 0; // MPEG_MOTION; + } else { + return 1; // MPEG_STILL; + } + } + } + if ( mpeg_info->has_audio ) { + for ( int i = 0; i < 3; i++ ) + if ( mpeg_info->audio[ i ].seen ) + return 2; // MPEG_AUDIO; + } + + return -1; // MPEG_UNKNOWN; +} + +const QString K3bVcdTrack::audio_type2str( unsigned int version, unsigned int audio_mode, unsigned int audio_type ) +{ + kdDebug() << "K3bVcdTrack::audio_type2str() version:" << version << " audio_mode:" << audio_mode << " audio_type:" << audio_type << endl; + + QString audio_types[ 3 ][ 5 ] = { + { + i18n( "unknown" ), + i18n( "invalid" ), + QString::null, + QString::null, + QString::null + }, + { + i18n( "stereo" ), + i18n( "joint stereo" ), + i18n( "dual channel" ), + i18n( "single channel" ) + }, + { + QString::null, + i18n( "dual channel" ), + i18n( "surround sound" ), + QString::null, + QString::null + } + }; + switch ( version ) { + case K3bMpegInfo::MPEG_VERS_MPEG1: + return audio_types[ 1 ][ audio_mode ]; + break; + + case K3bMpegInfo::MPEG_VERS_MPEG2: + if ( audio_type > 0 ) { + return audio_types[ 2 ][ audio_type ]; + } + return audio_types[ 1 ][ audio_mode ]; + break; + } + + return i18n( "n/a" ); +} + +// convert a time in second to HH:mm:ss notation +QString K3bVcdTrack::SecsToHMS( double duration ) +{ + byte hours = ( byte ) ( duration / 3600 ); + byte mins = ( byte ) ( ( duration / 60 ) - ( hours * 60 ) ); + float secs = duration - 60 * mins - 3600 * hours; + if ( hours != 0 ) { + return QString( "%1:" ).arg( hours ).rightJustify( 3, ' ' ) + QString( "%1:" ).arg( mins ).rightJustify( 3, '0' ) + QString::number( secs, 'f', 2 ); + } + if ( mins != 0 ) { + return QString( "%1:" ).arg( mins ).rightJustify( 3, '0' ) + QString::number( secs, 'f', 2 ); + } + return QString::number( secs, 'f', 2 ); +} + +void K3bVcdTrack::PrintInfo() +{ + + kdDebug() << "K3bVcdTrack::PrintInfo() ....................." << endl; + kdDebug() << " version : MPEG" << version() << endl; + kdDebug() << " duration : " << duration() << endl; + kdDebug() << " muxrate : " << muxrate() << endl; + kdDebug() << " video ......................................" << endl; + kdDebug() << " type : " << mpegTypeS() << endl; + kdDebug() << " resolution : " << resolution() << endl; + kdDebug() << " high resolution: " << highresolution() << endl; + kdDebug() << " frate : " << video_frate() << endl; + kdDebug() << " bitrate : " << video_bitrate() << endl; + kdDebug() << " format : " << video_format( ) << endl; + kdDebug() << " chroma : " << video_chroma( ) << endl; + kdDebug() << " audio ......................................" << endl; + kdDebug() << " type : " << mpegTypeS( true ) << endl; + kdDebug() << " mode : " << audio_mode() << endl; + kdDebug() << " layer : " << audio_layer() << endl; + kdDebug() << " bitrate : " << audio_bitrate() << endl; + kdDebug() << " sampfreq : " << audio_sampfreq() << endl; + +} diff --git a/libk3b/projects/videocd/k3bvcdtrack.h b/libk3b/projects/videocd/k3bvcdtrack.h new file mode 100644 index 0000000..0d9a3cf --- /dev/null +++ b/libk3b/projects/videocd/k3bvcdtrack.h @@ -0,0 +1,198 @@ +/* +* +* $Id: k3bvcdtrack.h 619556 2007-01-03 17:38:12Z trueg $ +* Copyright (C) 2003-2004 Christian Kvasny +* +* This file is part of the K3b project. +* Copyright (C) 1998-2007 Sebastian Trueg +* +* 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 2 of the License, or +* (at your option) any later version. +* See the file "COPYING" for the exact licensing terms. +*/ + +#ifndef K3BVCDTRACK_H +#define K3BVCDTRACK_H + +// Qt Includes +#include +#include +#include +#include + +// Kde Includes +#include + +// K3b Includes +#include "mpeginfo/k3bmpeginfo.h" +#include "k3b_export.h" +class LIBK3B_EXPORT K3bVcdTrack +{ + public: + K3bVcdTrack( QPtrList* parent, const QString& filename ); + ~K3bVcdTrack(); + + QString fileName() const + { + return QFileInfo( m_file ).fileName(); + } + QString absPath() const + { + return QFileInfo( m_file ).absFilePath(); + } + KIO::filesize_t size() const; + int index() const; + + const QString& title() const + { + return m_title; + } + void setTitle( const QString& t ) + { + m_title = t; + } + bool isSegment() + { + return mpegType() == 1; + }; + + + + // PBC + enum PbcTracks { PREVIOUS, NEXT, RETURN, DEFAULT, AFTERTIMEOUT, _maxPbcTracks }; + enum PbcTypes { DISABLED, VIDEOEND }; + + void addToRevRefList( K3bVcdTrack* revreftrack ); + void delFromRevRefList( K3bVcdTrack* revreftrack ); + bool hasRevRef(); + void delRefToUs(); + void delRefFromUs(); + + void setPbcTrack( int, K3bVcdTrack* pbctrack = 0L ); + void setPbcNonTrack( int, int ); + void setUserDefined( int, bool ); + void setPlayTime( int t ) + { + m_pbcplaytime = t; + } + void setWaitTime( int t ) + { + m_pbcwaittime = t; + } + void setReactivity( bool b ) + { + m_reactivity = b; + } + void setPbcNumKeys( const bool& b ) + { + m_pbcnumkeys = b; + } + bool PbcNumKeys() const + { + return m_pbcnumkeys; + }; + void setPbcNumKeysUserdefined( const bool& b ) + { + m_pbcnumkeysuserdefined = b; + }; + bool PbcNumKeysUserdefined() const + { + return m_pbcnumkeysuserdefined; + }; + + K3bVcdTrack* getPbcTrack( const int& ); + int getNonPbcTrack( const int& ); + bool isPbcUserDefined( int ); + int getPlayTime() + { + return m_pbcplaytime; + } + int getWaitTime() + { + return m_pbcwaittime; + } + bool Reactivity() + { + return m_reactivity; + } + + // Numeric keys + void setDefinedNumKey( int key, K3bVcdTrack* track ) + { + m_definedkeysmap.insert( key, track ); + } + void delDefinedNumKey( int key ) + { + m_definedkeysmap.remove( key ); + } + void delDefinedNumKey() + { + m_definedkeysmap.clear(); + } + QMap DefinedNumKey() + { + return m_definedkeysmap; + } + + // Mpeg Infos + const QString resolution(); + const QString highresolution(); + const QString video_frate(); + const QString video_bitrate(); + const QString audio_layer(); + const QString audio_bitrate(); + const QString audio_sampfreq(); + + const QString duration() + { + return SecsToHMS( mpeg_info->playing_time ); + }; + const int version() + { + return mpeg_info->version; + }; + const unsigned long muxrate() + { + return mpeg_info->muxrate; + }; + const QString video_format( ); + const QString video_chroma( ); + const QString audio_mode( ); + const QString audio_copyright( ); + const QString mpegTypeS( bool audio = false ); + const int mpegType(); + + void PrintInfo(); + + Mpeginfo* mpeg_info; + + protected: + + const QString audio_type2str( unsigned int , unsigned int, unsigned int ); + QString SecsToHMS( double ); + + QPtrList* m_parent; + + // PBC + QPtrList* m_revreflist; // List of Tracks which points to us + QMap m_pbctrackmap; // Pbc Tracks (Previous, Next, ...) + QMap m_pbcnontrackmap; // Pbc NON Track types (Previous, Next, ...) + QMap m_pbcusrdefmap; // Pbc is userdefined or defaults (Previous, Next, ...) + QMap m_definedkeysmap; + + bool m_pbcnumkeys; + bool m_pbcnumkeysuserdefined; + + int m_pbcplaytime; + int m_pbcwaittime; + /********************************************************************************/ + + bool m_reactivity; + int m_filetype; + QFile m_file; + QString m_title; +}; + +#endif diff --git a/libk3b/projects/videocd/k3bvcdxmlview.cpp b/libk3b/projects/videocd/k3bvcdxmlview.cpp new file mode 100644 index 0000000..0b6f250 --- /dev/null +++ b/libk3b/projects/videocd/k3bvcdxmlview.cpp @@ -0,0 +1,440 @@ +/* +* +* $Id: k3bvcdxmlview.cpp 619556 2007-01-03 17:38:12Z trueg $ +* Copyright (C) 2003-2004 Christian Kvasny +* THX to Manfred Odenstein +* +* This file is part of the K3b project. +* Copyright (C) 1998-2007 Sebastian Trueg +* +* 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 2 of the License, or +* (at your option) any later version. +* See the file "COPYING" for the exact licensing terms. +*/ + +#include + +#include +#include + + +#include "k3bvcdxmlview.h" +#include "k3bvcdtrack.h" +#include +#include + +K3bVcdXmlView::K3bVcdXmlView( K3bVcdDoc* pDoc ) +{ + + m_doc = pDoc; + +} + +K3bVcdXmlView::~K3bVcdXmlView() +{} + +bool K3bVcdXmlView::write( const QString& fname ) +{ + + QDomDocument xmlDoc( "videocd PUBLIC \"-//GNU//DTD VideoCD//EN\" \"http://www.gnu.org/software/vcdimager/videocd.dtd\"" ); + // xmlDoc.appendChild( xmlDoc.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"iso-8859-1\"" ) ); + xmlDoc.appendChild( xmlDoc.createProcessingInstruction( "xml", "version=\"1.0\"" ) ); + + // create root element + QDomElement root = xmlDoc.createElement( "videocd" ); + root.setAttribute( "xmlns", "http://www.gnu.org/software/vcdimager/1.0/" ); + root.setAttribute( "class", m_doc->vcdOptions() ->vcdClass() ); + root.setAttribute( "version", m_doc->vcdOptions() ->vcdVersion() ); + xmlDoc.appendChild( root ); + + // create option elements + + // Broken SVCD mode - NonCompliantMode + if ( m_doc->vcdOptions() ->NonCompliantMode() ) { + QDomElement elemOption; + elemOption = addSubElement( xmlDoc, root, "option" ); + elemOption.setAttribute( "name", "svcd vcd30 mpegav" ); + elemOption.setAttribute( "value", "true" ); + + elemOption = addSubElement( xmlDoc, root, "option" ); + elemOption.setAttribute( "name", "svcd vcd30 entrysvd" ); + elemOption.setAttribute( "value", "true" ); + } + + // VCD3.0 track interpretation + if ( m_doc->vcdOptions() ->VCD30interpretation() ) { + QDomElement elemOption; + elemOption = addSubElement( xmlDoc, root, "option" ); + elemOption.setAttribute( "name", "svcd vcd30 tracksvd" ); + elemOption.setAttribute( "value", "true" ); + } + + // Relaxed aps + if ( m_doc->vcdOptions() ->RelaxedAps() ) { + QDomElement elemOption; + elemOption = addSubElement( xmlDoc, root, "option" ); + elemOption.setAttribute( "name", "relaxed aps" ); + elemOption.setAttribute( "value", "true" ); + } + + // Update scan offsets + if ( m_doc->vcdOptions() ->UpdateScanOffsets() ) { + QDomElement elemOption; + elemOption = addSubElement( xmlDoc, root, "option" ); + elemOption.setAttribute( "name", "update scan offsets" ); + elemOption.setAttribute( "value", "true" ); + + } + + // Gaps & Margins + if ( m_doc->vcdOptions() ->UseGaps() ) { + QDomElement elemOption; + elemOption = addSubElement( xmlDoc, root, "option" ); + elemOption.setAttribute( "name", "leadout pregap" ); + elemOption.setAttribute( "value", m_doc->vcdOptions() ->PreGapLeadout() ); + + elemOption = addSubElement( xmlDoc, root, "option" ); + elemOption.setAttribute( "name", "track pregap" ); + elemOption.setAttribute( "value", m_doc->vcdOptions() ->PreGapTrack() ); + + if ( m_doc->vcdOptions() ->vcdClass() == "vcd" ) { + elemOption = addSubElement( xmlDoc, root, "option" ); + elemOption.setAttribute( "name", "track front margin" ); + elemOption.setAttribute( "value", m_doc->vcdOptions() ->FrontMarginTrack() ); + + elemOption = addSubElement( xmlDoc, root, "option" ); + elemOption.setAttribute( "name", "track rear margin" ); + elemOption.setAttribute( "value", m_doc->vcdOptions() ->RearMarginTrack() ); + } else { + elemOption = addSubElement( xmlDoc, root, "option" ); + elemOption.setAttribute( "name", "track front margin" ); + elemOption.setAttribute( "value", m_doc->vcdOptions() ->FrontMarginTrackSVCD() ); + + elemOption = addSubElement( xmlDoc, root, "option" ); + elemOption.setAttribute( "name", "track rear margin" ); + elemOption.setAttribute( "value", m_doc->vcdOptions() ->RearMarginTrackSVCD() ); + } + + } + + // create info element + QDomElement elemInfo = addSubElement( xmlDoc, root, "info" ); + addSubElement( xmlDoc, elemInfo, "album-id", m_doc->vcdOptions() ->albumId().upper() ); + addSubElement( xmlDoc, elemInfo, "volume-count", m_doc->vcdOptions() ->volumeCount() ); + addSubElement( xmlDoc, elemInfo, "volume-number", m_doc->vcdOptions() ->volumeNumber() ); + addSubElement( xmlDoc, elemInfo, "restriction", m_doc->vcdOptions() ->Restriction() ); + + // create pvd element + QDomElement elemPvd = addSubElement( xmlDoc, root, "pvd" ); + addSubElement( xmlDoc, elemPvd, "volume-id", m_doc->vcdOptions() ->volumeId().upper() ); + addSubElement( xmlDoc, elemPvd, "system-id", m_doc->vcdOptions() ->systemId() ); + addSubElement( xmlDoc, elemPvd, "application-id", m_doc->vcdOptions() ->applicationId() ); + addSubElement( xmlDoc, elemPvd, "preparer-id", QString( "K3b - Version %1" ).arg( k3bcore->version() ).upper() ); + addSubElement( xmlDoc, elemPvd, "publisher-id", m_doc->vcdOptions() ->publisher().upper() ); + + + // create filesystem element + QDomElement elemFileSystem = addSubElement( xmlDoc, root, "filesystem" ); + + // SEGMENT folder, some standalone DVD-Player need this + if ( !m_doc->vcdOptions() ->haveSegments() && m_doc->vcdOptions() ->SegmentFolder() ) + addFolderElement( xmlDoc, elemFileSystem, "SEGMENT" ); + + // create cdi element + if ( m_doc->vcdOptions() ->CdiSupport() ) { + QDomElement elemFolder = addFolderElement( xmlDoc, elemFileSystem, "CDI" ); + + addFileElement( xmlDoc, elemFolder, locate( "data", "k3b/cdi/cdi_imag.rtf" ), "CDI_IMAG.RTF", true ); + addFileElement( xmlDoc, elemFolder, locate( "data", "k3b/cdi/cdi_text.fnt" ), "CDI_TEXT.FNT" ); + addFileElement( xmlDoc, elemFolder, locate( "data", "k3b/cdi/cdi_vcd.app" ), "CDI_VCD.APP" ); + + QString usercdicfg = locateLocal( "appdata", "cdi/cdi_vcd.cfg" ); + if ( QFile::exists( usercdicfg ) ) + addFileElement( xmlDoc, elemFolder, usercdicfg, "CDI_VCD.CFG" ); + else + addFileElement( xmlDoc, elemFolder, locate( "data", "k3b/cdi/cdi_vcd.cfg" ), "CDI_VCD.CFG" ); + } + + // sequence-items element & segment-items element + QDomElement elemsequenceItems; + QDomElement elemsegmentItems; + + // sequence-item element & segment-item element + QDomElement elemsequenceItem; + QDomElement elemsegmentItem; + + // if we have segments, elemsegmentItems must be before any sequence in xml file order + if ( m_doc->vcdOptions()->haveSegments() ) + elemsegmentItems = addSubElement( xmlDoc, root, "segment-items" ); + + // sequence must always available ... + elemsequenceItems = addSubElement( xmlDoc, root, "sequence-items" ); + // if we have no sequence (photo (s)vcd) we must add a dummy sequence they inform the user to turn on pbc on there videoplayer + if ( !m_doc->vcdOptions()->haveSequence() ) { + QString filename; + if ( m_doc->vcdOptions()->mpegVersion() == 1 ) + filename = locate( "data", "k3b/extra/k3bphotovcd.mpg" ); + else + filename = locate( "data", "k3b/extra/k3bphotosvcd.mpg" ); + + elemsequenceItem = addSubElement( xmlDoc, elemsequenceItems, "sequence-item" ); + elemsequenceItem.setAttribute( "src", QString( "%1" ).arg( QFile::encodeName( filename ) ) ); + elemsequenceItem.setAttribute( "id", "sequence-000" ); + // default entry + QDomElement elemdefaultEntry; + elemdefaultEntry = addSubElement( xmlDoc, elemsequenceItem, "default-entry" ); + elemdefaultEntry.setAttribute( "id", "entry-000" ); + } + + + // pbc + QDomElement elemPbc; + + // Add Tracks to XML + QPtrListIterator it( *m_doc->tracks() ); + for ( ; it.current(); ++it ) { + if ( !it.current() ->isSegment() ) { + QString seqId = QString::number( it.current() ->index() ).rightJustify( 3, '0' ); + + elemsequenceItem = addSubElement( xmlDoc, elemsequenceItems, "sequence-item" ); + elemsequenceItem.setAttribute( "src", QString( "%1" ).arg( QFile::encodeName( it.current() ->absPath() ) ) ); + elemsequenceItem.setAttribute( "id", QString( "sequence-%1" ).arg( seqId ) ); + + // default entry + QDomElement elemdefaultEntry; + elemdefaultEntry = addSubElement( xmlDoc, elemsequenceItem, "default-entry" ); + elemdefaultEntry.setAttribute( "id", QString( "entry-%1" ).arg( seqId ) ); + + } else { + // sequence-items element needs at least one segment to fit the XML + elemsegmentItem = addSubElement( xmlDoc, elemsegmentItems, "segment-item" ); + elemsegmentItem.setAttribute( "src", QString( "%1" ).arg( QFile::encodeName( it.current() ->absPath() ) ) ); + elemsegmentItem.setAttribute( "id", QString( "segment-%1" ).arg( QString::number( it.current() ->index() ).rightJustify( 3, '0' ) ) ); + + } + } + for ( it.toFirst(); it.current(); ++it ) { + + if ( m_doc->vcdOptions() ->PbcEnabled() ) { + if ( elemPbc.isNull() ) + elemPbc = addSubElement( xmlDoc, root, "pbc" ); + + doPbc( xmlDoc, elemPbc, it.current() ); + } + } + + if ( ! elemPbc.isNull() ) { + QDomElement elemEndlist = addSubElement( xmlDoc, elemPbc, "endlist" ); + elemEndlist.setAttribute( "id", "end" ); + elemEndlist.setAttribute( "rejected", "true" ); + } + + m_xmlstring = xmlDoc.toString(); + kdDebug() << QString( "(K3bVcdXmlView) Write Data to %1:" ).arg( fname ) << endl; + + QFile xmlFile( fname ); + if ( xmlFile.open( IO_WriteOnly ) ) { + QTextStream ts( & xmlFile ); + ts << m_xmlstring; + xmlFile.close(); + return true; + } + + return false; +} + +void K3bVcdXmlView::addComment( QDomDocument& doc, QDomElement& parent, const QString& text ) +{ + QDomComment comment = doc.createComment( text ); + parent.appendChild( comment ); +} + +QDomElement K3bVcdXmlView::addSubElement( QDomDocument& doc, QDomElement& parent, const QString& name, const QString& value ) +{ + QDomElement element = doc.createElement( name ); + parent.appendChild( element ); + if ( !value.isNull() ) { + QDomText t = doc.createTextNode( value ); + element.appendChild( t ); + } + return element; +} + +QDomElement K3bVcdXmlView::addSubElement( QDomDocument& doc, QDomElement& parent, const QString& name, const int& value ) +{ + QDomElement element = doc.createElement( name ); + parent.appendChild( element ); + if ( value >= -1 ) { + QDomText t = doc.createTextNode( QString( "%1" ).arg( value ) ); + element.appendChild( t ); + } + return element; +} + +QDomElement K3bVcdXmlView::addFolderElement( QDomDocument& doc, QDomElement& parent, const QString& name ) +{ + QDomElement elemFolder = addSubElement( doc, parent, "folder" ); + addSubElement( doc, elemFolder, "name", name ); + + return elemFolder; +} + +void K3bVcdXmlView::addFileElement( QDomDocument& doc, QDomElement& parent, const QString& src, const QString& name, bool mixed ) +{ + QDomElement elemFile = addSubElement( doc, parent, "file" ); + elemFile.setAttribute( "src", QString( "%1" ).arg( src ) ); + if ( mixed ) + elemFile.setAttribute( "format", "mixed" ); + + addSubElement( doc, elemFile, "name", name ); +} + +void K3bVcdXmlView::doPbc( QDomDocument& doc, QDomElement& parent, K3bVcdTrack* track ) +{ + QString ref = ( track->isSegment() ) ? "segment" : "sequence"; + + QDomElement elemSelection = addSubElement( doc, parent, "selection" ); + elemSelection.setAttribute( "id", QString( "select-%1-%2" ).arg( ref ).arg( QString::number( track->index() ).rightJustify( 3, '0' ) ) ); + + setNumkeyBSN( doc, elemSelection, track ); + + for ( int i = 0; i < K3bVcdTrack::_maxPbcTracks; i++ ) { + QDomElement elemPbcSelectionPNRDT; + + if ( track->getPbcTrack( i ) ) { + int index = track->getPbcTrack( i ) ->index(); + QString ref = ( track->getPbcTrack( i ) ->isSegment() ) ? "segment" : "sequence"; + + switch ( i ) { + case K3bVcdTrack::PREVIOUS: + elemPbcSelectionPNRDT = addSubElement( doc, elemSelection, "prev" ); + elemPbcSelectionPNRDT.setAttribute( "ref", QString( "select-%1-%2" ).arg( ref ).arg( QString::number( index ).rightJustify( 3, '0' ) ) ); + break; + case K3bVcdTrack::NEXT: + elemPbcSelectionPNRDT = addSubElement( doc, elemSelection, "next" ); + elemPbcSelectionPNRDT.setAttribute( "ref", QString( "select-%1-%2" ).arg( ref ).arg( QString::number( index ).rightJustify( 3, '0' ) ) ); + break; + case K3bVcdTrack::RETURN: + elemPbcSelectionPNRDT = addSubElement( doc, elemSelection, "return" ); + elemPbcSelectionPNRDT.setAttribute( "ref", QString( "select-%1-%2" ).arg( ref ).arg( QString::number( index ).rightJustify( 3, '0' ) ) ); + break; + case K3bVcdTrack::DEFAULT: + elemPbcSelectionPNRDT = addSubElement( doc, elemSelection, "default" ); + elemPbcSelectionPNRDT.setAttribute( "ref", QString( "select-%1-%2" ).arg( ref ).arg( QString::number( index ).rightJustify( 3, '0' ) ) ); + break; + case K3bVcdTrack::AFTERTIMEOUT: + if ( track->getWaitTime() >= 0 ) { + elemPbcSelectionPNRDT = addSubElement( doc, elemSelection, "timeout" ); + elemPbcSelectionPNRDT.setAttribute( "ref", QString( "select-%1-%2" ).arg( ref ).arg( QString::number( index ).rightJustify( 3, '0' ) ) ); + } + break; + } + } else { + // jump to otherwise do noop while disabled + if ( track->getNonPbcTrack( i ) == K3bVcdTrack::VIDEOEND ) { + switch ( i ) { + case K3bVcdTrack::PREVIOUS: + elemPbcSelectionPNRDT = addSubElement( doc, elemSelection, "prev" ); + elemPbcSelectionPNRDT.setAttribute( "ref", "end" ); + break; + case K3bVcdTrack::NEXT: + elemPbcSelectionPNRDT = addSubElement( doc, elemSelection, "next" ); + elemPbcSelectionPNRDT.setAttribute( "ref", "end" ); + break; + case K3bVcdTrack::RETURN: + elemPbcSelectionPNRDT = addSubElement( doc, elemSelection, "return" ); + elemPbcSelectionPNRDT.setAttribute( "ref", "end" ); + break; + case K3bVcdTrack::DEFAULT: + elemPbcSelectionPNRDT = addSubElement( doc, elemSelection, "default" ); + elemPbcSelectionPNRDT.setAttribute( "ref", "end" ); + break; + case K3bVcdTrack::AFTERTIMEOUT: + if ( track->getWaitTime() >= 0 ) { + elemPbcSelectionPNRDT = addSubElement( doc, elemSelection, "timeout" ); + elemPbcSelectionPNRDT.setAttribute( "ref", "end" ); + } + break; + } + } + } + } + + addSubElement( doc, elemSelection, "wait", track->getWaitTime() ); + QDomElement loop = addSubElement( doc, elemSelection, "loop", track->getPlayTime() ); + if ( track->Reactivity() ) + loop.setAttribute( "jump-timing", "delayed" ); + else + loop.setAttribute( "jump-timing", "immediate" ); + + addSubElement( doc, elemSelection, "play-item" ).setAttribute( "ref", QString( "%1-%2" ).arg( ref ).arg( QString::number( track->index() ).rightJustify( 3, '0' ) ) ); + + setNumkeySEL( doc, elemSelection, track ); +} + +void K3bVcdXmlView::setNumkeyBSN( QDomDocument& doc, QDomElement& parent, K3bVcdTrack* track ) +{ + if ( track->PbcNumKeys() ) { + if ( track->PbcNumKeysUserdefined() ) { + QMap numKeyMap = track->DefinedNumKey(); + QMap::const_iterator trackIt; + + m_startkey = 0; + trackIt = numKeyMap.begin(); + if ( trackIt != numKeyMap.end() ) + m_startkey = trackIt.key(); + + if ( m_startkey > 0 ) + addSubElement( doc, parent, "bsn", m_startkey ); + else // user has no numKeys defined for this track + track->setPbcNumKeys( false ); + + } else { + // default start with key #1 + addSubElement( doc, parent, "bsn", 1 ); + } + } +} + +void K3bVcdXmlView::setNumkeySEL( QDomDocument& doc, QDomElement& parent, K3bVcdTrack* track ) +{ + if ( track->PbcNumKeys() ) { + QDomElement elemPbcSelectionNumKeySEL; + QString ref = ( track->isSegment() ) ? "segment" : "sequence"; + int none = m_startkey; + if ( track->PbcNumKeysUserdefined() ) { + QMap numKeyMap = track->DefinedNumKey(); + QMap::const_iterator trackIt; + + for ( trackIt = numKeyMap.begin(); trackIt != numKeyMap.end(); ++trackIt ) { + + kdDebug() << QString( "trackIt key: %1 none: %2" ).arg( trackIt.key() ).arg( none ) << endl; + while ( none < trackIt.key() ) { + elemPbcSelectionNumKeySEL = addSubElement( doc, parent, "select" ); + elemPbcSelectionNumKeySEL.setAttribute( "ref", QString( "select-%1-%2" ).arg( ref ).arg( QString::number( track->index() ).rightJustify( 3, '0' ) ) ); + addComment( doc, parent, QString( "key %1 -> %2 (normal none)" ).arg( none ).arg( QFile::encodeName( track->absPath() ) ) ); + none++; + } + + if ( trackIt.data() ) { + QString ref = ( trackIt.data() ->isSegment() ) ? "segment" : "sequence"; + elemPbcSelectionNumKeySEL = addSubElement( doc, parent, "select" ); + elemPbcSelectionNumKeySEL.setAttribute( "ref", QString( "select-%1-%2" ).arg( ref ).arg( QString::number( trackIt.data() ->index() ).rightJustify( 3, '0' ) ) ); + addComment( doc, parent, QString( "key %1 -> %2" ).arg( trackIt.key() ).arg( QFile::encodeName( trackIt.data() ->absPath() ) ) ); + } else { + elemPbcSelectionNumKeySEL = addSubElement( doc, parent, "select" ); + elemPbcSelectionNumKeySEL.setAttribute( "ref", "end" ); + addComment( doc, parent, QString( "key %1 -> end" ).arg( trackIt.key() ) ); + } + none++; + } + } else { + // default reference to itSelf + elemPbcSelectionNumKeySEL = addSubElement( doc, parent, "select" ); + elemPbcSelectionNumKeySEL.setAttribute( "ref", QString( "select-%1-%2" ).arg( ref ).arg( QString::number( track->index() ).rightJustify( 3, '0' ) ) ); + } + } +} + diff --git a/libk3b/projects/videocd/k3bvcdxmlview.h b/libk3b/projects/videocd/k3bvcdxmlview.h new file mode 100644 index 0000000..d99549b --- /dev/null +++ b/libk3b/projects/videocd/k3bvcdxmlview.h @@ -0,0 +1,59 @@ +/* +* +* $Id: k3bvcdxmlview.h 619556 2007-01-03 17:38:12Z trueg $ +* Copyright (C) 2003-2004 Christian Kvasny +* THX to Manfred Odenstein +* +* This file is part of the K3b project. +* Copyright (C) 1998-2007 Sebastian Trueg +* +* 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 2 of the License, or +* (at your option) any later version. +* See the file "COPYING" for the exact licensing terms. +*/ + +#ifndef K3B_VCD_XMLVIEW_H +#define K3B_VCD_XMLVIEW_H + +#include +#include +#include + +#include + +class K3bVcdOptions; +class K3bVcdTrack; + + +class K3bVcdXmlView +{ + + public: + K3bVcdXmlView( K3bVcdDoc* ); + ~K3bVcdXmlView(); + + bool write( const QString& ); + QString xmlString() + { + return m_xmlstring; + } + + private: + QString m_xmlstring; + + void addComment( QDomDocument& doc, QDomElement& parent, const QString& text ); + QDomElement addSubElement( QDomDocument&, QDomElement&, const QString& name, const QString& value = QString::null ); + QDomElement addSubElement( QDomDocument&, QDomElement&, const QString& name, const int& value ); + + QDomElement addFolderElement( QDomDocument&, QDomElement&, const QString& name ); + void addFileElement( QDomDocument&, QDomElement&, const QString& src, const QString& name, bool mixed = false ); + void doPbc( QDomDocument&, QDomElement&, K3bVcdTrack* ); + void setNumkeyBSN( QDomDocument& , QDomElement&, K3bVcdTrack* ); + void setNumkeySEL( QDomDocument& , QDomElement&, K3bVcdTrack* ); + K3bVcdDoc* m_doc; + int m_startkey; +}; + +#endif diff --git a/libk3b/projects/videocd/mpeginfo/Makefile.am b/libk3b/projects/videocd/mpeginfo/Makefile.am new file mode 100644 index 0000000..af1b06b --- /dev/null +++ b/libk3b/projects/videocd/mpeginfo/Makefile.am @@ -0,0 +1,5 @@ +INCLUDES = $(all_includes) +noinst_LTLIBRARIES = libmpeginfo.la + +libmpeginfo_la_SOURCES = k3bmpeginfo.cpp + diff --git a/libk3b/projects/videocd/mpeginfo/k3bmpeginfo.cpp b/libk3b/projects/videocd/mpeginfo/k3bmpeginfo.cpp new file mode 100644 index 0000000..583a0aa --- /dev/null +++ b/libk3b/projects/videocd/mpeginfo/k3bmpeginfo.cpp @@ -0,0 +1,844 @@ +/* +* +* $Id: k3bmpeginfo.cpp 619556 2007-01-03 17:38:12Z trueg $ +* Copyright (C) 2003-2004 Christian Kvasny +* +* This file is part of the K3b project. +* Copyright (C) 1998-2007 Sebastian Trueg +* +* 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 2 of the License, or +* (at your option) any later version. +* See the file "COPYING" for the exact licensing terms. +*/ + +// kde includes +#include + +// k3b includes +#include "k3bmpeginfo.h" + +static const double frame_rates[ 16 ] = + { + 0.0, 24000.0 / 1001, 24.0, 25.0, + 30000.0 / 1001, 30.0, 50.0, 60000.0 / 1001, + 60.0, 0.0, + }; + +K3bMpegInfo::K3bMpegInfo( const char* filename ) + : m_mpegfile( 0 ), + m_filename( filename ), + m_done( false ), + m_buffstart( 0 ), + m_buffend( 0 ), + m_buffer( 0 ), + m_initial_TS( 0.0 ) +{ + + mpeg_info = new Mpeginfo(); + + m_mpegfile = fopen( filename, "rb" ); + + if ( m_mpegfile == 0 ) { + kdDebug() << QString( "Unable to open %1" ).arg( m_filename ) << endl; + return ; + } + + if ( fseeko( m_mpegfile, 0, SEEK_END ) ) { + kdDebug() << QString( "Unable to seek in file %1" ).arg( m_filename ) << endl; + return ; + } + + llong lof = ftello( m_mpegfile ); + + if ( lof == -1 ) { + kdDebug() << QString( "Seeking to end of input file %1 failed." ).arg( m_filename ) << endl; + //give up.. + return ; + } else + m_filesize = lof; + + // nothing to do on an empty file + if ( !m_filesize ) { + kdDebug() << QString( "File %1 is empty." ).arg( m_filename ) << endl; + m_error_string = i18n( "File %1 is empty." ).arg( m_filename ); + return ; + } + + m_buffer = new byte[ BUFFERSIZE ]; + + MpegParsePacket ( ); + +} + +K3bMpegInfo::~K3bMpegInfo() +{ + if ( m_buffer ) { + delete[] m_buffer; + } + if ( m_mpegfile ) { + fclose( m_mpegfile ); + } + + delete mpeg_info; +} +bool K3bMpegInfo::MpegParsePacket () +{ + + /* verify the packet begins with a pack header */ + if ( !EnsureMPEG( 0, MPEG_PACK_HEADER_CODE ) ) { + llong code = GetNBytes( 0, 4 ); + + kdDebug() << QString( "(K3bMpegInfo::mpeg_parse_packet ()) pack header code 0x%1 expected, but 0x%2 found" ).arg( 0x00000100 + MPEG_PACK_HEADER_CODE, 0, 16 ).arg( code, 0, 16 ) << endl; + + if ( code == 0x00000100 + MPEG_SEQUENCE_CODE ) { + kdDebug() << "...this looks like a elementary video stream but a multiplexed program stream was required." << endl; + m_error_string = i18n( "This looks like a elementary video stream but a multiplexed program stream was required." ); + } + + if ( ( 0xfff00000 & code ) == 0xfff00000 ) { + kdDebug() << "...this looks like a elementary audio stream but a multiplexed program stream was required." << endl; + m_error_string = i18n( "This looks like a elementary audio stream but a multiplexed program stream was required." ); + } + + if ( code == 0x52494646 ) { + kdDebug() << "...this looks like a RIFF header but a plain multiplexed program stream was required." << endl; + m_error_string = i18n( "This looks like a RIFF header but a plain multiplexed program stream was required." ); + } + + return false; + } + + + /* take a look at the pack header */ + int offset = 0; + while ( GetByte( offset ) == 0x00 ) + offset ++; + //here we're on the first non null byte let's get back to leave two zeros (packet start code) + offset -= 2; + + if ( offset != 0 ) { + // we actually skipped some zeroes + kdDebug() << QString( "Skipped %1 zeroes at start of file" ).arg( offset ) << endl; + } + + // here while schleife + while ( offset != -1 ) { + offset = MpegParsePacket( offset ); + } + + /* + int pkt = 0; + offset = FindNextMarker( 0, MPEG_PACK_HEADER_CODE ); + + while ( offset != -1 ) { + pkt++; + offset = FindNextMarker( offset+1, MPEG_PACK_HEADER_CODE ); + } + + kdDebug() << "Pkt found: " << pkt << endl; + */ + + //seek the file duration by fetching the last PACK + //and reading its timestamp + llong last_pack = bdFindNextMarker( m_filesize - 13, MPEG_PACK_HEADER_CODE ); + // -12 because a PACK is at least 12 bytes + double duration; + last_pack += 4; + int bits = GetByte( last_pack ) >> 4; + + if ( bits == 0x2 ) /* %0010 ISO11172-1 */ + { + duration = ReadTS( last_pack ); + } else if ( bits >> 2 == 0x1 ) /* %01xx ISO13818-1 */ + { + duration = ReadTSMpeg2( last_pack ); + } else { + kdDebug() << QString( "no timestamp found" ) << endl; + duration = ReadTS( last_pack ); + } + + mpeg_info->playing_time = duration - m_initial_TS; + + + if ( !mpeg_info->has_video ) + for ( int i = 0; i < 2; i++ ) + if ( mpeg_info->video[ i ].seen ) + mpeg_info->has_video = true; + + if ( !mpeg_info->has_audio ) + for ( int i = 0; i < 2; i++ ) + if ( mpeg_info->audio[ i ].seen ) + mpeg_info->has_audio = true; + + return true; +} + +llong K3bMpegInfo::MpegParsePacket ( llong offset ) +{ + byte mark = 0; + uint size = 0; + + /* continue until start code seen */ + offset = FindNextMarker( offset, &mark ); + + if ( offset < 0 ) + return offset; + + switch ( mark ) { + int bits; + + case MPEG_PACK_HEADER_CODE: + // kdDebug() << QString( "MPEG_PACK_HEADER_CODE @ %1" ).arg( offset ) << endl; + + offset += 4; + + if ( mpeg_info->version != MPEG_VERS_INVALID ) + break; + + bits = GetByte( offset ) >> 4; + + if ( bits == 0x2 ) /* %0010 ISO11172-1 */ + { + mpeg_info->version = MPEG_VERS_MPEG1; + + unsigned long muxrate = 0; + + muxrate = ( GetByte( offset + 5 ) & 0x7F ) << 15; + muxrate |= ( GetByte( offset + 6 ) << 7 ); + muxrate |= ( GetByte( offset + 7 ) >> 1 ); + + mpeg_info->muxrate = muxrate * 50 * 8; + + if ( m_initial_TS == 0.0 ) + { + m_initial_TS = ReadTS( offset ); + kdDebug() << QString( "Initial TS = %1" ).arg( m_initial_TS ) << endl; + } + + } else if ( bits >> 2 == 0x1 ) /* %01xx ISO13818-1 */ + { + mpeg_info->version = MPEG_VERS_MPEG2; + + unsigned long muxrate = 0; + muxrate = GetByte( offset + 6 ) << 14; + muxrate |= GetByte( offset + 7 ) << 6; + muxrate |= GetByte( offset + 8 ) >> 2; + + mpeg_info->muxrate = muxrate * 50 * 8; + + if ( m_initial_TS == 0.0 ) + { + m_initial_TS = ReadTSMpeg2( offset ); + kdDebug() << QString( "Initial TS = %1" ).arg( m_initial_TS ) << endl; + } + + } else { + kdDebug() << QString( "packet not recognized as either version 1 or 2 (%1)" ).arg( bits ) << endl; + mpeg_info->version = MPEG_VERS_INVALID; + return -1; + } + break; + + case MPEG_SYSTEM_HEADER_CODE: + case MPEG_PAD_CODE: + case MPEG_PRIVATE_1_CODE: + case MPEG_VIDEO_E0_CODE: + case MPEG_VIDEO_E1_CODE: + case MPEG_VIDEO_E2_CODE: + case MPEG_AUDIO_C0_CODE: + case MPEG_AUDIO_C1_CODE: + case MPEG_AUDIO_C2_CODE: + + offset += 4; + size = GetSize( offset ); + offset += 2; + // kdDebug() << QString( "offset = %1, size = %2" ).arg( offset ).arg( size ) << endl; + + switch ( mark ) { + case MPEG_SYSTEM_HEADER_CODE: + // kdDebug() << QString( "Systemheader: %1" ).arg( m_code, 0, 16 ) << endl; + break; + + case MPEG_VIDEO_E0_CODE: + case MPEG_VIDEO_E1_CODE: + case MPEG_VIDEO_E2_CODE: + ParseVideo( offset, mark ); + // _analyze_video_pes (code & 0xff, buf + pos, size, !parse_pes, ctx); + if ( mpeg_info->has_video && mpeg_info->has_audio ) { + return -1; + } else if ( mark == MPEG_VIDEO_E0_CODE || mpeg_info->version == MPEG_VERS_MPEG2 && mark == MPEG_VIDEO_E1_CODE || mpeg_info->version == MPEG_VERS_MPEG1 && mark == MPEG_VIDEO_E2_CODE ) { + mpeg_info->has_video = true; + offset = FindNextAudio( offset ); + } + break; + case MPEG_AUDIO_C0_CODE: + case MPEG_AUDIO_C1_CODE: + case MPEG_AUDIO_C2_CODE: + offset = SkipPacketHeader( offset - 6 ); + ParseAudio( offset, mark ); + // audio packet doesn't begin with 0xFFF + if ( !mpeg_info->audio[ GetAudioIdx( mark ) ].seen ) { + int a_idx = GetAudioIdx( mark ); + while ( ( offset < m_filesize - 10 ) && !mpeg_info->audio[ a_idx ].seen ) { + if ( ( GetByte( offset ) == 0xFF ) && ( GetByte( offset + 1 ) & 0xF0 ) == 0xF0 ) + ParseAudio( offset, mark ); + offset++; + } + } + + mpeg_info->has_audio = true; + if ( mpeg_info->has_video ) + return -1; + + offset = FindNextVideo( offset ); + break; + + case MPEG_PRIVATE_1_CODE: + kdDebug() << QString( "PrivateCode: %1" ).arg( mark, 0, 16 ) << endl; + break; + } + break; + + case MPEG_PROGRAM_END_CODE: + kdDebug() << QString( "ProgramEndCode: %1" ).arg( mark, 0, 16 ) << endl; + offset += 4; + break; + + case MPEG_PICTURE_CODE: + kdDebug() << QString( "PictureCode: %1" ).arg( mark, 0, 16 ) << endl; + offset += 3; + break; + + default: + offset += 4; + break; + } + + return offset; +} + +byte K3bMpegInfo::GetByte( llong offset ) +{ + unsigned long nread; + if ( ( offset >= m_buffend ) || ( offset < m_buffstart ) ) { + + if ( fseeko( m_mpegfile, offset, SEEK_SET ) ) { + kdDebug() << QString( "could not get seek to offset (%1) in file %2 (size:%3)" ).arg( offset ).arg( m_filename ).arg( m_filesize ) << endl; + return 0x11; + } + nread = fread( m_buffer, 1, BUFFERSIZE, m_mpegfile ); + m_buffstart = offset; + m_buffend = offset + nread; + if ( ( offset >= m_buffend ) || ( offset < m_buffstart ) ) { + // weird + kdDebug() << QString( "could not get offset %1 in file %2 [%3]" ).arg( offset ).arg( m_filename ).arg( m_filesize ) << endl; + return 0x11; + } + } + return m_buffer[ offset - m_buffstart ]; +} + +// same as above but improved for backward search +byte K3bMpegInfo::bdGetByte( llong offset ) +{ + unsigned long nread; + if ( ( offset >= m_buffend ) || ( offset < m_buffstart ) ) { + llong start = offset - BUFFERSIZE + 1 ; + start = start >= 0 ? start : 0; + + fseeko( m_mpegfile, start, SEEK_SET ); + + nread = fread( m_buffer, 1, BUFFERSIZE, m_mpegfile ); + m_buffstart = start; + m_buffend = start + nread; + if ( ( offset >= m_buffend ) || ( offset < m_buffstart ) ) { + // weird + kdDebug() << QString( "could not get offset %1 in file %2 [%3]" ).arg( offset ).arg( m_filename ).arg( m_filesize ) << endl; + + return 0x11; + } + } + return m_buffer[ offset - m_buffstart ]; +} + + +llong K3bMpegInfo::GetNBytes( llong offset, int n ) +{ + llong nbytes = 0; + n--; + for ( int i = 0; i < n; i++ ) + ( ( char* ) & nbytes ) [ n - i ] = GetByte( offset + i ); + + return nbytes; + +} + +// get a two byte size +unsigned short int K3bMpegInfo::GetSize( llong offset ) +{ + return GetByte( offset ) * 256 + GetByte( offset + 1 ); + // return GetNBytes( offset, 2 ); + +} + +bool K3bMpegInfo::EnsureMPEG( llong offset, byte mark ) +{ + if ( ( GetByte( offset ) == 0x00 ) && + ( GetByte( offset + 1 ) == 0x00 ) && + ( GetByte( offset + 2 ) == 0x01 ) && + ( GetByte( offset + 3 ) == mark ) ) + return true; + else + return false; +} + + +// find next 0x 00 00 01 xx sequence, returns offset or -1 on err +llong K3bMpegInfo::FindNextMarker( llong from ) +{ + llong offset; + for ( offset = from; offset < ( m_filesize - 4 ); offset++ ) { + if ( + ( GetByte( offset + 0 ) == 0x00 ) && + ( GetByte( offset + 1 ) == 0x00 ) && + ( GetByte( offset + 2 ) == 0x01 ) ) { + return offset; + } + } + return -1; +} + +// find next 0x 00 00 01 xx sequence, returns offset or -1 on err and +// change mark to xx +llong K3bMpegInfo::FindNextMarker( llong from, byte* mark ) +{ + llong offset = FindNextMarker( from ); + if ( offset >= 0 ) { + *mark = GetByte( offset + 3 ); + return offset; + } else { + return -1; + } +} + +// find next 0X00 00 01 mark +llong K3bMpegInfo::FindNextMarker( llong from, byte mark ) +{ + llong offset = from; + while ( offset >= 0 ) { + offset = FindNextMarker( offset ); + if ( offset < 0 ) { + return -1; + } + if ( EnsureMPEG( offset, mark ) ) { + return offset; + } else + offset++; + } + + //shouldn't be here + return -1; +} + +llong K3bMpegInfo::bdFindNextMarker( llong from, byte mark ) +{ + llong offset; + for ( offset = from; offset >= 0; offset-- ) { + if ( + ( bdGetByte( offset ) == 0x00 ) && + ( bdGetByte( offset + 1 ) == 0x00 ) && + ( bdGetByte( offset + 2 ) == 0x01 ) && + ( bdGetByte( offset + 3 ) == mark ) ) { + return offset; + } + } + return -1; +} + +llong K3bMpegInfo::bdFindNextMarker( llong from, byte* mark ) +{ + llong offset; + for ( offset = from; offset >= 0; offset-- ) { + if ( ( bdGetByte( offset ) == 0x00 ) && + ( bdGetByte( offset + 1 ) == 0x00 ) && + ( bdGetByte( offset + 2 ) == 0x01 ) ) { + *mark = bdGetByte( offset + 3 ); + return offset; + } + } + return -1; + +} + +llong K3bMpegInfo::FindNextVideo( llong from ) +{ + llong offset = from; + while ( offset >= 0 ) { + offset = FindNextMarker( offset ); + if ( offset < 0 ) { + return -1; + } + if ( EnsureMPEG( offset, MPEG_VIDEO_E0_CODE ) || EnsureMPEG( offset, MPEG_VIDEO_E1_CODE ) || EnsureMPEG( offset, MPEG_VIDEO_E2_CODE ) ) { + return offset; + } else + offset++; + } + + //shouldn't be here + return -1; +} + +llong K3bMpegInfo::FindNextAudio( llong from ) +{ + llong offset = from; + while ( offset >= 0 ) { + offset = FindNextMarker( offset ); + if ( offset < 0 ) { + return -1; + } + if ( EnsureMPEG( offset, MPEG_AUDIO_C0_CODE ) || EnsureMPEG( offset, MPEG_AUDIO_C1_CODE ) || EnsureMPEG( offset, MPEG_AUDIO_C2_CODE ) ) { + return offset; + } else + offset++; + } + + return -1; +} + + +int K3bMpegInfo::GetVideoIdx ( byte marker ) +{ + switch ( marker ) { + case MPEG_VIDEO_E0_CODE: + return 0; + break; + + case MPEG_VIDEO_E1_CODE: + return 1; + break; + + case MPEG_VIDEO_E2_CODE: + return 2; + break; + + default: + kdDebug() << "VideoCode not reached" << endl; + break; + } + + return -1; +} + +int K3bMpegInfo::GetAudioIdx ( byte marker ) +{ + switch ( marker ) { + case MPEG_AUDIO_C0_CODE: + return 0; + break; + + case MPEG_AUDIO_C1_CODE: + return 1; + break; + + case MPEG_AUDIO_C2_CODE: + return 2; + break; + + default: + kdDebug() << "VideoCode not reached" << endl; + break; + } + + return -1; +} + +llong K3bMpegInfo::SkipPacketHeader( llong offset ) +{ + byte tmp_byte; + if ( mpeg_info->version == MPEG_VERS_MPEG1 ) { + // skip startcode and packet size + offset += 6; + //remove stuffing bytes + tmp_byte = GetByte( offset ); + while ( tmp_byte & 0x80 ) + tmp_byte = GetByte( ++offset ); + + if ( ( tmp_byte & 0xC0 ) == 0x40 ) // next two bits are 01 + offset += 2; + + tmp_byte = GetByte( offset ); + if ( ( tmp_byte & 0xF0 ) == 0x20 ) + offset += 5; + else if ( ( tmp_byte & 0xF0 ) == 0x30 ) + offset += 10; + else + offset++; + + return offset; + } else if ( mpeg_info->version == MPEG_VERS_MPEG2 ) { + return ( offset + 9 + GetByte( offset + 8 ) ); + } else + return ( offset + 10 ); +} + +void K3bMpegInfo::ParseAudio ( llong offset, byte marker ) +{ + unsigned brate, srate; + bool mpeg2_5 = false; + + const int a_idx = GetAudioIdx( marker ); + + if ( mpeg_info->audio[ a_idx ].seen ) /* we have it already */ + return ; + + if ( ( GetByte( offset ) != 0xFF ) || ( ( GetByte( offset + 1 ) & 0xF0 ) != 0xF0 ) ) { + // doesn't start with 12 bits set + if ( ( GetByte( offset ) != 0xFF ) || ( ( GetByte( offset + 1 ) & 0xE0 ) != 0xE0 ) ) { + // doesn't start with 11 bits set + return ; + } else { + // start with 11 bits set + mpeg2_5 = true; + } + } + + // Find mpeg version 1.0 or 2.0 + if ( GetByte( offset + 1 ) & 0x08 ) { + if ( !mpeg2_5 ) + mpeg_info->audio[ a_idx ].version = 1; + else + return ; // invalid 01 encountered + } else { + if ( !mpeg2_5 ) + mpeg_info->audio[ a_idx ].version = 2; + else + mpeg_info->audio[ a_idx ].version = 3; //for mpeg 2.5 + } + + // Find Layer + mpeg_info->audio[ a_idx ].layer = ( GetByte( offset + 1 ) & 0x06 ) >> 1; + switch ( mpeg_info->audio[ a_idx ].layer ) { + case 0: + mpeg_info->audio[ a_idx ].layer = 0; + break; + case 1: + mpeg_info->audio[ a_idx ].layer = 3; + break; + case 2: + mpeg_info->audio[ a_idx ].layer = 2; + break; + case 3: + mpeg_info->audio[ a_idx ].layer = 1; + break; + } + + // Protection Bit + mpeg_info->audio[ a_idx ].protect = GetByte( offset + 1 ) & 0x01; + if ( mpeg_info->audio[ a_idx ].protect ) + mpeg_info->audio[ a_idx ].protect = 0; + else + mpeg_info->audio[ a_idx ].protect = 1; + + const unsigned bit_rates[ 4 ][ 16 ] = { + { + 0, + }, + {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0}, + {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0}, + {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0} + }; + + + /* const unsigned bit_rates [ 3 ][ 3 ][ 16 ] = { + { + {0, }, + {0, }, + {0, }, + }, + { + {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0}, + {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0}, + {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0} + }, + { + {0, 32, 48, 56, 64, 80 , 96 , 112, 128, 144, 160, 176, 192, 224, 256, 0}, + {0, 8, 16, 24, 32, 40, 48, 56, 64 , 80 , 96 , 112, 128, 144, 160, 0}, + {0, 8, 16, 24, 32, 40, 48, 56, 64 , 80 , 96 , 112, 128, 144, 160, 0} + } + }; + */ + + const unsigned sampling_rates[ 4 ][ 4 ] = { + { + 0, + }, + {44100, 48000, 32000, 0}, //mpeg 1 + {22050, 24000, 16000, 0}, //mpeg 2 + {11025, 12000, 8000, 0} //mpeg 2.5 + }; + + + // Bitrate index and sampling index to pass through the array + brate = GetByte( offset + 2 ) >> 4; + srate = ( GetByte( offset + 2 ) & 0x0f ) >> 2; + + mpeg_info->audio[ a_idx ].bitrate = 1024 * bit_rates[ mpeg_info->audio[ a_idx ].layer ][ brate ]; + mpeg_info->audio[ a_idx ].byterate = ( float ) ( mpeg_info->audio[ a_idx ].bitrate / 8.0 ); + mpeg_info->audio[ a_idx ].sampfreq = sampling_rates[ mpeg_info->audio[ a_idx ].version ][ srate ]; + + // Audio mode + mpeg_info->audio[ a_idx ].mode = 1 + ( GetByte( offset + 3 ) >> 6 ) ; + + // Copyright bit + if ( GetByte( offset + 3 ) & 0x08 ) + mpeg_info->audio[ a_idx ].copyright = true; + else + mpeg_info->audio[ a_idx ].copyright = false; + + // Original/Copy bit + if ( GetByte( offset + 3 ) & 0x04 ) + mpeg_info->audio[ a_idx ].original = true; + else + mpeg_info->audio[ a_idx ].original = false; + + + mpeg_info->audio[ a_idx ].seen = true; +} + +void K3bMpegInfo::ParseVideo ( llong offset, byte marker ) +{ + unsigned long aratio, frate, brate; + + const int v_idx = GetVideoIdx( marker ); + + const double aspect_ratios[ 16 ] = { + 0.0000, 1.0000, 0.6735, 0.7031, + 0.7615, 0.8055, 0.8437, 0.8935, + 0.9375, 0.9815, 1.0255, 1.0695, + 1.1250, 1.1575, 1.2015, 0.0000 + }; + + if ( mpeg_info->video[ v_idx ].seen ) /* we have it already */ + return ; + + offset = FindNextMarker( offset + 1, MPEG_SEQUENCE_CODE ); + + if ( !offset ) + return ; + + offset += 4; + + mpeg_info->video[ v_idx ].hsize = GetSize( offset ) >> 4; + mpeg_info->video[ v_idx ].vsize = GetSize( offset + 1 ) & 0x0FFF; + + // Get picture rate + offset += 3; // after picture sizes + + aratio = ( GetByte( offset ) & 0x0F ) >> 4; + mpeg_info->video[ v_idx ].aratio = aspect_ratios[ aratio ]; + + // offset += 3; // after picture sizes + frate = GetByte( offset ) & 0x0F; + mpeg_info->video[ v_idx ].frate = frame_rates[ frate ]; + + offset += 1; // after picture rate + + // 18 following bytes are the bitrate /400 + + //read first 16 bytes + brate = GetSize( offset ); + // scale + brate <<= 2; + byte lasttwo = GetByte( offset + 2 ); + lasttwo >>= 6; + brate |= lasttwo; + + mpeg_info->video[ v_idx ].bitrate = 400 * brate; + + byte mark; + while ( true ) { + offset = FindNextMarker( offset, &mark ); + if ( mark == MPEG_GOP_CODE ) + break; + switch ( GetByte( offset + 3 ) ) { + case MPEG_EXT_CODE : + // Extension + offset += 4; + switch ( GetByte( offset ) >> 4 ) { + case 1: + //SequenceExt + if ( GetByte( offset + 1 ) & 0x08 ) + mpeg_info->video[ v_idx ].progressive = true; + mpeg_info->video[ v_idx ].chroma_format = ( GetByte( offset + 1 ) & 0x06 ) >> 1; + break; + case 2: + // SequenceDisplayExt + mpeg_info->video[ v_idx ].video_format = ( GetByte( offset ) & 0x0E ) >> 1; + break; + } + + break; + case MPEG_USER_CODE : + // UserData + break; + } + offset++; + } + + mpeg_info->video[ v_idx ].seen = true; +} + +double K3bMpegInfo::ReadTS( llong offset ) +{ + byte highbit; + unsigned long low4Bytes; + double TS; + + highbit = ( GetByte( offset ) >> 3 ) & 0x01; + + low4Bytes = ( ( GetByte( offset ) >> 1 ) & 0x03 ) << 30; + low4Bytes |= GetByte( offset + 1 ) << 22; + low4Bytes |= ( GetByte( offset + 2 ) >> 1 ) << 15; + low4Bytes |= GetByte( offset + 3 ) << 7; + low4Bytes |= GetByte( offset + 4 ) >> 1; + + + TS = ( double ) ( highbit * FLOAT_0x10000 * FLOAT_0x10000 ); + TS += ( double ) ( low4Bytes ); + TS /= ( double ) ( STD_SYSTEM_CLOCK_FREQ ); + + return TS; +} + +double K3bMpegInfo::ReadTSMpeg2( llong offset ) +{ + byte highbit; + unsigned long low4Bytes; + unsigned long sys_clock_ref; + double TS; + + highbit = ( GetByte( offset ) & 0x20 ) >> 5; + + low4Bytes = ( ( GetByte( offset ) & 0x18 ) >> 3 ) << 30; + low4Bytes |= ( GetByte( offset ) & 0x03 ) << 28; + low4Bytes |= GetByte( offset + 1 ) << 20; + low4Bytes |= ( GetByte( offset + 2 ) & 0xF8 ) << 12; + low4Bytes |= ( GetByte( offset + 2 ) & 0x03 ) << 13; + low4Bytes |= GetByte( offset + 3 ) << 5; + low4Bytes |= ( GetByte( offset + 4 ) ) >> 3; + + sys_clock_ref = ( GetByte( offset + 4 ) & 0x3 ) << 7; + sys_clock_ref |= ( GetByte( offset + 5 ) >> 1 ); + + TS = ( double ) ( highbit * FLOAT_0x10000 * FLOAT_0x10000 ); + TS += ( double ) ( low4Bytes ); + if ( sys_clock_ref == 0 ) + TS /= ( double ) ( STD_SYSTEM_CLOCK_FREQ ); + else { + TS /= ( double ) ( 27000000 / sys_clock_ref ); + } + + return TS; +} diff --git a/libk3b/projects/videocd/mpeginfo/k3bmpeginfo.h b/libk3b/projects/videocd/mpeginfo/k3bmpeginfo.h new file mode 100644 index 0000000..3436214 --- /dev/null +++ b/libk3b/projects/videocd/mpeginfo/k3bmpeginfo.h @@ -0,0 +1,178 @@ +/* +* +* $Id: k3bmpeginfo.h 619556 2007-01-03 17:38:12Z trueg $ +* Copyright (C) 2003-2004 Christian Kvasny +* +* This file is part of the K3b project. +* Copyright (C) 1998-2007 Sebastian Trueg +* +* 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 2 of the License, or +* (at your option) any later version. +* See the file "COPYING" for the exact licensing terms. +*/ + +#ifndef K3BMPEGINFO +#define K3BMPEGINFO + +#include + +// #define BUFFERSIZE 16384 +#define BUFFERSIZE 65536 + +#define MPEG_START_CODE_PATTERN ((ulong) 0x00000100) +#define MPEG_START_CODE_MASK ((ulong) 0xffffff00) + +#define MPEG_PICTURE_CODE ((ulong) 0x00000100) +/* [...slice codes... 0x1a7] */ + +#define MPEG_USER_CODE ((uchar) 0xb2) +#define MPEG_SEQUENCE_CODE ((uchar) 0xb3) +#define MPEG_EXT_CODE ((uchar) 0xb5) +#define MPEG_SEQ_END_CODE ((uchar) 0xb7) +#define MPEG_GOP_CODE ((uchar) 0xb8) +#define MPEG_PROGRAM_END_CODE ((uchar) 0xb9) +#define MPEG_PACK_HEADER_CODE ((uchar) 0xba) +#define MPEG_SYSTEM_HEADER_CODE ((uchar) 0xbb) +#define MPEG_PRIVATE_1_CODE ((uchar) 0xbd) +#define MPEG_PAD_CODE ((uchar) 0xbe) + +#define MPEG_AUDIO_C0_CODE ((uchar) 0xc0) /* default */ +#define MPEG_AUDIO_C1_CODE ((uchar) 0xc1) /* 2nd audio stream id (dual channel) */ +#define MPEG_AUDIO_C2_CODE ((uchar) 0xc2) /* 3rd audio stream id (surround sound) */ + +#define MPEG_VIDEO_E0_CODE ((uchar) 0xe0) /* motion */ +#define MPEG_VIDEO_E1_CODE ((uchar) 0xe1) /* lowres still */ +#define MPEG_VIDEO_E2_CODE ((uchar) 0xe2) /* hires still */ + +#define FLOAT_0x10000 (double)((unsigned long)1 << 16) +#define STD_SYSTEM_CLOCK_FREQ (unsigned long)90000 + +typedef unsigned char byte; +typedef long long llong; + +#include + +class video_info +{ + public: + bool seen; + unsigned long hsize; + unsigned long vsize; + double aratio; + double frate; + unsigned long bitrate; + unsigned long vbvsize; + bool progressive; + unsigned char video_format; + unsigned char chroma_format; + bool constrained_flag; +}; + +class audio_info +{ + public: + bool seen; + unsigned int version; + unsigned int layer; + unsigned int protect; + unsigned long bitrate; + float byterate; + unsigned long sampfreq; + int mode; + bool copyright; + bool original; +}; + +class Mpeginfo +{ + + public: + Mpeginfo() + : version( 0 ), + muxrate( 0 ), + playing_time( 0 ), + has_video ( false ), + has_audio ( false ) + { + for ( int i = 0; i < 3; i++ ) { + video[ i ].seen = false; + audio[ i ].seen = false; + } + }; + + ~Mpeginfo() + {} + ; + + unsigned int version; + unsigned long muxrate; + double playing_time; + bool has_video; + bool has_audio; + video_info video[ 3 ]; + audio_info audio[ 3 ]; +}; + +class K3bMpegInfo +{ + public: + K3bMpegInfo( const char* filename ); + ~K3bMpegInfo(); + enum mpeg_version { MPEG_VERS_INVALID = 0, MPEG_VERS_MPEG1 = 1, MPEG_VERS_MPEG2 = 2 }; + enum mode { MPEG_STEREO = 1, MPEG_JOINT_STEREO, MPEG_DUAL_CHANNEL, MPEG_SINGLE_CHANNEL }; + + const int version() + { + return mpeg_info->version; + }; + const QString error_string() + { + return m_error_string; + }; + Mpeginfo* mpeg_info; + + + private: + // General ToolBox + byte GetByte( llong offset ); + byte bdGetByte( llong offset ); + llong GetNBytes( llong, int ); + unsigned short int GetSize( llong offset ); + llong FindNextMarker( llong ); + llong FindNextMarker( llong, byte* ); + llong FindNextMarker( llong, byte ); + llong bdFindNextMarker( llong, byte ); + llong bdFindNextMarker( llong, byte* ); + llong FindNextVideo( llong ); + llong FindNextAudio( llong ); + + int GetVideoIdx ( byte ); + int GetAudioIdx ( byte ); + bool EnsureMPEG( llong, byte ); + void ParseVideo ( llong, byte ); + void ParseAudio ( llong, byte ); + bool MpegParsePacket (); + llong MpegParsePacket ( llong ); + llong SkipPacketHeader( llong ); + + double ReadTS( llong offset ); + double ReadTSMpeg2( llong offset ); + + FILE* m_mpegfile; + + const char* m_filename; + llong m_filesize; + + bool m_done; + + llong m_buffstart; + llong m_buffend; + byte* m_buffer; + double m_initial_TS; + QString m_error_string; + +}; + +#endif //K3bMpegInfo diff --git a/libk3b/projects/videodvd/Makefile.am b/libk3b/projects/videodvd/Makefile.am new file mode 100644 index 0000000..1b3e92b --- /dev/null +++ b/libk3b/projects/videodvd/Makefile.am @@ -0,0 +1,20 @@ +# we need the ../datacd for the uic generated header files +AM_CPPFLAGS= -I$(srcdir)/../../core \ + -I$(srcdir)/../../../libk3bdevice \ + -I$(srcdir)/../../../src \ + -I$(srcdir)/../../tools \ + -I$(srcdir)/../datadvd \ + -I$(srcdir)/../datacd \ + -I$(srcdir)/.. \ + -I../datacd \ + $(all_includes) + +METASOURCES = AUTO + +noinst_LTLIBRARIES = libvideodvd.la + +libvideodvd_la_SOURCES = k3bvideodvddoc.cpp \ + k3bvideodvdjob.cpp \ + k3bvideodvdimager.cpp + +include_HEADERS = k3bvideodvddoc.h k3bvideodvdjob.h diff --git a/libk3b/projects/videodvd/k3bvideodvddoc.cpp b/libk3b/projects/videodvd/k3bvideodvddoc.cpp new file mode 100644 index 0000000..2f02ac6 --- /dev/null +++ b/libk3b/projects/videodvd/k3bvideodvddoc.cpp @@ -0,0 +1,71 @@ +/* + * + * $Id: k3bvideodvddoc.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bvideodvddoc.h" +#include "k3bvideodvdjob.h" + +#include + +#include + +#include + + +K3bVideoDvdDoc::K3bVideoDvdDoc( QObject* parent ) + : K3bDvdDoc( parent ) +{ +} + + +K3bVideoDvdDoc::~K3bVideoDvdDoc() +{ +} + + +bool K3bVideoDvdDoc::newDocument() +{ + if( K3bDataDoc::newDocument() ) { + + // K3bDataDoc::newDocument already deleted m_videoTsDir (again: bad design!) + m_videoTsDir = new K3bDirItem( "VIDEO_TS", this, root() ); + m_videoTsDir->setRemoveable(false); + m_videoTsDir->setRenameable(false); + m_videoTsDir->setMoveable(false); + m_videoTsDir->setHideable(false); + + K3bDirItem* audioTsDir = new K3bDirItem( "AUDIO_TS", this, root() ); + audioTsDir->setRemoveable(false); + audioTsDir->setRenameable(false); + audioTsDir->setMoveable(false); + audioTsDir->setHideable(false); + + setMultiSessionMode( NONE ); + + setModified( false ); + + return true; + } + else + return false; +} + + +K3bBurnJob* K3bVideoDvdDoc::newBurnJob( K3bJobHandler* hdl, QObject* parent ) +{ + return new K3bVideoDvdJob( this, hdl, parent ); +} + +//#include "k3bdvddoc.moc" diff --git a/libk3b/projects/videodvd/k3bvideodvddoc.h b/libk3b/projects/videodvd/k3bvideodvddoc.h new file mode 100644 index 0000000..034ae4d --- /dev/null +++ b/libk3b/projects/videodvd/k3bvideodvddoc.h @@ -0,0 +1,46 @@ +/* + * + * $Id: k3bvideodvddoc.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_VIDEODVD_DOC_H_ +#define _K3B_VIDEODVD_DOC_H_ + +#include +#include "k3b_export.h" +class KConfig; + +class LIBK3B_EXPORT K3bVideoDvdDoc : public K3bDvdDoc +{ + public: + K3bVideoDvdDoc( QObject* parent = 0 ); + virtual ~K3bVideoDvdDoc(); + + virtual int type() const { return VIDEODVD; } + + virtual K3bBurnJob* newBurnJob( K3bJobHandler* hdl, QObject* parent ); + + virtual bool newDocument(); + + K3bDirItem* videoTsDir() const { return m_videoTsDir; } + + // TODO: implement load- and saveDocumentData since we do not need all those options + + protected: + virtual QString typeString() const { return "video_dvd"; } + + private: + K3bDirItem* m_videoTsDir; +}; + +#endif diff --git a/libk3b/projects/videodvd/k3bvideodvdimager.cpp b/libk3b/projects/videodvd/k3bvideodvdimager.cpp new file mode 100644 index 0000000..7362aa0 --- /dev/null +++ b/libk3b/projects/videodvd/k3bvideodvdimager.cpp @@ -0,0 +1,221 @@ +/* + * + * $Id: k3bvideodvdimager.cpp 633751 2007-02-15 08:22:49Z trueg $ + * Copyright (C) 2004-2007 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bvideodvdimager.h" +#include "k3bvideodvddoc.h" +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + + +class K3bVideoDvdImager::Private +{ +public: + K3bVideoDvdDoc* doc; + + QString tempPath; +}; + + +K3bVideoDvdImager::K3bVideoDvdImager( K3bVideoDvdDoc* doc, K3bJobHandler* jh, QObject* parent, const char* name ) + : K3bIsoImager( doc, jh, parent, name ) +{ + d = new Private; + d->doc = doc; +} + + +K3bVideoDvdImager::~K3bVideoDvdImager() +{ + delete d; +} + + +void K3bVideoDvdImager::start() +{ + fixVideoDVDSettings(); + K3bIsoImager::start(); +} + + +void K3bVideoDvdImager::init() +{ + fixVideoDVDSettings(); + K3bIsoImager::init(); +} + + +void K3bVideoDvdImager::fixVideoDVDSettings() +{ + // Video DVD defaults, we cannot set these in K3bVideoDvdDoc since they + // will be overwritten in the burn dialog unless we create some K3bVideoDVDIsoOptions + // class with different defaults. But since the whole Video DVD project is a hack we + // go the easy road. + K3bIsoOptions o = d->doc->isoOptions(); + o.setISOLevel(1); + o.setISOallow31charFilenames(false); + o.setCreateJoliet(false); + o.setJolietLong(false); + o.setCreateRockRidge(false); + o.setCreateUdf(true); + d->doc->setIsoOptions( o ); +} + + +void K3bVideoDvdImager::calculateSize() +{ + fixVideoDVDSettings(); + K3bIsoImager::calculateSize(); +} + + +int K3bVideoDvdImager::writePathSpec() +{ + // + // Create a temp dir and link all contents of the VIDEO_TS dir to make mkisofs + // able to handle the VideoDVD stuff. + // + // mkisofs is not able to create VideoDVDs from graft-points. + // + // We do this here since K3bIsoImager::start calls cleanup which deletes the temp files + // + QDir dir( KGlobal::dirs()->resourceDirs( "tmp" ).first() ); + d->tempPath = K3b::findUniqueFilePrefix( "k3bVideoDvd", dir.path() ); + kdDebug() << "(K3bVideoDvdImager) creating temp dir: " << d->tempPath << endl; + if( !dir.mkdir( d->tempPath, true ) ) { + emit infoMessage( i18n("Unable to create temporary directory '%1'.").arg(d->tempPath), ERROR ); + return -1; + } + + dir.cd( d->tempPath ); + if( !dir.mkdir( "VIDEO_TS" ) ) { + emit infoMessage( i18n("Unable to create temporary directory '%1'.").arg(d->tempPath + "/VIDEO_TS"), ERROR ); + return -1; + } + + for( QPtrListIterator it( d->doc->videoTsDir()->children() ); *it; ++it ) { + if( (*it)->isDir() ) { + emit infoMessage( i18n("Found invalid entry in the VIDEO_TS folder (%1).").arg((*it)->k3bName()), ERROR ); + return -1; + } + + // convert to upper case names + if( ::symlink( QFile::encodeName( (*it)->localPath() ), + QFile::encodeName( d->tempPath + "/VIDEO_TS/" + (*it)->k3bName().upper() ) ) == -1 ) { + emit infoMessage( i18n("Unable to link temporary file in folder %1.").arg( d->tempPath ), ERROR ); + return -1; + } + } + + + return K3bIsoImager::writePathSpec(); +} + + +int K3bVideoDvdImager::writePathSpecForDir( K3bDirItem* dirItem, QTextStream& stream ) +{ + // + // We handle the VIDEO_TS dir differently since otherwise mkisofs is not able to + // open the VideoDVD structures (see addMkisofsParameters) + // + if( dirItem == d->doc->videoTsDir() ) { + return 0; + } + + int num = 0; + for( QPtrListIterator it( dirItem->children() ); it.current(); ++it ) { + K3bDataItem* item = it.current(); + num++; + + if( item->isDir() ) { + // we cannot add the video_ts dir twice + if( item != d->doc->videoTsDir() ) { + stream << escapeGraftPoint( item->writtenPath() ) + << "=" + << escapeGraftPoint( dummyDir( static_cast(item) ) ) << "\n"; + } + + int x = writePathSpecForDir( dynamic_cast(item), stream ); + if( x >= 0 ) + num += x; + else + return -1; + } + else { + writePathSpecForFile( static_cast(item), stream ); + } + } + + return num; +} + + +bool K3bVideoDvdImager::addMkisofsParameters( bool printSize ) +{ + // Here is another bad design: we assume that K3bIsoImager::start does not add additional + // parameters to the process. :( + if( K3bIsoImager::addMkisofsParameters( printSize ) ) { + *m_process << "-dvd-video"; + *m_process << "-f"; // follow symlinks + *m_process << d->tempPath; + return true; + } + else + return false; +} + + +void K3bVideoDvdImager::cleanup() +{ + if( QFile::exists( d->tempPath ) ) { + QDir dir( d->tempPath ); + dir.cd( "VIDEO_TS" ); + for( QPtrListIterator it( d->doc->videoTsDir()->children() ); *it; ++it ) + dir.remove( (*it)->k3bName().upper() ); + dir.cdUp(); + dir.rmdir( "VIDEO_TS" ); + dir.cdUp(); + dir.rmdir( d->tempPath ); + } + d->tempPath = QString::null; + + K3bIsoImager::cleanup(); +} + + +void K3bVideoDvdImager::slotReceivedStderr( const QString& line ) +{ + if( line.contains( "Unable to make a DVD-Video image" ) ) { + emit infoMessage( i18n("The project does not contain all necessary VideoDVD files."), WARNING ); + emit infoMessage( i18n("The resulting DVD will most likely not be playable on a Hifi DVD player."), WARNING ); + } + else + K3bIsoImager::slotReceivedStderr( line ); +} + +#include "k3bvideodvdimager.moc" diff --git a/libk3b/projects/videodvd/k3bvideodvdimager.h b/libk3b/projects/videodvd/k3bvideodvdimager.h new file mode 100644 index 0000000..0062d55 --- /dev/null +++ b/libk3b/projects/videodvd/k3bvideodvdimager.h @@ -0,0 +1,61 @@ +/* + * + * $Id: k3bvideodvdimager.h 633751 2007-02-15 08:22:49Z trueg $ + * Copyright (C) 2004 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_VIDEODVD_IMAGER_H_ +#define _K3B_VIDEODVD_IMAGER_H_ + + +#include + +class K3bVideoDvdDoc; + + +/** + * Create VideoDVD images with mkisofs. The difference + * to the IsoImager is the -dvd-video option and the fact + * that all VIDEO_TS files need to be in one local folder since + * otherwise mkisofs is not able to find the dvd structures. + */ +class K3bVideoDvdImager : public K3bIsoImager +{ + Q_OBJECT + + public: + K3bVideoDvdImager( K3bVideoDvdDoc* doc, K3bJobHandler*, QObject* parent = 0, const char* name = 0 ); + virtual ~K3bVideoDvdImager(); + + public slots: + virtual void start(); + virtual void init(); + virtual void calculateSize(); + + protected: + bool addMkisofsParameters( bool printSize = false ); + int writePathSpec(); + void cleanup(); + int writePathSpecForDir( K3bDirItem* dirItem, QTextStream& stream ); + + protected slots: + virtual void slotReceivedStderr( const QString& ); + + private: + void fixVideoDVDSettings(); + + class Private; + Private* d; +}; + +#endif diff --git a/libk3b/projects/videodvd/k3bvideodvdjob.cpp b/libk3b/projects/videodvd/k3bvideodvdjob.cpp new file mode 100644 index 0000000..f4e6129 --- /dev/null +++ b/libk3b/projects/videodvd/k3bvideodvdjob.cpp @@ -0,0 +1,101 @@ +/* + * + * $Id: k3bvideodvdjob.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bvideodvdjob.h" +#include "k3bvideodvddoc.h" +#include "k3bvideodvdimager.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + + + +K3bVideoDvdJob::K3bVideoDvdJob( K3bVideoDvdDoc* doc, K3bJobHandler* jh, QObject* parent ) + : K3bDvdJob( doc, jh, parent ), + m_doc(doc) +{ +} + + +K3bVideoDvdJob::~K3bVideoDvdJob() +{ +} + + +void K3bVideoDvdJob::prepareImager() +{ + setImager( new K3bVideoDvdImager( m_doc, this ) ); +} + + +bool K3bVideoDvdJob::prepareWriterJob() +{ + K3bGrowisofsWriter* writer = new K3bGrowisofsWriter( m_doc->burner(), this, this ); + + // these do only make sense with DVD-R(W) + writer->setSimulate( m_doc->dummy() ); + writer->setBurnSpeed( m_doc->speed() ); + + // DAO seems to be the better default for Video DVD... !? + if( m_doc->writingMode() == K3b::DAO || m_doc->writingMode() == K3b::WRITING_MODE_AUTO ) + writer->setWritingMode( K3b::DAO ); + + writer->setMultiSession( false ); + writer->setCloseDvd( true ); + + if( m_doc->onTheFly() ) { + writer->setImageToWrite( QString::null ); // read from stdin + writer->setTrackSize( m_isoImager->size() ); + } + else + writer->setImageToWrite( m_doc->tempDir() ); + + setWriterJob( writer ); + + return true; +} + + +QString K3bVideoDvdJob::jobDescription() const +{ + if( m_doc->onlyCreateImages() ) { + return i18n("Creating Video DVD Image File"); + } + else { + return i18n("Writing Video DVD") + + ( m_doc->isoOptions().volumeID().isEmpty() + ? QString::null + : QString( " (%1)" ).arg(m_doc->isoOptions().volumeID()) ); + } +} + + +QString K3bVideoDvdJob::jobDetails() const +{ + return ( i18n("ISO9660/Udf Filesystem (Size: %1)").arg(KIO::convertSize( doc()->size() )) + + ( m_doc->copies() > 1 + ? i18n(" - %n copy", " - %n copies", m_doc->copies()) + : QString::null ) ); +} + +#include "k3bvideodvdjob.moc" diff --git a/libk3b/projects/videodvd/k3bvideodvdjob.h b/libk3b/projects/videodvd/k3bvideodvdjob.h new file mode 100644 index 0000000..3f03cea --- /dev/null +++ b/libk3b/projects/videodvd/k3bvideodvdjob.h @@ -0,0 +1,46 @@ +/* + * + * $Id: k3bvideodvdjob.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_VIDEO_DVD_JOB_H_ +#define _K3B_VIDEO_DVD_JOB_H_ + +#include + + +class K3bVideoDvdDoc; + +/** + * This class heavily depends on K3bDvdJob and uses some of it's internals. + */ +class K3bVideoDvdJob : public K3bDvdJob +{ + Q_OBJECT + + public: + K3bVideoDvdJob( K3bVideoDvdDoc*, K3bJobHandler*, QObject* parent = 0 ); + virtual ~K3bVideoDvdJob(); + + virtual QString jobDescription() const; + virtual QString jobDetails() const; + + private: + bool prepareWriterJob(); + void prepareImager(); + + K3bVideoDvdDoc* m_doc; +}; + +#endif diff --git a/libk3b/scripts/Makefile.am b/libk3b/scripts/Makefile.am new file mode 100644 index 0000000..6318b9b --- /dev/null +++ b/libk3b/scripts/Makefile.am @@ -0,0 +1,11 @@ +bin_SCRIPTS = k3b_automount + +# k3b_automount needs to be installed setuid root +install-exec-hook: + @(chown 0 $(DESTDIR)$(bindir)/k3b_automount && chmod 4755 $(DESTDIR)$(bindir)/k3b_automount) || echo "Please make k3b_automount setuid root" >&2 + @echo "" + @echo "k3b_automount is by default installed with a set SETUID root bit!" + @echo "This is needed for K3b to be able to temporarily disable automounting via" + @echo "subfs or supermount while burning." + @echo "" + diff --git a/libk3b/scripts/k3b_automount b/libk3b/scripts/k3b_automount new file mode 100755 index 0000000..e86e960 --- /dev/null +++ b/libk3b/scripts/k3b_automount @@ -0,0 +1,66 @@ +#!/bin/bash + +# +# This script is able to disable and enable automounting for a device. +# It's usage is as follows: +# +# k3b_automount disable /dev/cdrom +# or +# k3b_automount enable /dev/cdrom +# +# /dev/cdrom needs to have an entry in /etc/fstab. +# +# The supported automounting systems are subfs and supermount. +# +# Exit codes: +# 0 - success +# 1 - wrong usage +# 2 - device not configured with subfs/supermount in /etc/fstab +# X - failed to mount/umount +# + +DISABLE=1 + +if [ $1 = "disable" ]; then + DISABLE=1 +elif [ $1 = "enable" ]; then + DISABLE=0 +else + echo "Usage: $0 disable|enable " + exit 1 +fi + +DEVICE=$2 + +if [ -z $DEVICE ]; then + echo "Usage: $0 disable|enable " + exit 1 +fi + +# we have a mode and a device + +# open the fstab file and search the DEVICE +if [ -n "`grep $DEVICE /etc/fstab | grep "subfs\|supermount"`" ]; then + if [ $DISABLE = 1 ]; then + umount $DEVICE + else + mount $DEVICE + fi + exit $? +fi + +# +# Ok, not using subfs or supermount +# If some other userspace automounter (like ivman) is running it is sufficient +# to unmount the device now to get the burning started. This however does not +# fix the problem with DVD+RW burning which may be mounted once the burning has +# been started. +# +# So we unmount the device in case it is mounted with iso9660 or udf (just to add +# some security to this suid script. :( +# +if [ $DISABLE = 1 ] && [ -n "`grep $DEVICE /etc/mtab | grep "iso9660\|udf"`" ]; then + umount $DEVICE + exit $? +fi +exit 2 diff --git a/libk3b/tools/Makefile.am b/libk3b/tools/Makefile.am new file mode 100644 index 0000000..d48a295 --- /dev/null +++ b/libk3b/tools/Makefile.am @@ -0,0 +1,44 @@ +AM_CPPFLAGS= -I$(srcdir)/../../src \ + -I$(srcdir)/../core \ + -I$(srcdir)/../../libk3bdevice \ + -I$(srcdir)/.. \ + $(all_includes) + +noinst_LTLIBRARIES = libk3btools.la + +libk3btools_la_LIBADD = libisofs/libisofs.la + +libk3btools_la_LDFLAGS = $(all_libraries) + +libk3btools_la_SOURCES = k3bwavefilewriter.cpp k3bbusywidget.cpp k3bdeviceselectiondialog.cpp \ + k3bmd5job.cpp k3btitlelabel.cpp k3bcutcombobox.cpp \ + k3bstringutils.cpp k3bdevicecombobox.cpp kcutlabel.cpp \ + k3bstdguiitems.cpp k3bvalidators.cpp k3bthroughputestimator.cpp \ + k3biso9660.cpp k3bmultichoicedialog.cpp k3bdevicehandler.cpp \ + k3bcdparanoialib.cpp k3blistview.cpp k3bmsfedit.cpp \ + k3bcdtextvalidator.cpp k3bintvalidator.cpp k3bexceptions.cpp \ + k3bprogressdialog.cpp k3btoolbox.cpp k3bpushbutton.cpp \ + k3blistviewitemanimator.cpp k3bthreadwidget.cpp k3bradioaction.cpp \ + k3bsignalwaiter.cpp k3blibdvdcss.cpp k3biso9660backend.cpp \ + k3bpipe.cpp k3bchecksumpipe.cpp k3btoolbutton.cpp \ + k3bintmapcombobox.cpp k3bdirsizejob.cpp k3brichtextlabel.cpp \ + k3btempfile.cpp k3bactivepipe.cpp k3bfilesplitter.cpp \ + k3bfilesysteminfo.cpp + +include_HEADERS = k3bwavefilewriter.h k3bbusywidget.h k3bdeviceselectiondialog.h \ + k3bmd5job.h k3bcutcombobox.h k3bstringutils.h \ + k3bdevicecombobox.h kcutlabel.h k3bstdguiitems.h \ + k3bvalidators.h k3bthroughputestimator.h k3biso9660.h \ + k3bmultichoicedialog.h k3bdevicehandler.h k3bcdparanoialib.h \ + k3blistview.h k3bmsfedit.h k3bcdtextvalidator.h \ + k3bintvalidator.h k3bexceptions.h k3bprogressdialog.h \ + k3btoolbox.h k3bpushbutton.h k3blistviewitemanimator.h \ + k3bthreadwidget.h k3bradioaction.h k3bsignalwaiter.h \ + k3biso9660backend.h k3bpipe.h k3bdirsizejob.h \ + k3bchecksumpipe.h k3btoolbutton.h k3bintmapcombobox.h \ + k3brichtextlabel.h k3btempfile.h k3bactivepipe.h \ + k3bfilesplitter.h k3bfilesysteminfo.h + +METASOURCES = AUTO + +SUBDIRS = libisofs diff --git a/libk3b/tools/k3bactivepipe.cpp b/libk3b/tools/k3bactivepipe.cpp new file mode 100644 index 0000000..5a1e575 --- /dev/null +++ b/libk3b/tools/k3bactivepipe.cpp @@ -0,0 +1,255 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bactivepipe.h" + +#include + +#include + +#include +#include + +#include + + +class K3bActivePipe::Private : public QThread +{ +public: + Private( K3bActivePipe* pipe ) : + m_pipe( pipe ), + fdToReadFrom(-1), + fdToWriteTo(-1), + sourceIODevice(0), + sinkIODevice(0), + closeFdToReadFrom(false), + closeFdToWriteTo(false) { + } + + void run() { + kdDebug() << "(K3bActivePipe) started thread." << endl; + bytesRead = bytesWritten = 0; + buffer.resize( 10*2048 ); + ssize_t r = 0; + while( ( r = m_pipe->read( buffer.data(), buffer.size() ) ) > 0 ) { + + bytesRead += r; + + // write it out + ssize_t w = 0; + ssize_t ww = 0; + while( w < r ) { + if( ( ww = m_pipe->write( buffer.data()+w, r-w ) ) > 0 ) { + w += ww; + bytesWritten += ww; + } + else { + kdDebug() << "(K3bActivePipe) write failed." << endl; + close( closeWhenDone ); + return; + } + } + } + // kdDebug() << "(K3bActivePipe) thread done: " << r << " (total bytes read/written: " << bytesRead << "/" << bytesWritten << ")" << endl; + close( closeWhenDone ); + } + + int readFd() const { + if( fdToReadFrom == -1 ) + return pipeIn.out(); + else + return fdToReadFrom; + } + + int writeFd() const { + if( fdToWriteTo == -1 ) + return pipeOut.in(); + else + return fdToWriteTo; + } + + void close( bool closeAll ) { + if( sourceIODevice ) + sourceIODevice->close(); + if( sinkIODevice ) + sinkIODevice->close(); + + if( closeAll ) { + pipeIn.close(); + pipeOut.close(); + if( fdToWriteTo != -1 && + closeFdToWriteTo ) + ::close( fdToWriteTo ); + + if( fdToReadFrom != -1 && + closeFdToReadFrom ) + ::close( fdToReadFrom ); + } + } + +private: + K3bActivePipe* m_pipe; + +public: + int fdToReadFrom; + int fdToWriteTo; + K3bPipe pipeIn; + K3bPipe pipeOut; + + QIODevice* sourceIODevice; + QIODevice* sinkIODevice; + + bool closeWhenDone; + bool closeFdToReadFrom; + bool closeFdToWriteTo; + + QByteArray buffer; + + Q_UINT64 bytesRead; + Q_UINT64 bytesWritten; +}; + + +K3bActivePipe::K3bActivePipe() +{ + d = new Private( this ); +} + + +K3bActivePipe::~K3bActivePipe() +{ + delete d; +} + + +bool K3bActivePipe::open( bool closeWhenDone ) +{ + if( d->running() ) + return false; + + d->closeWhenDone = closeWhenDone; + + if( d->sourceIODevice ) { + if( !d->sourceIODevice->open( IO_ReadOnly ) ) + return false; + } + else if( d->fdToReadFrom == -1 && !d->pipeIn.open() ) { + return false; + } + + if( d->sinkIODevice ) { + if( !d->sinkIODevice->open( IO_WriteOnly ) ) + return false; + } + else if( d->fdToWriteTo == -1 && !d->pipeOut.open() ) { + close(); + return false; + } + + kdDebug() << "(K3bActivePipe) successfully opened pipe." << endl; + + d->start(); + return true; +} + + +void K3bActivePipe::close() +{ + d->pipeIn.closeIn(); + d->wait(); + d->close( true ); +} + + +void K3bActivePipe::readFromFd( int fd, bool close ) +{ + d->fdToReadFrom = fd; + d->sourceIODevice = 0; + d->closeFdToReadFrom = close; +} + + +void K3bActivePipe::writeToFd( int fd, bool close ) +{ + d->fdToWriteTo = fd; + d->sinkIODevice = 0; + d->closeFdToWriteTo = close; +} + + +void K3bActivePipe::readFromIODevice( QIODevice* dev ) +{ + d->fdToReadFrom = -1; + d->sourceIODevice = dev; +} + + +void K3bActivePipe::writeToIODevice( QIODevice* dev ) +{ + d->fdToWriteTo = -1; + d->sinkIODevice = dev; +} + + +int K3bActivePipe::in() const +{ + return d->pipeIn.in(); +} + + +int K3bActivePipe::out() const +{ + return d->pipeOut.out(); +} + + +int K3bActivePipe::read( char* data, int max ) +{ + if( d->sourceIODevice ) + return d->sourceIODevice->readBlock( data, max ); + else + return ::read( d->readFd(), data, max ); +} + + +int K3bActivePipe::write( char* data, int max ) +{ + if( d->sinkIODevice ) + return d->sinkIODevice->writeBlock( data, max ); + else + return ::write( d->writeFd(), data, max ); +} + + +bool K3bActivePipe::pumpSync() +{ + if( open( true ) ) + d->wait(); + else + return false; + return true; +} + + +Q_UINT64 K3bActivePipe::bytesRead() const +{ + return d->bytesRead; +} + + +Q_UINT64 K3bActivePipe::bytesWritten() const +{ + return d->bytesWritten; +} diff --git a/libk3b/tools/k3bactivepipe.h b/libk3b/tools/k3bactivepipe.h new file mode 100644 index 0000000..367646d --- /dev/null +++ b/libk3b/tools/k3bactivepipe.h @@ -0,0 +1,134 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_ACTIVE_PIPE_H_ +#define _K3B_ACTIVE_PIPE_H_ + +#include + +#include + + +class QIODevice; + + +/** + * The active pipe pumps data from a source to a sink using an + * additional thread. + */ +class LIBK3B_EXPORT K3bActivePipe +{ + public: + K3bActivePipe(); + virtual ~K3bActivePipe(); + + /** + * Opens the pipe and thus starts the + * pumping. + * + * \param closeWhenDone If true the pipes will be closed + * once all data has been read. + */ + virtual bool open( bool closeWhenDone = false ); + + /** + * Opens the pipe syncroneously and blocks until all data has been + * pumped through. + * The pipe is closed afterwards. + */ + bool pumpSync(); + + /** + * Close the pipe + */ + virtual void close(); + + /** + * Set the file descriptor to read from. If this is -1 (the default) then + * data has to be piped into the in() file descriptor. + * + * \param fd The file descriptor to read from. + * \param close If true the reading file descriptor will be closed on a call to close() + */ + void readFromFd( int fd, bool close = false ); + + /** + * Set the file descriptor to write to. If this is -1 (the default) then + * data has to read from the out() file descriptor. + * + * \param fd The file descriptor to write to. + * \param close If true the reading file descriptor will be closed on a call to close() + */ + void writeToFd( int fd, bool close = false ); + + /** + * Read from a QIODevice instead of a file descriptor. + * The device will be opened IO_ReadOnly and closed + * afterwards. + */ + void readFromIODevice( QIODevice* dev ); + + /** + * Write to a QIODevice instead of a file descriptor. + * The device will be opened IO_WriteOnly and closed + * afterwards. + */ + void writeToIODevice( QIODevice* dev ); + + /** + * The file descriptor to write into + * Only valid if no source has been set + */ + int in() const; + + /** + * The file descriptor to read from + * Only valid if no sink has been set + */ + int out() const; + + /** + * The number of bytes that have been read. + */ + Q_UINT64 bytesRead() const; + + /** + * The number of bytes that have been written. + */ + Q_UINT64 bytesWritten() const; + + protected: + /** + * Reads the data from the source. + * The default implementation reads from the file desc + * set via readFromFd or from in() + */ + virtual int read( char* data, int max ); + + /** + * Write the data to the sink. + * The default implementation writes to the file desc + * set via writeToFd or out() + * + * Can be reimplememented to further process the data. + */ + virtual int write( char* data, int max ); + + private: + class Private; + Private* d; +}; + +#endif diff --git a/libk3b/tools/k3bbusywidget.cpp b/libk3b/tools/k3bbusywidget.cpp new file mode 100644 index 0000000..d222107 --- /dev/null +++ b/libk3b/tools/k3bbusywidget.cpp @@ -0,0 +1,103 @@ +/* + * + * $Id: k3bbusywidget.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bbusywidget.h" + +#include +#include + +#include + + +K3bBusyWidget::K3bBusyWidget( QWidget* parent, const char* name ) + : QFrame( parent, name ) +{ + m_busyTimer = new QTimer( this ); + m_iBusyPosition = 0; + + connect( m_busyTimer, SIGNAL(timeout()), this, SLOT(animateBusy()) ); + + m_bBusy = false; +} + +K3bBusyWidget::~K3bBusyWidget() +{ +} + + +void K3bBusyWidget::showBusy( bool b ) +{ + m_bBusy = b; + +// if( b ) { +// m_iBusyCounter++; +// } +// else if( m_iBusyCounter > 0 ) { +// m_iBusyCounter--; +// } + + if( m_bBusy ) { + if( !m_busyTimer->isActive() ) + m_busyTimer->start( 500 ); + } + else { + if( m_busyTimer->isActive() ) + m_busyTimer->stop(); + update(); + m_iBusyPosition = 0; + } +} + + +void K3bBusyWidget::animateBusy() +{ + m_iBusyPosition++; + update(); +} + + +QSize K3bBusyWidget::sizeHint() const +{ + return minimumSizeHint(); +} + + +QSize K3bBusyWidget::minimumSizeHint() const +{ + return QSize( 2*frameWidth() + 62, 10 ); +} + + +void K3bBusyWidget::drawContents( QPainter* p ) +{ + QRect rect = contentsRect(); + + int squareSize = 8; + + int pos = 2 + m_iBusyPosition * (squareSize + 2); + + // check if the position is in the visible area + if( pos + 8 + 2> rect.width() ) { + m_iBusyPosition = 0; + pos = 2; + } + + // p->eraseRect( rect ); + if( m_bBusy ) + p->fillRect( pos, (rect.height() - squareSize)/2, squareSize, squareSize, KGlobalSettings::highlightColor() ); +} + + +#include "k3bbusywidget.moc" diff --git a/libk3b/tools/k3bbusywidget.h b/libk3b/tools/k3bbusywidget.h new file mode 100644 index 0000000..2a6934c --- /dev/null +++ b/libk3b/tools/k3bbusywidget.h @@ -0,0 +1,54 @@ +/* + * + * $Id: k3bbusywidget.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef K3B_BUSY_WIDGET_H +#define K3B_BUSY_WIDGET_H + + +#include +#include "k3b_export.h" + +class QPainter; +class QTimer; + + +class LIBK3B_EXPORT K3bBusyWidget : public QFrame +{ + Q_OBJECT + + public: + K3bBusyWidget( QWidget* parent = 0, const char* name = 0 ); + ~K3bBusyWidget(); + + void showBusy( bool b ); + + QSize sizeHint() const; + QSize minimumSizeHint() const; + + protected: + void drawContents( QPainter* p ); + + private slots: + void animateBusy(); + + private: + bool m_bBusy; + int m_iBusyPosition; + + QTimer* m_busyTimer; +}; + + +#endif diff --git a/libk3b/tools/k3bcdparanoialib.cpp b/libk3b/tools/k3bcdparanoialib.cpp new file mode 100644 index 0000000..5976941 --- /dev/null +++ b/libk3b/tools/k3bcdparanoialib.cpp @@ -0,0 +1,783 @@ +/* + * + * $Id: k3bcdparanoialib.cpp 621693 2007-01-09 14:38:25Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include + +#include "k3bcdparanoialib.h" + +#include +#include +#include + +#include + +#include + +#include +#include + + +static bool s_haveLibCdio = false; + + +void* K3bCdparanoiaLib::s_libInterface = 0; +void* K3bCdparanoiaLib::s_libParanoia = 0; +int K3bCdparanoiaLib::s_counter = 0; + + +#define CDDA_IDENTIFY s_haveLibCdio ? "cdio_cddap_identify" : "cdda_identify" +#define CDDA_CLOSE s_haveLibCdio ? "cdio_cddap_close" : "cdda_close" +#define CDDA_OPEN s_haveLibCdio ? "cdio_cddap_open" : "cdda_open" +#define CDDA_TRACK_FIRSTSECTOR s_haveLibCdio ? "cdio_cddap_track_firstsector" : "cdda_track_firstsector" +#define CDDA_TRACK_LASTSECTOR s_haveLibCdio ? "cdio_cddap_track_lastsector" : "cdda_track_lastsector" +#define CDDA_VERBOSE_SET s_haveLibCdio ? "cdio_cddap_verbose_set" : "cdda_verbose_set" +#define CDDA_DISC_FIRSTSECTOR s_haveLibCdio ? "cdio_cddap_disc_firstsector" : "cdda_disc_firstsector" + +#define PARANOIA_INIT s_haveLibCdio ? "cdio_paranoia_init" : "paranoia_init" +#define PARANOIA_FREE s_haveLibCdio ? "cdio_paranoia_free" : "paranoia_free" +#define PARANOIA_MODESET s_haveLibCdio ? "cdio_paranoia_modeset" : "paranoia_modeset" +#define PARANOIA_SEEK s_haveLibCdio ? "cdio_paranoia_seek" : "paranoia_seek" +#define PARANOIA_READ_LIMITED s_haveLibCdio ? "cdio_paranoia_read_limited" : "paranoia_read_limited" + + +// from cdda_paranoia.h +#define PARANOIA_CB_READ 0 +#define PARANOIA_CB_VERIFY 1 +#define PARANOIA_CB_FIXUP_EDGE 2 +#define PARANOIA_CB_FIXUP_ATOM 3 +#define PARANOIA_CB_SCRATCH 4 +#define PARANOIA_CB_REPAIR 5 +#define PARANOIA_CB_SKIP 6 +#define PARANOIA_CB_DRIFT 7 +#define PARANOIA_CB_BACKOFF 8 +#define PARANOIA_CB_OVERLAP 9 +#define PARANOIA_CB_FIXUP_DROPPED 10 +#define PARANOIA_CB_FIXUP_DUPED 11 +#define PARANOIA_CB_READERR 12 + + + +static void paranoiaCallback( long, int status ) +{ + // do nothing so far.... + return; + + switch( status ) { + case -1: + break; + case -2: + break; + case PARANOIA_CB_READ: + // no problem + // does only this mean that the sector has been read? +// m_lastReadSector = sector; // this seems to be rather useless +// m_readSectors++; + break; + case PARANOIA_CB_VERIFY: + break; + case PARANOIA_CB_FIXUP_EDGE: + break; + case PARANOIA_CB_FIXUP_ATOM: + break; + case PARANOIA_CB_SCRATCH: + // scratch detected + break; + case PARANOIA_CB_REPAIR: + break; + case PARANOIA_CB_SKIP: + // skipped sector + break; + case PARANOIA_CB_DRIFT: + break; + case PARANOIA_CB_BACKOFF: + break; + case PARANOIA_CB_OVERLAP: + // sector does not seem to contain the current + // sector but the amount of overlapped data + // m_overlap = sector; + break; + case PARANOIA_CB_FIXUP_DROPPED: + break; + case PARANOIA_CB_FIXUP_DUPED: + break; + case PARANOIA_CB_READERR: + break; + } +} + + + +extern "C" { + struct cdrom_drive; + struct cdrom_paranoia; + + // HINT: these pointers must NOT have the same name like the actual methods! + // I added "cdda_" as prefix + // Before doing that K3b crashed in cdda_open! + // Can anyone please explain that to me? + + // cdda_interface + cdrom_drive* (*cdda_cdda_identify)(const char*, int, char**); + int (*cdda_cdda_open)(cdrom_drive *d); + int (*cdda_cdda_close)(cdrom_drive *d); + long (*cdda_cdda_track_firstsector)( cdrom_drive*, int ); + long (*cdda_cdda_track_lastsector)( cdrom_drive*, int ); + long (*cdda_cdda_disc_firstsector)(cdrom_drive *d); + void (*cdda_cdda_verbose_set)(cdrom_drive *d,int err_action, int mes_action); + + // cdda_paranoia + cdrom_paranoia* (*cdda_paranoia_init)(cdrom_drive*); + void (*cdda_paranoia_free)(cdrom_paranoia *p); + void (*cdda_paranoia_modeset)(cdrom_paranoia *p, int mode); + int16_t* (*cdda_paranoia_read_limited)(cdrom_paranoia *p, void(*callback)(long,int), int); + long (*cdda_paranoia_seek)(cdrom_paranoia *p,long seek,int mode); +} + +// from cdda_paranoia.h +#define PARANOIA_MODE_FULL 0xff +#define PARANOIA_MODE_DISABLE 0 + +#define PARANOIA_MODE_VERIFY 1 +#define PARANOIA_MODE_FRAGMENT 2 +#define PARANOIA_MODE_OVERLAP 4 +#define PARANOIA_MODE_SCRATCH 8 +#define PARANOIA_MODE_REPAIR 16 +#define PARANOIA_MODE_NEVERSKIP 32 + + + +/** + * Internal class used by K3bCdparanoiaLib + */ +class K3bCdparanoiaLibData +{ + public: + K3bCdparanoiaLibData( K3bDevice::Device* dev ) + : m_device(dev), + m_drive(0), + m_paranoia(0), + m_currentSector(0) { + s_dataMap.insert( dev, this ); + } + + ~K3bCdparanoiaLibData() { + paranoiaFree(); + + s_dataMap.erase( m_device ); + } + + K3bDevice::Device* device() const { return m_device; } + void paranoiaModeSet( int ); + bool paranoiaInit(); + void paranoiaFree(); + int16_t* paranoiaRead( void(*callback)(long,int), int maxRetries ); + long paranoiaSeek( long, int ); + long firstSector( int ); + long lastSector( int ); + long sector() const { return m_currentSector; } + + static K3bCdparanoiaLibData* data( K3bDevice::Device* dev ) { + QMap::const_iterator it = s_dataMap.find( dev ); + if( it == s_dataMap.constEnd() ) + return new K3bCdparanoiaLibData( dev ); + else + return *it; + } + + static void freeAll() { + // clean up all K3bCdparanoiaLibData instances + for( QMap::iterator it = s_dataMap.begin(); + it != s_dataMap.end(); ++it ) + delete it.data(); + } + + private: + // + // We have exactly one instance of K3bCdparanoiaLibData per device + // + static QMap s_dataMap; + + K3bDevice::Device* m_device; + + cdrom_drive* m_drive; + cdrom_paranoia* m_paranoia; + + long m_currentSector; + + QMutex mutex; +}; + + +QMap K3bCdparanoiaLibData::s_dataMap; + +bool K3bCdparanoiaLibData::paranoiaInit() +{ + mutex.lock(); + + if( m_drive ) + paranoiaFree(); + + // since we use cdparanoia to open the device it is important to close + // the device here + m_device->close(); + + m_drive = cdda_cdda_identify( QFile::encodeName(m_device->blockDeviceName()), 0, 0 ); + if( m_drive == 0 ) { + mutex.unlock(); + return false; + } + + // cdda_cdda_verbose_set( m_drive, 1, 1 ); + + cdda_cdda_open( m_drive ); + m_paranoia = cdda_paranoia_init( m_drive ); + if( m_paranoia == 0 ) { + mutex.unlock(); + paranoiaFree(); + return false; + } + + m_currentSector = 0; + + mutex.unlock(); + + return true; +} + + +void K3bCdparanoiaLibData::paranoiaFree() +{ + mutex.lock(); + + if( m_paranoia ) { + cdda_paranoia_free( m_paranoia ); + m_paranoia = 0; + } + if( m_drive ) { + cdda_cdda_close( m_drive ); + m_drive = 0; + } + + mutex.unlock(); +} + + +void K3bCdparanoiaLibData::paranoiaModeSet( int mode ) +{ + mutex.lock(); + cdda_paranoia_modeset( m_paranoia, mode ); + mutex.unlock(); +} + + +int16_t* K3bCdparanoiaLibData::paranoiaRead( void(*callback)(long,int), int maxRetries ) +{ + if( m_paranoia ) { + mutex.lock(); + int16_t* data = cdda_paranoia_read_limited( m_paranoia, callback, maxRetries ); + if( data ) + m_currentSector++; + mutex.unlock(); + return data; + } + else + return 0; +} + + +long K3bCdparanoiaLibData::firstSector( int track ) +{ + if( m_drive ) { + mutex.lock(); + long sector = cdda_cdda_track_firstsector( m_drive, track ); + mutex.unlock(); + return sector; + } + else + return -1; +} + +long K3bCdparanoiaLibData::lastSector( int track ) +{ + if( m_drive ) { + mutex.lock(); + long sector = cdda_cdda_track_lastsector(m_drive, track ); + mutex.unlock(); + return sector; + } + else + return -1; +} + + +long K3bCdparanoiaLibData::paranoiaSeek( long sector, int mode ) +{ + if( m_paranoia ) { + mutex.lock(); + m_currentSector = cdda_paranoia_seek( m_paranoia, sector, mode ); + mutex.unlock(); + return m_currentSector; + } + else + return -1; +} + + + +class K3bCdparanoiaLib::Private +{ +public: + Private() + : device(0), + currentSector(0), + startSector(0), + lastSector(0), + status(S_OK), + paranoiaLevel(0), + neverSkip(true), + maxRetries(5), + data(0) { + } + + ~Private() { + } + + void updateParanoiaMode() { + // from cdrdao 1.1.7 + int paranoiaMode = PARANOIA_MODE_FULL^PARANOIA_MODE_NEVERSKIP; + + switch( paranoiaLevel ) { + case 0: + paranoiaMode = PARANOIA_MODE_DISABLE; + break; + + case 1: + paranoiaMode |= PARANOIA_MODE_OVERLAP; + paranoiaMode &= ~PARANOIA_MODE_VERIFY; + break; + + case 2: + paranoiaMode &= ~(PARANOIA_MODE_SCRATCH|PARANOIA_MODE_REPAIR); + break; + } + + if( neverSkip ) + paranoiaMode |= PARANOIA_MODE_NEVERSKIP; + + data->paranoiaModeSet( paranoiaMode ); + } + + // high-level api + K3bDevice::Device* device; + K3bDevice::Toc toc; + long currentSector; + long startSector; + long lastSector; + int status; + unsigned int currentTrack; + int paranoiaLevel; + bool neverSkip; + int maxRetries; + + K3bCdparanoiaLibData* data; +}; + + +K3bCdparanoiaLib::K3bCdparanoiaLib() +{ + d = new Private(); + s_counter++; +} + + +K3bCdparanoiaLib::~K3bCdparanoiaLib() +{ + delete d; + s_counter--; + if( s_counter == 0 ) { + K3bCdparanoiaLibData::freeAll(); + + // cleanup the dynamically loaded lib + dlclose( s_libInterface ); + dlclose( s_libParanoia ); + s_libInterface = 0; + s_libParanoia = 0; + } +} + + +bool K3bCdparanoiaLib::load() +{ + cdda_cdda_identify = (cdrom_drive* (*) (const char*, int, char**))dlsym( s_libInterface, CDDA_IDENTIFY ); + cdda_cdda_open = (int (*) (cdrom_drive*))dlsym( s_libInterface, CDDA_OPEN ); + cdda_cdda_close = (int (*) (cdrom_drive*))dlsym( s_libInterface, CDDA_CLOSE ); + cdda_cdda_track_firstsector = (long (*)(cdrom_drive*, int))dlsym( s_libInterface, CDDA_TRACK_FIRSTSECTOR ); + cdda_cdda_track_lastsector = (long (*)(cdrom_drive*, int))dlsym( s_libInterface, CDDA_TRACK_LASTSECTOR ); + cdda_cdda_verbose_set = (void (*)(cdrom_drive *d,int err_action, int mes_action))dlsym( s_libInterface, CDDA_VERBOSE_SET ); + cdda_cdda_disc_firstsector = (long (*)(cdrom_drive *d))dlsym( s_libInterface, CDDA_DISC_FIRSTSECTOR ); + + cdda_paranoia_init = (cdrom_paranoia* (*)(cdrom_drive*))dlsym( s_libParanoia, PARANOIA_INIT ); + cdda_paranoia_free = (void (*)(cdrom_paranoia *p))dlsym( s_libParanoia, PARANOIA_FREE ); + cdda_paranoia_modeset = (void (*)(cdrom_paranoia *p, int mode))dlsym( s_libParanoia, PARANOIA_MODESET ); + cdda_paranoia_read_limited = (int16_t* (*)(cdrom_paranoia *p, void(*callback)(long,int), int))dlsym( s_libParanoia, PARANOIA_READ_LIMITED ); + cdda_paranoia_seek = (long (*)(cdrom_paranoia *p,long seek,int mode))dlsym( s_libParanoia, PARANOIA_SEEK ); + + // check if all symbols could be resoled + if( cdda_cdda_identify == 0 ) { + kdDebug() << "(K3bCdparanoiaLib) Error: could not resolve 'cdda_identify'" << endl; + return false; + } + if( cdda_cdda_open == 0 ) { + kdDebug() << "(K3bCdparanoiaLib) Error: could not resolve 'cdda_open'" << endl; + return false; + } + if( cdda_cdda_close == 0 ) { + kdDebug() << "(K3bCdparanoiaLib) Error: could not resolve 'cdda_close'" << endl; + return false; + } + if( cdda_cdda_track_firstsector == 0 ) { + kdDebug() << "(K3bCdparanoiaLib) Error: could not resolve 'cdda_track_firstsector'" << endl; + return false; + } + if( cdda_cdda_track_lastsector == 0 ) { + kdDebug() << "(K3bCdparanoiaLib) Error: could not resolve 'cdda_track_lastsector'" << endl; + return false; + } + if( cdda_cdda_disc_firstsector == 0 ) { + kdDebug() << "(K3bCdparanoiaLib) Error: could not resolve 'cdda_disc_firstsector'" << endl; + return false; + } + if( cdda_cdda_verbose_set == 0 ) { + kdDebug() << "(K3bCdparanoiaLib) Error: could not resolve 'cdda_verbose_set'" << endl; + return false; + } + + if( cdda_paranoia_init == 0 ) { + kdDebug() << "(K3bCdparanoiaLib) Error: could not resolve 'paranoia_init'" << endl; + return false; + } + if( cdda_paranoia_free == 0 ) { + kdDebug() << "(K3bCdparanoiaLib) Error: could not resolve 'paranoia_free'" << endl; + return false; + } + if( cdda_paranoia_modeset == 0 ) { + kdDebug() << "(K3bCdparanoiaLib) Error: could not resolve 'paranoia_modeset'" << endl; + return false; + } + if( cdda_paranoia_read_limited == 0 ) { + kdDebug() << "(K3bCdparanoiaLib) Error: could not resolve 'paranoia_read_limited'" << endl; + return false; + } + if( cdda_paranoia_seek == 0 ) { + kdDebug() << "(K3bCdparanoiaLib) Error: could not resolve 'paranoia_seek'" << endl; + return false; + } + + return true; +} + + + +K3bCdparanoiaLib* K3bCdparanoiaLib::create() +{ + // check if libcdda_interface is avalilable + if( s_libInterface == 0 ) { + s_haveLibCdio = false; + + s_libInterface = dlopen( "libcdda_interface.so.0", RTLD_NOW|RTLD_GLOBAL ); + + // try the redhat & Co. location + if( s_libInterface == 0 ) + s_libInterface = dlopen( "cdda/libcdda_interface.so.0", RTLD_NOW|RTLD_GLOBAL ); + + // try the new cdio lib + if( s_libInterface == 0 ) { + s_libInterface = dlopen( "libcdio_cdda.so", RTLD_NOW|RTLD_GLOBAL ); + s_haveLibCdio = true; + } + + if( s_libInterface == 0 ) { + kdDebug() << "(K3bCdparanoiaLib) Error while loading libcdda_interface. " << endl; + return 0; + } + + + s_libParanoia = dlopen( "libcdda_paranoia.so.0", RTLD_NOW ); + + // try the redhat & Co. location + if( s_libParanoia == 0 ) + s_libParanoia = dlopen( "cdda/libcdda_paranoia.so.0", RTLD_NOW ); + + // try the new cdio lib + if( s_haveLibCdio && s_libParanoia == 0 ) + s_libParanoia = dlopen( "libcdio_paranoia.so.0", RTLD_NOW ); + + if( s_libParanoia == 0 ) { + kdDebug() << "(K3bCdparanoiaLib) Error while loading libcdda_paranoia. " << endl; + dlclose( s_libInterface ); + s_libInterface = 0; + return 0; + } + } + + K3bCdparanoiaLib* lib = new K3bCdparanoiaLib(); + if( !lib->load() ) { + kdDebug() << "(K3bCdparanoiaLib) Error: could not resolve all symbols!" << endl; + delete lib; + return 0; + } + return lib; +} + + +bool K3bCdparanoiaLib::initParanoia( K3bDevice::Device* dev, const K3bDevice::Toc& toc ) +{ + if( !dev ) { + kdError() << "(K3bCdparanoiaLib::initParanoia) dev = 0!" << endl; + return false; + } + + close(); + + d->device = dev; + d->toc = toc; + if( d->toc.isEmpty() ) { + kdDebug() << "(K3bCdparanoiaLib) empty toc." << endl; + cleanup(); + return false; + } + + if( d->toc.contentType() == K3bDevice::DATA ) { + kdDebug() << "(K3bCdparanoiaLib) No audio tracks found." << endl; + cleanup(); + return false; + } + + // + // Get the appropriate data instance for this device + // + d->data = K3bCdparanoiaLibData::data( dev ); + + if( d->data->paranoiaInit() ) { + d->startSector = d->currentSector = d->lastSector = 0; + + return true; + } + else { + cleanup(); + return false; + } +} + + +bool K3bCdparanoiaLib::initParanoia( K3bDevice::Device* dev ) +{ + return initParanoia( dev, dev->readToc() ); +} + + +void K3bCdparanoiaLib::close() +{ + cleanup(); +} + + +void K3bCdparanoiaLib::cleanup() +{ + if( d->data ) + d->data->paranoiaFree(); + d->device = 0; + d->currentSector = 0; +} + + +bool K3bCdparanoiaLib::initReading() +{ + if( d->device ) { + // find first audio track + K3bDevice::Toc::const_iterator trackIt = d->toc.begin(); + while( (*trackIt).type() != K3bDevice::Track::AUDIO ) { + ++trackIt; + } + + long start = (*trackIt).firstSector().lba(); + + // find last audio track + while( trackIt != d->toc.end() && (*trackIt).type() == K3bDevice::Track::AUDIO ) + ++trackIt; + --trackIt; + + long end = (*trackIt).lastSector().lba(); + + return initReading( start, end ); + } + else { + kdDebug() << "(K3bCdparanoiaLib) initReading without initParanoia." << endl; + return false; + } +} + + +bool K3bCdparanoiaLib::initReading( unsigned int track ) +{ + if( d->device ) { + if( track <= d->toc.count() ) { + const K3bDevice::Track& k3bTrack = d->toc[track-1]; + if( k3bTrack.type() == K3bDevice::Track::AUDIO ) { + return initReading( k3bTrack.firstSector().lba(), k3bTrack.lastSector().lba() ); + } + else { + kdDebug() << "(K3bCdparanoiaLib) Track " << track << " no audio track." << endl; + return false; + } + } + else { + kdDebug() << "(K3bCdparanoiaLib) Track " << track << " too high." << endl; + return false; + } + } + else { + kdDebug() << "(K3bCdparanoiaLib) initReading without initParanoia." << endl; + return false; + } +} + + +bool K3bCdparanoiaLib::initReading( long start, long end ) +{ + kdDebug() << "(K3bCdparanoiaLib) initReading( " << start << ", " << end << " )" << endl; + + if( d->device ) { + if( d->toc.firstSector().lba() <= start && + d->toc.lastSector().lba() >= end ) { + d->startSector = d->currentSector = start; + d->lastSector = end; + + // determine track number + d->currentTrack = 1; + while( d->toc[d->currentTrack-1].lastSector() < start ) + d->currentTrack++; + + // let the paranoia stuff point to the startSector + d->data->paranoiaSeek( start, SEEK_SET ); + return true; + } + else { + kdDebug() << "(K3bCdparanoiaLib) " << start << " and " << end << " out of range." << endl; + return false; + } + } + else { + kdDebug() << "(K3bCdparanoiaLib) initReading without initParanoia." << endl; + return false; + } +} + + +char* K3bCdparanoiaLib::read( int* statusCode, unsigned int* track, bool littleEndian ) +{ + if( d->currentSector > d->lastSector ) { + kdDebug() << "(K3bCdparanoiaLib) finished ripping. read " + << (d->currentSector - d->startSector) << " sectors." << endl + << " current sector: " << d->currentSector << endl; + d->status = S_OK; + if( statusCode ) + *statusCode = d->status; + return 0; + } + + if( d->currentSector != d->data->sector() ) { + kdDebug() << "(K3bCdparanoiaLib) need to seek before read. Looks as if we are reusing the paranoia instance." << endl; + if( !d->data->paranoiaSeek( d->currentSector, SEEK_SET ) ) + return 0; + } + + // + // The paranoia data could have been used by someone else before + // and setting the paranoia mode is fast + // + d->updateParanoiaMode(); + + Q_INT16* data = d->data->paranoiaRead( paranoiaCallback, d->maxRetries ); + + char* charData = reinterpret_cast(data); + +#ifdef WORDS_BIGENDIAN // __BYTE_ORDER == __BIG_ENDIAN + if( littleEndian ) { +#else + if( !littleEndian ) { +#endif + for( int i = 0; i < CD_FRAMESIZE_RAW-1; i+=2 ) { + char b = charData[i]; + charData[i] = charData[i+1]; + charData[i+1] = b; + } + } + + + if( data ) + d->status = S_OK; + else + d->status = S_ERROR; // We may skip this sector if we'd like... + + if( statusCode ) + *statusCode = d->status; + + if( track ) + *track = d->currentTrack; + + d->currentSector++; + + if( d->toc[d->currentTrack-1].lastSector() < d->currentSector ) + d->currentTrack++; + + return charData; +} + + +int K3bCdparanoiaLib::status() const +{ + return d->status; +} + + +const K3bDevice::Toc& K3bCdparanoiaLib::toc() const +{ + return d->toc; +} + + +long K3bCdparanoiaLib::rippedDataLength() const +{ + return d->lastSector - d->startSector + 1; +} + + +void K3bCdparanoiaLib::setParanoiaMode( int m ) +{ + d->paranoiaLevel = m; +} + + +void K3bCdparanoiaLib::setNeverSkip( bool b ) +{ + d->neverSkip = b; +} + + +void K3bCdparanoiaLib::setMaxRetries( int r ) +{ + d->maxRetries = r; +} diff --git a/libk3b/tools/k3bcdparanoialib.h b/libk3b/tools/k3bcdparanoialib.h new file mode 100644 index 0000000..70504de --- /dev/null +++ b/libk3b/tools/k3bcdparanoialib.h @@ -0,0 +1,161 @@ +/* + * + * $Id: k3bcdparanoialib.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3B_CDPARANOIA_LIB_H +#define K3B_CDPARANOIA_LIB_H + +// from cdda_interface.h +#define CD_FRAMESIZE_RAW 2352 + + +#include + +#include +#include "k3b_export.h" + +namespace K3bDevice { + class Device; + class Toc; +} + + +/** + * K3bCdparanoiaLib is a convenience wrapper around libcdda_interface + * and libcdda_paranoia. + * + * It uses four paranoia levels 0-3 which can be set via setParanoiaMode + * and are used the same way as in cdrdao: + * \li 0: No checking, data is copied directly from the drive. + * \li 1: Perform overlapped reading to avoid jitter. + * \li 2: Like 1 but with additional checks of the read audio data. + * \li 3: Like 2 but with additional scratch detection and repair. + * + * K3bCdparanoiaLib is based on a shared data approach which makes sure + * that each device can only be opened once. This is necessary since + * libcdda_interface opens the device exclusively on most distributions. + * + * However, it is perfectly possible to have two instances of K3bCdparanoiaLib + * accessing the same device at the same time. K3bCdparanoiaLib will take care + * of the syncing and seeking issues automatically. + * + * K3bCdparanoiaLib is thread-safe. + * + * Usage: + *

+ * K3bCdparanoiaLib lib;
+ * lib.initParanoia( mydevice );
+ * lib.initReading( tracknumber );
+ * while( char* data = lib.read() )
+ *   dosomethingcoolwithdata( data );
+ * 
+ */ +class LIBK3B_EXPORT K3bCdparanoiaLib +{ + public: + ~K3bCdparanoiaLib(); + + /** default: 1 */ + void setParanoiaMode( int ); + void setNeverSkip( bool b ); + + /** default: 5 */ + void setMaxRetries( int ); + + /** + * This will read the Toc and initialize some stuff. + * It will also call paranoiaInit( const QString& ) + */ + bool initParanoia( K3bDevice::Device* dev ); + + /** + * Use for faster initialization without reading the toc + */ + bool initParanoia( K3bDevice::Device* dev, const K3bDevice::Toc& ); + + void close(); + + /** + * Call this after initParanoia to set the data to rip. + * + * Rip all audio tracks. + */ + bool initReading(); + + /** + * Call this after initParanoia to set the data to rip. + */ + bool initReading( unsigned int track ); + + /** + * Call this after initParanoia to set the data to rip. + */ + bool initReading( long startSector, long endSector ); + + /** + * Read data. + * \param statusCode If not 0 will be set. + * \param track the tracknumer the data belongs to + * + * This method takes care of swapping the byte-order depending on the + * machine type. + * + * \return The read sector data or 0 if all data within the specified range + * has been read or an error has occured. + */ + char* read( int* statusCode = 0, unsigned int* track = 0, bool littleEndian = true ); + + /** + * This only is valid after a call to read() + */ + int status() const; + + enum Status { + S_OK, + S_ERROR + // to be extended with Jitter and stuff... + }; + + /** + * Only valid after a call to initParanoia() + */ + const K3bDevice::Toc& toc() const; + + long rippedDataLength() const; + + /** + * returns 0 if the cdparanoialib could not + * be found on the system. + * Otherwise you have to take care of + * deleting. + */ + static K3bCdparanoiaLib* create(); + + private: + void cleanup(); + + K3bCdparanoiaLib(); + bool load(); + + class Private; + Private* d; + + static void* s_libInterface; + static void* s_libParanoia; + static int s_counter; +}; + + +#endif diff --git a/libk3b/tools/k3bcdtextvalidator.cpp b/libk3b/tools/k3bcdtextvalidator.cpp new file mode 100644 index 0000000..8b3c97a --- /dev/null +++ b/libk3b/tools/k3bcdtextvalidator.cpp @@ -0,0 +1,42 @@ +/* + * + * $Id: k3bcdtextvalidator.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bcdtextvalidator.h" + +K3bCdTextValidator::K3bCdTextValidator(QObject *parent, const char *name) + : K3bLatin1Validator(parent, name) +{ +} + + +K3bCdTextValidator::~K3bCdTextValidator() +{ +} + + +QValidator::State K3bCdTextValidator::validate( QString& input, int& pos ) const +{ + if( input.length() > 160 ) + return Invalid; + + // forbid some characters that might introduce problems + for( unsigned int i = 0; i < input.length(); ++i ) { + if( input[i] == '/' || input[i] == '"' || input[i] == '\\' ) + return Invalid; + } + + return K3bLatin1Validator::validate( input, pos ); +} diff --git a/libk3b/tools/k3bcdtextvalidator.h b/libk3b/tools/k3bcdtextvalidator.h new file mode 100644 index 0000000..48ada05 --- /dev/null +++ b/libk3b/tools/k3bcdtextvalidator.h @@ -0,0 +1,33 @@ +/* + * + * $Id: k3bcdtextvalidator.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3BCDTEXTVALIDATOR_H_ +#define _K3BCDTEXTVALIDATOR_H_ + + +#include +#include "k3b_export.h" + +class LIBK3B_EXPORT K3bCdTextValidator : public K3bLatin1Validator +{ + public: + K3bCdTextValidator(QObject *parent = 0, const char *name = 0); + ~K3bCdTextValidator(); + + State validate( QString& input, int& pos ) const; +}; + +#endif diff --git a/libk3b/tools/k3bchecksumpipe.cpp b/libk3b/tools/k3bchecksumpipe.cpp new file mode 100644 index 0000000..21d308a --- /dev/null +++ b/libk3b/tools/k3bchecksumpipe.cpp @@ -0,0 +1,99 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bchecksumpipe.h" + +#include +#include + +#include + + +class K3bChecksumPipe::Private +{ +public: + Private() + : checksumType(MD5) { + } + + void update( const char* in, int len ) { + switch( checksumType ) { + case MD5: + md5.update( in, len ); + break; + } + } + + void reset() { + switch( checksumType ) { + case MD5: + md5.reset(); + break; + } + } + + int checksumType; + + KMD5 md5; +}; + + +K3bChecksumPipe::K3bChecksumPipe() + : K3bActivePipe() +{ + d = new Private(); +} + + +K3bChecksumPipe::~K3bChecksumPipe() +{ + delete d; +} + + +bool K3bChecksumPipe::open( bool closeWhenDone ) +{ + return open( MD5, closeWhenDone ); +} + + +bool K3bChecksumPipe::open( Type type, bool closeWhenDone ) +{ + if( K3bActivePipe::open( closeWhenDone ) ) { + d->reset(); + d->checksumType = type; + return true; + } + else + return false; +} + + +QCString K3bChecksumPipe::checksum() const +{ + switch( d->checksumType ) { + case MD5: + return d->md5.hexDigest(); + } + + return QCString(); +} + + +int K3bChecksumPipe::write( char* data, int max ) +{ + d->update( data, max ); + return K3bActivePipe::write( data, max ); +} diff --git a/libk3b/tools/k3bchecksumpipe.h b/libk3b/tools/k3bchecksumpipe.h new file mode 100644 index 0000000..88adc74 --- /dev/null +++ b/libk3b/tools/k3bchecksumpipe.h @@ -0,0 +1,66 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_CHECKSUM_PIPE_H_ +#define _K3B_CHECKSUM_PIPE_H_ + +#include + +#include + + +/** + * The checksum pipe calculates the checksum of the data + * passed through it. + */ +class LIBK3B_EXPORT K3bChecksumPipe : public K3bActivePipe +{ + public: + K3bChecksumPipe(); + ~K3bChecksumPipe(); + + enum Type { + MD5 + }; + + /** + * \reimplemented + * Defaults to MD5 checksum + */ + bool open( bool closeWhenDone = false ); + + /** + * Opens the pipe and thus starts the + * checksum calculation + * + * \param closeWhenDone If true the pipes will be closed + * once all data has been read. + */ + bool open( Type type, bool closeWhenDone = false ); + + /** + * Get the calculated checksum + */ + QCString checksum() const; + + protected: + int write( char* data, int max ); + + private: + class Private; + Private* d; +}; + +#endif diff --git a/libk3b/tools/k3bcutcombobox.cpp b/libk3b/tools/k3bcutcombobox.cpp new file mode 100644 index 0000000..d4f516b --- /dev/null +++ b/libk3b/tools/k3bcutcombobox.cpp @@ -0,0 +1,230 @@ +/* + * + * $Id: k3bcutcombobox.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bcutcombobox.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +class K3bCutComboBox::Private +{ +public: + Private() { + method = CUT; + } + + QStringList originalItems; + + int method; + int width; +}; + + +K3bCutComboBox::K3bCutComboBox( QWidget* parent, const char* name ) + : KComboBox( parent, name ) +{ + d = new Private(); + // setSizePolicy( QSizePolicy::Maximum, sizePolicy().horData(), sizePolicy().hasHeightForWidth() ); +} + + +K3bCutComboBox::K3bCutComboBox( int method, QWidget* parent, const char* name ) + : KComboBox( parent, name ) +{ + d = new Private(); + d->method = method; +} + + +K3bCutComboBox::~K3bCutComboBox() +{ + delete d; +} + + +void K3bCutComboBox::setMethod( int m ) +{ + d->method = m; + cutText(); +} + + +QSize K3bCutComboBox::sizeHint() const +{ +// QSize s(KComboBox::sizeHint()); + +// for( int i = 0; i < count(); i++ ) { +// int w = fontMetrics().width(d->originalItems[i]) + +// ( d->pixmaps[i].isNull() ? 0 : d->pixmaps[i].width() + 4); +// if( w > s.width() ) +// s.setWidth( w ); +// } + + return KComboBox::sizeHint(); +} + +QSize K3bCutComboBox::minimumSizeHint() const +{ + return KComboBox::minimumSizeHint(); +} + + +void K3bCutComboBox::setCurrentText( const QString& s ) +{ + int i; + for( i = 0; i < count(); i++ ) + if ( d->originalItems[i] == s ) + break; + if ( i < count() ) { + setCurrentItem(i); + } + else if( !d->originalItems.isEmpty() ) { + d->originalItems[currentItem()] = s; + cutText(); + } +} + + +void K3bCutComboBox::insertStringList( const QStringList&, int ) +{ + // FIXME +} + + +void K3bCutComboBox::insertStrList( const QStrList&, int ) +{ + // FIXME +} + +void K3bCutComboBox::insertStrList( const QStrList*, int ) +{ + // FIXME +} + +void K3bCutComboBox::insertStrList( const char**, int, int) +{ + // FIXME +} + +void K3bCutComboBox::insertItem( const QString& text, int index ) +{ + insertItem( QPixmap(), text, index ); +} + +void K3bCutComboBox::insertItem( const QPixmap& pix, int i ) +{ + insertItem( pix, "", i ); +} + +void K3bCutComboBox::insertItem( const QPixmap& pixmap, const QString& text, int index ) +{ + if( index != -1 ) + d->originalItems.insert( d->originalItems.at(index), text ); + else + d->originalItems.append( text ); + + if( !pixmap.isNull() ) + KComboBox::insertItem( pixmap, "xx", index ); + else + KComboBox::insertItem( "xx", index ); + + cutText(); +} + +void K3bCutComboBox::removeItem( int i ) +{ + d->originalItems.erase( d->originalItems.at(i) ); + KComboBox::removeItem( i ); +} + +void K3bCutComboBox::changeItem( const QString& s, int i ) +{ + d->originalItems[i] = s; + cutText(); +} + +void K3bCutComboBox::changeItem( const QPixmap& pix, const QString& s, int i ) +{ + KComboBox::changeItem( pix, i ); + changeItem( s, i ); +} + + +QString K3bCutComboBox::text( int i ) const +{ + if( i < (int)d->originalItems.count() ) + return d->originalItems[i]; + else + return QString::null; +} + + +QString K3bCutComboBox::currentText() const +{ + if( currentItem() < (int)d->originalItems.count() ) + return d->originalItems[currentItem()]; + else + return QString::null; +} + + +void K3bCutComboBox::clear() +{ + KComboBox::clear(); + d->originalItems.clear(); +} + +void K3bCutComboBox::resizeEvent( QResizeEvent* e ) +{ + cutText(); + + KComboBox::resizeEvent(e); +} + + +void K3bCutComboBox::cutText() +{ + d->width = QStyle::visualRect( style().querySubControlMetrics(QStyle::CC_ComboBox, this, + QStyle::SC_ComboBoxEditField), this ).width(); + + for( int i = 0; i < (int)d->originalItems.count(); ++i ) { + int w = d->width; + if ( pixmap(i) && !pixmap(i)->isNull() ) + w -= ( pixmap(i)->width() + 4 ); + + QString text; + if( d->method == SQUEEZE ) + text = K3b::squeezeTextToWidth( fontMetrics(), d->originalItems[i], w ); + else + text = K3b::cutToWidth( fontMetrics(), d->originalItems[i], w ); + + // now insert the cut text + if( pixmap(i) ) + KComboBox::changeItem( *pixmap(i), text, i ); + else + KComboBox::changeItem( text, i ); + } +} + +#include "k3bcutcombobox.moc" diff --git a/libk3b/tools/k3bcutcombobox.h b/libk3b/tools/k3bcutcombobox.h new file mode 100644 index 0000000..1c35e78 --- /dev/null +++ b/libk3b/tools/k3bcutcombobox.h @@ -0,0 +1,92 @@ +/* + * + * $Id: k3bcutcombobox.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_CUT_COMBOBOX_H_ +#define _K3B_CUT_COMBOBOX_H_ + +#include +#include "k3b_export.h" +class QResizeEvent; + + +/** + * Cuts it's text. + * Since it rebuilds the complete list of strings every time + * a new string is added or one gets removed it is not a good + * idea to use this for dynamic lists. + * + * Be aware that currently only insertItem works. + * none of the insertStrList or insertStringList methods are implemeted + * yet and also the removeItem methos does not work. + */ +class LIBK3B_EXPORT K3bCutComboBox : public KComboBox +{ + Q_OBJECT + + public: + K3bCutComboBox( QWidget* parent = 0, const char* name = 0 ); + K3bCutComboBox( int method, QWidget* parent = 0, const char* name = 0 ); + virtual ~K3bCutComboBox(); + + enum Method { + CUT, + SQUEEZE + }; + + /** + * The method to shorten the text + * defaut: CUT + */ + void setMethod( int ); + + /** reimplemeted */ + QSize sizeHint() const; + + /** reimplemeted */ + QSize minimumSizeHint() const; + + /** reimplemeted */ + virtual void setCurrentText( const QString& ); + + void insertStringList( const QStringList &, int index=-1 ); + void insertStrList( const QStrList &, int index=-1 ); + void insertStrList( const QStrList *, int index=-1 ); + void insertStrList( const char **, int numStrings=-1, int index=-1); + + void insertItem( const QString &text, int index=-1 ); + void insertItem( const QPixmap &pixmap, int index=-1 ); + void insertItem( const QPixmap &pixmap, const QString &text, int index=-1 ); + + void removeItem( int index ); + + void changeItem( const QString &text, int index ); + void changeItem( const QPixmap &pixmap, const QString &text, int index ); + + QString text( int ) const; + QString currentText() const; + + void clear(); + + protected: + void resizeEvent( QResizeEvent* e ); + void cutText(); + + private: + class Private; + Private* d; +}; + +#endif diff --git a/libk3b/tools/k3bdevicecombobox.cpp b/libk3b/tools/k3bdevicecombobox.cpp new file mode 100644 index 0000000..165b59d --- /dev/null +++ b/libk3b/tools/k3bdevicecombobox.cpp @@ -0,0 +1,174 @@ +/* + * + * $Id: k3bdevicecombobox.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bdevicecombobox.h" +#include +#include +#include + +#include + +#include +#include + + +class K3bDeviceComboBox::Private +{ +public: + QMap deviceIndexMap; + QPtrVector devices; +}; + + +K3bDeviceComboBox::K3bDeviceComboBox( QWidget* parent, const char* name ) + : KComboBox( parent, name ) +{ + d = new Private(); + connect( this, SIGNAL(activated(int)), + this, SLOT(slotActivated(int)) ); + connect( k3bcore->deviceManager(), SIGNAL(changed(K3bDevice::DeviceManager*)), + this, SLOT(slotDeviceManagerChanged(K3bDevice::DeviceManager*)) ); +} + + +K3bDeviceComboBox::~K3bDeviceComboBox() +{ + delete d; +} + +K3bDevice::Device* K3bDeviceComboBox::selectedDevice() const +{ + if ( count() > 0 ) + return d->devices[currentItem()]; + else + return 0; +} + + +void K3bDeviceComboBox::addDevice( K3bDevice::Device* dev ) +{ + int devIndex = -2; + bool addDevice = false; + for( int i = 0; i < count(); ++i ) { + if( dev->vendor() == d->devices[i]->vendor() && + dev->description() == d->devices[i]->description() ) { + addDevice = true; + if( devIndex < -1 ) // when devIndex == -1 we already found two devices. + devIndex = i; + else + devIndex = -1; // when there are already two or more equal devices they have already been updated + } + } + + // update the existing device item + if( devIndex >= 0 ) { + changeItem( d->devices[devIndex]->vendor() + " " + + d->devices[devIndex]->description() + + " (" + d->devices[devIndex]->blockDeviceName() + ")", + devIndex ); + d->deviceIndexMap[d->devices[devIndex]->devicename()] = devIndex; + } + + // add the new device item + if( addDevice ) + insertItem( dev->vendor() + " " + dev->description() + " (" + dev->blockDeviceName() + ")" ); + else + insertItem( dev->vendor() + " " + dev->description() ); + + d->deviceIndexMap[dev->devicename()] = count()-1; + d->devices.resize( count() ); + d->devices.insert(count()-1, dev); +} + + +void K3bDeviceComboBox::removeDevice( K3bDevice::Device* dev ) +{ + if( dev ) { + if( d->deviceIndexMap.contains(dev->devicename()) ) { + // let's make it easy and recreate the whole list + K3bDevice::Device* selDev = selectedDevice(); + QPtrList devices; + for( unsigned int i = 0; i < d->devices.size(); ++i ) + devices.append( d->devices[i] ); + + clear(); + + devices.removeRef( dev ); + + addDevices( devices ); + setSelectedDevice( selDev ); + } + } +} + + +void K3bDeviceComboBox::addDevices( const QPtrList& list ) +{ + for( QPtrListIterator it( list ); + it.current(); ++it ) + addDevice( it.current() ); +} + + +void K3bDeviceComboBox::refreshDevices( const QPtrList& list ) +{ + K3bDevice::Device* selDev = selectedDevice(); + clear(); + if( !list.containsRef( selDev ) ) + selDev = 0; + addDevices( list ); + setSelectedDevice( selDev ); +} + + +void K3bDeviceComboBox::setSelectedDevice( K3bDevice::Device* dev ) +{ + if( dev ) { + if( d->deviceIndexMap.contains(dev->devicename()) ) { + setCurrentItem( d->deviceIndexMap[dev->devicename()] ); + emit selectionChanged( dev ); + } + } +} + + +void K3bDeviceComboBox::clear() +{ + d->deviceIndexMap.clear(); + d->devices.clear(); + KComboBox::clear(); +} + + +void K3bDeviceComboBox::slotActivated( int i ) +{ + emit selectionChanged( d->devices[i] ); +} + + +void K3bDeviceComboBox::slotDeviceManagerChanged( K3bDevice::DeviceManager* dm ) +{ + unsigned int i = 0; + while( i < d->devices.size() ) { + if( !dm->allDevices().containsRef( d->devices[i] ) ) { + removeDevice( d->devices[i] ); + i = 0; + } + else + ++i; + } +} + +#include "k3bdevicecombobox.moc" diff --git a/libk3b/tools/k3bdevicecombobox.h b/libk3b/tools/k3bdevicecombobox.h new file mode 100644 index 0000000..5a9cb85 --- /dev/null +++ b/libk3b/tools/k3bdevicecombobox.h @@ -0,0 +1,67 @@ +/* + * + * $Id: k3bdevicecombobox.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_DEVICE_COMBO_BOX_H_ +#define _K3B_DEVICE_COMBO_BOX_H_ + +#include +#include "k3b_export.h" + +namespace K3bDevice { + class Device; + class DeviceManager; +} + + +/** + * A combobox to select a K3b device. + * + * It automatically removes devices that are removed from the system. + */ +class LIBK3B_EXPORT K3bDeviceComboBox : public KComboBox +{ + Q_OBJECT + + public: + K3bDeviceComboBox( QWidget* parent = 0, const char* name = 0 ); + ~K3bDeviceComboBox(); + + K3bDevice::Device* selectedDevice() const; + + signals: + void selectionChanged( K3bDevice::Device* ); + + public slots: + void addDevice( K3bDevice::Device* ); + void addDevices( const QPtrList& ); + /** + * Clears the device combo and tries to keep the current selection + */ + void refreshDevices( const QPtrList& ); + void removeDevice( K3bDevice::Device* ); + void setSelectedDevice( K3bDevice::Device* ); + void clear(); + + private slots: + void slotActivated( int ); + void slotDeviceManagerChanged( K3bDevice::DeviceManager* dm ); + + private: + class Private; + Private* d; +}; + +#endif diff --git a/libk3b/tools/k3bdevicehandler.cpp b/libk3b/tools/k3bdevicehandler.cpp new file mode 100644 index 0000000..c77f1e6 --- /dev/null +++ b/libk3b/tools/k3bdevicehandler.cpp @@ -0,0 +1,332 @@ +/* + * + * $Id: k3bdevicehandler.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bdevicehandler.h" +#include +#include +#include +#include + + + +class K3bDevice::DeviceHandler::DeviceHandlerThread : public K3bThread +{ +public: + DeviceHandlerThread() + : K3bThread(), + dev(0) { + } + + + void run() { + success = false; + m_bCanceled = false; + + // clear data + toc.clear(); + ngInfo = DiskInfo(); + cdText.clear(); + cdTextRaw.resize(0); + + if( dev ) { + success = dev->open(); + if( !m_bCanceled && command & DISKINFO ) { + ngInfo = dev->diskInfo(); + if( !m_bCanceled && !ngInfo.empty() ) { + toc = dev->readToc(); + if( toc.contentType() == AUDIO || + toc.contentType() == MIXED ) + cdText = dev->readCdText(); + } + } + + if( !m_bCanceled && command & (NG_DISKINFO| + DISKSIZE| + REMAININGSIZE| + NUMSESSIONS) ) { + ngInfo = dev->diskInfo(); + } + + if( !m_bCanceled && command & (TOC|TOCTYPE) ) { + toc = dev->readToc(); + } + + if( !m_bCanceled && command & CD_TEXT ) { + cdText = dev->readCdText(); + success = (success && !cdText.isEmpty()); + } + + if( !m_bCanceled && command & CD_TEXT_RAW ) { + unsigned char* data = 0; + unsigned int dataLen = 0; + if( dev->readTocPmaAtip( &data, dataLen, 5, false, 0 ) ) { + // we need more than the header and a multiple of 18 bytes to have valid CD-TEXT + if( dataLen > 4 && dataLen%18 == 4 ) { + cdTextRaw.assign( reinterpret_cast(data), dataLen ); + } + else { + kdDebug() << "(K3bDevice::DeviceHandler) invalid CD-TEXT length: " << dataLen << endl; + delete [] data; + success = false; + } + } + else + success = false; + } + + if( !m_bCanceled && command & BLOCK ) + success = (success && dev->block( true )); + + if( !m_bCanceled && command & UNBLOCK ) + success = (success && dev->block( false )); + + // + // It is important that eject is performed before load + // since the RELOAD command is a combination of both + // + + if( !m_bCanceled && command & EJECT ) + success = (success && dev->eject()); + + if( !m_bCanceled && command & LOAD ) + success = (success && dev->load()); + + if( !m_bCanceled && command & BUFFER_CAPACITY ) + success = dev->readBufferCapacity( bufferCapacity, availableBufferCapacity ); + + dev->close(); + } + + // + // This thread only gets cancelled if a new request was started. + // So we don't emit the finished signal for this (old) request. + // + if( !m_bCanceled ) + emitFinished(success); + } + + void cancel() { + m_bCanceled = true; + } + + + bool success; + int errorCode; + int command; + DiskInfo ngInfo; + Toc toc; + CdText cdText; + QByteArray cdTextRaw; + long long bufferCapacity; + long long availableBufferCapacity; + Device* dev; + +private: + bool m_bCanceled; +}; + + +K3bDevice::DeviceHandler::DeviceHandler( Device* dev, QObject* parent, const char* name ) + : K3bThreadJob( 0, parent, name ), + m_selfDelete(false) +{ + m_thread = new DeviceHandlerThread(); + m_thread->dev = dev; + setThread( m_thread ); +} + + +K3bDevice::DeviceHandler::DeviceHandler( QObject* parent, const char* name ) + : K3bThreadJob( 0, parent, name ), + m_selfDelete(false) +{ + m_thread = new DeviceHandlerThread(); + setThread( m_thread ); +} + + +K3bDevice::DeviceHandler::DeviceHandler( int command, Device* dev, const char* name ) + : K3bThreadJob( 0, 0, name ), + m_selfDelete(true) +{ + m_thread = new DeviceHandlerThread(); + setThread( m_thread ); + m_thread->dev = dev; + sendCommand(command); +} + +K3bDevice::DeviceHandler::~DeviceHandler() +{ + delete m_thread; +} + + +int K3bDevice::DeviceHandler::errorCode() const +{ + return m_thread->errorCode; +} + +bool K3bDevice::DeviceHandler::success() const +{ + return m_thread->success; +} + + +const K3bDevice::DiskInfo& K3bDevice::DeviceHandler::diskInfo() const +{ + return m_thread->ngInfo; +} + + +const K3bDevice::Toc& K3bDevice::DeviceHandler::toc() const +{ + return m_thread->toc; +} + +const K3bDevice::CdText& K3bDevice::DeviceHandler::cdText() const +{ + return m_thread->cdText; +} + + +const QByteArray& K3bDevice::DeviceHandler::cdTextRaw() const +{ + return m_thread->cdTextRaw; +} + + +K3b::Msf K3bDevice::DeviceHandler::diskSize() const +{ + return m_thread->ngInfo.capacity(); +} + +K3b::Msf K3bDevice::DeviceHandler::remainingSize() const +{ + return m_thread->ngInfo.remainingSize(); +} + +int K3bDevice::DeviceHandler::tocType() const +{ + return m_thread->toc.contentType(); +} + +int K3bDevice::DeviceHandler::numSessions() const +{ + return m_thread->ngInfo.numSessions(); +} + +long long K3bDevice::DeviceHandler::bufferCapacity() const +{ + return m_thread->bufferCapacity; +} + +long long K3bDevice::DeviceHandler::availableBufferCapacity() const +{ + return m_thread->availableBufferCapacity; +} + +void K3bDevice::DeviceHandler::setDevice( Device* dev ) +{ + m_thread->dev = dev; +} + + + +void K3bDevice::DeviceHandler::sendCommand( int command ) +{ + // + // We do not want the finished signal emitted in case the devicehandler was cancelled. This is a special case. + // That's why we do not use K3bThreadJob::start() becasue otherwise we would be registered twice. + // + if( m_thread->running() ) { + kdDebug() << "(K3bDevice::DeviceHandler) thread already running. canceling thread..." << endl; + m_thread->cancel(); + m_thread->wait(); + } + else + jobStarted(); + + kdDebug() << "(K3bDevice::DeviceHandler) starting command: " << command << endl; + + m_thread->command = command; + m_thread->start(); +} + +void K3bDevice::DeviceHandler::getToc() +{ + sendCommand(DeviceHandler::TOC); +} + +void K3bDevice::DeviceHandler::getDiskInfo() +{ + sendCommand(DeviceHandler::DISKINFO); +} + +void K3bDevice::DeviceHandler::getDiskSize() +{ + sendCommand(DeviceHandler::DISKSIZE); +} + +void K3bDevice::DeviceHandler::getRemainingSize() +{ + sendCommand(DeviceHandler::REMAININGSIZE); +} + +void K3bDevice::DeviceHandler::getTocType() +{ + sendCommand(DeviceHandler::TOCTYPE); +} + +void K3bDevice::DeviceHandler::getNumSessions() +{ + sendCommand(DeviceHandler::NUMSESSIONS); +} + + +void K3bDevice::DeviceHandler::block( bool b ) +{ + sendCommand(b ? DeviceHandler::BLOCK : DeviceHandler::UNBLOCK); +} + +void K3bDevice::DeviceHandler::eject() +{ + sendCommand(DeviceHandler::EJECT); +} + +K3bDevice::DeviceHandler* K3bDevice::sendCommand( int command, Device* dev ) +{ + return new DeviceHandler( command, dev, "DeviceHandler" ); +} + +void K3bDevice::DeviceHandler::customEvent( QCustomEvent* e ) +{ + K3bThreadJob::customEvent(e); + + if( (int)e->type() == K3bProgressInfoEvent::Finished ) { + emit finished( this ); + if( m_selfDelete ) { + kdDebug() << "(K3bDevice::DeviceHandler) thread emitted finished. Waiting for thread actually finishing" << endl; + kdDebug() << "(K3bDevice::DeviceHandler) success: " << m_thread->success << endl; + // wait for the thread to finish + m_thread->wait(); + kdDebug() << "(K3bDevice::DeviceHandler) deleting thread." << endl; + deleteLater(); + } + } +} + + +#include "k3bdevicehandler.moc" diff --git a/libk3b/tools/k3bdevicehandler.h b/libk3b/tools/k3bdevicehandler.h new file mode 100644 index 0000000..d5159a0 --- /dev/null +++ b/libk3b/tools/k3bdevicehandler.h @@ -0,0 +1,237 @@ +/* + * + * $Id: k3bdevicehandler.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_DEVICE_HANDLER_H_ +#define _K3B_DEVICE_HANDLER_H_ + +#include +#include "k3bdevice.h" +#include "k3bdiskinfo.h" +#include "k3bmsf.h" +#include "k3bcdtext.h" +#include "k3b_export.h" +#include + +class QCustomEvent; + + +namespace K3bDevice +{ + class Device; + + + /** + * The K3bDevice::Devicehandler is a threaded wrapper around K3bDevice::Device. + * It allows async access to the time comsuming blocking K3bDevice::Device methods. + * Since it's a K3bJob it is very easy to handle. Just use one of the methods and + * connect to the finished signal. + * Be aware that all methods only return valid values if the corresponding info has + * been successfuly requested. + * + * Be aware that multiple requests in a row (without waiting for the job to finish) will + * only result in one finished() signal answering the last request. + */ + class LIBK3B_EXPORT DeviceHandler : public K3bThreadJob + { + Q_OBJECT + + public: + DeviceHandler( Device*, QObject* parent = 0, const char* name = 0 ); + DeviceHandler( QObject* parent = 0, const char* name = 0 ); + + /** + * This constructor is used by the global "quick" methods and should not be used + * otherwise except for the same usage. + */ + DeviceHandler( int command, Device*, const char* name = 0 ); + + ~DeviceHandler(); + + const DiskInfo& diskInfo() const; + const Toc& toc() const; + const CdText& cdText() const; + const QByteArray& cdTextRaw() const; + K3b::Msf diskSize() const; + K3b::Msf remainingSize() const; + int tocType() const; + int numSessions() const; + long long bufferCapacity() const; + long long availableBufferCapacity() const; + + bool success() const; + + /** + * Use this when the command + * returnes some error code. + */ + int errorCode() const; + + enum Command { + /** + * Always successful, even with an empty or no media at all! + */ + NG_DISKINFO = 1, // TODO: rename this into DISKINFO + /** + * Always successful, even with an empty or no media at all! + */ + TOC = 2, + /** + * Successful if the media contains CD-Text. + */ + CD_TEXT = 4, + /** + * Successful if the media contains CD-Text. + */ + CD_TEXT_RAW = 8, + /** + * Always successful, even with an empty or no media at all! + */ + DISKSIZE = 16, + /** + * Always successful, even with an empty or no media at all! + */ + REMAININGSIZE = 32, + /** + * Always successful, even with an empty or no media at all! + */ + TOCTYPE = 64, + /** + * Always successful, even with an empty or no media at all! + */ + NUMSESSIONS = 128, + /** + * Successful if the drive could be blocked. + */ + BLOCK = 256, + /** + * Successful if the drive could be unblocked. + */ + UNBLOCK = 512, + /** + * Successful if the media was ejected. + */ + EJECT = 1024, + /** + * Successful if the media was loaded + */ + LOAD = 2048, + RELOAD = EJECT|LOAD, + /** + * Retrieves NG_DISKINFO, TOC, and CD-Text in case of an audio or mixed + * mode cd. + * The only difference to NG_DISKINFO|TOC|CD_TEXT is that no CD-Text is not + * considered an error. + * + * Always successful, even with an empty or no media at all! + */ + DISKINFO = 4096, // TODO: rename this in somthing like: DISKINFO_COMPLETE + /** + * Determine the device buffer state. + */ + BUFFER_CAPACITY = 8192 + }; + + signals: + void finished( K3bDevice::DeviceHandler* ); + + public slots: + void setDevice( Device* ); + void sendCommand( int command ); + + void getToc(); + void getDiskInfo(); + void getDiskSize(); + void getRemainingSize(); + void getTocType(); + void getNumSessions(); + void block( bool ); + void eject(); + + protected: + /** + * reimplemented from K3bThreadJob for internal reasons + */ + virtual void customEvent( QCustomEvent* ); + + private: + class DeviceHandlerThread; + DeviceHandlerThread* m_thread; + + bool m_selfDelete; + }; + + /** + * Usage: + * \code + * connect( K3bDevice::sendCommand( K3bDevice::DeviceHandler::MOUNT, dev ), + * SIGNAL(finished(DeviceHandler*)), + * this, SLOT(someSlot(DeviceHandler*)) ); + * + * void someSlot( DeviceHandler* dh ) { + * if( dh->success() ) { + * \endcode + * + * Be aware that the DeviceHandler will get destroyed once the signal has been + * emited. + */ + LIBK3B_EXPORT DeviceHandler* sendCommand( int command, Device* ); + + inline DeviceHandler* diskInfo(Device* dev) { + return sendCommand(DeviceHandler::DISKINFO,dev); + } + + inline DeviceHandler* toc(Device* dev) { + return sendCommand(DeviceHandler::TOC,dev); + } + + inline DeviceHandler* diskSize(Device* dev) { + return sendCommand(DeviceHandler::DISKSIZE,dev); + } + + inline DeviceHandler* remainingSize(Device* dev) { + return sendCommand(DeviceHandler::REMAININGSIZE,dev); + } + + inline DeviceHandler* tocType(Device* dev) { + return sendCommand(DeviceHandler::TOCTYPE,dev); + } + + inline DeviceHandler* numSessions(Device* dev) { + return sendCommand(DeviceHandler::NUMSESSIONS,dev); + } + + inline DeviceHandler* block(Device* dev) { + return sendCommand(DeviceHandler::BLOCK,dev); + } + + inline DeviceHandler* unblock(Device* dev) { + return sendCommand(DeviceHandler::UNBLOCK,dev); + } + + inline DeviceHandler* eject(Device* dev) { + return sendCommand(DeviceHandler::EJECT,dev); + } + + inline DeviceHandler* reload(Device* dev) { + return sendCommand(DeviceHandler::RELOAD,dev); + } + + inline DeviceHandler* load(Device* dev) { + return sendCommand(DeviceHandler::LOAD,dev); + } +} + +#endif diff --git a/libk3b/tools/k3bdeviceselectiondialog.cpp b/libk3b/tools/k3bdeviceselectiondialog.cpp new file mode 100644 index 0000000..d622457 --- /dev/null +++ b/libk3b/tools/k3bdeviceselectiondialog.cpp @@ -0,0 +1,130 @@ +/* + * + * $Id: k3bdeviceselectiondialog.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + + +#include "k3bdeviceselectiondialog.h" +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + + +class K3bDeviceSelectionDialog::Private +{ +public: + K3bDeviceComboBox* comboDevices; +}; + + +K3bDeviceSelectionDialog::K3bDeviceSelectionDialog( QWidget* parent, + const char* name, + const QString& text, + bool modal ) + : KDialogBase( KDialogBase::Plain, + i18n("Device Selection"), + Ok|Cancel, + Ok, + parent, + name, + modal ) +{ + d = new Private(); + + QGridLayout* lay = new QGridLayout( plainPage() ); + + QLabel* label = new QLabel( text.isEmpty() ? i18n("Please select a device:") : text, plainPage() ); + d->comboDevices = new K3bDeviceComboBox( plainPage() ); + + // lay->setMargin( marginHint() ); + lay->setSpacing( spacingHint() ); + lay->addWidget( label, 0, 0 ); + lay->addWidget( d->comboDevices, 1, 0 ); + lay->setRowStretch( 2, 1 ); +} + + +K3bDeviceSelectionDialog::~K3bDeviceSelectionDialog() +{ + delete d; +} + + +void K3bDeviceSelectionDialog::addDevice( K3bDevice::Device* dev ) +{ + d->comboDevices->addDevice( dev ); +} + + +void K3bDeviceSelectionDialog::addDevices( const QPtrList& list ) +{ + d->comboDevices->addDevices( list ); +} + + +K3bDevice::Device* K3bDeviceSelectionDialog::selectedDevice() const +{ + return d->comboDevices->selectedDevice(); +} + + +void K3bDeviceSelectionDialog::setSelectedDevice( K3bDevice::Device* dev ) +{ + d->comboDevices->setSelectedDevice( dev ); +} + + +K3bDevice::Device* K3bDeviceSelectionDialog::selectDevice( QWidget* parent, + const QPtrList& devices, + const QString& text ) +{ + if( devices.isEmpty() ) + return 0; + if( devices.count() == 1 ) + return devices.getFirst(); + + K3bDeviceSelectionDialog dlg( parent, 0, text ); + dlg.addDevices( devices ); + + if( dlg.exec() == Accepted ) + return dlg.selectedDevice(); + else + return 0; +} + +K3bDevice::Device* K3bDeviceSelectionDialog::selectDevice( QWidget* parent, + const QString& text ) +{ + return selectDevice( parent, k3bcore->deviceManager()->allDevices(), text ); + + +} + + +K3bDevice::Device* K3bDeviceSelectionDialog::selectWriter( QWidget* parent, const QString& text ) +{ + return selectDevice( parent, k3bcore->deviceManager()->burningDevices(), text ); +} + + +#include "k3bdeviceselectiondialog.moc" diff --git a/libk3b/tools/k3bdeviceselectiondialog.h b/libk3b/tools/k3bdeviceselectiondialog.h new file mode 100644 index 0000000..b61ce1e --- /dev/null +++ b/libk3b/tools/k3bdeviceselectiondialog.h @@ -0,0 +1,62 @@ +/* + * + * $Id: k3bdeviceselectiondialog.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + + +#ifndef K3B_DEVICE_SELECTION_DIALOG_H +#define K3B_DEVICE_SELECTION_DIALOG_H + + +#include +#include "k3b_export.h" +#include + +namespace K3bDevice { + class Device; +} + + +class LIBK3B_EXPORT K3bDeviceSelectionDialog : public KDialogBase +{ + Q_OBJECT + + public: + K3bDeviceSelectionDialog( QWidget* parent = 0, + const char* name = 0, + const QString& text = QString::null, + bool modal = false ); + ~K3bDeviceSelectionDialog(); + + void addDevice( K3bDevice::Device* ); + void addDevices( const QPtrList& ); + + void setSelectedDevice( K3bDevice::Device* ); + + K3bDevice::Device* selectedDevice() const; + + static K3bDevice::Device* selectWriter( QWidget* parent, + const QString& text = QString::null ); + static K3bDevice::Device* selectDevice( QWidget* parent, + const QString& text = QString::null ); + static K3bDevice::Device* selectDevice( QWidget* parent, + const QPtrList& devices, + const QString& text = QString::null ); + + private: + class Private; + Private* d; +}; + +#endif diff --git a/libk3b/tools/k3bdirsizejob.cpp b/libk3b/tools/k3bdirsizejob.cpp new file mode 100644 index 0000000..ab9cb8a --- /dev/null +++ b/libk3b/tools/k3bdirsizejob.cpp @@ -0,0 +1,184 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bdirsizejob.h" + +#include +#include +#include +#include + +#include +#include + +#include +#include + + +class K3bDirSizeJob::WorkThread : public K3bThread +{ +public: + WorkThread() + : K3bThread(), + followSymlinks(false), + totalSize(0), + totalFiles(0), + totalDirs(0), + totalSymlinks(0) { + } + + void init() { + m_canceled = false; + + totalSize = 0; + totalFiles = 0; + totalDirs = 0; + totalSymlinks = 0; + } + + void run() { + emitStarted(); + + QStringList l; + for( KURL::List::const_iterator it = urls.begin(); + it != urls.end(); ++it ) { + const KURL& url = *it; + + if( !url.isLocalFile() ) { + kdDebug() << "(K3bDirSizeJob) no remote support." << endl; + emitFinished( false ); + return; + } + + l.append( url.path() ); + } + + emitFinished( countFiles( l, QString() ) ); + } + + bool countDir( const QString& dir ) { + const QString& dot = KGlobal::staticQString( "." ); + const QString& dotdot = KGlobal::staticQString( ".." ); + QStringList l = QDir(dir).entryList( QDir::All|QDir::Hidden|QDir::System ); + l.remove( dot ); + l.remove( dotdot ); + + return countFiles( l, dir ); + } + + + bool countFiles( const QStringList& l, const QString& dir ) { + for( QStringList::const_iterator it = l.begin(); + it != l.end(); ++it ) { + + if( m_canceled ) + return false; + + k3b_struct_stat s; + if( k3b_lstat( QFile::encodeName( dir + *it ), &s ) ) + return false; + + if( S_ISLNK( s.st_mode ) ) { + ++totalSymlinks; + if( followSymlinks ) { + if( k3b_stat( QFile::encodeName( dir + *it ), &s ) ) + return false; + } + } + + if( S_ISDIR( s.st_mode ) ) { + ++totalDirs; + if( !countDir( dir + *it + '/' ) ) + return false; + } + else if( !S_ISLNK( s.st_mode ) ) { + ++totalFiles; + totalSize += (KIO::filesize_t)s.st_size; + } + } + + return true; + } + + void cancel() { + m_canceled = true; + emitCanceled(); + wait(); + } + + KURL::List urls; + bool followSymlinks; + + KIO::filesize_t totalSize; + KIO::filesize_t totalFiles; + KIO::filesize_t totalDirs; + KIO::filesize_t totalSymlinks; + +private: + bool m_canceled; +}; + + +K3bDirSizeJob::K3bDirSizeJob( QObject* parent ) + : K3bThreadJob( new K3bSimpleJobHandler(), parent ) +{ + d = new WorkThread; + setThread( d ); +} + + +K3bDirSizeJob::~K3bDirSizeJob() +{ + delete d; + delete jobHandler(); +} + + +KIO::filesize_t K3bDirSizeJob::totalSize() const +{ + return d->totalSize; +} + + +KIO::filesize_t K3bDirSizeJob::totalFiles() const +{ + return d->totalFiles; +} + + +KIO::filesize_t K3bDirSizeJob::totalDirs() const +{ + return d->totalDirs; +} + + +KIO::filesize_t K3bDirSizeJob::totalSymlinks() const +{ + return d->totalSymlinks; +} + + +void K3bDirSizeJob::setUrls( const KURL::List& urls ) +{ + d->urls = urls; +} + + +void K3bDirSizeJob::setFollowSymlinks( bool b ) +{ + d->followSymlinks = b; +} + +#include "k3bdirsizejob.moc" diff --git a/libk3b/tools/k3bdirsizejob.h b/libk3b/tools/k3bdirsizejob.h new file mode 100644 index 0000000..d6a3e5a --- /dev/null +++ b/libk3b/tools/k3bdirsizejob.h @@ -0,0 +1,67 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_DIR_SIZE_JOB_H_ +#define _K3B_DIR_SIZE_JOB_H_ + +#include +#include + +#include + +/** + * K3bDirSizeJob is a replacement for KDirSize which allows + * a much finer grained control over what is counted and how. + * Additionally it uses threading for enhanced speed. + * + * For now K3bDirSizeJob only works on local urls. + */ +class LIBK3B_EXPORT K3bDirSizeJob : public K3bThreadJob +{ + Q_OBJECT + + public: + K3bDirSizeJob( QObject* parent = 0 ); + ~K3bDirSizeJob(); + + KIO::filesize_t totalSize() const; + + /** + * Does also include symlinks to files, devices, and fifos + */ + KIO::filesize_t totalFiles() const; + + /** + * Total number of counted dirs. This does also + * include the first dirs the job was started with. + * Does also include symlinks to dirs. + */ + KIO::filesize_t totalDirs() const; + + /** + * Includes symlinks to files and folders + */ + KIO::filesize_t totalSymlinks() const; + + public slots: + void setUrls( const KURL::List& urls ); + void setFollowSymlinks( bool ); + + private: + class WorkThread; + WorkThread* d; +}; + +#endif diff --git a/libk3b/tools/k3bexceptions.cpp b/libk3b/tools/k3bexceptions.cpp new file mode 100644 index 0000000..1d8806f --- /dev/null +++ b/libk3b/tools/k3bexceptions.cpp @@ -0,0 +1,43 @@ +/* + * + * $Id: k3bexceptions.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bexceptions.h" +#include + +bool K3bExceptions::brokenDaoAudio( K3bDevice::Device* dev ) +{ + if( dev->vendor().upper().startsWith("PIONEER") ) + if( dev->description().upper().startsWith("DVR-106D") || + dev->description().upper().startsWith("DVD-RW DVR-K12D") ) + return true; + + if( dev->vendor().upper().startsWith("HL-DT-ST") ) + if( dev->description().upper().startsWith("RW/DVD GCC-4320B") || + dev->description().upper().contains("GCE-8520B") ) + return true; + + if( dev->vendor().upper().startsWith("PHILIPS") && + dev->description().upper().startsWith("CDRWDVD3210") ) + return true; + + if( dev->vendor().upper().startsWith("LITE-ON") ) + if( dev->description().upper().startsWith("LTR-32123S") || + dev->description().upper().startsWith("LTR-40125S") || + dev->description().upper().contains("LTC-48161H") || + dev->description().upper().startsWith("DVDRW LDW-811S") ) + return true; + + return false; +} diff --git a/libk3b/tools/k3bexceptions.h b/libk3b/tools/k3bexceptions.h new file mode 100644 index 0000000..a078992 --- /dev/null +++ b/libk3b/tools/k3bexceptions.h @@ -0,0 +1,35 @@ +/* + * + * $Id: k3bexceptions.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_EXCEPTIONS_H_ +#define _K3B_EXCEPTIONS_H_ + +namespace K3bDevice { + class Device; +} + +class K3bExceptions +{ + public: + /** + * Returns true if the drive's firmware produces broken + * Audio CDs with zero length pregaps. + * + * It simply uses a compiled in table. + */ + static bool brokenDaoAudio( K3bDevice::Device* ); +}; + +#endif diff --git a/libk3b/tools/k3bfilesplitter.cpp b/libk3b/tools/k3bfilesplitter.cpp new file mode 100644 index 0000000..af5b83f --- /dev/null +++ b/libk3b/tools/k3bfilesplitter.cpp @@ -0,0 +1,307 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bfilesplitter.h" +#include "k3bfilesysteminfo.h" + +#include + +#include + + +class K3bFileSplitter::Private +{ +public: + Private( K3bFileSplitter* splitter ) + : m_splitter( splitter ) { + } + + QString filename; + QFile file; + int counter; + + // QIODevice::Offset is too small on most compilations + KIO::filesize_t maxFileSize; + + KIO::filesize_t currentOverallPos; + KIO::filesize_t currentFilePos; + + void determineMaxFileSize() { + if( maxFileSize == 0 ) { + if( K3bFileSystemInfo( filename ).type() == K3bFileSystemInfo::FS_FAT ) + maxFileSize = 1024ULL*1024ULL*1024ULL; // 1GB + else + maxFileSize = 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL; // incredibly big, 1024 TB + } + } + + QString buildFileName( int counter ) { + if( counter > 0 ) + return filename + '.' + QString::number(counter).rightJustify( 3, '0' ); + else + return filename; + } + + QString currentFileName() { + return buildFileName( counter ); + } + + bool openPrevFile() { + return openFile( --counter ); + } + + bool openNextFile() { + return openFile( ++counter ); + } + + bool openFile( int counter ) { + file.close(); + file.setName( buildFileName( counter ) ); + currentFilePos = 0; + if( file.open( m_splitter->mode() ) ) { + m_splitter->setState( IO_Open ); + return true; + } + else { + m_splitter->setState( ~IO_Open ); + return false; + } + } + +private: + K3bFileSplitter* m_splitter; +}; + + +K3bFileSplitter::K3bFileSplitter() +{ + d = new Private( this ); +} + + +K3bFileSplitter::K3bFileSplitter( const QString& filename ) +{ + d = new Private( this ); + setName( filename ); +} + + +K3bFileSplitter::~K3bFileSplitter() +{ + delete d; +} + + +const QString& K3bFileSplitter::name() const +{ + return d->filename; +} + + +void K3bFileSplitter::setName( const QString& filename ) +{ + close(); + d->maxFileSize = 0; + d->filename = filename; +} + + +bool K3bFileSplitter::open( int mode ) +{ + close(); + + d->determineMaxFileSize(); + + d->counter = 0; + d->currentFilePos = 0; + d->currentOverallPos = 0; + setMode( mode ); + + return d->openFile( 0 ); +} + + +void K3bFileSplitter::close() +{ + d->file.close(); + d->counter = 0; + d->currentFilePos = 0; + d->currentOverallPos = 0; +} + + +int K3bFileSplitter::handle() const +{ + // FIXME: use a K3bPipe to simulate this + return -1; +} + + + +void K3bFileSplitter::flush() +{ + d->file.flush(); +} + + +QIODevice::Offset K3bFileSplitter::size() const +{ + // not implemented due to Offset size limitations + return 0; +} + + +QIODevice::Offset K3bFileSplitter::at() const +{ + return d->currentOverallPos; +} + + +bool K3bFileSplitter::at( QIODevice::Offset pos ) +{ + Q_UNUSED( pos ); + // not implemented due to Offset size limitations + return false; +} + + +bool K3bFileSplitter::atEnd() const +{ + return d->file.atEnd() && !QFile::exists( d->buildFileName( d->counter+1 ) ); +} + + +Q_LONG K3bFileSplitter::readBlock( char *data, Q_ULONG maxlen ) +{ + Q_LONG r = d->file.readBlock( data, maxlen ); + if( r == 0 ) { + if( atEnd() ) { + return r; + } + else if( d->openNextFile() ) { + // recursively call us + return readBlock( data, maxlen ); + } + } + else if( r > 0 ) { + d->currentOverallPos += r; + d->currentFilePos += r; + } + + return r; +} + + +Q_LONG K3bFileSplitter::writeBlock( const char *data, Q_ULONG len ) +{ + // We cannot rely on QFile::at since it uses long on most copmpilations + Q_ULONG max = (Q_ULONG)QMIN( (KIO::filesize_t)len, d->maxFileSize - d->currentFilePos ); + + Q_LONG r = d->file.writeBlock( data, max ); + + if( r < 0 ) + return r; + + d->currentOverallPos += r; + d->currentFilePos += r; + + // recursively call us + if( (Q_ULONG)r < len ) { + if( d->openNextFile() ) + return r + writeBlock( data+r, len-r ); + else + return -1; + } + else + return r; +} + + +int K3bFileSplitter::getch() +{ + int r = d->file.getch(); + if( r == -1 ) { + if( !d->file.atEnd() ) { + return -1; + } + else if( !atEnd() ) { + if( !d->openNextFile() ) + return -1; + else + return getch(); + } + } + + d->currentOverallPos++; + d->currentFilePos++; + + return r; +} + + +int K3bFileSplitter::putch( int c ) +{ + if( d->currentFilePos < d->maxFileSize ) { + d->currentOverallPos++; + d->currentFilePos++; + return d->file.putch( c ); + } + else if( d->openNextFile() ) { + // recursively call us + return putch( c ); + } + else + return -1; +} + + +int K3bFileSplitter::ungetch( int c ) +{ + if( d->currentFilePos > 0 ) { + int r = d->file.ungetch( c ); + if( r != -1 ) { + d->currentOverallPos--; + d->currentFilePos--; + } + return r; + } + else if( d->counter > 0 ) { + // open prev file + if( d->openPrevFile() ) { + // seek to the end + d->file.at( d->file.size() ); + d->currentFilePos = d->file.at(); + return getch(); + } + else + return -1; + } + else + return -1; +} + + +void K3bFileSplitter::remove() +{ + close(); + while( QFile::exists( d->buildFileName( d->counter ) ) ) + QFile::remove( d->buildFileName( d->counter++ ) ); +} + + +void K3bFileSplitter::setMaxFileSize( KIO::filesize_t size ) +{ + d->maxFileSize = size; +} diff --git a/libk3b/tools/k3bfilesplitter.h b/libk3b/tools/k3bfilesplitter.h new file mode 100644 index 0000000..22dcad9 --- /dev/null +++ b/libk3b/tools/k3bfilesplitter.h @@ -0,0 +1,108 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_FILE_SPLITTER_H_ +#define _K3B_FILE_SPLITTER_H_ + +#include +#include + +#include + +#include + + +/** + * QFile replacement which splits + * big files according to the underlying file system's + * maximum file size. + * + * The filename will be changed to include a counter + * if the file has to be splitted like so: + * + *
+ * filename.iso
+ * filename.iso.001
+ * filename.iso.002
+ * ...
+ * 
+ */ +class LIBK3B_EXPORT K3bFileSplitter : public QIODevice +{ + public: + K3bFileSplitter(); + K3bFileSplitter( const QString& filename ); + ~K3bFileSplitter(); + + /** + * Set the maximum file size. If this is set to 0 + * (the default) the max filesize is determined based on + * the filesystem type. + * + * Be aware that setName will reset the max file size. + */ + void setMaxFileSize( KIO::filesize_t size ); + + const QString& name() const; + + void setName( const QString& filename ); + + virtual bool open( int mode ); + + virtual void close(); + + /** + * File descriptor to read from and write to. + * Not implemented yet! + */ + int handle() const; + + virtual void flush(); + + /** + * Not implemented + */ + virtual Offset size() const; + + /** + * Not implemented + */ + virtual Offset at() const; + + /** + * Not implemented + */ + virtual bool at( Offset ); + + virtual bool atEnd() const; + virtual Q_LONG readBlock( char *data, Q_ULONG maxlen ); + virtual Q_LONG writeBlock( const char *data, Q_ULONG len ); + virtual int getch(); + virtual int putch( int ); + virtual int ungetch( int ); + + /** + * Deletes all the splitted files. + * Caution: Does remove all files that fit the naming scheme without any + * additional checks. + */ + void remove(); + + private: + class Private; + Private* d; +}; + +#endif diff --git a/libk3b/tools/k3bfilesysteminfo.cpp b/libk3b/tools/k3bfilesysteminfo.cpp new file mode 100644 index 0000000..fe1eaf8 --- /dev/null +++ b/libk3b/tools/k3bfilesysteminfo.cpp @@ -0,0 +1,141 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include + +#include "k3bfilesysteminfo.h" + +#include + +#include +#include +#include + +#include + +#ifdef Q_OS_FREEBSD +#include +#include +#endif +#ifdef HAVE_SYS_STATVFS_H +# include +# if defined(Q_OS_NETBSD) +# include +# if __NetBSD_Version__ > 299000000 +# define statfs statvfs +# define f_type f_fsid +# endif +# endif +#endif +#ifdef HAVE_SYS_VFS_H +# include +#endif + +#include +#include + + + +class K3bFileSystemInfo::Private +{ +public: + Private() + : type(FS_UNKNOWN), + statDone(false) { + } + + FileSystemType type; + QString path; + + bool statDone; + + void stat() { + struct statfs fs; + if( !::statfs( QFile::encodeName( QFileInfo(path).dirPath( true ) ), &fs ) ) { + switch( fs.f_type ) { + case 0x4d44: // MS-DOS + type = FS_FAT; + default: + type = FS_UNKNOWN; + } + + statDone = true; + } + else { + kdDebug() << "(K3bFileSystemInfo) statfs failed: " << ::strerror(errno) << endl; + } + } +}; + + +K3bFileSystemInfo::K3bFileSystemInfo() +{ + d = new Private; +} + + +K3bFileSystemInfo::K3bFileSystemInfo( const QString& path ) +{ + d = new Private; + d->path = path; +} + + +K3bFileSystemInfo::K3bFileSystemInfo( const K3bFileSystemInfo& other ) +{ + d = new Private; + d->type = other.d->type; + d->path = other.d->path; + d->statDone = other.d->statDone; +} + + +K3bFileSystemInfo::~K3bFileSystemInfo() +{ + delete d; +} + + +QString K3bFileSystemInfo::path() const +{ + return d->path; +} + + +void K3bFileSystemInfo::setPath( const QString& path ) +{ + if( d->path != path ) { + d->path = path; + d->statDone = false; + } +} + + +K3bFileSystemInfo::FileSystemType K3bFileSystemInfo::type() const +{ + if( !d->statDone ) + d->stat(); + return d->type; +} + + +QString K3bFileSystemInfo::fixupPath( const QString& path ) +{ + QString s = K3b::fixupPath( path ); + if( type() == K3bFileSystemInfo::FS_FAT ) + return s.replace( QRegExp("[\"\\?\\*/\\\\[\\]\\|\\=\\:;]"), "_" ); + else + return s; +} diff --git a/libk3b/tools/k3bfilesysteminfo.h b/libk3b/tools/k3bfilesysteminfo.h new file mode 100644 index 0000000..be9995c --- /dev/null +++ b/libk3b/tools/k3bfilesysteminfo.h @@ -0,0 +1,56 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_FILE_SYSTEM_INFO_H_ +#define _K3B_FILE_SYSTEM_INFO_H_ + +#include + +#include + +class LIBK3B_EXPORT K3bFileSystemInfo +{ + public: + K3bFileSystemInfo(); + K3bFileSystemInfo( const QString& path ); + K3bFileSystemInfo( const K3bFileSystemInfo& ); + ~K3bFileSystemInfo(); + + QString path() const; + void setPath( const QString& path ); + + enum FileSystemType { + FS_UNKNOWN, + FS_FAT + // FIXME: add way more file system types + }; + + FileSystemType type() const; + + /** + * Ensures that the file path does not contain + * any invalid chars. + * + * For now it only replaces characters like * or [ + * on FAT file systems. + */ + QString fixupPath( const QString& ); + + private: + class Private; + Private* d; +}; + +#endif diff --git a/libk3b/tools/k3bintmapcombobox.cpp b/libk3b/tools/k3bintmapcombobox.cpp new file mode 100644 index 0000000..19ac649 --- /dev/null +++ b/libk3b/tools/k3bintmapcombobox.cpp @@ -0,0 +1,127 @@ +/* + * + * $Id: k3bwritingmodewidget.cpp 554512 2006-06-24 07:25:39Z trueg $ + * Copyright (C) 2006 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bintmapcombobox.h" + +#include +#include +#include + + +class K3bIntMapComboBox::Private +{ +public: + QMap valueIndexMap; + QMap > indexValueDescriptionMap; + + QString topWhatsThis; + QString bottomWhatsThis; +}; + + +K3bIntMapComboBox::K3bIntMapComboBox( QWidget* parent, const char* name ) + : KComboBox( parent, name ) +{ + d = new Private; + connect( this, SIGNAL(highlighted(int)), + this, SLOT(slotItemHighlighted(int)) ); + connect( this, SIGNAL(activated(int)), + this, SLOT(slotItemActivated(int)) ); +} + + +K3bIntMapComboBox::~K3bIntMapComboBox() +{ + delete d; +} + + +int K3bIntMapComboBox::selectedValue() const +{ + if( (int)d->indexValueDescriptionMap.count() > KComboBox::currentItem() ) + return d->indexValueDescriptionMap[KComboBox::currentItem()].first; + else + return 0; +} + + +void K3bIntMapComboBox::setSelectedValue( int value ) +{ + if( d->valueIndexMap.contains( value ) ) + KComboBox::setCurrentItem( d->valueIndexMap[value] ); +} + + +void K3bIntMapComboBox::clear() +{ + d->valueIndexMap.clear(); + d->indexValueDescriptionMap.clear(); + + KComboBox::clear(); +} + + +bool K3bIntMapComboBox::insertItem( int value, const QString& text, const QString& description, int index ) +{ + if( d->valueIndexMap.contains( value ) ) + return false; + + // FIXME: allow inserition at any index + index = KComboBox::count(); + + d->valueIndexMap[value] = index; + d->indexValueDescriptionMap[index] = qMakePair( value, description ); + + KComboBox::insertItem( text ); + + updateWhatsThis(); + + return true; +} + + +void K3bIntMapComboBox::updateWhatsThis() +{ + QString ws( d->topWhatsThis ); + for( unsigned int i = 0; i < d->indexValueDescriptionMap.count(); ++i ) { + ws += "

" + KComboBox::text( i ) + "
"; + ws += d->indexValueDescriptionMap[i].second; + } + ws += "

" + d->bottomWhatsThis; + + QWhatsThis::add( this, ws ); +} + + +void K3bIntMapComboBox::slotItemHighlighted( int index ) +{ + emit valueHighlighted( d->indexValueDescriptionMap[index].first ); +} + + +void K3bIntMapComboBox::slotItemActivated( int index ) +{ + emit valueChanged( d->indexValueDescriptionMap[index].first ); +} + + +void K3bIntMapComboBox::addGlobalWhatsThisText( const QString& top, const QString& bottom ) +{ + d->topWhatsThis = top; + d->bottomWhatsThis = bottom; + updateWhatsThis(); +} + +#include "k3bintmapcombobox.moc" diff --git a/libk3b/tools/k3bintmapcombobox.h b/libk3b/tools/k3bintmapcombobox.h new file mode 100644 index 0000000..b0ae717 --- /dev/null +++ b/libk3b/tools/k3bintmapcombobox.h @@ -0,0 +1,83 @@ +/* + * + * $Id: k3bwritingmodewidget.cpp 554512 2006-06-24 07:25:39Z trueg $ + * Copyright (C) 2006 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_INT_MAP_COMBOBOX_H_ +#define _K3B_INT_MAP_COMBOBOX_H_ + +#include + +#include "k3b_export.h" + +/** + * The K3bIntMapComboBox allows a simple selection of integer + * values. + * + * The K3bIntMapComboBox will create a WhatsThis help automatically from + * the description texts (if all are set). The ToolTip has to be set manually. + */ +class LIBK3B_EXPORT K3bIntMapComboBox : public KComboBox +{ + Q_OBJECT + + public: + K3bIntMapComboBox( QWidget* parent = 0, const char* name = 0 ); + ~K3bIntMapComboBox(); + + int selectedValue() const; + + signals: + /** + * Emitted if the selected value changes by user interaction. + */ + void valueChanged( int ); + + /** + * Emitted if the current highlighted value changed by user interaction. + */ + void valueHighlighted( int ); + + public slots: + /** + * If \a v has not been added via insertItem the selection will not be changed + */ + void setSelectedValue( int v ); + + void clear(); + + /** + * Insert a new item + * \param value The integer value to insert + * \param text The text to be displayed in the combobox + * \param description The text to be used to describe the item in the whatsthis help + * \param index The position where to inserts the item. The item will be appended if index is negative. + * + * \return true if the item could be inserted. False if the value had already been inserted. + */ + bool insertItem( int value, const QString& text, const QString& description, int index = -1 ); + + void addGlobalWhatsThisText( const QString& top, const QString& bottom ); + + private slots: + void slotItemActivated( int ); + void slotItemHighlighted( int ); + + private: + void updateWhatsThis(); + + class Private; + Private* d; +}; + +#endif diff --git a/libk3b/tools/k3bintvalidator.cpp b/libk3b/tools/k3bintvalidator.cpp new file mode 100644 index 0000000..dabf719 --- /dev/null +++ b/libk3b/tools/k3bintvalidator.cpp @@ -0,0 +1,137 @@ +/* + * + * $Id: k3bintvalidator.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include +#include + +#include "k3bintvalidator.h" + +#include +#include +#include + + +K3bIntValidator::K3bIntValidator ( QWidget * parent, const char * name ) + : QValidator(parent, name) +{ + m_min = m_max = 0; +} + + +K3bIntValidator::K3bIntValidator ( int bottom, int top, QWidget * parent, const char * name ) + : QValidator(parent, name) +{ + m_min = bottom; + m_max = top; +} + + +K3bIntValidator::~K3bIntValidator () +{ +} + + +QValidator::State K3bIntValidator::validate ( QString &str, int & ) const +{ + bool ok; + int val = 0; + QString newStr; + + newStr = str.stripWhiteSpace(); + newStr = newStr.upper(); + + if( newStr.length() ) { + // check for < 0 + bool minus = newStr.startsWith( "-" ); + if( minus ) + newStr.remove( 0, 1 ); + + // check for hex + bool hex = newStr.startsWith( "0X" ); + + if( hex ) + newStr.remove( 0, 2 ); + + // a special case + if( newStr.isEmpty() ) { + if( minus && m_min && m_min >= 0) + ok = false; + else + return QValidator::Acceptable; + } + + val = newStr.toInt( &ok, hex ? 16 : 10 ); + if( minus ) + val *= -1; + } + else { + val = 0; + ok = true; + } + + if( !ok ) + return QValidator::Invalid; + + if( m_min && val > 0 && val < m_min ) + return QValidator::Acceptable; + + if( m_max && val < 0 && val > m_max ) + return QValidator::Acceptable; + + if( (m_max && val > m_max) || (m_min && val < m_min) ) + return QValidator::Invalid; + + return QValidator::Valid; +} + + +void K3bIntValidator::fixup ( QString& ) const +{ + // TODO: remove preceding zeros +} + + +void K3bIntValidator::setRange ( int bottom, int top ) +{ + m_min = bottom; + m_max = top; + + if( m_max < m_min ) + m_max = m_min; +} + + +int K3bIntValidator::bottom () const +{ + return m_min; +} + + +int K3bIntValidator::top () const +{ + return m_max; +} + + +int K3bIntValidator::toInt( const QString& s, bool* ok ) +{ + if( s.lower().startsWith( "0x" ) ) + return s.right( s.length()-2 ).toInt( ok, 16 ); + else if( s.lower().startsWith( "-0x" ) ) + return -1 * s.right( s.length()-3 ).toInt( ok, 16 ); + else + return s.toInt( ok, 10 ); +} diff --git a/libk3b/tools/k3bintvalidator.h b/libk3b/tools/k3bintvalidator.h new file mode 100644 index 0000000..551d56a --- /dev/null +++ b/libk3b/tools/k3bintvalidator.h @@ -0,0 +1,84 @@ +/* + * + * $Id: k3bintvalidator.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_INT_VALIDATOR_H_ +#define _K3B_INT_VALIDATOR_H_ + +#include +#include "k3b_export.h" +class QWidget; +class QString; + +/** + * QValidator for integers. + * + * It differs from QIntValidator and KIntValidator in the fact that + * it also accepts hex numbers prefixed with 0x. + */ +class LIBK3B_EXPORT K3bIntValidator : public QValidator +{ + public: + /** + * Constuctor. Also sets the base value. + */ + K3bIntValidator ( QWidget * parent, const char * name = 0 ); + + /** + * Constructor. Also sets the minimum, maximum, and numeric base values. + */ + K3bIntValidator ( int bottom, int top, QWidget * parent, const char * name = 0 ); + + /** + * Destructs the validator. + */ + virtual ~K3bIntValidator (); + + /** + * Validates the text, and return the result. Does not modify the parameters. + */ + virtual State validate ( QString &, int & ) const; + + /** + * Fixes the text if possible, providing a valid string. The parameter may be modified. + */ + virtual void fixup ( QString & ) const; + + /** + * Sets the minimum and maximum values allowed. + */ + virtual void setRange ( int bottom, int top ); + + /** + * Returns the current minimum value allowed. + */ + virtual int bottom () const; + + /** + * Returns the current maximum value allowed. + */ + virtual int top () const; + + /** + * If the string starts with 0x it's assumed to be a hex number. + */ + static int toInt( const QString&, bool* ok = 0 ); + + private: + int m_min; + int m_max; +}; + +#endif diff --git a/libk3b/tools/k3biso9660.cpp b/libk3b/tools/k3biso9660.cpp new file mode 100644 index 0000000..84edc4b --- /dev/null +++ b/libk3b/tools/k3biso9660.cpp @@ -0,0 +1,899 @@ +/* + * + * $Id: k3biso9660.cpp 690529 2007-07-21 10:51:47Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include +#include + +#include "k3biso9660.h" +#include "k3biso9660backend.h" + +#include + +#include "libisofs/isofs.h" + +#include +#include +#include +#include + +#include + + +/* callback function for libisofs */ +int K3bIso9660::read_callback( char* buf, sector_t start, int len, void* udata ) +{ + K3bIso9660* isoF = static_cast(udata); + + return isoF->read( start, buf, len ); +} + +/* callback function for libisofs */ +int K3bIso9660::isofs_callback( struct iso_directory_record *idr, void *udata ) +{ + K3bIso9660 *iso = static_cast (udata); + QString path, isoPath,user,group,symlink; + int i; + int access; + int time,cdate,adate; + rr_entry rr; + bool special=false; + K3bIso9660Entry *entry=0; + //K3bIso9660Entry *oldentry=0; + char z_algo[2],z_params[2]; + int z_size=0; + + if (isonum_711(idr->name_len)==1) { + switch (idr->name[0]) { + case 0: + path+=("."); + special=true; + break; + case 1: + path+=(".."); + special=true; + break; + } + } + // + // First extract the raw iso9660 name + // + if( !special ) { + for( i = 0; i < isonum_711( idr->name_len ); i++ ) { + if( idr->name[i] ) + isoPath += idr->name[i]; + } + } + else + isoPath = path; + + // + // Now see if we have RockRidge + // + if( !iso->plainIso9660() && ParseRR(idr,&rr) > 0 ) { + iso->m_rr = true; + if (!special) + path = QString::fromLocal8Bit( rr.name ); + symlink=rr.sl; + access=rr.mode; + time=0;//rr.st_mtime; + adate=0;//rr.st_atime; + cdate=0;//rr.st_ctime; + user.setNum(rr.uid); + group.setNum(rr.gid); + z_algo[0]=rr.z_algo[0];z_algo[1]=rr.z_algo[1]; + z_params[0]=rr.z_params[0];z_params[1]=rr.z_params[1]; + z_size=rr.z_size; + } + else { + access=iso->dirent->permissions() & ~S_IFMT; + adate=cdate=time=isodate_915(idr->date,0); + user=iso->dirent->user(); + group=iso->dirent->group(); + if (idr->flags[0] & 2) access |= S_IFDIR; else access |= S_IFREG; + if (!special) { + if( !iso->plainIso9660() && iso->jolietLevel() ) { + for (i=0;i<(isonum_711(idr->name_len)-1);i+=2) { + QChar ch( be2me_16(*((ushort*)&(idr->name[i]))) ); + if (ch==';') break; + path+=ch; + } + } + else { + // no RR, no Joliet, just plain iso9660 + path = isoPath; + + // remove the version field + int pos = path.find( ';' ); + if( pos > 0 ) + path.truncate( pos ); + } + if (path.endsWith(".")) path.setLength(path.length()-1); + } + } + + if( !iso->plainIso9660() ) + FreeRR(&rr); + + if (idr->flags[0] & 2) { + entry = new K3bIso9660Directory( iso, isoPath, path, access | S_IFDIR, time, adate, cdate, + user, group, symlink, + special ? 0 : isonum_733(idr->extent), + special ? 0 : isonum_733(idr->size) ); + } + else { + entry = new K3bIso9660File( iso, isoPath, path, access, time, adate, cdate, + user, group, symlink, isonum_733(idr->extent), isonum_733(idr->size) ); + if (z_size) + (static_cast(entry))->setZF( z_algo, z_params, z_size ); + } + iso->dirent->addEntry(entry); + + return 0; +} + + + +K3bIso9660Entry::K3bIso9660Entry( K3bIso9660* archive, + const QString& isoName, + const QString& name, + int access, + int date, + int adate, + int cdate, + const QString& user, + const QString& group, + const QString& symlink ) + : m_adate( adate ), + m_cdate( cdate ), + m_name( name ), + m_isoName( isoName ), + m_date( date ), + m_access( access ), + m_user( user ), + m_group( group ), + m_symlink( symlink ), + m_archive( archive ) +{ +} + + +K3bIso9660Entry::~K3bIso9660Entry() +{ +} + + + + + + +K3bIso9660File::K3bIso9660File( K3bIso9660* archive, + const QString& isoName, + const QString& name, + int access, + int date, + int adate, + int cdate, + const QString& user, + const QString& group, + const QString& symlink, + unsigned int pos, + unsigned int size ) + : K3bIso9660Entry( archive, isoName, name, access, date, adate, cdate, user, group, symlink ), + m_startSector(pos), + m_size(size) +{ + m_algo[0] = 0; + m_algo[1] = 0; + m_parms[0] = 0; + m_parms[1] = 0; + m_realsize = 0; +} + +K3bIso9660File::~K3bIso9660File() +{ +} + +void K3bIso9660File::setZF(char algo[2],char parms[2],int realsize) +{ + m_algo[0]=algo[0];m_algo[1]=algo[1]; + m_parms[0]=parms[0];m_parms[1]=parms[1]; + m_realsize=realsize; +} + + +int K3bIso9660File::read( unsigned int pos, char* data, int maxlen ) const +{ + if( pos >= size() ) + return 0; + + unsigned long startSec = m_startSector + pos/2048; + int startSecOffset = pos%2048; + char* buffer = data; + bool buffered = false; + unsigned long bufferLen = maxlen+startSecOffset; + + // cut to size + if( pos + maxlen > size() ) + bufferLen = size() - pos + startSecOffset; + + // pad to 2048 + if( bufferLen%2048 ) + bufferLen += (2048-(bufferLen%2048)); + + // we need to buffer if we changed the startSec or need a bigger buffer + if( startSecOffset || bufferLen > (unsigned int)maxlen ) { + buffered = true; + buffer = new char[bufferLen]; + } + + int read = archive()->read( startSec, buffer, bufferLen/2048 )*2048; + + if( buffered ) { + if( read > 0 ) { + // cut to requested data + read -= startSecOffset; + if( read + pos > size() ) + read = size() - pos; + if( read > maxlen ) + read = maxlen; + + ::memcpy( data, buffer+startSecOffset, read ); + } + delete [] buffer; + + return read; + } + else { + // cut read data + if( read + pos > size() ) + read = size() - pos; + + return read; + } +} + + +bool K3bIso9660File::copyTo( const QString& url ) const +{ + QFile of( url ); + if( of.open( IO_WriteOnly ) ) { + char buffer[2048*10]; + unsigned int pos = 0; + int r = 0; + while( ( r = read( pos, buffer, 2048*10 ) ) > 0 ) { + of.writeBlock( buffer, r ); + pos += r; + } + + return !r; + } + else { + kdDebug() << "(K3bIso9660File) could not open " << url << " for writing." << endl; + return false; + } +} + + +K3bIso9660Directory::K3bIso9660Directory( K3bIso9660* archive, + const QString& isoName, + const QString& name, + int access, + int date, + int adate, + int cdate, + const QString& user, + const QString& group, + const QString& symlink, + unsigned int pos, + unsigned int size ) + : K3bIso9660Entry( archive, isoName, name, access, date, adate, cdate, user, group, symlink ), + m_bExpanded( size == 0 ), // we can only expand entries that represent an actual directory + m_startSector(pos), + m_size(size) +{ + m_entries.setAutoDelete( true ); +} + +K3bIso9660Directory::~K3bIso9660Directory() +{ +} + + +void K3bIso9660Directory::expand() +{ + if( !m_bExpanded ) { + archive()->dirent = this; + if( ProcessDir( &K3bIso9660::read_callback, m_startSector, m_size, &K3bIso9660::isofs_callback, archive() ) ) + kdDebug() << "(K3bIso9660) failed to expand dir: " << name() << " with size: " << m_size << endl; + + m_bExpanded = true; + } +} + + +QStringList K3bIso9660Directory::entries() const +{ + // create a fake const method to fool the user ;) + const_cast(this)->expand(); + + QStringList l; + + QDictIterator it( m_entries ); + for( ; it.current(); ++it ) + l.append( it.currentKey() ); + + return l; +} + + +QStringList K3bIso9660Directory::iso9660Entries() const +{ + // create a fake const method to fool the user ;) + const_cast(this)->expand(); + + QStringList l; + + QDictIterator it( m_iso9660Entries ); + for( ; it.current(); ++it ) + l.append( it.currentKey() ); + + return l; +} + + +K3bIso9660Entry* K3bIso9660Directory::entry( const QString& n ) +{ + if( n.isEmpty() ) + return 0; + + expand(); + + QString name(n); + + // trailing slash ? -> remove + if( name.length() > 1 && name[name.length()-1] == '/' ) { + name.truncate( name.length()-1 ); + } + + int pos = name.find( '/' ); + while( pos == 0 ) { + if( name.length() > 1 ) { + name = name.mid( 1 ); // remove leading slash + pos = name.find( '/' ); // look again + } + else // "/" + return this; + } + + if ( pos != -1 ) { + QString left = name.left( pos ); + QString right = name.mid( pos + 1 ); + + K3bIso9660Entry* e = m_entries[ left ]; + if ( !e || !e->isDirectory() ) + return 0; + return static_cast(e)->entry( right ); + } + + return m_entries[ name ]; +} + + +K3bIso9660Entry* K3bIso9660Directory::iso9660Entry( const QString& n ) +{ + if( n.isEmpty() ) + return 0; + + expand(); + + QString name(n); + + // trailing slash ? -> remove + if( name.length() > 1 && name[name.length()-1] == '/' ) { + name.truncate( name.length()-1 ); + } + + int pos = name.find( '/' ); + while( pos == 0 ) { + if( name.length() > 1 ) { + name = name.mid( 1 ); // remove leading slash + pos = name.find( '/' ); // look again + } + else // "/" + return this; + } + + if ( pos != -1 ) { + QString left = name.left( pos ); + QString right = name.mid( pos + 1 ); + + K3bIso9660Entry* e = m_iso9660Entries[ left ]; + if ( !e || !e->isDirectory() ) + return 0; + return static_cast(e)->iso9660Entry( right ); + } + + return m_iso9660Entries[ name ]; +} + + +const K3bIso9660Entry* K3bIso9660Directory::entry( const QString& name ) const +{ + return const_cast(this)->entry( name ); +} + + +const K3bIso9660Entry* K3bIso9660Directory::iso9660Entry( const QString& name ) const +{ + return const_cast(this)->iso9660Entry( name ); +} + + +void K3bIso9660Directory::addEntry( K3bIso9660Entry* entry ) +{ + m_entries.insert( entry->name(), entry ); + m_iso9660Entries.insert( entry->isoName(), entry ); +} + + + + + +class K3bIso9660::Private +{ +public: + Private() + : cdDevice(0), + fd(-1), + isOpen(false), + startSector(0), + plainIso9660(false), + backend(0) { + } + + QPtrList elToritoDirs; + QPtrList jolietDirs; + QPtrList isoDirs; + QPtrList rrDirs; // RockRidge + + K3bIso9660SimplePrimaryDescriptor primaryDesc; + + K3bDevice::Device* cdDevice; + int fd; + + bool isOpen; + + // only used for direkt K3bDevice::Device access + unsigned int startSector; + + bool plainIso9660; + + K3bIso9660Backend* backend; +}; + + +K3bIso9660::K3bIso9660( const QString& filename ) + : m_filename( filename ) +{ + d = new Private(); +} + + +K3bIso9660::K3bIso9660( int fd ) +{ + d = new Private(); + d->fd = fd; +} + + +K3bIso9660::K3bIso9660( K3bIso9660Backend* backend ) +{ + d = new Private(); + d->backend = backend; +} + + +K3bIso9660::K3bIso9660( K3bDevice::Device* dev, unsigned int startSector ) +{ + d = new Private(); + d->cdDevice = dev; + d->startSector = startSector; +} + + +K3bIso9660::~K3bIso9660() +{ + close(); + delete d->backend; + delete d; +} + + +void K3bIso9660::setStartSector( unsigned int startSector ) +{ + d->startSector = startSector; +} + + +void K3bIso9660::setPlainIso9660( bool b ) +{ + d->plainIso9660 = b; +} + + +bool K3bIso9660::plainIso9660() const +{ + return d->plainIso9660; +} + + +int K3bIso9660::read( unsigned int sector, char* data, int count ) +{ + if( count == 0 ) + return 0; + else + return d->backend->read( sector, data, count ); +} + + +void K3bIso9660::addBoot(struct el_torito_boot_descriptor* bootdesc) +{ + int i,size; + boot_head boot; + boot_entry *be; + QString path; + K3bIso9660File *entry; + + entry=new K3bIso9660File( this, "Catalog", "Catalog", dirent->permissions() & ~S_IFDIR, + dirent->date(), dirent->adate(), dirent->cdate(), + dirent->user(), dirent->group(), QString::null, + isonum_731(bootdesc->boot_catalog), 2048 ); + dirent->addEntry(entry); + if (!ReadBootTable(&K3bIso9660::read_callback,isonum_731(bootdesc->boot_catalog),&boot,this)) { + i=1; + be=boot.defentry; + while (be) { + size=BootImageSize(&K3bIso9660::read_callback, + isonum_711(((struct default_entry*) be->data)->media), + isonum_731(((struct default_entry*) be->data)->start), + isonum_721(((struct default_entry*) be->data)->seccount), + this); + path="Default Image"; + if (i>1) path += " (" + QString::number(i) + ")"; + entry=new K3bIso9660File( this, path, path, dirent->permissions() & ~S_IFDIR, + dirent->date(), dirent->adate(), dirent->cdate(), + dirent->user(), dirent->group(), QString::null, + isonum_731(((struct default_entry*) be->data)->start), size<<9 ); + dirent->addEntry(entry); + be=be->next; + i++; + } + + FreeBootTable(&boot); + } +} + + +bool K3bIso9660::open() +{ + if( d->isOpen ) + return true; + + if( !d->backend ) { + // create a backend + + if( !m_filename.isEmpty() ) + d->backend = new K3bIso9660FileBackend( m_filename ); + + else if( d->fd > 0 ) + d->backend = new K3bIso9660FileBackend( d->fd ); + + else if( d->cdDevice ) { + // now check if we have a scrambled video dvd + if( d->cdDevice->copyrightProtectionSystemType() == 1 ) { + + kdDebug() << "(K3bIso9660) found encrypted dvd. using libdvdcss." << endl; + + // open the libdvdcss stuff + d->backend = new K3bIso9660LibDvdCssBackend( d->cdDevice ); + if( !d->backend->open() ) { + // fallback to devicebackend + delete d->backend; + d->backend = new K3bIso9660DeviceBackend( d->cdDevice ); + } + } + else + d->backend = new K3bIso9660DeviceBackend( d->cdDevice ); + } + } + + d->isOpen = d->backend->open(); + if( !d->isOpen ) + return false; + + iso_vol_desc *desc; + QString path,tmp,uid,gid; + k3b_struct_stat buf; + int access,c_i,c_j; + struct el_torito_boot_descriptor* bootdesc; + + + /* We'll use the permission and user/group of the 'host' file except + * in Rock Ridge, where the permissions are stored on the file system + */ + if ( k3b_stat( QFile::encodeName(m_filename), &buf ) < 0 ) { + /* defaults, if stat fails */ + memset(&buf,0,sizeof(k3b_struct_stat)); + buf.st_mode=0777; + } + uid.setNum(buf.st_uid); + gid.setNum(buf.st_gid); + access = buf.st_mode & ~S_IFMT; + + + int c_b=1; + c_i=1;c_j=1; + + desc = ReadISO9660( &K3bIso9660::read_callback, d->startSector, this ); + + if (!desc) { + kdDebug() << "K3bIso9660::openArchive no volume descriptors" << endl; + close(); + return false; + } + + while (desc) { + + m_rr = false; + + switch (isonum_711(desc->data.type)) { + case ISO_VD_BOOT: + + bootdesc=(struct el_torito_boot_descriptor*) &(desc->data); + if( !memcmp( EL_TORITO_ID, bootdesc->system_id, ISODCL(8,39) ) ) { + path="El Torito Boot"; + if( c_b > 1 ) + path += " (" + QString::number(c_b) + ")"; + + dirent = new K3bIso9660Directory( this, path, path, access | S_IFDIR, + buf.st_mtime, buf.st_atime, buf.st_ctime, uid, gid, QString::null ); + d->elToritoDirs.append( dirent ); + + addBoot(bootdesc); + c_b++; + } + break; + + case ISO_VD_PRIMARY: + createSimplePrimaryDesc( (struct iso_primary_descriptor*)&desc->data ); + // fall through + case ISO_VD_SUPPLEMENTARY: + { + struct iso_primary_descriptor* primaryDesc = (struct iso_primary_descriptor*)&desc->data; + struct iso_directory_record* idr = (struct iso_directory_record*)&primaryDesc->root_directory_record; + + m_joliet = JolietLevel(&desc->data); + + // skip joliet in plain iso mode + if( m_joliet && plainIso9660() ) + break; + + if (m_joliet) { + path = "Joliet level " + QString::number(m_joliet); + if( c_j > 1 ) + path += " (" + QString::number(c_j) + ")"; + } + else { + path = QString::fromLocal8Bit( primaryDesc->volume_id, 32 ); + if( c_i > 1 ) + path += " (" + QString::number(c_i) + ")"; + } + + dirent = new K3bIso9660Directory( this, path, path, access | S_IFDIR, + buf.st_mtime, buf.st_atime, buf.st_ctime, uid, gid, QString::null ); + + // expand the root entry + ProcessDir( &K3bIso9660::read_callback, isonum_733(idr->extent),isonum_733(idr->size),&K3bIso9660::isofs_callback,this); + + if (m_joliet) + c_j++; + else + c_i++; + + if( m_joliet ) + d->jolietDirs.append( dirent ); + else { + if( m_rr ) + d->rrDirs.append( dirent ); + d->isoDirs.append( dirent ); + } + + break; + } + } + desc = desc->next; + } + + FreeISO9660(desc); + + return true; +} + + +bool K3bIso9660::isOpen() const +{ + return d->isOpen; +} + + +void K3bIso9660::createSimplePrimaryDesc( struct iso_primary_descriptor* desc ) +{ + d->primaryDesc.volumeId = QString::fromLocal8Bit( desc->volume_id, 32 ).stripWhiteSpace(); + d->primaryDesc.systemId = QString::fromLocal8Bit( desc->system_id, 32 ).stripWhiteSpace(); + d->primaryDesc.volumeSetId = QString::fromLocal8Bit( desc->volume_set_id, 128 ).stripWhiteSpace(); + d->primaryDesc.publisherId = QString::fromLocal8Bit( desc->publisher_id, 128 ).stripWhiteSpace(); + d->primaryDesc.preparerId = QString::fromLocal8Bit( desc->preparer_id, 128 ).stripWhiteSpace(); + d->primaryDesc.applicationId = QString::fromLocal8Bit( desc->application_id, 128 ).stripWhiteSpace(); + d->primaryDesc.volumeSetSize = isonum_723(desc->volume_set_size); + d->primaryDesc.volumeSetNumber = isonum_723(desc->volume_set_size); + d->primaryDesc.logicalBlockSize = isonum_723(desc->logical_block_size); + d->primaryDesc.volumeSpaceSize = isonum_733(desc->volume_space_size); +} + + +void K3bIso9660::close() +{ + if( d->isOpen ) { + d->backend->close(); + + // Since the first isoDir is the KArchive + // root we must not delete it but all the + // others. + + d->elToritoDirs.setAutoDelete(true); + d->jolietDirs.setAutoDelete(true); + d->isoDirs.setAutoDelete(true); + d->elToritoDirs.clear(); + d->jolietDirs.clear(); + d->isoDirs.clear(); + + d->isOpen = false; + } +} + + +const K3bIso9660Directory* K3bIso9660::firstJolietDirEntry() const +{ + return d->jolietDirs.first(); +} + + +const K3bIso9660Directory* K3bIso9660::firstIsoDirEntry() const +{ + return d->isoDirs.first(); +} + + +const K3bIso9660Directory* K3bIso9660::firstElToritoEntry() const +{ + return d->elToritoDirs.first(); +} + + +const K3bIso9660Directory* K3bIso9660::firstRRDirEntry() const +{ + return d->rrDirs.first(); +} + + +const K3bIso9660SimplePrimaryDescriptor& K3bIso9660::primaryDescriptor() const +{ + return d->primaryDesc; +} + + +void K3bIso9660::debug() const +{ + if( isOpen() ) { + kdDebug() << "System Id: " << primaryDescriptor().systemId << endl; + kdDebug() << "Volume Id: " << primaryDescriptor().volumeId << endl; + kdDebug() << "Volume Set Id: " << primaryDescriptor().volumeSetId << endl; + kdDebug() << "Preparer Id: " << primaryDescriptor().preparerId << endl; + kdDebug() << "Publisher Id: " << primaryDescriptor().publisherId << endl; + kdDebug() << "Application Id: " << primaryDescriptor().applicationId << endl; + kdDebug() << "Volume Set Size: " << primaryDescriptor().volumeSetSize << endl; + kdDebug() << "Volume Set Number: " << primaryDescriptor().volumeSetNumber << endl; + + if( firstIsoDirEntry() ) { + kdDebug() << "First ISO Dir entry:" << endl; + kdDebug() << "----------------------------------------------" << endl; + debugEntry( firstIsoDirEntry(), 0 ); + kdDebug() << "----------------------------------------------" << endl << endl; + } + if( firstRRDirEntry() ) { + kdDebug() << "First RR Dir entry:" << endl; + kdDebug() << "----------------------------------------------" << endl; + debugEntry( firstRRDirEntry(), 0 ); + kdDebug() << "----------------------------------------------" << endl << endl; + } + if( firstJolietDirEntry() ) { + kdDebug() << "First Joliet Dir entry:" << endl; + kdDebug() << "----------------------------------------------" << endl; + debugEntry( firstJolietDirEntry(), 0 ); + kdDebug() << "----------------------------------------------" << endl << endl; + } + } +} + + +void K3bIso9660::debugEntry( const K3bIso9660Entry* entry, int depth ) const +{ + if( !entry ) { + kdDebug() << "(K3bIso9660::debugEntry) null entry." << endl; + return; + } + + QString spacer; + spacer.fill( ' ', depth*3 ); + kdDebug() << spacer << "- " << entry->name() << " (" << entry->isoName() << ")" << endl; + if( entry->isDirectory() ) { + const K3bIso9660Directory* dir = dynamic_cast(entry); + QStringList entries = dir->entries(); + for( QStringList::const_iterator it = entries.begin(); it != entries.end(); ++it ) { + debugEntry( dir->entry( *it ), depth+1 ); + } + } +} + + +K3bIso9660SimplePrimaryDescriptor::K3bIso9660SimplePrimaryDescriptor() + : volumeSetSize(0), + volumeSetNumber(0), + logicalBlockSize(0), + volumeSpaceSize(0) +{ +} + + +bool operator==( const K3bIso9660SimplePrimaryDescriptor& d1, + const K3bIso9660SimplePrimaryDescriptor& d2 ) +{ + return( d1.volumeId == d2.volumeId && + d1.systemId == d2.systemId && + d1.volumeSetId == d2.volumeSetId && + d1.publisherId == d2.publisherId && + d1.preparerId == d2.preparerId && + d1.applicationId == d2.applicationId && + d1.volumeSetSize == d2.volumeSetSize && + d1.volumeSetNumber == d2.volumeSetNumber && + d1.logicalBlockSize == d2.logicalBlockSize && + d1.volumeSpaceSize == d2.volumeSpaceSize ); +} + + +bool operator!=( const K3bIso9660SimplePrimaryDescriptor& d1, + const K3bIso9660SimplePrimaryDescriptor& d2 ) +{ + return( d1.volumeId != d2.volumeId || + d1.systemId != d2.systemId || + d1.volumeSetId != d2.volumeSetId || + d1.publisherId != d2.publisherId || + d1.preparerId != d2.preparerId || + d1.applicationId != d2.applicationId || + d1.volumeSetSize != d2.volumeSetSize || + d1.volumeSetNumber != d2.volumeSetNumber || + d1.logicalBlockSize != d2.logicalBlockSize || + d1.volumeSpaceSize != d2.volumeSpaceSize ); +} diff --git a/libk3b/tools/k3biso9660.h b/libk3b/tools/k3biso9660.h new file mode 100644 index 0000000..7fc52d9 --- /dev/null +++ b/libk3b/tools/k3biso9660.h @@ -0,0 +1,453 @@ +/* + * + * $Id: k3biso9660.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_ISO9660_H_ +#define _K3B_ISO9660_H_ + +#include +#include + +#include +#include +#include +#include + +#include "k3b_export.h" + + +namespace K3bDevice { + class Device; +} + +class K3bIso9660; +class K3bIso9660Backend; +struct iso_directory_record; +struct el_torito_boot_descriptor; +struct iso_primary_descriptor; + +typedef long sector_t; + + + +/** + * Simplyfied primary descriptor which just contains the fields + * used by K3b. + */ +class LIBK3B_EXPORT K3bIso9660SimplePrimaryDescriptor +{ + public: + /** + * Creates an empty descriptor + */ + K3bIso9660SimplePrimaryDescriptor(); + + QString volumeId; + QString systemId; + QString volumeSetId; + QString publisherId; + QString preparerId; + QString applicationId; + int volumeSetSize; + int volumeSetNumber; + long logicalBlockSize; + long long volumeSpaceSize; +}; + + +LIBK3B_EXPORT bool operator==( const K3bIso9660SimplePrimaryDescriptor& d1, + const K3bIso9660SimplePrimaryDescriptor& d2 ); +LIBK3B_EXPORT bool operator!=( const K3bIso9660SimplePrimaryDescriptor& d1, + const K3bIso9660SimplePrimaryDescriptor& d2 ); + + +/** + * Base class for all entries in a K3bIso9660 archive. A lot has been copied + * from KArchive. + */ +class LIBK3B_EXPORT K3bIso9660Entry +{ + public: + K3bIso9660Entry( K3bIso9660* archive, + const QString& isoName, + const QString& name, + int access, + int date, + int adate, + int cdate, + const QString& user, + const QString& group, + const QString& symlink ); + virtual ~K3bIso9660Entry(); + + int adate() const { return m_adate; } + int cdate() const { return m_cdate; } + + /** + * Creation date of the file. + * @return the creation date + */ + QDateTime datetime() const; + + /** + * Creation date of the file. + * @return the creation date in seconds since 1970 + */ + int date() const { return m_date; } + + /** + * Name of the file without path. + * @return The file name without path. + */ + const QString& name() const { return m_name; } + + /** + * \return The raw name as saved in the ISO9660 tree + */ + const QString& isoName() const { return m_isoName; } + + /** + * The permissions and mode flags as returned by the stat() function + * in st_mode. + * @return the permissions + */ + mode_t permissions() const { return m_access; } + + /** + * User who created the file. + * @return the owner of the file + */ + const QString& user() const { return m_user; } + + /** + * Group of the user who created the file. + * @return the group of the file + */ + const QString& group() const { return m_group; } + + /** + * Symlink if there is one. + * @return the symlink, or QString::null + */ + const QString& symlink() const { return m_symlink; } + + /** + * Checks whether the entry is a file. + * @return true if this entry is a file + */ + virtual bool isFile() const { return false; } + + /** + * Checks whether the entry is a directory. + * @return true if this entry is a directory + */ + virtual bool isDirectory() const { return false; } + + K3bIso9660* archive() const { return m_archive; } + + private: + int m_adate; + int m_cdate; + QString m_name; + QString m_isoName; + int m_date; + mode_t m_access; + QString m_user; + QString m_group; + QString m_symlink; + K3bIso9660* m_archive; +}; + + +class LIBK3B_EXPORT K3bIso9660Directory : public K3bIso9660Entry +{ + public: + K3bIso9660Directory( K3bIso9660* archive, + const QString& isoName, + const QString& name, + int access, + int date, + int adate, + int cdate, + const QString& user, + const QString& group, + const QString& symlink, + unsigned int pos = 0, + unsigned int size = 0 ); + ~K3bIso9660Directory(); + + /** + * Returns a list of sub-entries. + * @return the names of all entries in this directory (filenames, no path). + */ + QStringList entries() const; + + /** + * Returns the entry with the given name. + * @param name may be "test1", "mydir/test3", "mydir/mysubdir/test3", etc. + * @return a pointer to the entry in the directory. + */ + K3bIso9660Entry* entry( const QString& name ); + + /** + * Returns the entry with the given name. + * @param name may be "test1", "mydir/test3", "mydir/mysubdir/test3", etc. + * @return a pointer to the entry in the directory. + */ + const K3bIso9660Entry* entry( const QString& name ) const; + + /** + * Returns a list of sub-entries. + * Searches for Iso9660 names. + * @return the names of all entries in this directory (filenames, no path). + */ + QStringList iso9660Entries() const; + + /** + * Returns the entry with the given name. + * Searches for Iso9660 names. + * @param name may be "test1", "mydir/test3", "mydir/mysubdir/test3", etc. + * @return a pointer to the entry in the directory. + */ + K3bIso9660Entry* iso9660Entry( const QString& name ); + + /** + * Returns the entry with the given name. + * Searches for Iso9660 names. + * @param name may be "test1", "mydir/test3", "mydir/mysubdir/test3", etc. + * @return a pointer to the entry in the directory. + */ + const K3bIso9660Entry* iso9660Entry( const QString& name ) const; + + /** + * @internal + * Adds a new entry to the directory. + */ + void addEntry( K3bIso9660Entry* ); + + /** + * Checks whether this entry is a directory. + * @return true, since this entry is a directory + */ + bool isDirectory() const { return true; } + + private: + void expand(); + + QDict m_entries; + QDict m_iso9660Entries; + + bool m_bExpanded; + unsigned int m_startSector; + unsigned int m_size; +}; + + +class LIBK3B_EXPORT K3bIso9660File : public K3bIso9660Entry +{ + public: + /** + * @param pos start sector + */ + K3bIso9660File( K3bIso9660* archive, + const QString& isoName, + const QString& name, + int access, + int date, + int adate, + int cdate, + const QString& user, + const QString& group, + const QString& symlink, + unsigned int pos, + unsigned int size ); + ~K3bIso9660File(); + + bool isFile() const { return true; } + + void setZF( char algo[2], char parms[2], int realsize ); + int realsize() const { return m_realsize; } + + /** + * @return size in bytes. + */ + unsigned int size() const { return m_size; } + + /** + * Returnes the startSector of the file. + */ + unsigned int startSector() const { return m_startSector; } + + /** + * Returnes the startOffset of the file in bytes. + */ + unsigned long long startPostion() const { return (unsigned long long)m_startSector * 2048; } + + /** + * @param pos offset in bytes + * @param len max number of bytes to read + */ + int read( unsigned int pos, char* data, int len ) const; + + /** + * Copy this file to a url. + */ + bool copyTo( const QString& url ) const; + + private: + char m_algo[2]; + char m_parms[2]; + int m_realsize; + + unsigned int m_curpos; + unsigned int m_startSector; + unsigned int m_size; +}; + + +/** + * This class is based on the KIso class by + * Gy�gy Szombathelyi . + * A lot has been changed and bugfixed. + * The API has been improved to be useful. + * + * Due to the stupid Qt which does not support large files as default + * we cannot use QIODevice with DVDs! That's why we have our own + * reading code which is not allowed by KArchive (which is limited to int + * by the way... who the hell designed this?) + * I also removed the KArchive inheritance because of the named reasons. + * So this stuff contains a lot KArchive code which has been made usable. + * + * That does not mean that this class is well designed. No, it's not. :) + * + * Opening a K3bIso9660 object should be fast since creation of the directory + * and file entries is not done until a call to K3bIso9660Directory::entries. +*/ +class LIBK3B_EXPORT K3bIso9660 +{ + public: + /** + * Creates an instance that operates on the given filename. + * using the compression filter associated to given mimetype. + * + * @param filename is a local path (e.g. "/home/weis/myfile.tgz") + */ + K3bIso9660( const QString& filename ); + + /** + * Special case which always reads the TOC from the specified sector + * thus supporting multisession CDs. + */ + K3bIso9660( K3bDevice::Device* dev, unsigned int startSector = 0 ); + + /** + * @param fd open file descriptor + */ + K3bIso9660( int fd ); + + /** + * Directly specify the backend to read from. + * K3bIso9660 will take ownership of the backend and delete it. + */ + K3bIso9660( K3bIso9660Backend* ); + + /** + * If the .iso is still opened, then it will be + * closed automatically by the destructor. + */ + virtual ~K3bIso9660(); + + /** + * Set where to start reading in the source. + */ + void setStartSector( unsigned int startSector ); + + /** + * If set to true before opening K3bIso9660 will ignore RR and joliet extensions + * and only create plain iso9660 names. + */ + void setPlainIso9660( bool ); + + bool plainIso9660() const; + + /** + * Opens the archive for reading. + * Parses the directory listing of the archive + * and creates the K3bIso9660Directory/K3bIso9660File entries. + */ + bool open(); + + bool isOpen() const; + + /** + * Closes everything. + * This is also called in the destructor + */ + void close(); + + /** + * @param sector startsector + * @param len number of sectors + * @return number of sectors read or -1 on error + */ + int read( unsigned int sector, char* data, int len ); + + /** + * The name of the os file, as passed to the constructor + * Null if you did not use the QString constructor. + */ + const QString& fileName() { return m_filename; } + + const K3bIso9660Directory* firstJolietDirEntry() const; + const K3bIso9660Directory* firstRRDirEntry() const; + const K3bIso9660Directory* firstIsoDirEntry() const; + const K3bIso9660Directory* firstElToritoEntry() const; + + /** + * @returns 0 if no joliet desc could be found + * the joliet level (1-3) otherwise + */ + int jolietLevel() const { return m_joliet; } + + const K3bIso9660SimplePrimaryDescriptor& primaryDescriptor() const; + + void debug() const; + + private: + /** + * @internal + */ + void addBoot( struct el_torito_boot_descriptor* bootdesc ); + void createSimplePrimaryDesc( struct iso_primary_descriptor* desc ); + + void debugEntry( const K3bIso9660Entry*, int depth ) const; + + int m_joliet; + + // only used for creation + static int read_callback( char* buf, sector_t start, int len, void* udata ); + static int isofs_callback( struct iso_directory_record* idr, void *udata ); + K3bIso9660Directory *dirent; + bool m_rr; + friend class K3bIso9660Directory; + + private: + QString m_filename; + + class Private; + Private * d; +}; + +#endif diff --git a/libk3b/tools/k3biso9660backend.cpp b/libk3b/tools/k3biso9660backend.cpp new file mode 100644 index 0000000..aacc079 --- /dev/null +++ b/libk3b/tools/k3biso9660backend.cpp @@ -0,0 +1,239 @@ +/* + * + * $Id: sourceheader 380067 2005-01-19 13:03:46Z trueg $ + * Copyright (C) 2005 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3biso9660backend.h" +#include "k3blibdvdcss.h" + +#include +#include +#include +#include + +#include + +#include + + +// +// K3bIso9660DeviceBackend ----------------------------------- +// + +K3bIso9660DeviceBackend::K3bIso9660DeviceBackend( K3bDevice::Device* dev ) + : m_device( dev ), + m_isOpen(false) +{ +} + + +K3bIso9660DeviceBackend::~K3bIso9660DeviceBackend() +{ + close(); +} + + +bool K3bIso9660DeviceBackend::open() +{ + if( m_isOpen ) + return true; + else if( m_device->open() ) { + // set optimal reading speed + m_device->setSpeed( 0xffff, 0xffff ); + m_isOpen = true; + return true; + } + else + return false; +} + + +void K3bIso9660DeviceBackend::close() +{ + if( m_isOpen ) { + m_isOpen = false; + m_device->close(); + } +} + + +int K3bIso9660DeviceBackend::read( unsigned int sector, char* data, int len ) +{ + if( isOpen() ) { + // + // split the number of sectors to be read + // FIXME: use a "real" value, not some arbitrary one + // + static const int maxReadSectors = 20; + int sectorsRead = 0; + int retries = 10; // TODO: no fixed value + while( retries ) { + int read = QMIN(len-sectorsRead, maxReadSectors); + if( !m_device->read10( (unsigned char*)(data+sectorsRead*2048), + read*2048, + sector+sectorsRead, + read ) ) { + retries--; + } + else { + sectorsRead += read; + retries = 10; // new retires for every read part + if( sectorsRead == len ) + return len; + } + } + } + + return -1; +} + + +// +// K3bIso9660FileBackend ----------------------------------- +// + +K3bIso9660FileBackend::K3bIso9660FileBackend( const QString& filename ) + : m_filename( filename ), + m_fd( -1 ), + m_closeFd( true ) +{ +} + + +K3bIso9660FileBackend::K3bIso9660FileBackend( int fd ) + : m_fd( fd ), + m_closeFd( false ) +{ +} + + +K3bIso9660FileBackend::~K3bIso9660FileBackend() +{ + close(); +} + + +#ifndef O_LARGEFILE +#define O_LARGEFILE 0 +#endif + +bool K3bIso9660FileBackend::open() +{ + if( m_fd > 0 ) + return true; + else { + m_fd = ::open( QFile::encodeName( m_filename ), O_RDONLY|O_LARGEFILE ); + return ( m_fd > 0 ); + } +} + + +void K3bIso9660FileBackend::close() +{ + if( m_closeFd && m_fd > 0 ) { + ::close( m_fd ); + m_fd = -1; + } +} + + + +bool K3bIso9660FileBackend::isOpen() const +{ + return ( m_fd > 0 ); +} + + +int K3bIso9660FileBackend::read( unsigned int sector, char* data, int len ) +{ + int read = 0; + if( ::lseek( m_fd, static_cast(sector)*2048, SEEK_SET ) != -1 ) + if( (read = ::read( m_fd, data, len*2048 )) != -1 ) + return read / 2048; + + return -1; +} + + + +// +// K3bIso9660LibDvdCssBackend ----------------------------------- +// + +K3bIso9660LibDvdCssBackend::K3bIso9660LibDvdCssBackend( K3bDevice::Device* dev ) + : m_device( dev ), + m_libDvdCss( 0 ) +{ +} + + +K3bIso9660LibDvdCssBackend::~K3bIso9660LibDvdCssBackend() +{ + close(); +} + + +bool K3bIso9660LibDvdCssBackend::open() +{ + if( !m_libDvdCss ) { + // open the libdvdcss stuff + m_libDvdCss = K3bLibDvdCss::create(); + + if( m_libDvdCss ) { + + if( !m_libDvdCss->open( m_device ) || + !m_libDvdCss->crackAllKeys() ) { + kdDebug() << "(K3bIso9660LibDvdCssBackend) Failed to retrieve all CSS keys." << endl; + close(); + } + } + else + kdDebug() << "(K3bIso9660LibDvdCssBackend) failed to open libdvdcss." << endl; + } + + return ( m_libDvdCss != 0 ); +} + + +void K3bIso9660LibDvdCssBackend::close() +{ + delete m_libDvdCss; + m_libDvdCss = 0; +} + + + +bool K3bIso9660LibDvdCssBackend::isOpen() const +{ + return ( m_libDvdCss != 0 ); +} + + +int K3bIso9660LibDvdCssBackend::read( unsigned int sector, char* data, int len ) +{ + int read = -1; + + if( isOpen() ) { + int retries = 10; // TODO: no fixed value + while( retries && !m_libDvdCss->readWrapped( reinterpret_cast(data), + sector, + len ) ) + retries--; + + if( retries > 0 ) + read = len; + } + + return read; +} + diff --git a/libk3b/tools/k3biso9660backend.h b/libk3b/tools/k3biso9660backend.h new file mode 100644 index 0000000..78937e5 --- /dev/null +++ b/libk3b/tools/k3biso9660backend.h @@ -0,0 +1,95 @@ +/* + * + * $Id: sourceheader 380067 2005-01-19 13:03:46Z trueg $ + * Copyright (C) 2005 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_ISO9660_BACKEND_H_ +#define _K3B_ISO9660_BACKEND_H_ + +#include + +#include "k3b_export.h" + +namespace K3bDevice { + class Device; +} + +class K3bLibDvdCss; + + +class K3bIso9660Backend +{ + public: + K3bIso9660Backend() {} + virtual ~K3bIso9660Backend() {} + + virtual bool open() = 0; + virtual void close() = 0; + virtual bool isOpen() const = 0; + virtual int read( unsigned int sector, char* data, int len ) = 0; +}; + + +class K3bIso9660DeviceBackend : public K3bIso9660Backend +{ + public: + LIBK3B_EXPORT K3bIso9660DeviceBackend( K3bDevice::Device* dev ); + ~K3bIso9660DeviceBackend(); + + bool open(); + void close(); + bool isOpen() const { return m_isOpen; } + int read( unsigned int sector, char* data, int len ); + + private: + K3bDevice::Device* m_device; + bool m_isOpen; +}; + + +class K3bIso9660FileBackend : public K3bIso9660Backend +{ + public: + LIBK3B_EXPORT K3bIso9660FileBackend( const QString& filename ); + K3bIso9660FileBackend( int fd ); + ~K3bIso9660FileBackend(); + + bool open(); + void close(); + bool isOpen() const; + int read( unsigned int sector, char* data, int len ); + + private: + QString m_filename; + int m_fd; + bool m_closeFd; +}; + + +class K3bIso9660LibDvdCssBackend : public K3bIso9660Backend +{ + public: + LIBK3B_EXPORT K3bIso9660LibDvdCssBackend( K3bDevice::Device* ); + ~K3bIso9660LibDvdCssBackend(); + + bool open(); + void close(); + bool isOpen() const; + int read( unsigned int sector, char* data, int len ); + + private: + K3bDevice::Device* m_device; + K3bLibDvdCss* m_libDvdCss; +}; + +#endif diff --git a/libk3b/tools/k3blibdvdcss.cpp b/libk3b/tools/k3blibdvdcss.cpp new file mode 100644 index 0000000..0a8d1f0 --- /dev/null +++ b/libk3b/tools/k3blibdvdcss.cpp @@ -0,0 +1,307 @@ +/* + * + * $Id: k3blibdvdcss.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include + +#include "k3blibdvdcss.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include + + +void* K3bLibDvdCss::s_libDvdCss = 0; +int K3bLibDvdCss::s_counter = 0; + + +extern "C" { + struct dvdcss_s; + typedef struct dvdcss_s* dvdcss_t; + + dvdcss_t (*k3b_dvdcss_open)(char*); + int (*k3b_dvdcss_close)( dvdcss_t ); + int (*k3b_dvdcss_seek)( dvdcss_t, int, int ); + int (*k3b_dvdcss_read)( dvdcss_t, void*, int, int ); +} + + + +class K3bLibDvdCss::Private +{ +public: + Private() + :dvd(0) { + } + + dvdcss_t dvd; + K3bDevice::Device* device; + QValueVector< QPair > titleOffsets; + int currentSector; + bool currentSectorInTitle; +}; + +K3bLibDvdCss::K3bLibDvdCss() +{ + d = new Private(); + s_counter++; +} + + +K3bLibDvdCss::~K3bLibDvdCss() +{ + close(); + delete d; + s_counter--; + if( s_counter == 0 ) { + dlclose( s_libDvdCss ); + s_libDvdCss = 0; + } +} + + +bool K3bLibDvdCss::open( K3bDevice::Device* dev ) +{ + d->device = dev; + dev->close(); + d->dvd = k3b_dvdcss_open( const_cast( QFile::encodeName(dev->blockDeviceName()).data() ) ); + d->currentSector = 0; + d->currentSectorInTitle = false; + return ( d->dvd != 0 ); +} + + +void K3bLibDvdCss::close() +{ + if( d->dvd ) + k3b_dvdcss_close( d->dvd ); + d->dvd = 0; +} + + +int K3bLibDvdCss::seek( int sector, int flags ) +{ + return k3b_dvdcss_seek( d->dvd, sector, flags ); +} + + +int K3bLibDvdCss::read( void* buffer, int sectors, int flags ) +{ + return k3b_dvdcss_read( d->dvd, buffer, sectors, flags ); +} + + +int K3bLibDvdCss::readWrapped( void* buffer, int firstSector, int sectors ) +{ + // 1. are we in a title? + // 2. does a new title start in the read sector area? + // - see below, set title if firstSector is the first sector of a new title + // 3. does a title end in the read sector area? + // 3.1 does a previous title end + // 3.2 does the title from 2. already end + + // we need to seek to the first sector. Otherwise we get faulty data. + bool needToSeek = ( firstSector != d->currentSector || firstSector == 0 ); + bool inTitle = false; + bool startOfTitle = false; + + // + // Make sure we never read encrypted and unencrypted data at once since libdvdcss + // only decrypts the whole area of read sectors or nothing at all. + // + for( unsigned int i = 0; i < d->titleOffsets.count(); ++i ) { + int titleStart = d->titleOffsets[i].first; + int titleEnd = titleStart + d->titleOffsets[i].second - 1; + + // update key when entrering a new title + // FIXME: we also need this if we seek into a new title (not only the start of the title) + if( titleStart == firstSector ) + startOfTitle = needToSeek = inTitle = true; + + // check if a new title or non-title area starts inside the read sector range + if( firstSector < titleStart && firstSector+sectors > titleStart ) { + kdDebug() << "(K3bLibDvdCss) title start inside of sector range (" + << firstSector << "-" << (firstSector+sectors-1) + << "). only reading " << (titleStart - firstSector) << " sectors up to title offset " + << (titleStart-1) << endl; + sectors = titleStart - firstSector; + } + + if( firstSector < titleEnd && firstSector+sectors > titleEnd ) { + kdDebug() << "(K3bLibDvdCss) title end inside of sector range (" + << firstSector << "-" << (firstSector+sectors-1) + << "). only reading " << (titleEnd - firstSector + 1) << " sectors up to title offset " + << titleEnd << endl; + sectors = titleEnd - firstSector + 1; + inTitle = true; + } + + // is our read range part of one title + if( firstSector >= titleStart && firstSector+sectors-1 <= titleEnd ) + inTitle = true; + } + + if( needToSeek ) { + int flags = DVDCSS_NOFLAGS; + if( startOfTitle ) + flags = DVDCSS_SEEK_KEY; + else if( inTitle ) + flags = DVDCSS_SEEK_MPEG; + + kdDebug() << "(K3bLibDvdCss) need to seek from " << d->currentSector << " to " << firstSector << " with " << flags << endl; + + d->currentSector = seek( firstSector, flags ); + if( d->currentSector != firstSector ) { + kdDebug() << "(K3bLibDvdCss) seek failed: " << d->currentSector << endl; + return -1; + } + + kdDebug() << "(K3bLibDvdCss) seek done: " << d->currentSector << endl; + } + + + int flags = DVDCSS_NOFLAGS; + if( inTitle ) + flags = DVDCSS_READ_DECRYPT; + + int ret = read( buffer, sectors, flags ); + if( ret >= 0 ) + d->currentSector += ret; + else + d->currentSector = 0; // force a seek the next time + + return ret; +} + + +bool K3bLibDvdCss::crackAllKeys() +{ + // + // Loop over all titles and crack the keys (inspired by libdvdread) + // + kdDebug() << "(K3bLibDvdCss) cracking all keys." << endl; + + d->titleOffsets.clear(); + + K3bIso9660 iso( new K3bIso9660DeviceBackend( d->device ) ); + iso.setPlainIso9660( true ); + if( !iso.open() ) { + kdDebug() << "(K3bLibDvdCss) could not open iso9660 fs." << endl; + return false; + } + +#ifdef K3B_DEBUG + iso.debug(); +#endif + + const K3bIso9660Directory* dir = iso.firstIsoDirEntry(); + + int title = 0; + for( ; title < 100; ++title ) { + QString filename; + + // first we get the menu vob + if( title == 0 ) + filename.sprintf( "VIDEO_TS/VIDEO_TS.VOB" ); + else + filename.sprintf( "VIDEO_TS/VTS_%02d_%d.VOB", title, 0 ); + + const K3bIso9660File* file = dynamic_cast( dir->entry( filename ) ); + if( file && file->size() > 0 ) { + d->titleOffsets.append( qMakePair( (int)file->startSector(), (int)(file->size() / 2048U) ) ); + kdDebug() << "(K3bLibDvdCss) Get key for /" << filename << " at " << file->startSector() << endl; + if( seek( (int)file->startSector(), DVDCSS_SEEK_KEY ) < 0 ) { + kdDebug() << "(K3bLibDvdCss) unable to seek to " << file->startSector() << endl; + return false; + } + } + + if( title > 0 ) { + QPair p; + int vob = 1; + for( ; vob < 100; ++vob ) { + filename.sprintf( "VIDEO_TS/VTS_%02d_%d.VOB", title, vob ); + file = dynamic_cast( dir->entry( filename ) ); + if( file ) { + if( file->size() % 2048 ) + kdError() << "(K3bLibDvdCss) FILESIZE % 2048 != 0!!!" << endl; + if( vob == 1 ) { + p.first = file->startSector(); + p.second = file->size() / 2048; + kdDebug() << "(K3bLibDvdCss) Get key for /" << filename << " at " << file->startSector() << endl; + if( seek( (int)file->startSector(), DVDCSS_SEEK_KEY ) < 0 ) { + kdDebug() << "(K3bLibDvdCss) unable to seek to " << file->startSector() << endl; + return false; + } + } + else { + p.second += file->size() / 2048; + } + } + else { + // last vob + break; + } + } + --vob; + + // last title + if( vob == 0 ) + break; + + kdDebug() << "(K3bLibDvdCss) Title " << title << " " << vob << " vobs with length " << p.second << endl; + d->titleOffsets.append( p ); + } + } + + --title; + + kdDebug() << "(K3bLibDvdCss) found " << title << " titles." << endl; + + return (title > 0); +} + + +K3bLibDvdCss* K3bLibDvdCss::create() +{ + if( s_libDvdCss == 0 ) { + s_libDvdCss = dlopen( "libdvdcss.so.2", RTLD_LAZY|RTLD_GLOBAL ); + if( s_libDvdCss ) { + k3b_dvdcss_open = (dvdcss_t (*)(char*))dlsym( s_libDvdCss, "dvdcss_open" ); + k3b_dvdcss_close = (int (*)( dvdcss_t ))dlsym( s_libDvdCss, "dvdcss_close" ); + k3b_dvdcss_seek = (int (*)( dvdcss_t, int, int ))dlsym( s_libDvdCss, "dvdcss_seek" ); + k3b_dvdcss_read = (int (*)( dvdcss_t, void*, int, int ))dlsym( s_libDvdCss, "dvdcss_read" ); + + if( !k3b_dvdcss_open || !k3b_dvdcss_close || !k3b_dvdcss_seek || !k3b_dvdcss_read ) { + kdDebug() << "(K3bLibDvdCss) unable to resolve libdvdcss." << endl; + dlclose( s_libDvdCss ); + s_libDvdCss = 0; + } + } + else + kdDebug() << "(K3bLibDvdCss) unable to load libdvdcss." << endl; + } + + if( s_libDvdCss ) + return new K3bLibDvdCss(); + else + return 0; +} diff --git a/libk3b/tools/k3blibdvdcss.h b/libk3b/tools/k3blibdvdcss.h new file mode 100644 index 0000000..308296f --- /dev/null +++ b/libk3b/tools/k3blibdvdcss.h @@ -0,0 +1,84 @@ +/* + * + * $Id: k3blibdvdcss.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_LIBDVDCSS_H_ +#define _K3B_LIBDVDCSS_H_ + +#include "k3b_export.h" + +namespace K3bDevice { + class Device; +} + + +/** + * Wrapper class for libdvdcss. dynamically openes the library if it + * is available on the system. + */ +class LIBK3B_EXPORT K3bLibDvdCss +{ + public: + ~K3bLibDvdCss(); + + static const int DVDCSS_BLOCK_SIZE = 2048; + static const int DVDCSS_NOFLAGS = 0; + static const int DVDCSS_READ_DECRYPT = (1 << 0); + static const int DVDCSS_SEEK_MPEG = (1 << 0); + static const int DVDCSS_SEEK_KEY = (1 << 1); + + /** + * Try to open a Video DVD and authenticate it. + * @return true if the Video DVD could be authenticated successfully, false otherwise. + */ + bool open( K3bDevice::Device* dev ); + void close(); + + int seek( int sector, int flags ); + int read( void* buffer, int sectors, int flags ); + + /** + * This method optimized the seek calls to maximize reading performance. + * It also makes sure we never read unscrambled and scrambled data at the same time. + * + * You have to call crackAllKeys() before using this. Do never call this in combination + * with seek or read! + */ + int readWrapped( void* buffer, int firstSector, int sectors ); + + /** + * Cache all CSS keys to guarantee smooth reading further on. + * This method also creates a title offset list which is needed by readWrapped. + */ + bool crackAllKeys(); + + /** + * returns 0 if the libdvdcss could not + * be found on the system. + * Otherwise you have to take care of + * deleting. + */ + static K3bLibDvdCss* create(); + + private: + class Private; + Private* d; + + K3bLibDvdCss(); + + static void* s_libDvdCss; + static int s_counter; +}; + +#endif diff --git a/libk3b/tools/k3blistview.cpp b/libk3b/tools/k3blistview.cpp new file mode 100644 index 0000000..34a3aa0 --- /dev/null +++ b/libk3b/tools/k3blistview.cpp @@ -0,0 +1,1290 @@ +/* + * + * $Id: k3blistview.cpp 768493 2008-01-30 08:44:05Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + + +#include "k3blistview.h" + +#include "k3bmsfedit.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + + + +// /////////////////////////////////////////////// +// +// K3BLISTVIEWITEM +// +// /////////////////////////////////////////////// + + +class K3bListViewItem::ColumnInfo +{ +public: + ColumnInfo() + : showProgress(false), + progressValue(0), + totalProgressSteps(100), + margin(0), + validator(0) { + editorType = NONE; + button = false; + comboEditable = false; + next = 0; + fontSet = false; + backgroundColorSet = false; + foregroundColorSet = false; + } + + ~ColumnInfo() { + if( next ) + delete next; + } + + bool button; + int editorType; + QStringList comboItems; + bool comboEditable; + bool fontSet; + bool backgroundColorSet; + bool foregroundColorSet; + QFont font; + QColor backgroundColor; + QColor foregroundColor; + ColumnInfo* next; + + bool showProgress; + int progressValue; + int totalProgressSteps; + int margin; + + QValidator* validator; +}; + + + +K3bListViewItem::K3bListViewItem(QListView *parent) + : KListViewItem( parent ) +{ + init(); +} + +K3bListViewItem::K3bListViewItem(QListViewItem *parent) + : KListViewItem( parent ) +{ + init(); +} + +K3bListViewItem::K3bListViewItem(QListView *parent, QListViewItem *after) + : KListViewItem( parent, after ) +{ + init(); +} + +K3bListViewItem::K3bListViewItem(QListViewItem *parent, QListViewItem *after) + : KListViewItem( parent, after ) +{ + init(); +} + + +K3bListViewItem::K3bListViewItem(QListView *parent, + const QString& s1, const QString& s2, + const QString& s3, const QString& s4, + const QString& s5, const QString& s6, + const QString& s7, const QString& s8) + : KListViewItem( parent, s1, s2, s3, s4, s5, s6, s7, s8 ) +{ + init(); +} + + +K3bListViewItem::K3bListViewItem(QListViewItem *parent, + const QString& s1, const QString& s2, + const QString& s3, const QString& s4, + const QString& s5, const QString& s6, + const QString& s7, const QString& s8) + : KListViewItem( parent, s1, s2, s3, s4, s5, s6, s7, s8 ) +{ + init(); +} + + +K3bListViewItem::K3bListViewItem(QListView *parent, QListViewItem *after, + const QString& s1, const QString& s2, + const QString& s3, const QString& s4, + const QString& s5, const QString& s6, + const QString& s7, const QString& s8) + : KListViewItem( parent, after, s1, s2, s3, s4, s5, s6, s7, s8 ) +{ + init(); +} + + +K3bListViewItem::K3bListViewItem(QListViewItem *parent, QListViewItem *after, + const QString& s1, const QString& s2, + const QString& s3, const QString& s4, + const QString& s5, const QString& s6, + const QString& s7, const QString& s8) + : KListViewItem( parent, after, s1, s2, s3, s4, s5, s6, s7, s8 ) +{ + init(); +} + + +K3bListViewItem::~K3bListViewItem() +{ + if( K3bListView* lv = dynamic_cast(listView()) ) + if( lv->currentlyEditedItem() == this ) + lv->hideEditor(); + + if( m_columns ) + delete m_columns; +} + + +void K3bListViewItem::init() +{ + m_columns = 0; + m_vMargin = 0; +} + + +int K3bListViewItem::width( const QFontMetrics& fm, const QListView* lv, int c ) const +{ + return KListViewItem::width( fm, lv, c ) + getColumnInfo(c)->margin*2; +} + + +void K3bListViewItem::setEditor( int column, int editor, const QStringList& cs ) +{ + ColumnInfo* colInfo = getColumnInfo(column); + + colInfo->editorType = editor; + if( !cs.isEmpty() ) + colInfo->comboItems = cs; +} + + +void K3bListViewItem::setValidator( int column, QValidator* v ) +{ + getColumnInfo(column)->validator = v; +} + + +QValidator* K3bListViewItem::validator( int col ) const +{ + return getColumnInfo(col)->validator; +} + + +void K3bListViewItem::setButton( int column, bool on ) +{ + ColumnInfo* colInfo = getColumnInfo(column); + + colInfo->button = on; +} + + +K3bListViewItem::ColumnInfo* K3bListViewItem::getColumnInfo( int col ) const +{ + if( !m_columns ) + m_columns = new ColumnInfo(); + + ColumnInfo* info = m_columns; + int i = 0; + while( i < col ) { + if( !info->next ) + info->next = new ColumnInfo(); + info = info->next; + ++i; + } + + return info; +} + + +int K3bListViewItem::editorType( int col ) const +{ + ColumnInfo* info = getColumnInfo( col ); + return info->editorType; +} + + +bool K3bListViewItem::needButton( int col ) const +{ + ColumnInfo* info = getColumnInfo( col ); + return info->button; +} + + +const QStringList& K3bListViewItem::comboStrings( int col ) const +{ + ColumnInfo* info = getColumnInfo( col ); + return info->comboItems; +} + + +void K3bListViewItem::setFont( int col, const QFont& f ) +{ + ColumnInfo* info = getColumnInfo( col ); + info->fontSet = true; + info->font = f; +} + + +void K3bListViewItem::setBackgroundColor( int col, const QColor& c ) +{ + ColumnInfo* info = getColumnInfo( col ); + info->backgroundColorSet = true; + info->backgroundColor = c; + repaint(); +} + + +void K3bListViewItem::setForegroundColor( int col, const QColor& c ) +{ + ColumnInfo* info = getColumnInfo( col ); + info->foregroundColorSet = true; + info->foregroundColor = c; + repaint(); +} + + +void K3bListViewItem::setDisplayProgressBar( int col, bool displ ) +{ + ColumnInfo* info = getColumnInfo( col ); + info->showProgress = displ; +} + + +void K3bListViewItem::setProgress( int col, int p ) +{ + ColumnInfo* info = getColumnInfo( col ); + if( !info->showProgress ) + setDisplayProgressBar( col, true ); + if( info->progressValue != p ) { + info->progressValue = p; + repaint(); + } +} + + +void K3bListViewItem::setTotalSteps( int col, int steps ) +{ + ColumnInfo* info = getColumnInfo( col ); + info->totalProgressSteps = steps; + + repaint(); +} + + +void K3bListViewItem::setMarginHorizontal( int col, int margin ) +{ + ColumnInfo* info = getColumnInfo( col ); + info->margin = margin; + + repaint(); +} + + +void K3bListViewItem::setMarginVertical( int margin ) +{ + m_vMargin = margin; + repaint(); +} + + +int K3bListViewItem::marginHorizontal( int col ) const +{ + return getColumnInfo( col )->margin; +} + + +int K3bListViewItem::marginVertical() const +{ + return m_vMargin; +} + + +void K3bListViewItem::setup() +{ + KListViewItem::setup(); + + setHeight( height() + 2*m_vMargin ); +} + + +void K3bListViewItem::paintCell( QPainter* p, const QColorGroup& cg, int col, int width, int align ) +{ + ColumnInfo* info = getColumnInfo( col ); + + p->save(); + + QFont oldFont( p->font() ); + QFont newFont = info->fontSet ? info->font : oldFont; + p->setFont( newFont ); + QColorGroup cgh(cg); + if( info->foregroundColorSet ) + cgh.setColor( QColorGroup::Text, info->foregroundColor ); + if( info->backgroundColorSet ) + cgh.setColor( QColorGroup::Base, info->backgroundColor ); + + // in case this is the selected row has a margin we need to repaint the selection bar + if( isSelected() && + (col == 0 || listView()->allColumnsShowFocus()) && + info->margin > 0 ) { + + p->fillRect( 0, 0, info->margin, height(), + cgh.brush( QColorGroup::Highlight ) ); + p->fillRect( width-info->margin, 0, info->margin, height(), + cgh.brush( QColorGroup::Highlight ) ); + } + else { // in case we use the KListView alternate color stuff + p->fillRect( 0, 0, info->margin, height(), + cgh.brush( QColorGroup::Base ) ); + p->fillRect( width-info->margin, 0, info->margin, height(), + cgh.brush( QColorGroup::Base ) ); + } + + // FIXME: the margin (we can only translate horizontally since height() is used for painting) + p->translate( info->margin, 0 ); + + if( info->showProgress ) { + paintProgressBar( p, cgh, col, width-2*info->margin ); + } + else { + paintK3bCell( p, cgh, col, width-2*info->margin, align ); + } + + p->restore(); +} + + +void K3bListViewItem::paintK3bCell( QPainter* p, const QColorGroup& cg, int col, int width, int align ) +{ + QListViewItem::paintCell( p, cg, col, width, align ); +} + + +void K3bListViewItem::paintProgressBar( QPainter* p, const QColorGroup& cgh, int col, int width ) +{ + ColumnInfo* info = getColumnInfo( col ); + + QStyle::SFlags flags = QStyle::Style_Default; + if( listView()->isEnabled() ) + flags |= QStyle::Style_Enabled; + if( listView()->hasFocus() ) + flags |= QStyle::Style_HasFocus; + + // FIXME: the QPainter is translated so 0, m_vMargin is the upper left of our paint rect + QRect r( 0, m_vMargin, width, height()-2*m_vMargin ); + + // create the double buffer pixmap + static QPixmap *doubleBuffer = 0; + if( !doubleBuffer ) + doubleBuffer = new QPixmap; + doubleBuffer->resize( width, height() ); + + QPainter dbPainter( doubleBuffer ); + + // clear the background (we cannot use paintEmptyArea since it's protected in QListView) + if( K3bListView* lv = dynamic_cast(listView()) ) + lv->paintEmptyArea( &dbPainter, r ); + else + dbPainter.fillRect( 0, 0, width, height(), + cgh.brush( QPalette::backgroundRoleFromMode(listView()->viewport()->backgroundMode()) ) ); + + // we want a little additional margin + r.setLeft( r.left()+1 ); + r.setWidth( r.width()-2 ); + r.setTop( r.top()+1 ); + r.setHeight( r.height()-2 ); + + // this might be a stupid hack but most styles do not reimplement drawPrimitive PE_ProgressBarChunk + // so this way the user is happy.... + static QProgressBar* s_dummyProgressBar = 0; + if( !s_dummyProgressBar ) { + s_dummyProgressBar = new QProgressBar(); + } + + s_dummyProgressBar->setTotalSteps( info->totalProgressSteps ); + s_dummyProgressBar->setProgress( info->progressValue ); + + // some styles use the widget's geometry + s_dummyProgressBar->setGeometry( r ); + + listView()->style().drawControl(QStyle::CE_ProgressBarContents, &dbPainter, s_dummyProgressBar, r, cgh, flags ); + listView()->style().drawControl(QStyle::CE_ProgressBarLabel, &dbPainter, s_dummyProgressBar, r, cgh, flags ); + + // now we really paint the progress in the listview + p->drawPixmap( 0, 0, *doubleBuffer ); +} + + + + + + + +K3bCheckListViewItem::K3bCheckListViewItem(QListView *parent) + : K3bListViewItem( parent ), + m_checked(false) +{ +} + + +K3bCheckListViewItem::K3bCheckListViewItem(QListViewItem *parent) + : K3bListViewItem( parent ), + m_checked(false) +{ +} + + +K3bCheckListViewItem::K3bCheckListViewItem(QListView *parent, QListViewItem *after) + : K3bListViewItem( parent, after ), + m_checked(false) +{ +} + + +K3bCheckListViewItem::K3bCheckListViewItem(QListViewItem *parent, QListViewItem *after) + : K3bListViewItem( parent, after ), + m_checked(false) +{ +} + + +bool K3bCheckListViewItem::isChecked() const +{ + return m_checked; +} + + +void K3bCheckListViewItem::setChecked( bool checked ) +{ + m_checked = checked; + repaint(); +} + + +void K3bCheckListViewItem::paintK3bCell( QPainter* p, const QColorGroup& cg, int col, int width, int align ) +{ + K3bListViewItem::paintK3bCell( p, cg, col, width, align ); + + if( col == 0 ) { + if( m_checked ) { + QRect r( 0, marginVertical(), width, /*listView()->style().pixelMetric( QStyle::PM_CheckListButtonSize )*/height()-2*marginVertical() ); + + QStyle::SFlags flags = QStyle::Style_Default; + if( listView()->isEnabled() ) + flags |= QStyle::Style_Enabled; + if( listView()->hasFocus() ) + flags |= QStyle::Style_HasFocus; + if( isChecked() ) + flags |= QStyle::Style_On; + else + flags |= QStyle::Style_Off; + + listView()->style().drawPrimitive( QStyle::PE_CheckMark, p, r, cg, flags ); + } + } +} + + + + + + +// /////////////////////////////////////////////// +// +// K3BLISTVIEW +// +// /////////////////////////////////////////////// + + +class K3bListView::Private +{ +public: + QLineEdit* spinBoxLineEdit; + QLineEdit* msfEditLineEdit; +}; + + +K3bListView::K3bListView( QWidget* parent, const char* name ) + : KListView( parent, name ), + m_noItemVMargin( 20 ), + m_noItemHMargin( 20 ) +{ + d = new Private; + + connect( header(), SIGNAL( sizeChange( int, int, int ) ), + this, SLOT( updateEditorSize() ) ); + + m_editorButton = 0; + m_editorComboBox = 0; + m_editorSpinBox = 0; + m_editorLineEdit = 0; + m_editorMsfEdit = 0; + m_currentEditItem = 0; + m_currentEditColumn = 0; + m_doubleClickForEdit = true; + m_lastClickedItem = 0; +} + +K3bListView::~K3bListView() +{ + delete d; +} + + +QWidget* K3bListView::editor( K3bListViewItem::EditorType t ) const +{ + switch( t ) { + case K3bListViewItem::COMBO: + return m_editorComboBox; + case K3bListViewItem::LINE: + return m_editorLineEdit; + case K3bListViewItem::SPIN: + return m_editorSpinBox; + case K3bListViewItem::MSF: + return m_editorMsfEdit; + default: + return 0; + } +} + + +void K3bListView::clear() +{ + hideEditor(); + KListView::clear(); +} + + +void K3bListView::editItem( K3bListViewItem* item, int col ) +{ + if( item == 0 ) + hideEditor(); + else if( item->isEnabled() ) { + showEditor( item, col ); + } +} + + +void K3bListView::hideEditor() +{ + m_lastClickedItem = 0; + m_currentEditItem = 0; + m_currentEditColumn = 0; + + if( m_editorSpinBox ) + m_editorSpinBox->hide(); + if( m_editorLineEdit ) + m_editorLineEdit->hide(); + if( m_editorComboBox ) + m_editorComboBox->hide(); + if( m_editorButton ) + m_editorButton->hide(); + if( m_editorMsfEdit ) + m_editorMsfEdit->hide(); +} + +void K3bListView::showEditor( K3bListViewItem* item, int col ) +{ + if( !item ) + return; + + if( item->needButton( col ) || item->editorType(col) != K3bListViewItem::NONE ) { + m_currentEditColumn = col; + m_currentEditItem = item; + } + + placeEditor( item, col ); + if( item->needButton( col ) ) { + m_editorButton->show(); + } + switch( item->editorType(col) ) { + case K3bListViewItem::COMBO: + m_editorComboBox->show(); + m_editorComboBox->setFocus(); + m_editorComboBox->setValidator( item->validator(col) ); + break; + case K3bListViewItem::LINE: + m_editorLineEdit->show(); + m_editorLineEdit->setFocus(); + m_editorLineEdit->setValidator( item->validator(col) ); + break; + case K3bListViewItem::SPIN: + m_editorSpinBox->show(); + m_editorSpinBox->setFocus(); + break; + case K3bListViewItem::MSF: + m_editorMsfEdit->show(); + m_editorMsfEdit->setFocus(); + break; + default: + break; + } +} + + +void K3bListView::placeEditor( K3bListViewItem* item, int col ) +{ + ensureItemVisible( item ); + QRect r = itemRect( item ); + + r.setX( contentsToViewport( QPoint(header()->sectionPos( col ), 0) ).x() ); + r.setWidth( header()->sectionSize( col ) - 1 ); + + // check if the column is fully visible + if( visibleWidth() < r.right() ) + r.setRight(visibleWidth()); + + r = QRect( viewportToContents( r.topLeft() ), r.size() ); + + if( item->pixmap( col ) ) { + r.setX( r.x() + item->pixmap(col)->width() ); + } + + // the tree-stuff is painted in the first column + if( col == 0 ) { + r.setX( r.x() + item->depth() * treeStepSize() ); + if( rootIsDecorated() ) + r.setX( r.x() + treeStepSize() ); + } + + if( item->needButton(col) ) { + prepareButton( item, col ); + m_editorButton->setFixedHeight( r.height() ); + // for now we make a square button + m_editorButton->setFixedWidth( m_editorButton->height() ); + r.setWidth( r.width() - m_editorButton->width() ); + moveChild( m_editorButton, r.right(), r.y() ); + } + + if( QWidget* editor = prepareEditor( item, col ) ) { + editor->resize( r.size() ); + // editor->resize( QSize( r.width(), editor->minimumSizeHint().height() ) ); + moveChild( editor, r.x(), r.y() ); + } +} + + +void K3bListView::prepareButton( K3bListViewItem*, int ) +{ + if( !m_editorButton ) { + m_editorButton = new QPushButton( viewport() ); + connect( m_editorButton, SIGNAL(clicked()), + this, SLOT(slotEditorButtonClicked()) ); + } + + // TODO: do some useful things + m_editorButton->setText( "..." ); +} + + +QWidget* K3bListView::prepareEditor( K3bListViewItem* item, int col ) +{ + switch( item->editorType(col) ) { + case K3bListViewItem::COMBO: + if( !m_editorComboBox ) { + m_editorComboBox = new QComboBox( viewport() ); + connect( m_editorComboBox, SIGNAL(activated(const QString&)), + this, SLOT(slotEditorComboBoxActivated(const QString&)) ); + m_editorComboBox->installEventFilter( this ); + } + m_editorComboBox->clear(); + if( item->comboStrings( col ).isEmpty() ) { + m_editorComboBox->insertItem( item->text( col ) ); + } + else { + m_editorComboBox->insertStringList( item->comboStrings(col) ); + int current = item->comboStrings(col).findIndex( item->text(col) ); + if( current != -1 ) + m_editorComboBox->setCurrentItem( current ); + } + return m_editorComboBox; + + case K3bListViewItem::LINE: { + if( !m_editorLineEdit ) { + m_editorLineEdit = new QLineEdit( viewport() ); + m_editorLineEdit->setFrameStyle( QFrame::Box | QFrame::Plain ); + m_editorLineEdit->setLineWidth(1); + m_editorLineEdit->installEventFilter( this ); + } + + QString txt = item->text( col ); + m_editorLineEdit->setText( txt ); + + // select the edit text (handle extensions while doing so) + int pos = txt.findRev( '.' ); + if( pos > 0 ) + m_editorLineEdit->setSelection( 0, pos ); + else + m_editorLineEdit->setSelection( 0, txt.length() ); + + return m_editorLineEdit; + } + + // + // A QSpinBox (and thus also a K3bMsfEdit) uses a QLineEdit), thus + // we have to use this QLineEdit as the actual object to dead with + // + + case K3bListViewItem::SPIN: + if( !m_editorSpinBox ) { + m_editorSpinBox = new QSpinBox( viewport() ); + d->spinBoxLineEdit = static_cast( m_editorSpinBox->child( 0, "QLineEdit" ) ); + connect( m_editorSpinBox, SIGNAL(valueChanged(int)), + this, SLOT(slotEditorSpinBoxValueChanged(int)) ); + // m_editorSpinBox->installEventFilter( this ); + d->spinBoxLineEdit->installEventFilter( this ); + } + // set the range + m_editorSpinBox->setValue( item->text(col).toInt() ); + return m_editorSpinBox; + + case K3bListViewItem::MSF: + if( !m_editorMsfEdit ) { + m_editorMsfEdit = new K3bMsfEdit( viewport() ); + d->msfEditLineEdit = static_cast( m_editorMsfEdit->child( 0, "QLineEdit" ) ); + connect( m_editorMsfEdit, SIGNAL(valueChanged(int)), + this, SLOT(slotEditorMsfEditValueChanged(int)) ); + // m_editorMsfEdit->installEventFilter( this ); + d->msfEditLineEdit->installEventFilter( this ); + } + m_editorMsfEdit->setText( item->text(col) ); + return m_editorMsfEdit; + + default: + return 0; + } +} + +void K3bListView::setCurrentItem( QListViewItem* i ) +{ + if( !i || i == currentItem() ) + return; + + // I cannot remember why I did this here exactly. However, it resets the + // m_lastClickedItem and thus invalidates the editing. +// doRename(); +// hideEditor(); +// m_currentEditItem = 0; + KListView::setCurrentItem( i ); +} + + +void K3bListView::setNoItemText( const QString& text ) +{ + m_noItemText = text; + triggerUpdate(); +} + + +void K3bListView::viewportPaintEvent( QPaintEvent* e ) +{ + KListView::viewportPaintEvent( e ); +} + + +// FIXME: move this to viewportPaintEvent +void K3bListView::drawContentsOffset( QPainter * p, int ox, int oy, int cx, int cy, int cw, int ch ) +{ + KListView::drawContentsOffset( p, ox, oy, cx, cy, cw, ch ); + + if( childCount() == 0 && !m_noItemText.isEmpty()) { + + p->setPen( Qt::darkGray ); + + QStringList lines = QStringList::split( "\n", m_noItemText ); + int xpos = m_noItemHMargin; + int ypos = m_noItemVMargin + p->fontMetrics().height(); + + QStringList::Iterator end ( lines.end() ); + for( QStringList::Iterator str = lines.begin(); str != end; ++str ) { + p->drawText( xpos, ypos, *str ); + ypos += p->fontMetrics().lineSpacing(); + } + } +} + +void K3bListView::paintEmptyArea( QPainter* p, const QRect& rect ) +{ + KListView::paintEmptyArea( p, rect ); + +// if( childCount() == 0 && !m_noItemText.isEmpty()) { + +// QPainter pp( viewport() ); +// pp.fillRect( viewport()->rect(), viewport()->paletteBackgroundColor() ); +// pp.end(); + +// p->setPen( Qt::darkGray ); + +// QStringList lines = QStringList::split( "\n", m_noItemText ); +// int xpos = m_noItemHMargin; +// int ypos = m_noItemVMargin + p->fontMetrics().height(); + +// for( QStringList::Iterator str = lines.begin(); str != lines.end(); str++ ) { +// p->drawText( xpos, ypos, *str ); +// ypos += p->fontMetrics().lineSpacing(); +// } +// } +} + +void K3bListView::resizeEvent( QResizeEvent* e ) +{ + KListView::resizeEvent( e ); + updateEditorSize(); +} + + +void K3bListView::updateEditorSize() +{ + if( m_currentEditItem ) + placeEditor( m_currentEditItem, m_currentEditColumn ); +} + + +void K3bListView::slotEditorLineEditReturnPressed() +{ + if( doRename() ) { + // edit the next line + // TODO: add config for this + if( K3bListViewItem* nextItem = dynamic_cast( m_currentEditItem->nextSibling() ) ) + editItem( nextItem, currentEditColumn() ); + else { + hideEditor(); + + // keep the focus here + viewport()->setFocus(); + } + } +} + + +void K3bListView::slotEditorComboBoxActivated( const QString& ) +{ + doRename(); +// if( renameItem( m_currentEditItem, m_currentEditColumn, str ) ) { +// m_currentEditItem->setText( m_currentEditColumn, str ); +// emit itemRenamed( m_currentEditItem, str, m_currentEditColumn ); +// } +// else { +// for( int i = 0; i < m_editorComboBox->count(); ++i ) { +// if( m_editorComboBox->text(i) == m_currentEditItem->text(m_currentEditColumn) ) { +// m_editorComboBox->setCurrentItem( i ); +// break; +// } +// } +// } +} + + +void K3bListView::slotEditorSpinBoxValueChanged( int ) +{ +// if( renameItem( m_currentEditItem, m_currentEditColumn, QString::number(value) ) ) { +// m_currentEditItem->setText( m_currentEditColumn, QString::number(value) ); +// emit itemRenamed( m_currentEditItem, QString::number(value), m_currentEditColumn ); +// } +// else +// m_editorSpinBox->setValue( m_currentEditItem->text( m_currentEditColumn ).toInt() ); +} + + +void K3bListView::slotEditorMsfEditValueChanged( int ) +{ + // FIXME: do we always need to update the value. Isn't it enough to do it at the end? +// if( renameItem( m_currentEditItem, m_currentEditColumn, QString::number(value) ) ) { +// m_currentEditItem->setText( m_currentEditColumn, QString::number(value) ); +// emit itemRenamed( m_currentEditItem, QString::number(value), m_currentEditColumn ); +// } +// else +// m_editorMsfEdit->setText( m_currentEditItem->text( m_currentEditColumn ) ); +} + + +bool K3bListView::doRename() +{ + if( m_currentEditItem ) { + QString newValue; + switch( m_currentEditItem->editorType( m_currentEditColumn ) ) { + case K3bListViewItem::COMBO: + newValue = m_editorComboBox->currentText(); + break; + case K3bListViewItem::LINE: + newValue = m_editorLineEdit->text(); + break; + case K3bListViewItem::SPIN: + newValue = QString::number(m_editorSpinBox->value()); + break; + case K3bListViewItem::MSF: + newValue = QString::number(m_editorMsfEdit->value()); + break; + } + + if( renameItem( m_currentEditItem, m_currentEditColumn, newValue ) ) { + m_currentEditItem->setText( m_currentEditColumn, newValue ); + emit itemRenamed( m_currentEditItem, newValue, m_currentEditColumn ); + return true; + } + else { + switch( m_currentEditItem->editorType( m_currentEditColumn ) ) { + case K3bListViewItem::COMBO: + for( int i = 0; i < m_editorComboBox->count(); ++i ) { + if( m_editorComboBox->text(i) == m_currentEditItem->text(m_currentEditColumn) ) { + m_editorComboBox->setCurrentItem( i ); + break; + } + } + break; + case K3bListViewItem::LINE: + m_editorLineEdit->setText( m_currentEditItem->text( m_currentEditColumn ) ); + break; + case K3bListViewItem::SPIN: + m_editorSpinBox->setValue( m_currentEditItem->text( m_currentEditColumn ).toInt() ); + break; + case K3bListViewItem::MSF: + m_editorMsfEdit->setText( m_currentEditItem->text( m_currentEditColumn ) ); + break; + } + } + } + + + return false; +} + + +void K3bListView::slotEditorButtonClicked() +{ + slotEditorButtonClicked( m_currentEditItem, m_currentEditColumn ); +} + + +bool K3bListView::renameItem( K3bListViewItem* item, int col, const QString& text ) +{ + Q_UNUSED(item); + Q_UNUSED(col); + Q_UNUSED(text); + return true; +} + + +void K3bListView::slotEditorButtonClicked( K3bListViewItem* item, int col ) +{ + emit editorButtonClicked( item, col ); +} + + +bool K3bListView::eventFilter( QObject* o, QEvent* e ) +{ + if( e->type() == QEvent::KeyPress ) { + QKeyEvent* ke = static_cast(e); + if( ke->key() == Key_Tab ) { + if( o == m_editorLineEdit || + o == d->msfEditLineEdit || + o == d->spinBoxLineEdit ) { + K3bListViewItem* lastEditItem = m_currentEditItem; + + doRename(); + + if( lastEditItem ) { + // can we rename one of the other columns? + int col = currentEditColumn()+1; + while( col < columns() && lastEditItem->editorType( col ) == K3bListViewItem::NONE ) + ++col; + if( col < columns() ) + editItem( lastEditItem, col ); + else { + hideEditor(); + + // keep the focus here + viewport()->setFocus(); + + // search for the next editable item + while( K3bListViewItem* nextItem = + dynamic_cast( lastEditItem->nextSibling() ) ) { + // edit first column + col = 0; + while( col < columns() && nextItem->editorType( col ) == K3bListViewItem::NONE ) + ++col; + if( col < columns() ) { + editItem( nextItem, col ); + break; + } + + lastEditItem = nextItem; + } + } + } + + return true; + } + } + if( ke->key() == Key_Return || + ke->key() == Key_Enter ) { + if( o == m_editorLineEdit || + o == d->msfEditLineEdit || + o == d->spinBoxLineEdit ) { + K3bListViewItem* lastEditItem = m_currentEditItem; + doRename(); + + if( K3bListViewItem* nextItem = + dynamic_cast( lastEditItem->nextSibling() ) ) + editItem( nextItem, currentEditColumn() ); + else { + hideEditor(); + + // keep the focus here + viewport()->setFocus(); + } + + return true; + } + } + else if( ke->key() == Key_Escape ) { + if( o == m_editorLineEdit || + o == d->msfEditLineEdit || + o == d->spinBoxLineEdit ) { + hideEditor(); + + // keep the focus here + viewport()->setFocus(); + + return true; + } + } + } + + else if( e->type() == QEvent::MouseButtonPress && o == viewport() ) { + + // first let's grab the focus + viewport()->setFocus(); + + QMouseEvent* me = static_cast( e ); + QListViewItem* item = itemAt( me->pos() ); + int col = header()->sectionAt( me->pos().x() ); + if( K3bCheckListViewItem* ci = dynamic_cast( item ) ) { + if( col == 0 ) { + // FIXME: improve this click area! + ci->setChecked( !ci->isChecked() ); + return true; + } + } + + if( me->button() == QMouseEvent::LeftButton ) { + if( item != m_currentEditItem || m_currentEditColumn != col ) { + doRename(); + if( K3bListViewItem* k3bItem = dynamic_cast(item) ) { + if( me->pos().x() > item->depth()*treeStepSize() && + item->isEnabled() && + (m_lastClickedItem == item || !m_doubleClickForEdit) ) + showEditor( k3bItem, col ); + else { + hideEditor(); + + // keep the focus here + viewport()->setFocus(); + } + } + else { + hideEditor(); + + // keep the focus here + viewport()->setFocus(); + } + + // do not count clicks in the item tree for editing + if( item && me->pos().x() > item->depth()*treeStepSize() ) + m_lastClickedItem = item; + } + } + } + + else if( e->type() == QEvent::FocusOut ) { + if( o == m_editorLineEdit || + o == d->msfEditLineEdit || + o == d->spinBoxLineEdit || + o == m_editorComboBox ) { + // make sure we did not lose the focus to one of the edit widgets' children + if( !qApp->focusWidget() || qApp->focusWidget()->parentWidget() != o ) { + doRename(); + hideEditor(); + } + } + } + + return KListView::eventFilter( o, e ); +} + + +void K3bListView::setK3bBackgroundPixmap( const QPixmap& pix, int pos ) +{ + m_backgroundPixmap = pix; + m_backgroundPixmapPosition = pos; +} + + +void K3bListView::viewportResizeEvent( QResizeEvent* e ) +{ + if( !m_backgroundPixmap.isNull() ) { + + QSize size = viewport()->size().expandedTo( QSize( contentsWidth(), contentsHeight() ) ); + + QPixmap bgPix( size ); + + // FIXME: let the user specify the color + bgPix.fill( colorGroup().base() ); + + if( bgPix.width() < m_backgroundPixmap.width() || + bgPix.height() < m_backgroundPixmap.height() ) { + QPixmap newBgPix( m_backgroundPixmap.convertToImage().scale( bgPix.size(), QImage::ScaleMin ) ); + if( m_backgroundPixmapPosition == TOP_LEFT ) + bitBlt( &bgPix, 0, 0, + &newBgPix, 0, 0, + newBgPix.width(), newBgPix.height() ); + else { + int dx = bgPix.width() / 2 - m_backgroundPixmap.width() /2; + int dy = bgPix.height() / 2 - m_backgroundPixmap.height() /2; + bitBlt( &bgPix, dx, dy, &newBgPix, 0, 0, + newBgPix.width(), newBgPix.height() ); + } + } + else { + if( m_backgroundPixmapPosition == TOP_LEFT ) + bitBlt( &bgPix, 0, 0, + &m_backgroundPixmap, 0, 0, + m_backgroundPixmap.width(), m_backgroundPixmap.height() ); + else { + int dx = bgPix.width() / 2 - m_backgroundPixmap.width() /2; + int dy = bgPix.height() / 2 - m_backgroundPixmap.height() /2; + bitBlt( &bgPix, dx, dy, &m_backgroundPixmap, 0, 0, + m_backgroundPixmap.width(), m_backgroundPixmap.height() ); + } + } + + viewport()->setPaletteBackgroundPixmap( bgPix ); + } + + KListView::viewportResizeEvent( e ); +} + + +QListViewItem* K3bListView::parentItem( QListViewItem* item ) +{ + if( !item ) + return 0; + if( item->parent() ) + return item->parent(); + else + return K3bListView::parentItem( item->itemAbove() ); +} + + +KPixmap K3bListView::createDragPixmap( const QPtrList& items ) +{ + // + // Create drag pixmap. + // If there are too many items fade the pixmap using the mask + // always fade invisible items + // + int width = header()->width(); + int height = 0; + for( QPtrListIterator it( items ); *it; ++it ) { + QRect r = itemRect( *it ); + + if( r.isValid() ) { + height += ( *it )->height(); + } + } + + // now we should have a range top->bottom which includes all visible items + + // there are two situations in which we fade the pixmap on the top or the bottom: + // 1. there are invisible items above (below) the visible + // 2. the range is way too big + + // FIXME: how do we determine if there are invisible items outside our range? + + KPixmap pix; + pix.resize( width, height ); + pix.fill( Qt::white ); + // QBitmap mask( width, bottom-top ); + + // now paint all the visible items into the pixmap + // FIXME: only paint the visible items + QPainter p( &pix ); + for( QListViewItemIterator it( this ); *it; ++it ) { + QListViewItem* item = *it; + + // FIXME: items on other than the top level have a smaller first column + // the same goes for all items if root is decorated + bool alreadyDrawing = false; + QRect r = itemRect( item ); + if( r.isValid() ) { + if( items.containsRef( item ) ) { + // paint all columns + int x = 0; + for( int i = 0; i < columns(); ++i ) { + item->paintCell( &p, colorGroup(), i, columnWidth( i ), columnAlignment( i ) ); + p.translate( columnWidth( i ), 0 ); + x += columnWidth( i ); + } + + p.translate( -x, item->height() ); + + alreadyDrawing = true; + } + else if( alreadyDrawing ) + p.translate( 0, item->height() ); + + if( p.worldMatrix().dy() >= pix.height() ) + break; + } + } + + // make it a little lighter + KPixmapEffect::fade( pix, 0.3, Qt::white ); + + // FIXME: fade the pixmap at the right side if the items are longer than width + + return pix; +} + +#include "k3blistview.moc" diff --git a/libk3b/tools/k3blistview.h b/libk3b/tools/k3blistview.h new file mode 100644 index 0000000..f8eb2ad --- /dev/null +++ b/libk3b/tools/k3blistview.h @@ -0,0 +1,296 @@ +/* + * + * $Id: k3blistview.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BLISTVIEW_H +#define K3BLISTVIEW_H + + +#include +#include "k3b_export.h" +#include +#include +#include +#include + +class QPainter; +class QPushButton; +class QIconSet; +class QResizeEvent; +class QComboBox; +class QSpinBox; +class QLineEdit; +class QEvent; +class QValidator; +class K3bMsfEdit; + +class K3bListView; + + +class LIBK3B_EXPORT K3bListViewItem : public KListViewItem +{ + public: + K3bListViewItem(QListView *parent); + K3bListViewItem(QListViewItem *parent); + K3bListViewItem(QListView *parent, QListViewItem *after); + K3bListViewItem(QListViewItem *parent, QListViewItem *after); + + K3bListViewItem(QListView *parent, + const QString&, const QString& = QString::null, + const QString& = QString::null, const QString& = QString::null, + const QString& = QString::null, const QString& = QString::null, + const QString& = QString::null, const QString& = QString::null); + + K3bListViewItem(QListViewItem *parent, + const QString&, const QString& = QString::null, + const QString& = QString::null, const QString& = QString::null, + const QString& = QString::null, const QString& = QString::null, + const QString& = QString::null, const QString& = QString::null); + + K3bListViewItem(QListView *parent, QListViewItem *after, + const QString&, const QString& = QString::null, + const QString& = QString::null, const QString& = QString::null, + const QString& = QString::null, const QString& = QString::null, + const QString& = QString::null, const QString& = QString::null); + + K3bListViewItem(QListViewItem *parent, QListViewItem *after, + const QString&, const QString& = QString::null, + const QString& = QString::null, const QString& = QString::null, + const QString& = QString::null, const QString& = QString::null, + const QString& = QString::null, const QString& = QString::null); + + virtual ~K3bListViewItem(); + + /** + * reimplemented from KListViewItem + */ + void setup(); + + virtual int width( const QFontMetrics& fm, const QListView* lv, int c ) const; + + void setEditor( int col, int type, const QStringList& = QStringList() ); + void setButton( int col, bool ); + + void setValidator( int col, QValidator* v ); + QValidator* validator( int col ) const; + + int editorType( int col ) const; + bool needButton( int col ) const; + const QStringList& comboStrings( int col ) const; + + enum EditorType { NONE, COMBO, LINE, SPIN, MSF }; + + void setFont( int col, const QFont& f ); + void setBackgroundColor( int col, const QColor& ); + void setForegroundColor( int col, const QColor& ); + + void setDisplayProgressBar( int col, bool ); + void setProgress( int, int ); + void setTotalSteps( int col, int steps ); + + /** + * The margin left and right of the cell + */ + void setMarginHorizontal( int col, int margin ); + + /** + * The top and button margin of the cell + */ + void setMarginVertical( int margin ); + + int marginHorizontal( int col ) const; + int marginVertical() const; + + /** + * Do not reimplement this but paintK3bCell to use the margin and background stuff. + */ + virtual void paintCell( QPainter* p, const QColorGroup& cg, int col, int width, int align ); + + virtual void paintK3bCell( QPainter* p, const QColorGroup& cg, int col, int width, int align ); + + private: + void paintProgressBar( QPainter* p, const QColorGroup& cgh, int col, int width ); + + class ColumnInfo; + mutable ColumnInfo* m_columns; + + ColumnInfo* getColumnInfo( int ) const; + void init(); + + int m_vMargin; +}; + + +class LIBK3B_EXPORT K3bCheckListViewItem : public K3bListViewItem +{ + public: + K3bCheckListViewItem(QListView *parent); + K3bCheckListViewItem(QListViewItem *parent); + K3bCheckListViewItem(QListView *parent, QListViewItem *after); + K3bCheckListViewItem(QListViewItem *parent, QListViewItem *after); + + virtual bool isChecked() const; + virtual void setChecked( bool checked ); + + protected: + virtual void paintK3bCell( QPainter* p, const QColorGroup& cg, int col, int width, int align ); + + private: + bool m_checked; +}; + + + +class LIBK3B_EXPORT K3bListView : public KListView +{ + friend class K3bListViewItem; + + Q_OBJECT + + public: + K3bListView (QWidget *parent = 0, const char *name = 0); + virtual ~K3bListView(); + + virtual void setCurrentItem( QListViewItem* ); + + K3bListViewItem* currentlyEditedItem() const { return m_currentEditItem; } + + QWidget* editor( K3bListViewItem::EditorType ) const; + + enum BgPixPosition { + TOP_LEFT, + CENTER + }; + + /** + * This will set a background pixmap which is not tiled. + * @param pos position on the viewport. + */ + void setK3bBackgroundPixmap( const QPixmap&, int pos = CENTER ); + + /** + * Create a faded pixmap showing the items. + */ + KPixmap createDragPixmap( const QPtrList& items ); + + /** + * Searches for the first item above @p i which is one level higher. + * For 1st level items this will always be the listview's root item. + */ + static QListViewItem* parentItem( QListViewItem* i ); + + signals: + void editorButtonClicked( K3bListViewItem*, int ); + + public slots: + void setNoItemText( const QString& ); + // void setNoItemPixmap( const QPixmap& ); + void setNoItemVerticalMargin( int i ) { m_noItemVMargin = i; } + void setNoItemHorizontalMargin( int i ) { m_noItemHMargin = i; } + void setDoubleClickForEdit( bool b ) { m_doubleClickForEdit = b; } + void hideEditor(); + void editItem( K3bListViewItem*, int ); + + virtual void clear(); + + private slots: + void updateEditorSize(); + virtual void slotEditorLineEditReturnPressed(); + virtual void slotEditorComboBoxActivated( const QString& ); + virtual void slotEditorSpinBoxValueChanged( int ); + virtual void slotEditorMsfEditValueChanged( int ); + virtual void slotEditorButtonClicked(); + + protected slots: + void showEditor( K3bListViewItem*, int col ); + void placeEditor( K3bListViewItem*, int col ); + + /** + * This is called whenever one of the editor's contents changes + * the default implementation just returnes true + * + * FIXME: should be called something like mayRename + */ + virtual bool renameItem( K3bListViewItem*, int, const QString& ); + + /** + * default impl just emits signal + * editorButtonClicked(...) + */ + virtual void slotEditorButtonClicked( K3bListViewItem*, int ); + + protected: + /** + * calls KListView::drawContentsOffset + * and paints a the noItemText if no item is in the list + */ + virtual void drawContentsOffset ( QPainter * p, int ox, int oy, int cx, int cy, int cw, int ch ); + virtual void resizeEvent( QResizeEvent* ); + virtual void paintEmptyArea( QPainter*, const QRect& rect ); + + /** + * Reimplemented for internal reasons. + * + * Further reimplementations should call this function or else some features may not work correctly. + * + * The API is unaffected. + */ + virtual void viewportResizeEvent( QResizeEvent* ); + + /** + * Reimplemented for internal reasons. + * Further reimplementations should call this function or else + * some features may not work correctly. + * + * The API is unaffected. + */ + virtual void viewportPaintEvent(QPaintEvent*); + + virtual bool eventFilter( QObject*, QEvent* ); + + K3bListViewItem* currentEditItem() const { return m_currentEditItem; } + int currentEditColumn() const { return m_currentEditColumn; } + + private: + QWidget* prepareEditor( K3bListViewItem* item, int col ); + void prepareButton( K3bListViewItem* item, int col ); + bool doRename(); + + QString m_noItemText; + // QPixmap m_noItemPixmap; + int m_noItemVMargin; + int m_noItemHMargin; + + K3bListViewItem* m_currentEditItem; + int m_currentEditColumn; + + bool m_doubleClickForEdit; + QListViewItem* m_lastClickedItem; + + QPushButton* m_editorButton; + QComboBox* m_editorComboBox; + QSpinBox* m_editorSpinBox; + QLineEdit* m_editorLineEdit; + K3bMsfEdit* m_editorMsfEdit; + + QPixmap m_backgroundPixmap; + int m_backgroundPixmapPosition; + + class Private; + Private* d; +}; + + +#endif diff --git a/libk3b/tools/k3blistviewitemanimator.cpp b/libk3b/tools/k3blistviewitemanimator.cpp new file mode 100644 index 0000000..1c729b6 --- /dev/null +++ b/libk3b/tools/k3blistviewitemanimator.cpp @@ -0,0 +1,137 @@ +/* + * + * $Id: k3blistviewitemanimator.cpp 689561 2007-07-18 15:19:38Z trueg $ + * Copyright (C) 2004 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3blistviewitemanimator.h" + +#include +#include + +#include +#include + + +K3bListViewItemAnimator::K3bListViewItemAnimator( QObject* parent, const char* name ) + : QObject( parent, name ) +{ + init(); +} + + +K3bListViewItemAnimator::K3bListViewItemAnimator( QListViewItem* item, int col, QObject* parent, const char* name ) + : QObject( parent, name ) +{ + init(); + setItem( item, col ); +} + + +K3bListViewItemAnimator::~K3bListViewItemAnimator() +{ +} + + +QListViewItem* K3bListViewItemAnimator::item() const +{ + return m_item; +} + + +void K3bListViewItemAnimator::init() +{ + m_item = 0; + m_column = 0; + m_timer = new QTimer( this ); + connect( m_timer, SIGNAL(timeout()), this, SLOT(slotAnimate()) ); +} + + +void K3bListViewItemAnimator::start() +{ + if( m_item && !m_pixmap.isNull() ) { + m_animationStep = 0; + m_animationBack = false; + m_timer->start( 150 ); + } + else + stop(); +} + + +void K3bListViewItemAnimator::stop() +{ + m_timer->stop(); +} + + +void K3bListViewItemAnimator::setItem( QListViewItem* item, int col ) +{ + m_item = item; + m_column = col; + m_pixmap = *item->pixmap(col); + m_fadeColor = item->listView()->colorGroup().base(); + start(); +} + + +void K3bListViewItemAnimator::setPixmap( const QPixmap& p ) +{ + m_pixmap = p; + start(); +} + + +void K3bListViewItemAnimator::setColumn( int col ) +{ + m_column = col; + start(); +} + + +void K3bListViewItemAnimator::setFadeColor( const QColor& c ) +{ + m_fadeColor = c; + start(); +} + + +void K3bListViewItemAnimator::slotAnimate() +{ + if( m_item->isVisible() ) { + double val = (double)m_animationStep; + val /= 10.0; + // we need a temp pixmap since KPixmapEffect changes our pixmap + KPixmap pix( m_pixmap ); + m_item->setPixmap( m_column, KPixmapEffect::fade( pix, val, m_fadeColor ) );; + } + + if( m_animationBack ) { + --m_animationStep; + if( m_animationStep < 0 ) { + // two steps full + m_animationStep = 0; + m_animationBack = false; + } + } + else { + ++m_animationStep; + // do not fade it completely + if( m_animationStep > 9 ) { + m_animationStep = 8; + m_animationBack = true; + } + } +} + +#include "k3blistviewitemanimator.moc" diff --git a/libk3b/tools/k3blistviewitemanimator.h b/libk3b/tools/k3blistviewitemanimator.h new file mode 100644 index 0000000..200079a --- /dev/null +++ b/libk3b/tools/k3blistviewitemanimator.h @@ -0,0 +1,78 @@ +/* + * + * $Id: k3blistviewitemanimator.h 689561 2007-07-18 15:19:38Z trueg $ + * Copyright (C) 2004 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_LISTVIEWITEM_ANIMATOR_H_ +#define _K3B_LISTVIEWITEM_ANIMATOR_H_ + +#include +#include +#include "k3b_export.h" + +class QListViewItem; +class QTimer; + + +/** + * Fades an icon on a listview item in and out. + */ +class LIBK3B_EXPORT K3bListViewItemAnimator : public QObject +{ + Q_OBJECT + + public: + K3bListViewItemAnimator( QObject* parent = 0, const char* name = 0 ); + /** + * Will use the items pixmap. + */ + K3bListViewItemAnimator( QListViewItem* item, int col, QObject* parent = 0, const char* name = 0 ); + ~K3bListViewItemAnimator(); + + QListViewItem* item() const; + + public slots: + void start(); + void stop(); + + void setItem( QListViewItem*, int col ); + + /** + * Default is the pixmap from the item. + */ + void setPixmap( const QPixmap& ); + + void setColumn( int col ); + + /** + * Default is the base color of the listview. + */ + void setFadeColor( const QColor& ); + + private slots: + void slotAnimate(); + + private: + void init(); + + int m_animationStep; + bool m_animationBack; + QPixmap m_pixmap; + QColor m_fadeColor; + QListViewItem* m_item; + int m_column; + + QTimer* m_timer; +}; + +#endif diff --git a/libk3b/tools/k3bmd5job.cpp b/libk3b/tools/k3bmd5job.cpp new file mode 100644 index 0000000..2679f33 --- /dev/null +++ b/libk3b/tools/k3bmd5job.cpp @@ -0,0 +1,322 @@ +/* + * + * $Id: k3bmd5job.cpp 633751 2007-02-15 08:22:49Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bmd5job.h" +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include + + +class K3bMd5Job::K3bMd5JobPrivate +{ +public: + K3bMd5JobPrivate() + : fileDes(-1), + fdNotifier(0), + finished(true), + data(0), + isoFile(0), + maxSize(0), + lastProgress(0) { + } + + KMD5 md5; + K3bFileSplitter file; + QTimer timer; + QString filename; + int fileDes; + K3bDevice::Device* device; + QSocketNotifier* fdNotifier; + + bool finished; + char* data; + const K3bIso9660File* isoFile; + + unsigned long long maxSize; + unsigned long long readData; + + int lastProgress; + + KIO::filesize_t imageSize; + + static const int BUFFERSIZE = 2048*10; +}; + + +K3bMd5Job::K3bMd5Job( K3bJobHandler* jh, QObject* parent, const char* name ) + : K3bJob( jh, parent, name ) +{ + d = new K3bMd5JobPrivate; + d->data = new char[K3bMd5JobPrivate::BUFFERSIZE]; + connect( &d->timer, SIGNAL(timeout()), + this, SLOT(slotUpdate()) ); +} + + +K3bMd5Job::~K3bMd5Job() +{ + delete [] d->data; + delete d; +} + + +void K3bMd5Job::start() +{ + cancel(); + + jobStarted(); + d->readData = 0; + + if( d->isoFile ) { + d->imageSize = d->isoFile->size(); + } + else if( !d->filename.isEmpty() ) { + if( !QFile::exists( d->filename ) ) { + emit infoMessage( i18n("Could not find file %1").arg(d->filename), ERROR ); + jobFinished(false); + return; + } + + d->file.setName( d->filename ); + if( !d->file.open( IO_ReadOnly ) ) { + emit infoMessage( i18n("Could not open file %1").arg(d->filename), ERROR ); + jobFinished(false); + return; + } + + d->imageSize = K3b::filesize( KURL::fromPathOrURL(d->filename) ); + } + else + d->imageSize = 0; + + if( d->device ) { + // + // Let the drive determine the optimal reading speed + // + d->device->setSpeed( 0xffff, 0xffff ); + } + + d->md5.reset(); + d->finished = false; + if( d->fileDes != -1 ) + setupFdNotifier(); + else + d->timer.start(0); +} + + +void K3bMd5Job::setupFdNotifier() +{ + // the QSocketNotifier will fire once the fd is closed + delete d->fdNotifier; + d->fdNotifier = new QSocketNotifier( d->fileDes, QSocketNotifier::Read, this ); + connect( d->fdNotifier, SIGNAL(activated(int)), this, SLOT(slotUpdate()) ); + d->fdNotifier->setEnabled( true ); +} + + +void K3bMd5Job::cancel() +{ + if( !d->finished ) { + stopAll(); + + emit canceled(); + jobFinished( false ); + } +} + + +void K3bMd5Job::setFile( const QString& filename ) +{ + d->filename = filename; + d->isoFile = 0; + d->fileDes = -1; + d->device = 0; +} + + +void K3bMd5Job::setFile( const K3bIso9660File* file ) +{ + d->isoFile = file; + d->fileDes = -1; + d->filename.truncate(0); + d->device = 0; +} + + +void K3bMd5Job::setFd( int fd ) +{ + d->fileDes = fd; + d->filename.truncate(0); + d->isoFile = 0; + d->device = 0; +} + + +void K3bMd5Job::setDevice( K3bDevice::Device* dev ) +{ + d->device = dev; + d->fileDes = -1; + d->filename.truncate(0); + d->isoFile = 0; +} + + +void K3bMd5Job::setMaxReadSize( unsigned long long size ) +{ + d->maxSize = size; +} + + +void K3bMd5Job::slotUpdate() +{ + if( !d->finished ) { + + // determine bytes to read + unsigned int readSize = K3bMd5JobPrivate::BUFFERSIZE; + if( d->maxSize > 0 ) + readSize = QMIN( readSize, d->maxSize - d->readData ); + + if( readSize <= 0 ) { + // kdDebug() << "(K3bMd5Job) reached max size of " << d->maxSize << ". Stopping." << endl; + emit debuggingOutput( "K3bMd5Job", QString("Reached max read of %1. Stopping after %2 bytes.").arg(d->maxSize).arg(d->readData) ); + stopAll(); + emit percent( 100 ); + jobFinished(true); + } + else { + int read = 0; + + // + // read from the iso9660 file + // + if( d->isoFile ) { + read = d->isoFile->read( d->readData, d->data, readSize ); + } + + // + // read from the device + // + else if( d->device ) { + // + // when reading from a device we always read multiples of 2048 bytes. + // Only the last sector may not be used completely. + // + unsigned long sector = d->readData/2048; + unsigned int sectorCnt = QMAX( readSize/2048, 1 ); + read = -1; + if( d->device->read10( reinterpret_cast(d->data), + sectorCnt*2048, + sector, + sectorCnt ) ) + read = QMIN( readSize, sectorCnt*2048 ); + } + + // + // read from the file + // + else if( d->fileDes < 0 ) { + read = d->file.readBlock( d->data, readSize ); + } + + // + // reading from the file descriptor + // + else { + read = ::read( d->fileDes, d->data, readSize ); + } + + if( read < 0 ) { + emit infoMessage( i18n("Error while reading from file %1").arg(d->filename), ERROR ); + stopAll(); + jobFinished(false); + } + else if( read == 0 ) { + // kdDebug() << "(K3bMd5Job) read all data. Total size: " << d->readData << ". Stopping." << endl; + emit debuggingOutput( "K3bMd5Job", QString("All data read. Stopping after %1 bytes.").arg(d->readData) ); + stopAll(); + emit percent( 100 ); + jobFinished(true); + } + else { + d->readData += read; + d->md5.update( d->data, read ); + int progress = 0; + if( d->isoFile || !d->filename.isEmpty() ) + progress = (int)((double)d->readData * 100.0 / (double)d->imageSize); + else if( d->maxSize > 0 ) + progress = (int)((double)d->readData * 100.0 / (double)d->maxSize); + + if( progress != d->lastProgress ) { + d->lastProgress = progress; + emit percent( progress ); + } + } + } + } +} + + +QCString K3bMd5Job::hexDigest() +{ + if( d->finished ) + return d->md5.hexDigest(); + else + return ""; +} + + +QCString K3bMd5Job::base64Digest() +{ + if( d->finished ) + return d->md5.base64Digest(); + else + return ""; + +} + + +void K3bMd5Job::stop() +{ + emit debuggingOutput( "K3bMd5Job", QString("Stopped manually after %1 bytes.").arg(d->readData) ); + stopAll(); + jobFinished( true ); +} + + +void K3bMd5Job::stopAll() +{ + if( d->fdNotifier ) + d->fdNotifier->setEnabled( false ); + if( d->file.isOpen() ) + d->file.close(); + d->timer.stop(); + d->finished = true; +} + +#include "k3bmd5job.moc" diff --git a/libk3b/tools/k3bmd5job.h b/libk3b/tools/k3bmd5job.h new file mode 100644 index 0000000..cd64795 --- /dev/null +++ b/libk3b/tools/k3bmd5job.h @@ -0,0 +1,92 @@ +/* + * + * $Id: k3bmd5job.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_MD5_JOB_H_ +#define _K3B_MD5_JOB_H_ + +#include +#include +#include "k3b_export.h" + +namespace K3bDevice { + class Device; +} + +class K3bIso9660File; + + +class LIBK3B_EXPORT K3bMd5Job : public K3bJob +{ + Q_OBJECT + + public: + K3bMd5Job( K3bJobHandler* jh , QObject* parent = 0, const char* name = 0 ); + ~K3bMd5Job(); + + QCString hexDigest(); + QCString base64Digest(); + + public slots: + void start(); + void stop(); + void cancel(); + + // FIXME: read from QIODevice and thus add K3bFileSplitter support + + /** + * read from a file. + * + * Be aware that the K3bMd5Job uses K3bFileSplitter to read splitted + * images. In the future this will be changed with the introduction + * of a setIODevice method. + */ + void setFile( const QString& filename ); + + /** + * read from an iso9660 file + */ + void setFile( const K3bIso9660File* ); + + /** + * read from a device + * This should be used in combination with setMaxReadSize + */ + void setDevice( K3bDevice::Device* dev ); + + /** + * read from the opened file descriptor. + * One needs to set the max read length or call stop() + * to finish calculation. + */ + void setFd( int fd ); + + /** + * Set the maximum bytes to read. + */ + void setMaxReadSize( unsigned long long ); + + private slots: + void slotUpdate(); + + private: + void setupFdNotifier(); + void stopAll(); + + class K3bMd5JobPrivate; + K3bMd5JobPrivate* d; +}; + +#endif diff --git a/libk3b/tools/k3bmsfedit.cpp b/libk3b/tools/k3bmsfedit.cpp new file mode 100644 index 0000000..13ad0a3 --- /dev/null +++ b/libk3b/tools/k3bmsfedit.cpp @@ -0,0 +1,153 @@ +/* + * + * $Id: k3bmsfedit.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + + +#include "k3bmsfedit.h" +#include "k3bglobals.h" + +#include +#include +#include +#include +#include + + + +K3bMsfValidator::K3bMsfValidator( QObject* parent, const char* name ) + : QRegExpValidator( K3b::Msf::regExp(), parent, name ) +{ +} + + + +K3bMsfEdit::K3bMsfEdit( QWidget* parent, const char* name ) + : QSpinBox( parent, name ) +{ + setValidator( new K3bMsfValidator( this ) ); + setMinValue( 0 ); + // some very high value (10000 minutes) + setMaxValue( 10000*60*75 ); + + connect( this, SIGNAL(valueChanged(int)), + this, SLOT(slotValueChanged(int)) ); +} + + +K3bMsfEdit::~K3bMsfEdit() +{} + + +QSize K3bMsfEdit::sizeHint() const +{ + // more or less copied from QSpinBox + constPolish(); + QSize sz = editor()->sizeHint(); + int h = sz.height(); + QFontMetrics fm( font() ); + int w = fm.width( "00:00:00" ); + int wx = fm.width( ' ' )*2; + int frame = style().pixelMetric( QStyle::PM_SpinBoxFrameWidth ); + return style().sizeFromContents(QStyle::CT_SpinBox, this, + QSize( w + wx + downRect().width() + frame*2, + h + frame*2). + expandedTo( QApplication::globalStrut() )); +} + + +QString K3bMsfEdit::mapValueToText( int value ) +{ + return K3b::framesToString( value, true ); +} + + +K3b::Msf K3bMsfEdit::msfValue() const +{ + return K3b::Msf(value()); +} + + +void K3bMsfEdit::setMsfValue( const K3b::Msf& msf ) +{ + setValue( msf.totalFrames() ); +} + + +int K3bMsfEdit::mapTextToValue( bool* ok ) +{ + return K3b::Msf::fromString( text(), ok ).lba(); +} + + +void K3bMsfEdit::setText( const QString& str ) +{ + bool ok; + editor()->setText( str ); + setValue( mapTextToValue( &ok) ); +} + + +void K3bMsfEdit::setFrameStyle( int style ) +{ + editor()->setFrameStyle( style ); +} + +void K3bMsfEdit::setLineWidth( int v ) +{ + editor()->setLineWidth( v ); +} + +void K3bMsfEdit::setValue( int v ) +{ + int i = editor()->cursorPosition(); + QSpinBox::setValue( v ); + editor()->setCursorPosition( i ); +} + +void K3bMsfEdit::stepUp() +{ + setValue( value() + currentStepValue() ); +} + +void K3bMsfEdit::stepDown() +{ + setValue( value() - currentStepValue() ); +} + +int K3bMsfEdit::currentStepValue() const +{ + int val = 1; + + // look if we are currently editing minutes or seconds + QString text = editor()->text(); + if( text.length() == 8 ) { + text = text.mid( editor()->cursorPosition() ); + int num = text.contains( ':' ); + if( num == 1 ) + val = 75; + else if( num == 2 ) + val = 60*75; + } + + return val; +} + + +void K3bMsfEdit::slotValueChanged( int v ) +{ + emit valueChanged( K3b::Msf(v) ); +} + +#include "k3bmsfedit.moc" diff --git a/libk3b/tools/k3bmsfedit.h b/libk3b/tools/k3bmsfedit.h new file mode 100644 index 0000000..c573910 --- /dev/null +++ b/libk3b/tools/k3bmsfedit.h @@ -0,0 +1,70 @@ +/* + * + * $Id: k3bmsfedit.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3B_MSF_EDIT_H +#define K3B_MSF_EDIT_H + + +#include +#include +#include + +#include +#include "k3b_export.h" + +class K3bMsfValidator : public QRegExpValidator +{ + public: + K3bMsfValidator( QObject* parent = 0, const char* name = 0 ); +}; + + +class LIBK3B_EXPORT K3bMsfEdit : public QSpinBox +{ + Q_OBJECT + + public: + K3bMsfEdit( QWidget* parent = 0, const char* name = 0 ); + ~K3bMsfEdit(); + + QSize sizeHint() const; + + void setFrameStyle( int style ); + void setLineWidth(int); + + K3b::Msf msfValue() const; + + signals: + void valueChanged( const K3b::Msf& ); + + public slots: + void setValue( int v ); + void setText( const QString& ); + void setMsfValue( const K3b::Msf& ); + void stepUp(); + void stepDown(); + + protected: + QString mapValueToText( int ); + int mapTextToValue( bool* ok ); + int currentStepValue() const; + + private slots: + void slotValueChanged( int ); +}; + + +#endif diff --git a/libk3b/tools/k3bmultichoicedialog.cpp b/libk3b/tools/k3bmultichoicedialog.cpp new file mode 100644 index 0000000..4c12554 --- /dev/null +++ b/libk3b/tools/k3bmultichoicedialog.cpp @@ -0,0 +1,191 @@ +/* + * + * $Id: k3bmultichoicedialog.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bmultichoicedialog.h" +#include "k3bstdguiitems.h" +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +class K3bMultiChoiceDialog::Private +{ +public: + Private() + : mapper(0), + buttonLayout(0) { + } + + QSignalMapper* mapper; + QPtrList buttons; + QHBoxLayout* buttonLayout; + + bool buttonClicked; +}; + + +// from kmessagebox.cpp +static QPixmap themedMessageBoxIcon(QMessageBox::Icon icon) +{ + QString icon_name; + + switch(icon) { + case QMessageBox::NoIcon: + return QPixmap(); + break; + case QMessageBox::Information: + icon_name = "messagebox_info"; + break; + case QMessageBox::Warning: + icon_name = "messagebox_warning"; + break; + case QMessageBox::Critical: + icon_name = "messagebox_critical"; + break; + default: + break; + } + + QPixmap ret = KApplication::kApplication()->iconLoader()->loadIcon(icon_name, KIcon::NoGroup, KIcon::SizeMedium, KIcon::DefaultState, 0, true); + + if (ret.isNull()) + return QMessageBox::standardIcon(icon); + else + return ret; +} + +K3bMultiChoiceDialog::K3bMultiChoiceDialog( const QString& caption, + const QString& text, + QMessageBox::Icon icon, + QWidget* parent, const char* name ) + : KDialog( parent, name ) +{ + d = new Private(); + d->mapper = new QSignalMapper( this ); + connect( d->mapper, SIGNAL(mapped(int)), this, SLOT(done(int)) ); + + setCaption( caption ); + + QGridLayout* mainGrid = new QGridLayout( this ); + mainGrid->setSpacing( spacingHint() ); + mainGrid->setMargin( marginHint() ); + + QHBox* contents = new QHBox( this ); + contents->setSpacing( KDialog::spacingHint()*2 ); + contents->setMargin( 0 ); + + QLabel* pixLabel = new QLabel( contents ); + pixLabel->setPixmap( themedMessageBoxIcon( icon ) ); + pixLabel->setScaledContents( false ); + QLabel* label = new K3bRichTextLabel( text, contents ); + contents->setStretchFactor( label, 1 ); + + d->buttonLayout = new QHBoxLayout; + d->buttonLayout->setSpacing( spacingHint() ); + d->buttonLayout->setMargin( 0 ); + + mainGrid->addMultiCellWidget( contents, 0, 0, 0, 2 ); + mainGrid->addMultiCellWidget( K3bStdGuiItems::horizontalLine( this ), 1, 1, 0, 2 ); + mainGrid->addLayout( d->buttonLayout, 2, 1 ); + + mainGrid->setColStretch( 0, 1 ); + mainGrid->setColStretch( 2, 1 ); + mainGrid->setRowStretch( 0, 1 ); +} + + +K3bMultiChoiceDialog::~K3bMultiChoiceDialog() +{ + delete d; +} + + +int K3bMultiChoiceDialog::addButton( const KGuiItem& b ) +{ + KPushButton* button = new KPushButton( b, this ); + d->buttonLayout->add( button ); + d->buttons.append(button); + d->mapper->setMapping( button, d->buttons.count() ); + connect( button, SIGNAL(clicked()), d->mapper, SLOT(map()) ); + return d->buttons.count(); +} + + +void K3bMultiChoiceDialog::slotButtonClicked( int code ) +{ + d->buttonClicked = true; + done( code ); +} + + +int K3bMultiChoiceDialog::exec() +{ + d->buttonClicked = false; + return KDialog::exec(); +} + + +void K3bMultiChoiceDialog::closeEvent( QCloseEvent* e ) +{ + // make sure the dialog can only be closed by the buttons + // otherwise we may get an undefined return value in exec + + if( d->buttonClicked ) + KDialog::closeEvent( e ); + else + e->ignore(); +} + + +int K3bMultiChoiceDialog::choose( const QString& caption, + const QString& text, + QMessageBox::Icon icon, + QWidget* parent, + const char* name, + int buttonCount, + const KGuiItem& b1, + const KGuiItem& b2, + const KGuiItem& b3, + const KGuiItem& b4, + const KGuiItem& b5, + const KGuiItem& b6 ) +{ + K3bMultiChoiceDialog dlg( caption, text, icon, parent, name ); + dlg.addButton( b1 ); + if( buttonCount > 1 ) + dlg.addButton( b2 ); + if( buttonCount > 2 ) + dlg.addButton( b3 ); + if( buttonCount > 3 ) + dlg.addButton( b4 ); + if( buttonCount > 4 ) + dlg.addButton( b5 ); + if( buttonCount > 5 ) + dlg.addButton( b6 ); + + return dlg.exec(); +} + + +#include "k3bmultichoicedialog.moc" diff --git a/libk3b/tools/k3bmultichoicedialog.h b/libk3b/tools/k3bmultichoicedialog.h new file mode 100644 index 0000000..f293fef --- /dev/null +++ b/libk3b/tools/k3bmultichoicedialog.h @@ -0,0 +1,73 @@ +/* + * + * $Id: k3bmultichoicedialog.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_MULTI_CHOICE_DIALOG_H_ +#define _K3B_MULTI_CHOICE_DIALOG_H_ + +#include +#include +#include "k3b_export.h" + +#include + + +class QCloseEvent; + +class LIBK3B_EXPORT K3bMultiChoiceDialog : public KDialog +{ + Q_OBJECT + + public: + K3bMultiChoiceDialog( const QString& caption, + const QString& text, + QMessageBox::Icon = QMessageBox::Information, + QWidget* parent = 0, const char* name = 0 ); + ~K3bMultiChoiceDialog(); + + /** + * Adds a new button. returns it's number starting at 1. + */ + int addButton( const KGuiItem& ); + + static int choose( const QString& caption, + const QString& text, + QMessageBox::Icon = QMessageBox::Information, + QWidget* parent = 0, + const char* name = 0, + int buttonCount = 2, + const KGuiItem& b1 = KStdGuiItem::yes(), + const KGuiItem& b2 = KStdGuiItem::no(), + const KGuiItem& b3 = KStdGuiItem::no(), + const KGuiItem& b4 = KStdGuiItem::no(), + const KGuiItem& b5 = KStdGuiItem::no(), + const KGuiItem& b6 = KStdGuiItem::no() ); + + public slots: + /** + * returnes the number of the clicked button starting at 1. + */ + int exec(); + + private slots: + void slotButtonClicked( int ); + + private: + void closeEvent( QCloseEvent* ); + + class Private; + Private* d; +}; + +#endif diff --git a/libk3b/tools/k3bpipe.cpp b/libk3b/tools/k3bpipe.cpp new file mode 100644 index 0000000..6f15915 --- /dev/null +++ b/libk3b/tools/k3bpipe.cpp @@ -0,0 +1,79 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bpipe.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + + +K3bPipe::K3bPipe() +{ + m_fd[0] = m_fd[1] = -1; +} + + +K3bPipe::~K3bPipe() +{ + close(); +} + + +bool K3bPipe::open() +{ + close(); + + if( ::socketpair( AF_UNIX, SOCK_STREAM, 0, m_fd ) == 0 ) { + fcntl( m_fd[0], F_SETFD, FD_CLOEXEC ); + fcntl( m_fd[1], F_SETFD, FD_CLOEXEC ); + return true; + } + else { + kdDebug() << "(K3bPipe) failed to setup socket pair." << endl; + return false; + } +} + + +void K3bPipe::closeIn() +{ + if( m_fd[1] != -1 ) { + ::close( m_fd[1] ); + m_fd[1] = -1; + } +} + + +void K3bPipe::closeOut() +{ + if( m_fd[0] != -1 ) { + ::close( m_fd[0] ); + m_fd[0] = -1; + } +} + + +void K3bPipe::close() +{ + closeIn(); + closeOut(); +} diff --git a/libk3b/tools/k3bpipe.h b/libk3b/tools/k3bpipe.h new file mode 100644 index 0000000..fba3455 --- /dev/null +++ b/libk3b/tools/k3bpipe.h @@ -0,0 +1,60 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_PIPE_H_ +#define _K3B_PIPE_H_ + +#include "k3b_export.h" + +/** + * The K3bPipe class represents a file descriptor pair + * which can for example be used to connect two processes + */ +class LIBK3B_EXPORT K3bPipe +{ + public: + /** + * Creates a closed pipe object + */ + K3bPipe(); + + /** + * The destructor takes care of closing the pipe + */ + ~K3bPipe(); + + /** + * Open the pipe. This creates a file descriptor pair + * which can be accessed using the in() and out() + * methods. + */ + bool open(); + + /** + * Calls both closeIn() and closeOut() + */ + void close(); + + void closeIn(); + void closeOut(); + + int in() const { return m_fd[1]; } + int out() const { return m_fd[0]; } + + private: + int m_fd[2]; +}; + +#endif diff --git a/libk3b/tools/k3bprogressdialog.cpp b/libk3b/tools/k3bprogressdialog.cpp new file mode 100644 index 0000000..69a81f5 --- /dev/null +++ b/libk3b/tools/k3bprogressdialog.cpp @@ -0,0 +1,107 @@ +/* + * + * $Id: k3bprogressdialog.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bprogressdialog.h" + +#include + +#include +#include +#include +#include +#include + +#include +#include + + +K3bProgressDialog::K3bProgressDialog( const QString& text, + QWidget* parent, + const QString& caption, + const char* name ) + : KDialogBase( parent, name, true, caption, Cancel|Ok, Ok, true ) +{ + QFrame* main = makeMainWidget(); + QGridLayout* mainLayout = new QGridLayout( main ); + mainLayout->setMargin( marginHint() ); + mainLayout->setSpacing( spacingHint() ); + + m_label = new QLabel( text, main ); + m_stack = new QWidgetStack( main ); + m_progressBar = new KProgress( m_stack ); + m_busyWidget = new K3bBusyWidget( m_stack ); + m_stack->addWidget( m_progressBar ); + m_stack->addWidget( m_busyWidget ); + + mainLayout->addWidget( m_label, 0, 0 ); + mainLayout->addWidget( m_stack, 1, 0 ); + + showButtonOK( false ); +} + + +K3bProgressDialog::~K3bProgressDialog() +{} + + +int K3bProgressDialog::exec( bool progress ) +{ + if( progress ) + m_stack->raiseWidget( m_progressBar ); + else + m_stack->raiseWidget( m_busyWidget ); + + m_busyWidget->showBusy( !progress ); + + actionButton( Cancel )->setEnabled(true); + + return KDialogBase::exec(); +} + + +void K3bProgressDialog::setText( const QString& text ) +{ + m_label->setText( text ); +} + + +void K3bProgressDialog::slotFinished( bool success ) +{ + m_busyWidget->showBusy( false ); + + showButtonOK( true ); + showButtonCancel( false ); + + if( success ) + m_label->setText( i18n("Disk successfully erased. Please reload the disk.") ); + else + m_label->setText( i18n("K3b was unable to erase the disk.") ); +} + + +void K3bProgressDialog::slotCancel() +{ + emit cancelClicked(); + // we simply forbid to click cancel twice + actionButton( Cancel )->setEnabled(false); +} + + +void K3bProgressDialog::setProgress( int p ) +{ + m_progressBar->setProgress( p ); +} + +#include "k3bprogressdialog.moc" diff --git a/libk3b/tools/k3bprogressdialog.h b/libk3b/tools/k3bprogressdialog.h new file mode 100644 index 0000000..32a0544 --- /dev/null +++ b/libk3b/tools/k3bprogressdialog.h @@ -0,0 +1,63 @@ +/* + * + * $Id: k3bprogressdialog.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_PROGRESS_DIALOG_H_ +#define _K3B_PROGRESS_DIALOG_H_ + +#include +#include "k3b_export.h" + +class K3bBusyWidget; +class QLabel; +class KProgress; +class QWidgetStack; + + +/** + * A progressdialog which displays a line of text and a progress + * bar or a moving dot for tasks that do not provide any progress + * information. + */ +class LIBK3B_EXPORT K3bProgressDialog : public KDialogBase +{ + Q_OBJECT + + public: + K3bProgressDialog( const QString& text = QString::null, + QWidget* parent = 0, + const QString& caption = QString::null, + const char* name = 0 ); + ~K3bProgressDialog(); + + int exec( bool showProgress ); + + public slots: + void setText( const QString& ); + void slotFinished( bool success ); + void setProgress( int p ); + + private slots: + void slotCancel(); + + private: + QLabel* m_label; + QWidgetStack* m_stack; + K3bBusyWidget* m_busyWidget; + KProgress* m_progressBar; +}; + + +#endif diff --git a/libk3b/tools/k3bpushbutton.cpp b/libk3b/tools/k3bpushbutton.cpp new file mode 100644 index 0000000..11425ad --- /dev/null +++ b/libk3b/tools/k3bpushbutton.cpp @@ -0,0 +1,136 @@ +/* + * + * $Id: k3bpushbutton.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bpushbutton.h" + +#include +#include +#include + +#include +#include + + + +class K3bPushButton::Private +{ +public: + Private() + : popupTimer(0) { + } + + QTimer* popupTimer; + QPoint mousePressPos; +}; + + + +K3bPushButton::K3bPushButton( QWidget* parent, const char* name ) + : KPushButton( parent, name ) +{ + d = new Private(); + installEventFilter(this); +} + + +K3bPushButton::K3bPushButton( const QString& text, QWidget* parent, const char* name ) + : KPushButton( text, parent, name ) +{ + d = new Private(); + installEventFilter(this); +} + + +K3bPushButton::K3bPushButton( const QIconSet& icon, const QString& text, + QWidget* parent, const char* name ) + : KPushButton( icon, text, parent, name ) +{ + d = new Private(); + installEventFilter(this); +} + + +K3bPushButton::K3bPushButton( const KGuiItem& item, QWidget* parent, const char* name ) + : KPushButton( item, parent, name ) +{ + d = new Private(); + installEventFilter(this); +} + + +K3bPushButton::~K3bPushButton() +{ + delete d; +} + + +void K3bPushButton::setDelayedPopupMenu( QPopupMenu* popup ) +{ + if( !d->popupTimer ) { + d->popupTimer = new QTimer( this ); + connect( d->popupTimer, SIGNAL(timeout()), this, SLOT(slotDelayedPopup()) ); + } + + setPopup( popup ); + + // we need to do the popup handling ourselves so we cheat a little + // QPushButton connects a popup slot to the pressed signal which we disconnect here + disconnect( this ); +} + + +bool K3bPushButton::eventFilter( QObject* o, QEvent* ev ) +{ + if( dynamic_cast(o) == this ) { + + // Popup the menu when the left mousebutton is pressed and the mouse + // is moved by a small distance. + if( popup() ) { + if( ev->type() == QEvent::MouseButtonPress ) { + QMouseEvent* mev = static_cast(ev); + d->mousePressPos = mev->pos(); + d->popupTimer->start( QApplication::startDragTime() ); + } + else if( ev->type() == QEvent::MouseMove ) { + QMouseEvent* mev = static_cast(ev); + if( ( mev->pos() - d->mousePressPos).manhattanLength() > KGlobalSettings::dndEventDelay() ) { + d->popupTimer->stop(); + slotDelayedPopup(); + return true; + } + } + } + } + + return KPushButton::eventFilter( o, ev ); +} + + +void K3bPushButton::slotDelayedPopup() +{ + d->popupTimer->stop(); + + if( isDown() ) { + // popup the menu. + // this has been taken from the QPushButton code + if( mapToGlobal( QPoint( 0, rect().bottom() ) ).y() + popup()->sizeHint().height() <= qApp->desktop()->height() ) + popup()->exec( mapToGlobal( rect().bottomLeft() ) ); + else + popup()->exec( mapToGlobal( rect().topLeft() - QPoint( 0, popup()->sizeHint().height() ) ) ); + setDown( false ); + } +} + +#include "k3bpushbutton.moc" diff --git a/libk3b/tools/k3bpushbutton.h b/libk3b/tools/k3bpushbutton.h new file mode 100644 index 0000000..1369af3 --- /dev/null +++ b/libk3b/tools/k3bpushbutton.h @@ -0,0 +1,75 @@ +/* + * + * $Id: k3bpushbutton.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004-2007 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_PUSH_BUTTON_H_ +#define _K3B_PUSH_BUTTON_H_ + + +#include +#include "k3b_export.h" + +/** + * A pushbutton with delayed popu pmenu support just like the KToolBarButton + */ +class LIBK3B_EXPORT K3bPushButton : public KPushButton +{ + Q_OBJECT + + public: + /** + * Default constructor. + */ + K3bPushButton( QWidget* parent = 0, const char* name = 0 ); + + /** + * Constructor, that sets the button-text to @p text + */ + K3bPushButton( const QString& text, QWidget* parent = 0, const char* name = 0 ); + + /** + * Constructor, that sets an icon and the button-text to @p text + */ + K3bPushButton( const QIconSet& icon, const QString& text, + QWidget* parent = 0, const char* name = 0 ); + + /** + * Constructor that takes a KGuiItem for the text, the icon, the tooltip + * and the what's this help + */ + K3bPushButton( const KGuiItem& item, QWidget* parent = 0, const char* name = 0 ); + + /** + * Destructs the button. + */ + ~K3bPushButton(); + + /** + * The popup menu will show if the button is pressed down for about half a second + * or if the mouse is moved while pressed just like the KToolBarButton. + */ + void setDelayedPopupMenu( QPopupMenu* ); + + protected: + virtual bool eventFilter( QObject*, QEvent* ); + + private slots: + void slotDelayedPopup(); + + private: + class Private; + Private* d; +}; + +#endif diff --git a/libk3b/tools/k3bradioaction.cpp b/libk3b/tools/k3bradioaction.cpp new file mode 100644 index 0000000..08fbece --- /dev/null +++ b/libk3b/tools/k3bradioaction.cpp @@ -0,0 +1,94 @@ +/* + * + * $Id: k3bradioaction.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2005 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bradioaction.h" + +#include + +K3bRadioAction::K3bRadioAction( const QString& text, const KShortcut& cut, + QObject* parent, const char* name ) + : KToggleAction( text, cut, parent, name ), + m_alwaysEmit(false) +{ +} + +K3bRadioAction::K3bRadioAction( const QString& text, const KShortcut& cut, + const QObject* receiver, const char* slot, + QObject* parent, const char* name ) + : KToggleAction( text, cut, receiver, slot, parent, name ), + m_alwaysEmit(false) +{ +} + +K3bRadioAction::K3bRadioAction( const QString& text, const QIconSet& pix, + const KShortcut& cut, + QObject* parent, const char* name ) + : KToggleAction( text, pix, cut, parent, name ), + m_alwaysEmit(false) +{ +} + +K3bRadioAction::K3bRadioAction( const QString& text, const QString& pix, + const KShortcut& cut, + QObject* parent, const char* name ) + : KToggleAction( text, pix, cut, parent, name ), + m_alwaysEmit(false) +{ +} + +K3bRadioAction::K3bRadioAction( const QString& text, const QIconSet& pix, + const KShortcut& cut, + const QObject* receiver, const char* slot, + QObject* parent, const char* name ) + : KToggleAction( text, pix, cut, receiver, slot, parent, name ), + m_alwaysEmit(false) +{ +} + +K3bRadioAction::K3bRadioAction( const QString& text, const QString& pix, + const KShortcut& cut, + const QObject* receiver, const char* slot, + QObject* parent, const char* name ) + : KToggleAction( text, pix, cut, receiver, slot, parent, name ), + m_alwaysEmit(false) +{ +} + +K3bRadioAction::K3bRadioAction( QObject* parent, const char* name ) + : KToggleAction( parent, name ), + m_alwaysEmit(false) +{ +} + +void K3bRadioAction::slotActivated() +{ + if( isChecked() ) { + if( m_alwaysEmit ) + emit activated(); + + const QObject *senderObj = sender(); + + if ( !senderObj || !::qt_cast( senderObj ) ) + return; + + const_cast( static_cast( senderObj ) )->on( true ); + + return; + } + + KToggleAction::slotActivated(); +} + +#include "k3bradioaction.moc" diff --git a/libk3b/tools/k3bradioaction.h b/libk3b/tools/k3bradioaction.h new file mode 100644 index 0000000..104b598 --- /dev/null +++ b/libk3b/tools/k3bradioaction.h @@ -0,0 +1,122 @@ +/* + * + * $Id: k3bradioaction.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2005 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_RADIO_ACTION_H_ +#define _K3B_RADIO_ACTION_H_ + +#include +#include "k3b_export.h" + +/** + * This differs from KRadioAction only in the boolean + * flag which says if it should always emit the signals + * even if it was checked twice. + * + * Docu copied from kdelibs + */ +class LIBK3B_EXPORT K3bRadioAction : public KToggleAction +{ + Q_OBJECT + + public: + /** + * Constructs a radio action with text and potential keyboard + * accelerator but nothing else. Use this only if you really + * know what you are doing. + * + * @param text The text that will be displayed. + * @param cut The corresponding keyboard accelerator (shortcut). + * @param parent This action's parent. + * @param name An internal name for this action. + */ + K3bRadioAction( const QString& text, const KShortcut& cut = KShortcut(), QObject* parent = 0, const char* name = 0 ); + + /** + * @param text The text that will be displayed. + * @param cut The corresponding keyboard accelerator (shortcut). + * @param receiver The SLOT's parent. + * @param slot The SLOT to invoke to execute this action. + * @param parent This action's parent. + * @param name An internal name for this action. + */ + K3bRadioAction( const QString& text, const KShortcut& cut, + const QObject* receiver, const char* slot, QObject* parent, const char* name = 0 ); + + /** + * @param text The text that will be displayed. + * @param pix The icons that go with this action. + * @param cut The corresponding keyboard accelerator (shortcut). + * @param parent This action's parent. + * @param name An internal name for this action. + */ + K3bRadioAction( const QString& text, const QIconSet& pix, const KShortcut& cut = KShortcut(), + QObject* parent = 0, const char* name = 0 ); + + /** + * @param text The text that will be displayed. + * @param pix The dynamically loaded icon that goes with this action. + * @param cut The corresponding keyboard accelerator (shortcut). + * @param parent This action's parent. + * @param name An internal name for this action. + */ + K3bRadioAction( const QString& text, const QString& pix, const KShortcut& cut = KShortcut(), + QObject* parent = 0, const char* name = 0 ); + + /** + * @param text The text that will be displayed. + * @param pix The icons that go with this action. + * @param cut The corresponding keyboard accelerator (shortcut). + * @param receiver The SLOT's parent. + * @param slot The SLOT to invoke to execute this action. + * @param parent This action's parent. + * @param name An internal name for this action. + */ + K3bRadioAction( const QString& text, const QIconSet& pix, const KShortcut& cut, + const QObject* receiver, const char* slot, QObject* parent, const char* name = 0 ); + + /** + * @param text The text that will be displayed. + * @param pix The dynamically loaded icon that goes with this action. + * @param cut The corresponding keyboard accelerator (shortcut). + * @param receiver The SLOT's parent. + * @param slot The SLOT to invoke to execute this action. + * @param parent This action's parent. + * @param name An internal name for this action. + */ + K3bRadioAction( const QString& text, const QString& pix, const KShortcut& cut, + const QObject* receiver, const char* slot, + QObject* parent, const char* name = 0 ); + + /** + * @param parent This action's parent. + * @param name An internal name for this action. + */ + K3bRadioAction( QObject* parent = 0, const char* name = 0 ); + + /** + * @param b if true the action will always emit the activated signal + * even if the toggled state did not change. The default is false. + * which is the same behaviour as KRadioAction + */ + void setAlwaysEmitActivated( bool b ) { m_alwaysEmit = b; } + + protected: + virtual void slotActivated(); + + private: + bool m_alwaysEmit; +}; + +#endif diff --git a/libk3b/tools/k3brichtextlabel.cpp b/libk3b/tools/k3brichtextlabel.cpp new file mode 100644 index 0000000..747bba1 --- /dev/null +++ b/libk3b/tools/k3brichtextlabel.cpp @@ -0,0 +1,109 @@ +/* + * + * $Id: k3brichtextlabel.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2005 Waldo Bastian + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3brichtextlabel.h" + +#include +#include +#include + +#include + +static QString qrichtextify( const QString& text ) +{ + if ( text.isEmpty() || text[0] == '<' ) + return text; + + QStringList lines = QStringList::split('\n', text); + for(QStringList::Iterator it = lines.begin(); it != lines.end(); ++it) + { + *it = QStyleSheet::convertFromPlainText( *it, QStyleSheetItem::WhiteSpaceNormal ); + } + + return lines.join(QString::null); +} + +K3bRichTextLabel::K3bRichTextLabel( const QString &text , QWidget *parent, const char *name ) + : QLabel ( parent, name ) { + m_defaultWidth = QMIN(400, KGlobalSettings::desktopGeometry(this).width()*2/5); + setAlignment( Qt::WordBreak ); + setText(text); +} + +K3bRichTextLabel::K3bRichTextLabel( QWidget *parent, const char *name ) + : QLabel ( parent, name ) { + m_defaultWidth = QMIN(400, KGlobalSettings::desktopGeometry(this).width()*2/5); + setAlignment( Qt::WordBreak ); +} + +void K3bRichTextLabel::setDefaultWidth(int defaultWidth) +{ + m_defaultWidth = defaultWidth; + updateGeometry(); +} + +QSizePolicy K3bRichTextLabel::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum, false); +} + +QSize K3bRichTextLabel::minimumSizeHint() const +{ + QString qt_text = qrichtextify( text() ); + int pref_width = 0; + int pref_height = 0; + QSimpleRichText rt(qt_text, font()); + pref_width = m_defaultWidth; + rt.setWidth(pref_width); + int used_width = rt.widthUsed(); + if (used_width <= pref_width) + { + while(true) + { + int new_width = (used_width * 9) / 10; + rt.setWidth(new_width); + int new_height = rt.height(); + if (new_height > pref_height) + break; + used_width = rt.widthUsed(); + if (used_width > new_width) + break; + } + pref_width = used_width; + } + else + { + if (used_width > (pref_width *2)) + pref_width = pref_width *2; + else + pref_width = used_width; + } + + return QSize(pref_width, rt.height()); +} + +QSize K3bRichTextLabel::sizeHint() const +{ + return minimumSizeHint(); +} + +void K3bRichTextLabel::setText( const QString &text ) { + QLabel::setText(text); +} + +void K3bRichTextLabel::virtual_hook( int, void* ) +{ /*BASE::virtual_hook( id, data );*/ } + +#include "k3brichtextlabel.moc" diff --git a/libk3b/tools/k3brichtextlabel.h b/libk3b/tools/k3brichtextlabel.h new file mode 100644 index 0000000..0a25395 --- /dev/null +++ b/libk3b/tools/k3brichtextlabel.h @@ -0,0 +1,62 @@ +/* + * + * $Id: k3brichtextlabel.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2005 Waldo Bastian + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef K3BRICHTEXTLABEL_H +#define K3BRICHTEXTLABEL_H + +#include + +#include + +/** + * @short A replacement for QLabel that supports richtext and proper layout management + * + * @author Waldo Bastian + */ + +/* + * QLabel + */ +class LIBK3B_EXPORT K3bRichTextLabel : public QLabel { + Q_OBJECT + +public: + /** + * Default constructor. + */ + K3bRichTextLabel( QWidget *parent, const char *name = 0 ); + K3bRichTextLabel( const QString &text, QWidget *parent, const char *name = 0 ); + + int defaultWidth() const { return m_defaultWidth; } + void setDefaultWidth(int defaultWidth); + + virtual QSize minimumSizeHint() const; + virtual QSize sizeHint() const; + QSizePolicy sizePolicy() const; + +public slots: + void setText( const QString & ); + +protected: + int m_defaultWidth; + +protected: + virtual void virtual_hook( int id, void* data ); +private: + class K3bRichTextLabelPrivate; + K3bRichTextLabelPrivate *d; +}; + +#endif // K3BRICHTEXTLABEL_H diff --git a/libk3b/tools/k3bsignalwaiter.cpp b/libk3b/tools/k3bsignalwaiter.cpp new file mode 100644 index 0000000..fcee2e0 --- /dev/null +++ b/libk3b/tools/k3bsignalwaiter.cpp @@ -0,0 +1,62 @@ +/* + * + * $Id: sourceheader 380067 2005-01-19 13:03:46Z trueg $ + * Copyright (C) 2005 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bsignalwaiter.h" +#include "k3bjob.h" + +#include +#include + + +K3bSignalWaiter::K3bSignalWaiter() + : QObject(), + m_inLoop(true) +{ +} + + +K3bSignalWaiter::~K3bSignalWaiter() +{ +} + + +void K3bSignalWaiter::waitForSignal( QObject* o, const char* signal ) +{ + K3bSignalWaiter w; + connect( o, signal, + &w, SLOT(slotSignal()) ); + + QApplication::eventLoop()->enterLoop(); +} + + +void K3bSignalWaiter::waitForJob( K3bJob* job ) +{ + if( !job->active() ) + return; + + waitForSignal( job, SIGNAL(finished(bool)) ); +} + + +void K3bSignalWaiter::slotSignal() +{ + if( m_inLoop ) { + m_inLoop = false; + QApplication::eventLoop()->exitLoop(); + } +} + +#include "k3bsignalwaiter.moc" diff --git a/libk3b/tools/k3bsignalwaiter.h b/libk3b/tools/k3bsignalwaiter.h new file mode 100644 index 0000000..19876b4 --- /dev/null +++ b/libk3b/tools/k3bsignalwaiter.h @@ -0,0 +1,51 @@ +/* + * + * $Id: sourceheader 380067 2005-01-19 13:03:46Z trueg $ + * Copyright (C) 2005 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_SIGNAL_WAITER_H_ +#define _K3B_SIGNAL_WAITER_H_ + +#include + +#include + +class K3bJob; + +class K3bSignalWaiter : public QObject +{ + Q_OBJECT + + public: + /** + * Use this to syncroneously wait for a signal. + */ + LIBK3B_EXPORT static void waitForSignal( QObject* o, const char* signal ); + + /** + * Use this to syncroneously wait for a job to finish. + * If the job is not running at all this returns immedeately. + */ + LIBK3B_EXPORT static void waitForJob( K3bJob* job ); + + private slots: + void slotSignal(); + + private: + K3bSignalWaiter(); + ~K3bSignalWaiter(); + + bool m_inLoop; +}; + +#endif diff --git a/libk3b/tools/k3bstdguiitems.cpp b/libk3b/tools/k3bstdguiitems.cpp new file mode 100644 index 0000000..8a6ab00 --- /dev/null +++ b/libk3b/tools/k3bstdguiitems.cpp @@ -0,0 +1,215 @@ +/* + * + * $Id: k3bstdguiitems.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bstdguiitems.h" + +#include +#include +#include +#include +#include +#include + +#include + + +QCheckBox* K3bStdGuiItems::simulateCheckbox( QWidget* parent, const char* name ) +{ + QCheckBox* c = new QCheckBox( i18n("Simulate"), parent, name ); + QWhatsThis::add( c, i18n("

If this option is checked K3b will perform all writing steps with the " + "laser turned off." + "

This is useful, for example, to test a higher writing speed " + "or whether your system is able to write on-the-fly." + "

Caution: DVD+R(W) does not support simulated writing.") ); + QToolTip::add( c, i18n("Only simulate the writing process") ); + return c; +} + +QCheckBox* K3bStdGuiItems::daoCheckbox( QWidget* parent, const char* name ) +{ + QCheckBox* c = new QCheckBox( i18n("Disk at once"), parent, name ); + QWhatsThis::add( c, i18n("

If this option is checked, K3b will write the CD in 'disk at once' mode as " + "compared to 'track at once' (TAO)." + "

It is always recommended to use DAO where possible." + "

Caution: Track pregaps with a length other than 2 seconds are only supported " + "in DAO mode.") ); + QToolTip::add( c, i18n("Write in disk at once mode") ); + return c; +} + +QCheckBox* K3bStdGuiItems::burnproofCheckbox( QWidget* parent, const char* name ) +{ + QCheckBox* c = new QCheckBox( i18n("Use Burnfree"), parent, name ); + QToolTip::add( c, i18n("Enable Burnfree (or Just Link) to avoid buffer underruns") ); + QWhatsThis::add( c, i18n("

If this option is checked, K3b enables Burnfree " + "(or Just Link). This is " + "a feature of the CD writer which avoids buffer underruns." + "

Without burnfree, if the writer cannot get any more " + "data a buffer underrun would occurs, since the writer needs " + "a constant stream of data to write the CD." + "

With burnfree the writer can mark the current " + "position of the laser and get back to it when the buffer is filled again;" + "but, since this means having little data gaps on the CD, it is " + "highly recommended to always choose an appropriate writing " + "speed to prevent the usage of burnfree, especially for audio CDs " + "(in the worst case one would hear the gap)." + "

Burnfree was formerly known as Burnproof, " + "but has since been renamed when it became part of the MMC standard.") ); + return c; +} + +QCheckBox* K3bStdGuiItems::onlyCreateImagesCheckbox( QWidget* parent, const char* name ) +{ + QCheckBox* c = new QCheckBox( i18n("Only create image"), parent, name ); + QWhatsThis::add( c, i18n("

If this option is checked, K3b will only create an " + "image and not do any actual writing." + "

The image can later be written to a CD/DVD with most current writing " + "programs (including K3b of course).") ); + QToolTip::add( c, i18n("Only create an image") ); + return c; +} + +QCheckBox* K3bStdGuiItems::createCacheImageCheckbox( QWidget* parent, const char* name ) +{ + QCheckBox* c = new QCheckBox( i18n("Create image"), parent, name ); + QWhatsThis::add( c, i18n("

If this option is checked, K3b will create an image before writing " + "the files to the CD/DVD. Otherwise the data will be written on-the-fly, " + "i.e. no intermediate image will be created." + "

Caution: Although writing on-the-fly should work on most systems, make sure " + "the data is sent to the writer fast enough.") + + i18n("

It is recommended to try a simulation first.") ); + QToolTip::add( c, i18n("Cache the data to be written on the harddisk") ); + return c; +} + +QCheckBox* K3bStdGuiItems::removeImagesCheckbox( QWidget* parent, const char* name ) +{ + QCheckBox* c = new QCheckBox( i18n("Remove image"), parent, name ); + QWhatsThis::add( c, i18n("

If this option is checked, K3b will remove any created images after the " + "writing has finished." + "

Uncheck this if you want to keep the images.") ); + QToolTip::add( c, i18n("Remove images from disk when finished") ); + return c; +} + +QCheckBox* K3bStdGuiItems::onTheFlyCheckbox( QWidget* parent, const char* name ) +{ + QCheckBox* c = new QCheckBox( i18n("On the fly"), parent, name ); + QWhatsThis::add( c, i18n("

If this option is checked, K3b will not create an image first but write " + "the files directly to the CD/DVD." + "

Caution: Although this should work on most systems, make sure " + "the data is sent to the writer fast enough.") + + i18n("

It is recommended to try a simulation first.") ); + QToolTip::add( c, i18n("Write files directly to CD/DVD without creating an image") ); + return c; +} + +QCheckBox* K3bStdGuiItems::cdTextCheckbox( QWidget* parent, const char* name ) +{ + QCheckBox* c = new QCheckBox( i18n("Write CD-TEXT"), parent, name ); + QToolTip::add( c, i18n("Create CD-TEXT entries") ); + QWhatsThis::add( c, i18n("

If this option is checked K3b uses some otherwise-unused space on the audio " + "CD to store additional information, like the artist or the CD title." + "

CD-TEXT is an extension to the audio CD standard introduced by Sony." + "

CD-TEXT will only be usable on CD players that support this extension " + "(mostly car CD players)." + "

Since a CD-TEXT-enhanced CDs will work in any CD player it is never a bad " + "idea to enable this (if you specify CD-TEXT data).") ); + return c; +} + + +QComboBox* K3bStdGuiItems::paranoiaModeComboBox( QWidget* parent, const char* name ) +{ + QComboBox* c = new QComboBox( parent, name ); + c->insertItem( "0" ); + c->insertItem( "1" ); + c->insertItem( "2" ); + c->insertItem( "3" ); + c->setCurrentItem( 3 ); + QToolTip::add( c, i18n("Set the paranoia level for reading audio CDs") ); + QWhatsThis::add( c, i18n("

Sets the correction mode for digital audio extraction." + "

  • 0: No checking, data is copied directly from the drive. " + "
  • 1: Perform overlapped reading to avoid jitter.
  • " + "
  • 2: Like 1 but with additional checks of the read audio data.
  • " + "
  • 3: Like 2 but with additional scratch detection and repair.
" + "

The extraction speed reduces from 0 to 3.") ); + return c; +} + + +QCheckBox* K3bStdGuiItems::startMultisessionCheckBox( QWidget* parent, const char* name ) +{ + QCheckBox* c = new QCheckBox( i18n("Start multisession CD"), parent, name ); + QToolTip::add( c, i18n("Do not close the disk to allow additional sessions to be added later") ); + QWhatsThis::add( c, i18n("

If this option is checked K3b will not close the CD, and will write " + "a temporary table of contents.

" + "

This allows further sessions to be appended to the CD later.

") ); + return c; +} + + +QCheckBox* K3bStdGuiItems::normalizeCheckBox( QWidget* parent, const char* name ) +{ + QCheckBox* c = new QCheckBox( i18n("Normalize volume levels"), parent, name ); + QToolTip::add( c, i18n("Adjust the volume levels of all tracks") ); + QWhatsThis::add( c, i18n("

If this option is checked K3b will adjust the volume of all tracks " + "to a standard level. This is useful for things like creating mixes, " + "where different recording levels on different albums can cause the volume " + "to vary greatly from song to song." + "

Be aware that K3b currently does not support normalizing when writing " + "on the fly.") ); + return c; +} + + +QCheckBox* K3bStdGuiItems::verifyCheckBox( QWidget* parent, const char* name ) +{ + QCheckBox* c = new QCheckBox( i18n("Verify written data"), parent, name ); + QToolTip::add( c, i18n("Compare original with written data") ); + QWhatsThis::add( c, i18n("

If this option is checked, then after successfully " + "writing the disk K3b will compare the original source data " + "with the written data to verify that the disk has been written " + "correctly.") ); + return c; +} + + +QCheckBox* K3bStdGuiItems::ignoreAudioReadErrorsCheckBox( QWidget* parent, const char* name ) +{ + QCheckBox* c = new QCheckBox( i18n("Ignore read errors"), parent, name ); + QToolTip::add( c, i18n("Skip unreadable audio sectors") ); + QWhatsThis::add( c, i18n("

If this option is checked and K3b is not able to read an " + "audio sector from the source CD it will be replaced with zeros " + "on the resulting copy." + "

Since audio CD Player are able to interpolate small errors " + "in the data it is no problem to let K3b skip unreadable sectors.") ); + return c; +} + + +QFrame* K3bStdGuiItems::horizontalLine( QWidget* parent, const char* name ) +{ + QFrame* line = new QFrame( parent, name ); + line->setFrameStyle( QFrame::HLine | QFrame::Sunken ); + return line; +} + +QFrame* K3bStdGuiItems::verticalLine( QWidget* parent, const char* name ) +{ + QFrame* line = new QFrame( parent, name ); + line->setFrameStyle( QFrame::VLine | QFrame::Sunken ); + return line; +} diff --git a/libk3b/tools/k3bstdguiitems.h b/libk3b/tools/k3bstdguiitems.h new file mode 100644 index 0000000..e118b6a --- /dev/null +++ b/libk3b/tools/k3bstdguiitems.h @@ -0,0 +1,45 @@ +/* + * + * $Id: k3bstdguiitems.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef K3B_STD_GUIITEMS_H +#define K3B_STD_GUIITEMS_H +#include "k3b_export.h" + +class QWidget; +class QCheckBox; +class QComboBox; +class QFrame; + + +namespace K3bStdGuiItems +{ + LIBK3B_EXPORT QCheckBox* simulateCheckbox( QWidget* parent = 0, const char* name = 0 ); + LIBK3B_EXPORT QCheckBox* daoCheckbox( QWidget* parent = 0, const char* name = 0 ); + LIBK3B_EXPORT QCheckBox* burnproofCheckbox( QWidget* parent = 0, const char* name = 0 ); + LIBK3B_EXPORT QCheckBox* onlyCreateImagesCheckbox( QWidget* parent = 0, const char* name = 0 ); + LIBK3B_EXPORT QCheckBox* createCacheImageCheckbox( QWidget* parent = 0, const char* name = 0 ); + LIBK3B_EXPORT QCheckBox* removeImagesCheckbox( QWidget* parent = 0, const char* name = 0 ); + LIBK3B_EXPORT QCheckBox* onTheFlyCheckbox( QWidget* parent = 0, const char* name = 0 ); + LIBK3B_EXPORT QCheckBox* cdTextCheckbox( QWidget* parent = 0, const char* name = 0); + LIBK3B_EXPORT QComboBox* paranoiaModeComboBox( QWidget* parent = 0, const char* name = 0 ); + LIBK3B_EXPORT QCheckBox* startMultisessionCheckBox( QWidget* parent = 0, const char* name = 0 ); + LIBK3B_EXPORT QCheckBox* normalizeCheckBox( QWidget* parent = 0, const char* name = 0 ); + LIBK3B_EXPORT QCheckBox* verifyCheckBox( QWidget* parent = 0, const char* name = 0 ); + LIBK3B_EXPORT QCheckBox* ignoreAudioReadErrorsCheckBox( QWidget* parent = 0, const char* name = 0 ); + LIBK3B_EXPORT QFrame* horizontalLine( QWidget* parent = 0, const char* name = 0 ); + LIBK3B_EXPORT QFrame* verticalLine( QWidget* parent = 0, const char* name = 0 ); +} + +#endif diff --git a/libk3b/tools/k3bstringutils.cpp b/libk3b/tools/k3bstringutils.cpp new file mode 100644 index 0000000..198bb9e --- /dev/null +++ b/libk3b/tools/k3bstringutils.cpp @@ -0,0 +1,111 @@ +/* + * + * $Id: k3bstringutils.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bstringutils.h" + +#include + +#include + + +QString K3b::cutToWidth( const QFontMetrics& fm, const QString& fullText, int cutWidth ) +{ + QString squeezedText = "..."; + int squeezedWidth = fm.width(squeezedText); + int textWidth = fm.width(fullText); + + if( textWidth <= cutWidth ) { + return fullText; + } + + if( fm.width(fullText.right(1) + "..." ) > cutWidth ) { + kdDebug() << "(K3b::cutToWidth) not able to cut text to " << cutWidth << "!" << endl; + return fullText.right(1) + "..."; + } + + // estimate how many letters we can add to the dots + int letters = fullText.length() * (cutWidth - squeezedWidth) / textWidth; + squeezedText = fullText.left(letters) + "..."; + squeezedWidth = fm.width(squeezedText); + + if (squeezedWidth < cutWidth) { + // we estimated too short + // add letters while text < label + do { + letters++; + squeezedText = fullText.left(letters) + "..."; + squeezedWidth = fm.width(squeezedText); + } while (squeezedWidth < cutWidth); + letters--; + squeezedText = fullText.left(letters) + "..."; + } else if (squeezedWidth > cutWidth) { + // we estimated too long + // remove letters while text > label + do { + letters--; + squeezedText = fullText.left(letters) + "..."; + squeezedWidth = fm.width(squeezedText); + } while (squeezedWidth > cutWidth); + } + + return squeezedText; +} + + +// from KSqueezedTextLabel +QString K3b::squeezeTextToWidth( const QFontMetrics& fm, const QString& fullText, int cutWidth ) +{ + int textWidth = fm.width(fullText); + if (textWidth > cutWidth) { + // start with the dots only + QString squeezedText = "..."; + int squeezedWidth = fm.width(squeezedText); + + // estimate how many letters we can add to the dots on both sides + int letters = fullText.length() * (cutWidth - squeezedWidth) / textWidth / 2; + if (cutWidth < squeezedWidth) letters=1; + squeezedText = fullText.left(letters) + "..." + fullText.right(letters); + squeezedWidth = fm.width(squeezedText); + + if (squeezedWidth < cutWidth) { + // we estimated too short + // add letters while text < label + do { + letters++; + squeezedText = fullText.left(letters) + "..." + fullText.right(letters); + squeezedWidth = fm.width(squeezedText); + } while (squeezedWidth < cutWidth); + letters--; + squeezedText = fullText.left(letters) + "..." + fullText.right(letters); + } + else if (squeezedWidth > cutWidth) { + // we estimated too long + // remove letters while text > label + do { + letters--; + squeezedText = fullText.left(letters) + "..." + fullText.right(letters); + squeezedWidth = fm.width(squeezedText); + } while (letters > 2 && squeezedWidth > cutWidth); + } + + if (letters == 2) + kdDebug() << "(K3b::squeezeTextToWidth) WARNING: unable to squeeze text to width " + << cutWidth << endl; + + return squeezedText; + } + else + return fullText; +} diff --git a/libk3b/tools/k3bstringutils.h b/libk3b/tools/k3bstringutils.h new file mode 100644 index 0000000..05cfd32 --- /dev/null +++ b/libk3b/tools/k3bstringutils.h @@ -0,0 +1,39 @@ +/* + * + * $Id: k3bstringutils.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_STRING_UTILS_H_ +#define _K3B_STRING_UTILS_H_ + +#include + +class QFontMetrics; + +namespace K3b +{ + /** + * Cuts the text at the end. + * Example: "some long text" -> "some lo..." + */ + QString cutToWidth( const QFontMetrics&, const QString&, int ); + + /** + * squeezes the text. + * Example: "some long text" -> "some...ext" + */ + QString squeezeTextToWidth( const QFontMetrics& fm, const QString& fullText, int cutWidth ); +} + +#endif diff --git a/libk3b/tools/k3btempfile.cpp b/libk3b/tools/k3btempfile.cpp new file mode 100644 index 0000000..635be40 --- /dev/null +++ b/libk3b/tools/k3btempfile.cpp @@ -0,0 +1,51 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3btempfile.h" + +#include +#include + + +static inline QString defaultTempDir() +{ + // we need a world-readable temp dir + + // FIXME: check if the default is world-readable +// QStringList dirs = KGlobal::dirs()->resourceDirs( "tmp" ); +// for( QStringList::const_iterator it = dirs.begin(); +// it != dirs.end(); ++it ) { +// const QString& dir = *it; + +// } + + // fallback to /tmp + return "/tmp/k3b"; +} + + +K3bTempFile::K3bTempFile( const QString& filePrefix, + const QString& fileExtension, + int mode ) + : KTempFile( filePrefix.isEmpty() ? defaultTempDir() : filePrefix, + fileExtension, + mode ) +{ +} + + +K3bTempFile::~K3bTempFile() +{ +} diff --git a/libk3b/tools/k3btempfile.h b/libk3b/tools/k3btempfile.h new file mode 100644 index 0000000..41a8756 --- /dev/null +++ b/libk3b/tools/k3btempfile.h @@ -0,0 +1,43 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_TEMP_FILE_H_ +#define _K3B_TEMP_FILE_H_ + +#include + +#include + +/** + * K3bTempFile does only change one thing over KTempFile: + * It tries to use a default temp dir which is always world-readable. + * + * This is important in the following situation: + * + * cdrecord often runs suid root. Some distributions like Mandriva + * set the default KDE temp dir to $HOME/tmp-$USER. Thus, if the home + * dir is mounted via NFS root has no read permissions htere and cdrecord + * fails to read the temp files. + */ +class LIBK3B_EXPORT K3bTempFile : public KTempFile +{ + public: + K3bTempFile( const QString& filePrefix = QString::null, + const QString& fileExtension = QString::null, + int mode = 0600 ); + ~K3bTempFile(); +}; + +#endif diff --git a/libk3b/tools/k3bthreadwidget.cpp b/libk3b/tools/k3bthreadwidget.cpp new file mode 100644 index 0000000..ea82101 --- /dev/null +++ b/libk3b/tools/k3bthreadwidget.cpp @@ -0,0 +1,142 @@ +/* + * + * $Id: k3bthreadwidget.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2005 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bthreadwidget.h" +#include "k3bdeviceselectiondialog.h" +#include + +#include +#include +#include + + +class K3bThreadWidget::Data +{ +public: + int id; + void* data; + QWaitCondition con; +}; + + +class K3bThreadWidget::DeviceSelectionEvent : public QCustomEvent +{ +public: + DeviceSelectionEvent( QWidget* parent, const QString& text, int id ) + : QCustomEvent( QEvent::User + 22 ), + m_parent(parent), + m_text(text), + m_id(id) { + } + + QWidget* parent() const { return m_parent; } + const QString& text() const { return m_text; } + int id() const { return m_id; } + +private: + QWidget* m_parent; + QString m_text; + int m_id; +}; + + +K3bThreadWidget* K3bThreadWidget::s_instance = 0; + + +K3bThreadWidget::K3bThreadWidget() + : QObject(), + m_idCounter(1) +{ + m_dataMap.setAutoDelete(true); + s_instance = this; +} + + +K3bThreadWidget::~K3bThreadWidget() +{ + s_instance = 0; +} + + +int K3bThreadWidget::getNewId() +{ + // create new data + Data* data = new Data; + data->id = m_idCounter++; + data->data = 0; + m_dataMap.insert( data->id, data ); + return data->id; +} + + +void K3bThreadWidget::clearId( int id ) +{ + m_dataMap.remove( id ); +} + + +K3bThreadWidget::Data* K3bThreadWidget::data( int id ) +{ + return m_dataMap[id]; +} + + +K3bThreadWidget* K3bThreadWidget::instance() +{ + if( !s_instance ) + s_instance = new K3bThreadWidget(); + return s_instance; +} + + +// static +K3bDevice::Device* K3bThreadWidget::selectDevice( QWidget* parent, + const QString& text ) +{ + // request a new data set + Data* data = K3bThreadWidget::instance()->data( K3bThreadWidget::instance()->getNewId() ); + + // inform the instance about the request + QApplication::postEvent( K3bThreadWidget::instance(), + new K3bThreadWidget::DeviceSelectionEvent( parent, text, data->id ) ); + + // wait for the result to be ready + data->con.wait(); + + K3bDevice::Device* dev = static_cast( data->data ); + + // delete the no longer needed data + K3bThreadWidget::instance()->clearId( data->id ); + + return dev; +} + + +void K3bThreadWidget::customEvent( QCustomEvent* e ) +{ + if( DeviceSelectionEvent* dse = dynamic_cast(e) ) { + // create dialog + K3bDevice::Device* dev = K3bDeviceSelectionDialog::selectDevice( dse->parent(), dse->text() ); + + // return it to the thread + Data* dat = data( dse->id() ); + dat->data = static_cast( dev ); + + // wake the thread + dat->con.wakeAll(); + } +} + +#include "k3bthreadwidget.moc" diff --git a/libk3b/tools/k3bthreadwidget.h b/libk3b/tools/k3bthreadwidget.h new file mode 100644 index 0000000..b3fedb2 --- /dev/null +++ b/libk3b/tools/k3bthreadwidget.h @@ -0,0 +1,78 @@ +/* + * + * $Id: k3bthreadwidget.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2005 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_THREAD_WIDGET_H_ +#define _K3B_THREAD_WIDGET_H_ + +#include +#include + + +class QCustomEvent; +namespace K3bDevice { + class Device; +} + +/** + * This class allows a thread other than the GUI thread to perform simple GUI + * operations. Mainly creating some simple K3b Dialogs like Device selection. + * + * Since the calling thread cannot create the K3bThreadWidget by himself there exists + * exactly one instance created by K3bCore which is used by all threads. + */ +class K3bThreadWidget : public QObject +{ + Q_OBJECT + + public: + ~K3bThreadWidget(); + + static K3bThreadWidget* instance(); + + /** + * Call this from a thread to show a device selection dialog. + */ + static K3bDevice::Device* selectDevice( QWidget* parent, + const QString& text = QString::null ); + + protected: + /** + * communication between the threads + */ + void customEvent( QCustomEvent* ); + + private: + /** + * used internally + */ + class DeviceSelectionEvent; + class Data; + + K3bThreadWidget(); + + /** + * Get unique id + */ + int getNewId(); + void clearId( int id ); + Data* data( int id ); + + int m_idCounter; + QIntDict m_dataMap; + + static K3bThreadWidget* s_instance; +}; + +#endif diff --git a/libk3b/tools/k3bthroughputestimator.cpp b/libk3b/tools/k3bthroughputestimator.cpp new file mode 100644 index 0000000..aa52478 --- /dev/null +++ b/libk3b/tools/k3bthroughputestimator.cpp @@ -0,0 +1,98 @@ +/* + * + * $Id: k3bthroughputestimator.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bthroughputestimator.h" + +#include +#include + + +class K3bThroughputEstimator::Private +{ +public: + Private() + : started(false) { + } + + QTime firstDataTime; + unsigned long firstData; + QTime lastDataTime; + unsigned long lastData; + + int lastThroughput; + + bool started; +}; + + +K3bThroughputEstimator::K3bThroughputEstimator( QObject* parent, const char* name ) + : QObject( parent, name ) +{ + d = new Private(); +} + + +K3bThroughputEstimator::~K3bThroughputEstimator() +{ + delete d; +} + + +int K3bThroughputEstimator::average() const +{ + int msecs = d->firstDataTime.msecsTo( d->lastDataTime ); + if( msecs > 0 ) + return (int)( 1000.0*(double)(d->lastData - d->firstData)/(double)msecs); + else + return 0; +} + + +void K3bThroughputEstimator::reset() +{ + d->started = false; +} + + +void K3bThroughputEstimator::dataWritten( unsigned long data ) +{ + if( !d->started ) { + d->started = true; + d->firstData = d->lastData = data; + d->firstDataTime.start(); + d->lastDataTime.start(); + d->lastThroughput = 0; + } + else if( data > d->lastData ) { + unsigned long diff = data - d->lastData; + int msecs = d->lastDataTime.elapsed(); + + //if( msecs > 0 ) { + // down the update sequence a little bit + if( msecs > 500 ) { + d->lastData = data; + d->lastDataTime.start(); + int t = (int)(1000.0*(double)diff/(double)msecs); + if( t != d->lastThroughput ) { + d->lastThroughput = t; + emit throughput( t ); + } + } + } +} + + +#include "k3bthroughputestimator.moc" diff --git a/libk3b/tools/k3bthroughputestimator.h b/libk3b/tools/k3bthroughputestimator.h new file mode 100644 index 0000000..aed71e0 --- /dev/null +++ b/libk3b/tools/k3bthroughputestimator.h @@ -0,0 +1,57 @@ +/* + * + * $Id: k3bthroughputestimator.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_THROUGHPUT_ESTIMATOR_H_ +#define _K3B_THROUGHPUT_ESTIMATOR_H_ + +#include + + +/** + * Little helper class that allows an estimation of the current writing + * speed. Just init with @p reset() then always call @p dataWritten with + * the already written data in KB. The class will emit throughput signals + * whenever the throughput changes. + */ +class K3bThroughputEstimator : public QObject +{ + Q_OBJECT + + public: + K3bThroughputEstimator( QObject* parent = 0, const char* name = 0 ); + ~K3bThroughputEstimator(); + + int average() const; + + signals: + /** + * kb/s if differs from previous + */ + void throughput( int ); + + public slots: + void reset(); + + /** + * @param data written kb + */ + void dataWritten( unsigned long data ); + + private: + class Private; + Private* d; +}; + +#endif diff --git a/libk3b/tools/k3btitlelabel.cpp b/libk3b/tools/k3btitlelabel.cpp new file mode 100644 index 0000000..9e1f18b --- /dev/null +++ b/libk3b/tools/k3btitlelabel.cpp @@ -0,0 +1,266 @@ +/* + * + * $Id: k3btitlelabel.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3btitlelabel.h" + +#include + +#include +#include +#include +#include +#include + + +class K3bTitleLabel::Private +{ +public: + Private() { + titleLength = subTitleLength = 0; + margin = 2; + alignment = Qt::AlignLeft; + cachedMinimumWidth = 0; + titleBaseLine = 0; + } + + QString title; + QString subTitle; + + QString displayTitle; + QString displaySubTitle; + + int alignment; + + int titleLength; + int subTitleLength; + int displayTitleLength; + int displaySubTitleLength; + int titleBaseLine; + int subTitleBaseLine; + int margin; + + int cachedMinimumWidth; +}; + + +class K3bTitleLabel::ToolTip : public QToolTip +{ +public: + ToolTip( K3bTitleLabel* label ) + : QToolTip( label ), + m_label(label) { + } + + void maybeTip( const QPoint &pos ) { + QRect r = m_label->contentsRect(); + + int neededWidth = m_label->d->displayTitleLength; + if( !m_label->d->displaySubTitle.isEmpty() ) + neededWidth += m_label->d->displaySubTitleLength + 5; + + int startPos = 0; + if( m_label->d->alignment & Qt::AlignHCenter ) + startPos = r.left() + ( r.width() - 2*m_label->d->margin - neededWidth ) / 2; + else if( m_label->d->alignment & Qt::AlignRight ) + startPos = r.right() - m_label->d->margin - neededWidth; + else + startPos = r.left() + m_label->d->margin; + + QRect titleTipRect( startPos, 0, m_label->d->displayTitleLength, m_label->height() ); + QRect subTitleTipRect( startPos + m_label->d->displayTitleLength, 0, m_label->d->displaySubTitleLength, m_label->height() ); + + if( titleTipRect.contains( pos ) && + m_label->d->displayTitle != m_label->d->title ) + tip( titleTipRect, m_label->d->title ); + else if( subTitleTipRect.contains( pos ) && + m_label->d->displaySubTitle != m_label->d->subTitle ) + tip( subTitleTipRect, m_label->d->subTitle ); + } + + K3bTitleLabel* m_label; +}; + + + +K3bTitleLabel::K3bTitleLabel( QWidget* parent, const char* name ) + : QFrame( parent, name ) +{ + d = new Private(); + m_toolTip = new ToolTip( this ); +} + + +K3bTitleLabel::~K3bTitleLabel() +{ + delete m_toolTip; + delete d; +} + + +void K3bTitleLabel::setTitle( const QString& title, const QString& subTitle ) +{ + d->title = title; + d->subTitle = subTitle; + updatePositioning(); + update(); +} + + +void K3bTitleLabel::setSubTitle( const QString& subTitle ) +{ + d->subTitle = subTitle; + updatePositioning(); + update(); +} + + +void K3bTitleLabel::setAlignment( int align ) +{ + d->alignment = align; + update(); +} + + +QSize K3bTitleLabel::sizeHint() const +{ + return QSize( d->titleLength + d->subTitleLength + 2*d->margin, d->titleBaseLine ); +} + +QSize K3bTitleLabel::minimumSizeHint() const +{ + return QSize( d->cachedMinimumWidth, d->titleBaseLine ); +} + +void K3bTitleLabel::resizeEvent( QResizeEvent* e ) +{ + QFrame::resizeEvent( e ); + updatePositioning(); + update(); +} + +void K3bTitleLabel::drawContents( QPainter* p ) +{ + p->save(); + + QRect r = contentsRect(); + p->eraseRect( r ); + + QFont f(font()); + f.setBold(true); + f.setPointSize( f.pointSize() + 2 ); + + p->setFont(f); + + int neededWidth = d->displayTitleLength; + if( !d->displaySubTitle.isEmpty() ) + neededWidth += d->displaySubTitleLength + 5; + + int startPos = 0; + if( d->alignment & Qt::AlignHCenter ) + startPos = r.left() + ( r.width() - 2*d->margin - neededWidth ) / 2; + else if( d->alignment & Qt::AlignRight ) + startPos = r.right() - d->margin - neededWidth; + else + startPos = r.left() + d->margin; + + // paint title + p->drawText( startPos, r.top() + d->titleBaseLine, d->displayTitle ); + + if( !d->subTitle.isEmpty() ) { + f.setBold(false); + f.setPointSize( f.pointSize() - 4 ); + p->setFont(f); + p->drawText( startPos + d->displayTitleLength + 5, r.top() + d->subTitleBaseLine, d->displaySubTitle ); + } + + p->restore(); +} + + +void K3bTitleLabel::setMargin( int m ) +{ + d->margin = m; + updatePositioning(); + update(); +} + + +void K3bTitleLabel::updatePositioning() +{ + QFont f(font()); + f.setBold(true); + f.setPointSize( f.pointSize() + 2 ); + QFontMetrics titleFm(f); + + f.setBold(false); + f.setPointSize( f.pointSize() - 4 ); + QFontMetrics subTitleFm(f); + + d->titleBaseLine = contentsRect().height()/2 + titleFm.height()/2 - titleFm.descent(); + d->titleLength = titleFm.width( d->title ); + + d->subTitleBaseLine = d->titleBaseLine - titleFm.underlinePos() + subTitleFm.underlinePos(); + + d->subTitleLength = ( d->subTitle.isEmpty() ? 0 : subTitleFm.width( d->subTitle ) ); + + // cut the text to window width + d->displayTitle = d->title; + d->displaySubTitle = d->subTitle; + int widthAvail = contentsRect().width() - 2*margin(); + + // 5 pix spacing between title and subtitle + if( !d->subTitle.isEmpty() ) + widthAvail -= 5; + + if( d->titleLength > widthAvail/2 ) { + if( d->subTitleLength <= widthAvail/2 ) + d->displayTitle = K3b::cutToWidth( titleFm, d->title, widthAvail - d->subTitleLength ); + else + d->displayTitle = K3b::cutToWidth( titleFm, d->title, widthAvail/2 ); + } + if( d->subTitleLength > widthAvail/2 ) { + if( d->titleLength <= widthAvail/2 ) + d->displaySubTitle = K3b::cutToWidth( subTitleFm, d->subTitle, widthAvail - d->titleLength ); + else + d->displaySubTitle = K3b::cutToWidth( subTitleFm, d->subTitle, widthAvail/2 ); + } + + d->displayTitleLength = titleFm.width( d->displayTitle ); + d->displaySubTitleLength = subTitleFm.width( d->displaySubTitle ); + + + // + // determine the minimum width for the minumum size hint + // + d->cachedMinimumWidth = 2*d->margin; + + QString cutTitle = d->title; + if( cutTitle.length() > 2 ) { + cutTitle.truncate( 2 ); + cutTitle += "..."; + } + QString cutSubTitle = d->subTitle; + if( cutSubTitle.length() > 2 ) { + cutSubTitle.truncate( 2 ); + cutSubTitle += "..."; + } + + d->cachedMinimumWidth += titleFm.width( cutTitle ) + subTitleFm.width( cutSubTitle ); + // 5 pix spacing between title and subtitle + if( !d->subTitle.isEmpty() ) + d->cachedMinimumWidth += 5; +} + +#include "k3btitlelabel.moc" diff --git a/libk3b/tools/k3btitlelabel.h b/libk3b/tools/k3btitlelabel.h new file mode 100644 index 0000000..ba1044d --- /dev/null +++ b/libk3b/tools/k3btitlelabel.h @@ -0,0 +1,68 @@ +/* + * + * $Id: k3btitlelabel.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_TITLE_LABEL_H_ +#define _K3B_TITLE_LABEL_H_ + +#include +#include "k3b_export.h" +class QPainter; +class QResizeEvent; + + +class LIBK3B_EXPORT K3bTitleLabel : public QFrame +{ + Q_OBJECT + + public: + K3bTitleLabel( QWidget* parent = 0, const char* name = 0 ); + ~K3bTitleLabel(); + + QSize sizeHint() const; + QSize minimumSizeHint() const; + + public slots: + /** + * default: 2 + */ + void setMargin( int ); + + void setTitle( const QString& title, const QString& subTitle = QString::null ); + void setSubTitle( const QString& subTitle ); + + /** + * The title label only supports alignments left, hcenter, and right + * + * Default alignment is left. + */ + // FIXME: honor right-to-left languages + void setAlignment( int align ); + + protected: + void resizeEvent( QResizeEvent* ); + void drawContents( QPainter* p ); + + private: + void updatePositioning(); + + class ToolTip; + ToolTip* m_toolTip; + + class Private; + Private* d; +}; + +#endif diff --git a/libk3b/tools/k3btoolbox.cpp b/libk3b/tools/k3btoolbox.cpp new file mode 100644 index 0000000..b08dfc8 --- /dev/null +++ b/libk3b/tools/k3btoolbox.cpp @@ -0,0 +1,293 @@ +/* + * + * $Id$ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3btoolbox.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/** + * internal class. Do not use! + */ +class K3bToolBoxSeparator : public QWidget +{ + // Q_OBJECT + + public: + K3bToolBoxSeparator( K3bToolBox* parent ); + + QSize sizeHint() const; + + protected: + void paintEvent( QPaintEvent * ); +}; + + +K3bToolBoxSeparator::K3bToolBoxSeparator( K3bToolBox* parent ) + : QWidget( parent ) +{ + setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Minimum ) ); +} + + +QSize K3bToolBoxSeparator::sizeHint() const +{ + int extent = style().pixelMetric( QStyle::PM_DockWindowSeparatorExtent, + this ); + return QSize( extent, 0 ); +} + + +void K3bToolBoxSeparator::paintEvent( QPaintEvent* ) +{ + QPainter p( this ); + QStyle::SFlags flags = QStyle::Style_Default|QStyle::Style_Horizontal; + + style().drawPrimitive( QStyle::PE_DockWindowSeparator, &p, rect(), + colorGroup(), flags ); +} + + + +K3bToolBoxButton::K3bToolBoxButton( KAction* action, QWidget* parent ) + : QToolButton( parent ), + m_popupMenu(0) +{ + setSizePolicy( QSizePolicy(QSizePolicy::Fixed, sizePolicy().verData()) ); + setAutoRaise( true ); + + setIconSet( action->iconSet() ); + setTextLabel( action->text() ); + setEnabled( action->isEnabled() ); + + QWhatsThis::add( this, action->whatsThis() ); + if( action->toolTip().isEmpty() ) + QToolTip::add( this, action->text() ); + else + QToolTip::add( this, action->toolTip() ); + +// if( KToggleAction* ta = dynamic_cast( action ) ) { +// setToggleButton( true ); + +// // initial state +// if( ta->isChecked() ) +// toggle(); + +// connect( ta, SIGNAL(toggled(bool)), this, SLOT(toggle()) ); +// connect( this, SIGNAL(toggled(bool)), ta, SLOT(setChecked(bool)) ); +// } + +// else + if( KActionMenu* am = dynamic_cast( action ) ) { + m_popupMenu = am->popupMenu(); + connect( this, SIGNAL(pressed()), this, SLOT(slotPopupActivated()) ); + setPopup( m_popupMenu ); + } + + else { + connect( this, SIGNAL(clicked()), action, SLOT(activate()) ); + } + + connect( action, SIGNAL(enabled(bool)), this, SLOT(setEnabled(bool)) ); +} + + +K3bToolBoxButton::K3bToolBoxButton( const QString& text, const QString& icon, + const QString& tooltip, const QString& whatsthis, + QObject* receiver, const char* slot, + QWidget* parent ) + : QToolButton( parent ), + m_popupMenu(0) +{ + setSizePolicy( QSizePolicy(QSizePolicy::Fixed, sizePolicy().verData()) ); + setAutoRaise( true ); + + setTextLabel( text ); + + if( icon.isEmpty() ) + setUsesTextLabel( true ); + else + setIconSet( SmallIconSet( icon ) ); + + QWhatsThis::add( this, whatsthis ); + QToolTip::add( this, tooltip ); + + if( receiver && slot ) + connect( this, SIGNAL(clicked()), receiver, slot ); +} + + +void K3bToolBoxButton::slotPopupActivated() +{ + // force the toolbutton to open the popupmenu instantly + openPopup(); +} + + +void K3bToolBoxButton::resizeEvent( QResizeEvent* e ) +{ + QToolButton::resizeEvent( e ); + + // force icon-only buttons to be square + if( e->oldSize().height() != e->size().height() && + !usesTextLabel() ) + setFixedWidth( e->size().height() ); +} + + + + + + + +K3bToolBox::K3bToolBox( QWidget* parent, const char* name ) + : QFrame( parent, name ) +{ + setSizePolicy( QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed) ); + + m_mainLayout = new QGridLayout( this ); + m_mainLayout->setMargin( 1 ); + m_mainLayout->setSpacing( 0 ); +} + + +K3bToolBox::~K3bToolBox() +{ + clear(); +} + + +K3bToolBoxButton* K3bToolBox::addButton( KAction* action, bool forceText ) +{ + if( action ) { + K3bToolBoxButton* b = new K3bToolBoxButton( action, this ); + if( forceText ) { + b->setUsesTextLabel( true ); + b->setTextPosition( QToolButton::BesideIcon ); + } + addWidget( b ); + return b; + } + else + return 0; +} + + +K3bToolBoxButton* K3bToolBox::addButton( const QString& text, const QString& icon, + const QString& tooltip, const QString& whatsthis, + QObject* receiver, const char* slot, + bool forceText ) +{ + K3bToolBoxButton* b = new K3bToolBoxButton( text, icon, tooltip, whatsthis, receiver, slot, this ); + if( forceText ) { + b->setUsesTextLabel( true ); + b->setTextPosition( QToolButton::BesideIcon ); + } + addWidget( b ); + return b; +} + + +void K3bToolBox::addSpacing() +{ + int lastStretch = m_mainLayout->colStretch( m_mainLayout->numCols()-1 ); + m_mainLayout->setColStretch( m_mainLayout->numCols()-1, 0 ); + m_mainLayout->addColSpacing( m_mainLayout->numCols()-1, 8 ); + m_mainLayout->setColStretch( m_mainLayout->numCols(), lastStretch ); +} + + +void K3bToolBox::addSeparator() +{ + K3bToolBoxSeparator* s = new K3bToolBoxSeparator( this ); + addWidget( s ); +} + + +void K3bToolBox::addStretch() +{ + // add an empty widget + addWidget( new QWidget( this ) ); + m_mainLayout->setColStretch( m_mainLayout->numCols(), 1 ); +} + + +void K3bToolBox::addLabel( const QString& text ) +{ + QLabel* label = new QLabel( text, this ); + label->setSizePolicy( QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed) ); + + addWidget( label ); +} + + +void K3bToolBox::addWidget( QWidget* w ) +{ + w->reparent( this, QPoint() ); + + m_mainLayout->setColStretch( m_mainLayout->numCols()-1, 0 ); + + m_mainLayout->addWidget( w, 0, m_mainLayout->numCols()-1 ); + + if( w->sizePolicy().horData() == QSizePolicy::Fixed || w->sizePolicy().horData() == QSizePolicy::Maximum ) + m_mainLayout->setColStretch( m_mainLayout->numCols(), 1 ); + else { + m_mainLayout->setColStretch( m_mainLayout->numCols()-1, 1 ); + m_mainLayout->setColStretch( m_mainLayout->numCols(), 0 ); + } +} + + +K3bToolBoxButton* K3bToolBox::addToggleButton( KToggleAction* action ) +{ + return addButton( action ); +} + + +void K3bToolBox::addWidgetAction( KWidgetAction* action ) +{ + addWidget( action->widget() ); + m_doNotDeleteWidgets.append( action->widget() ); +} + + +void K3bToolBox::clear() +{ + // we do not want to delete the widgets from the widgetactions becasue they + // might be used afterwards + for( QPtrListIterator it( m_doNotDeleteWidgets ); it.current(); ++it ) + it.current()->reparent( 0L, QPoint() ); + + for( QObjectListIterator it2( *children() ); it2.current(); ++it2 ) + if( it2.current()->isWidgetType() ) + delete it2.current(); +} + +#include "k3btoolbox.moc" diff --git a/libk3b/tools/k3btoolbox.h b/libk3b/tools/k3btoolbox.h new file mode 100644 index 0000000..828fca1 --- /dev/null +++ b/libk3b/tools/k3btoolbox.h @@ -0,0 +1,93 @@ +/* + * + * $Id$ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef K3B_TOOLBOX_H +#define K3B_TOOLBOX_H + +#include +#include +#include +#include +#include "k3b_export.h" + +class KAction; +class KToggleAction; +class KWidgetAction; +class QGridLayout; +class QPopupMenu; +class QResizeEvent; + + +/** + * internal class. Do not use! + */ +class LIBK3B_EXPORT K3bToolBoxButton : public QToolButton +{ + Q_OBJECT + + public: + K3bToolBoxButton( KAction*, QWidget* parent ); + K3bToolBoxButton( const QString& text, const QString& icon, + const QString& tooltip, const QString& whatsthis, + QObject* receiver, const char* slot, + QWidget* parent ); + + private slots: + void slotPopupActivated(); + + protected: + void resizeEvent( QResizeEvent* ); + + private: + QPopupMenu* m_popupMenu; +}; + + +class LIBK3B_EXPORT K3bToolBox : public QFrame +{ + Q_OBJECT + + public: + K3bToolBox( QWidget* parent = 0, const char* name = 0 ); + ~K3bToolBox(); + + K3bToolBoxButton* addButton( const QString& text, const QString& icon, + const QString& tooltip = QString::null, const QString& whatsthis = QString::null, + QObject* receiver = 0, const char* slot = 0, + bool forceTextLabel = false ); + K3bToolBoxButton* addButton( KAction*, bool forceTextLabel = false ); + K3bToolBoxButton* addToggleButton( KToggleAction* ); + void addWidgetAction( KWidgetAction* ); + + /** + * Be aware that the toolbox will take ownership of the widget + * and destroy it on destruction. Becasue of this it is not fitted + * for WidgetActions. + */ + void addWidget( QWidget* ); + void addLabel( const QString& ); + void addSpacing(); + void addSeparator(); + void addStretch(); + + void clear(); + + protected: + QGridLayout* m_mainLayout; + QPtrList m_doNotDeleteWidgets; +}; + + +#endif diff --git a/libk3b/tools/k3btoolbutton.cpp b/libk3b/tools/k3btoolbutton.cpp new file mode 100644 index 0000000..2e3e468 --- /dev/null +++ b/libk3b/tools/k3btoolbutton.cpp @@ -0,0 +1,109 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3btoolbutton.h" + +#include +#include +#include + +#include +#include + + +class K3bToolButton::Private +{ +public: + QPoint mousePressPos; + bool instantMenu; +}; + + +K3bToolButton::K3bToolButton( QWidget* parent ) + : QToolButton( parent ) +{ + d = new Private; + d->instantMenu = false; + installEventFilter(this); +} + + +K3bToolButton::~K3bToolButton() +{ + delete d; +} + + +void K3bToolButton::setInstantMenu( bool b ) +{ + d->instantMenu = b; +} + + +void K3bToolButton::drawButton( QPainter* p ) +{ + QToolButton::drawButton( p ); + + // + // code below comes from ktoolbarbutton.cpp from the kdelibs sources + // see the file for copyright information + // + if( QToolButton::popup() ) { + QStyle::SFlags arrowFlags = QStyle::Style_Default; + + if( isDown() ) + arrowFlags |= QStyle::Style_Down; + if( isEnabled() ) + arrowFlags |= QStyle::Style_Enabled; + + style().drawPrimitive(QStyle::PE_ArrowDown, p, + QRect(width()-7, height()-7, 7, 7), colorGroup(), + arrowFlags, QStyleOption() ); + } +} + + +bool K3bToolButton::eventFilter( QObject* o, QEvent* ev ) +{ + if( dynamic_cast(o) == this ) { + + // Popup the menu when the left mousebutton is pressed and the mouse + // is moved by a small distance. + if( QToolButton::popup() ) { + if( ev->type() == QEvent::MouseButtonPress ) { + QMouseEvent* mev = static_cast(ev); + + if( d->instantMenu ) { + setDown(true); + openPopup(); + return true; + } + else { + d->mousePressPos = mev->pos(); + } + } + else if( ev->type() == QEvent::MouseMove ) { + QMouseEvent* mev = static_cast(ev); + if( !d->instantMenu && + ( mev->pos() - d->mousePressPos).manhattanLength() > KGlobalSettings::dndEventDelay() ) { + openPopup(); + return true; + } + } + } + } + + return QToolButton::eventFilter( o, ev ); +} diff --git a/libk3b/tools/k3btoolbutton.h b/libk3b/tools/k3btoolbutton.h new file mode 100644 index 0000000..fe96e4c --- /dev/null +++ b/libk3b/tools/k3btoolbutton.h @@ -0,0 +1,50 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_TOOL_BUTTON_H_ +#define _K3B_TOOL_BUTTON_H_ + +#include "k3b_export.h" + +#include + +class QPainter; +class QEvent; + + +/** + * the K3bToolButton is an enhanced QToolButton which adds two functionalities: + *

  • A delayed popup menu is shown immiadetely once the mouse is dragged downwards + * much like the KToolBarButton + *
  • If a popup menu is set a little arrow indicates this. + */ +class LIBK3B_EXPORT K3bToolButton : public QToolButton +{ + public: + K3bToolButton( QWidget* parent = 0 ); + ~K3bToolButton(); + + void setInstantMenu( bool ); + + protected: + virtual void drawButton( QPainter* ); + virtual bool eventFilter( QObject*, QEvent* ); + + private: + class Private; + Private* d; +}; + +#endif diff --git a/libk3b/tools/k3bvalidators.cpp b/libk3b/tools/k3bvalidators.cpp new file mode 100644 index 0000000..9252fdd --- /dev/null +++ b/libk3b/tools/k3bvalidators.cpp @@ -0,0 +1,154 @@ +/* + * + * $Id: k3bvalidators.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bvalidators.h" + +#include + + +K3bCharValidator::K3bCharValidator( QObject* parent, const char* name ) + : QValidator( parent, name ), + m_replaceChar( '_' ) +{ +} + + +QValidator::State K3bCharValidator::validate( QString& s, int& pos ) const +{ + Q_UNUSED(pos); + + for( unsigned int i = 0; i < s.length(); ++i ) { + State r = validateChar( s[i] ); + if( r != Acceptable ) + return r; + } + + return Acceptable; +} + + +void K3bCharValidator::fixup( QString& s ) const +{ + for( unsigned int i = 0; i < s.length(); ++i ) { + if( validateChar( s[i] ) != Acceptable ) + s[i] = m_replaceChar; + } +} + + +K3bLatin1Validator::K3bLatin1Validator( QObject* parent, const char* name ) + : K3bCharValidator( parent, name ) +{ +} + + +QValidator::State K3bLatin1Validator::validateChar( const QChar& c ) const +{ + if( !c.latin1() ) + return Invalid; + else + return Acceptable; +} + + +K3bAsciiValidator::K3bAsciiValidator( QObject* parent, const char* name ) + : K3bLatin1Validator( parent, name ) +{ +} + + +QValidator::State K3bAsciiValidator::validateChar( const QChar& c ) const +{ + if( K3bLatin1Validator::validateChar( c ) == Invalid ) + return Invalid; + else if( !isascii( c.latin1() ) ) + return Invalid; + else + return Acceptable; +} + + + +K3bValidator::K3bValidator( QObject* parent, const char* name ) + : QRegExpValidator( parent, name ), + m_replaceChar('_') +{ +} + + +K3bValidator::K3bValidator( const QRegExp& rx, QObject* parent, const char* name ) + : QRegExpValidator( rx, parent, name ), + m_replaceChar('_') +{ +} + + +void K3bValidator::fixup( QString& input ) const +{ + for( unsigned int i = 0; i < input.length(); ++i ) + if( !regExp().exactMatch( input.mid(i, 1) ) ) + input[i] = m_replaceChar; +} + + +QString K3bValidators::fixup( const QString& input, const QRegExp& rx, const QChar& replaceChar ) +{ + QString s; + for( unsigned int i = 0; i < input.length(); ++i ) + if( rx.exactMatch( input.mid(i, 1) ) ) + s += input[i]; + else + s += replaceChar; + return s; +} + + +K3bValidator* K3bValidators::isrcValidator( QObject* parent, const char* name ) +{ + return new K3bValidator( QRegExp("^[A-Z\\d]{2,2}-[A-Z\\d]{3,3}-\\d{2,2}-\\d{5,5}$"), parent, name ); +} + + +K3bValidator* K3bValidators::iso9660Validator( bool allowEmpty, QObject* parent, const char* name ) +{ + if( allowEmpty ) + return new K3bValidator( QRegExp( "[^/]*" ), parent, name ); + else + return new K3bValidator( QRegExp( "[^/]+" ), parent, name ); +} + + +K3bValidator* K3bValidators::iso646Validator( int type, bool AllowLowerCase, QObject* parent, const char* name ) +{ + QRegExp rx; + switch ( type ) { + case Iso646_d: + if ( AllowLowerCase ) + rx = QRegExp( "[a-zA-Z0-9_]*" ); + else + rx = QRegExp( "[A-Z0-9_]*" ); + break; + case Iso646_a: + default: + if ( AllowLowerCase ) + rx = QRegExp( "[a-zA-Z0-9!\"\\s%&'\\(\\)\\*\\+,\\-\\./:;<=>\\?_]*" ); + else + rx = QRegExp( "[A-Z0-9!\"\\s%&'\\(\\)\\*\\+,\\-\\./:;<=>\\?_]*" ); + break; + } + + return new K3bValidator( rx, parent, name ); +} diff --git a/libk3b/tools/k3bvalidators.h b/libk3b/tools/k3bvalidators.h new file mode 100644 index 0000000..89c6397 --- /dev/null +++ b/libk3b/tools/k3bvalidators.h @@ -0,0 +1,131 @@ +/* + * + * $Id: k3bvalidators.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_VALIDATORS_H_ +#define _K3B_VALIDATORS_H_ + +#include +#include "k3b_export.h" + + +/** + * Simple validator that validates a string char by char + */ +class LIBK3B_EXPORT K3bCharValidator : public QValidator +{ + public: + K3bCharValidator( QObject* parent = 0, const char* name = 0 ); + + virtual State validateChar( const QChar& ) const = 0; + + virtual State validate( QString& s, int& pos ) const; + + /** + * Replaces all invalid chars with the repplace char + */ + virtual void fixup( QString& ) const; + + /** + * Default to '_' + */ + void setReplaceChar( const QChar& c ) { m_replaceChar = c; } + + private: + QChar m_replaceChar; +}; + + +class LIBK3B_EXPORT K3bLatin1Validator : public K3bCharValidator +{ + public: + K3bLatin1Validator( QObject* parent = 0, const char* name = 0 ); + + virtual State validateChar( const QChar& ) const; +}; + + +class LIBK3B_EXPORT K3bAsciiValidator : public K3bLatin1Validator +{ + public: + K3bAsciiValidator( QObject* parent = 0, const char* name = 0 ); + + virtual State validateChar( const QChar& ) const; +}; + + +/** + * The K3bValidator extends QRegExpValidator with a fixup method + * that just replaces all characters that are not allowed with the + * replace character. It only makes sense for QRegExps that simply + * allow or forbid some characters. + */ +class LIBK3B_EXPORT K3bValidator : public QRegExpValidator +{ + public: + K3bValidator( QObject* parent, const char * name = 0 ); + K3bValidator( const QRegExp& rx, QObject* parent, const char* name = 0 ); + + void setReplaceChar( const QChar& s ) { m_replaceChar = s; } + const QChar& replaceChar() const { return m_replaceChar; } + + virtual void fixup( QString& ) const; + + private: + QChar m_replaceChar; +}; + + +namespace K3bValidators +{ + /** + * just replaces all characters that are not allowed with the + * replace character. It only makes sense for QRegExps that simply + * allow or forbid some characters. + */ + LIBK3B_EXPORT QString fixup( const QString&, const QRegExp&, const QChar& replaceChar = '_' ); + + /** + * Validates an ISRC code of the form "CCOOOYYSSSSS" where: + *
      + *
    • C: country code (upper case letters or digits)
    • + *
    • O: owner code (upper case letters or digits)
    • + *
    • Y: year (digits)
    • + *
    • S: serial number (digits)
    • + *
    + */ + LIBK3B_EXPORT K3bValidator* isrcValidator( QObject* parent = 0, const char* name = 0 ); + + /** + * This needs to be replaced by something better in the future... + * Even the name sucks! + */ + LIBK3B_EXPORT K3bValidator* iso9660Validator( bool allowEmpty = true, QObject* parent = 0, const char* name = 0 ); + + /** + * (1) d-characters are: A-Z, 0-9, _ (see ISO-9660:1988, Annex A, Table 15) + * (2) a-characters are: A-Z, 0-9, _, space, !, ", %, &, ', (, ), *, +, ,, -, ., /, :, ;, <, =, >, ? + * (see ISO-9660:1988, Annex A, Table 14) + */ + enum Iso646Type { + Iso646_a, + Iso646_d + }; + + LIBK3B_EXPORT K3bValidator* iso646Validator( int type = Iso646_a, + bool AllowLowerCase = false, + QObject* parent = 0, const char* name = 0 ); +} + +#endif diff --git a/libk3b/tools/k3bwavefilewriter.cpp b/libk3b/tools/k3bwavefilewriter.cpp new file mode 100644 index 0000000..36267c2 --- /dev/null +++ b/libk3b/tools/k3bwavefilewriter.cpp @@ -0,0 +1,186 @@ +/* + * + * $Id: k3bwavefilewriter.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bwavefilewriter.h" +#include + +K3bWaveFileWriter::K3bWaveFileWriter() + : m_outputStream( &m_outputFile ) +{ +} + + +K3bWaveFileWriter::~K3bWaveFileWriter() +{ + close(); +} + + +bool K3bWaveFileWriter::open( const QString& filename ) +{ + close(); + + m_outputFile.setName( filename ); + + if( m_outputFile.open( IO_ReadWrite ) ) { + m_filename = filename; + + writeEmptyHeader(); + + return true; + } + else { + return false; + } +} + + +void K3bWaveFileWriter::close() +{ + if( isOpen() ) { + if( m_outputFile.at() > 0 ) { + padTo2352(); + + // update wave header + updateHeader(); + + m_outputFile.close(); + } + else { + m_outputFile.close(); + m_outputFile.remove(); + } + } + + m_filename = QString::null; +} + + +bool K3bWaveFileWriter::isOpen() +{ + return m_outputFile.isOpen(); +} + + +const QString& K3bWaveFileWriter::filename() const +{ + return m_filename; +} + + +void K3bWaveFileWriter::write( const char* data, int len, Endianess e ) +{ + if( isOpen() ) { + if( e == LittleEndian ) { + m_outputStream.writeRawBytes( data, len ); + } + else { + if( len % 2 > 0 ) { + kdDebug() << "(K3bWaveFileWriter) data length (" + << len << ") is not a multiple of 2! Cannot swap bytes." << endl; + return; + } + + // we need to swap the bytes + char* buffer = new char[len]; + for( int i = 0; i < len-1; i+=2 ) { + buffer[i] = data[i+1]; + buffer[i+1] = data[i]; + } + m_outputStream.writeRawBytes( buffer, len ); + + delete [] buffer; + } + } +} + + +void K3bWaveFileWriter::writeEmptyHeader() +{ + static const char riffHeader[] = + { + 0x52, 0x49, 0x46, 0x46, // 0 "RIFF" + 0x00, 0x00, 0x00, 0x00, // 4 wavSize + 0x57, 0x41, 0x56, 0x45, // 8 "WAVE" + 0x66, 0x6d, 0x74, 0x20, // 12 "fmt " + 0x10, 0x00, 0x00, 0x00, // 16 + 0x01, 0x00, 0x02, 0x00, // 20 + 0x44, 0xac, 0x00, 0x00, // 24 + 0x10, 0xb1, 0x02, 0x00, // 28 + 0x04, 0x00, 0x10, 0x00, // 32 + 0x64, 0x61, 0x74, 0x61, // 36 "data" + 0x00, 0x00, 0x00, 0x00 // 40 byteCount + }; + + m_outputStream.writeRawBytes( riffHeader, 44 ); +} + + +void K3bWaveFileWriter::updateHeader() +{ + if( isOpen() ) { + + m_outputFile.flush(); + + Q_INT32 dataSize( m_outputFile.at() - 44 ); + Q_INT32 wavSize(dataSize + 44 - 8); + char c[4]; + + // jump to the wavSize position in the header + if( m_outputFile.at( 4 ) ) { + c[0] = (wavSize >> 0 ) & 0xff; + c[1] = (wavSize >> 8 ) & 0xff; + c[2] = (wavSize >> 16) & 0xff; + c[3] = (wavSize >> 24) & 0xff; + m_outputStream.writeRawBytes( c, 4 ); + } + else + kdDebug() << "(K3bWaveFileWriter) unable to seek in file: " << m_outputFile.name() << endl; + + if( m_outputFile.at( 40 ) ) { + c[0] = (dataSize >> 0 ) & 0xff; + c[1] = (dataSize >> 8 ) & 0xff; + c[2] = (dataSize >> 16) & 0xff; + c[3] = (dataSize >> 24) & 0xff; + m_outputStream.writeRawBytes( c, 4 ); + } + else + kdDebug() << "(K3bWaveFileWriter) unable to seek in file: " << m_outputFile.name() << endl; + + // jump back to the end + m_outputFile.at( m_outputFile.size() ); + } +} + + +void K3bWaveFileWriter::padTo2352() +{ + int bytesToPad = ( m_outputFile.at() - 44 ) % 2352; + if( bytesToPad > 0 ) { + kdDebug() << "(K3bWaveFileWriter) padding wave file with " << bytesToPad << " bytes." << endl; + + char* c = new char[bytesToPad]; + memset( c, 0, bytesToPad ); + m_outputStream.writeRawBytes( c, bytesToPad ); + delete [] c; + } +} + + +int K3bWaveFileWriter::fd() const +{ + return m_outputFile.handle(); +} diff --git a/libk3b/tools/k3bwavefilewriter.h b/libk3b/tools/k3bwavefilewriter.h new file mode 100644 index 0000000..e5394a5 --- /dev/null +++ b/libk3b/tools/k3bwavefilewriter.h @@ -0,0 +1,78 @@ +/* + * + * $Id: k3bwavefilewriter.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BWAVEFILEWRITER_H +#define K3BWAVEFILEWRITER_H + +#include +#include +#include +#include "k3b_export.h" +/** + * @author Sebastian Trueg + * Creates wave files from 16bit stereo little or big endian + * sound samples + */ +class LIBK3B_EXPORT K3bWaveFileWriter +{ + public: + + enum Endianess { BigEndian, LittleEndian }; + + K3bWaveFileWriter(); + ~K3bWaveFileWriter(); + + /** + * open a new wave file. + * closes any opened file. + */ + bool open( const QString& filename ); + + bool isOpen(); + const QString& filename() const; + + /** + * closes the file. + * Length of the wave file will be written into the header. + * If no data has been written to the file except the header + * it will be removed. + */ + void close(); + + /** + * write 16bit samples to the file. + * @param e the endianess of the data + * (it will be swapped to little endian byte order if necessary) + */ + void write( const char* data, int len, Endianess e = BigEndian ); + + /** + * returnes a filedescriptor with the already opened file + * or -1 if isOpen() is false + */ + int fd() const; + + private: + void writeEmptyHeader(); + void updateHeader(); + void padTo2352(); + + QFile m_outputFile; + QDataStream m_outputStream; + QString m_filename; +}; + +#endif diff --git a/libk3b/tools/kcutlabel.cpp b/libk3b/tools/kcutlabel.cpp new file mode 100644 index 0000000..accbe17 --- /dev/null +++ b/libk3b/tools/kcutlabel.cpp @@ -0,0 +1,115 @@ +/* + * + * $Id: kcutlabel.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "kcutlabel.h" + +#include + +#include +#include +#include + + +KCutLabel::KCutLabel( const QString &text , QWidget *parent, const char *name ) + : QLabel ( parent, name ), + m_minChars(1) { + QSizePolicy myLabelSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ); + setSizePolicy(myLabelSizePolicy); + m_fullText = text; + cutTextToLabel(); +} + +KCutLabel::KCutLabel( QWidget *parent, const char *name ) + : QLabel ( parent, name ), + m_minChars(1) { + QSizePolicy myLabelSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ); + setSizePolicy(myLabelSizePolicy); +} + +QSize KCutLabel::minimumSizeHint() const +{ + QSize sh = QLabel::minimumSizeHint(); + if( m_minChars == 0 ) + sh.setWidth(-1); + else if( m_minChars < (int)m_fullText.length() ) + sh.setWidth( QMIN( fontMetrics().width( m_fullText.left(m_minChars) + "..." ), + fontMetrics().width( m_fullText ) ) ); + + return sh; +} + + +void KCutLabel::setMinimumVisibleText( int i ) +{ + m_minChars = i; + cutTextToLabel(); +} + + +void KCutLabel::resizeEvent( QResizeEvent * ) +{ + cutTextToLabel(); +} + +void KCutLabel::setText( const QString &text ) +{ + m_fullText = text; + cutTextToLabel(); +} + + +const QString& KCutLabel::fullText() const +{ + return m_fullText; +} + + +void KCutLabel::cutTextToLabel() +{ + QToolTip::remove( this ); + QToolTip::hide(); + + if( m_fullText.contains( "\n" ) ) { + QString newText; + QStringList lines = QStringList::split( "\n", m_fullText ); + for( QStringList::Iterator it = lines.begin(); it != lines.end(); ++it ) { + QString squeezedText = K3b::cutToWidth( fontMetrics(), + *it, + QMAX( size().width(), + QMIN( fontMetrics().width( m_fullText.left(m_minChars) + "..." ), + fontMetrics().width( m_fullText ) ) ) ); + newText += squeezedText; + newText += "\n"; + if( squeezedText != *it ) + QToolTip::add( this, m_fullText ); + } + newText.truncate( newText.length() - 1 ); // get rid of the last newline + + QLabel::setText( newText ); + } + else { + QString squeezedText = K3b::cutToWidth( fontMetrics(), + m_fullText, + QMAX( size().width(), + QMIN( fontMetrics().width( m_fullText.left(m_minChars) + "..." ), + fontMetrics().width( m_fullText ) ) ) ); + QLabel::setText( squeezedText ); + if( squeezedText != m_fullText ) + QToolTip::add( this, m_fullText ); + } +} + +#include "kcutlabel.moc" diff --git a/libk3b/tools/kcutlabel.h b/libk3b/tools/kcutlabel.h new file mode 100644 index 0000000..6cf459c --- /dev/null +++ b/libk3b/tools/kcutlabel.h @@ -0,0 +1,68 @@ +/* + * + * $Id: kcutlabel.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef KCUTLABEL_H +#define KCUTLABEL_H + +#include +#include "k3b_export.h" + + +/* + * @ref QLabel + */ +class LIBK3B_EXPORT KCutLabel : public QLabel +{ + Q_OBJECT + + public: + /** + * Default constructor. + */ + KCutLabel( QWidget *parent = 0, const char *name = 0); + KCutLabel( const QString &text, QWidget *parent = 0, const char *name = 0 ); + + virtual QSize minimumSizeHint() const; + + /** + * \return the full text while text() returns the cut text + */ + const QString& fullText() const; + + public slots: + void setText( const QString & ); + + /** + * \param i the number of characters that have to be visible. Default is 1. + */ + void setMinimumVisibleText( int i ); + + protected: + /** + * used when widget is resized + */ + void resizeEvent( QResizeEvent * ); + /** + * does the dirty work + */ + void cutTextToLabel(); + + private: + QString m_fullText; + int m_minChars; +}; + +#endif // KCUTLABEL_H diff --git a/libk3b/tools/libisofs/COPYING b/libk3b/tools/libisofs/COPYING new file mode 100644 index 0000000..9fe1a71 --- /dev/null +++ b/libk3b/tools/libisofs/COPYING @@ -0,0 +1,280 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Steet, Fifth Floor, Cambridge, MA 02110-1301, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) 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 +this service 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 make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. 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. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +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 +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the 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 a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE 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. + + END OF TERMS AND CONDITIONS diff --git a/libk3b/tools/libisofs/ChangeLog b/libk3b/tools/libisofs/ChangeLog new file mode 100644 index 0000000..78d7e66 --- /dev/null +++ b/libk3b/tools/libisofs/ChangeLog @@ -0,0 +1,9 @@ +K3b Changes +- renamed the st_xxx time fileds in rr_entry to rr_st_xxx to make it compile + +0.1 -> 0.2 + +- Critical directory parsing bug fixed +- Call backs only if some sanity checks on the directory entry succeeds + (length checks to avoid buffer overrun if received corrupt data) +- Preliminary El Torito boot specification support (No multiple boot entries yet) diff --git a/libk3b/tools/libisofs/Makefile.am b/libk3b/tools/libisofs/Makefile.am new file mode 100644 index 0000000..cd5594c --- /dev/null +++ b/libk3b/tools/libisofs/Makefile.am @@ -0,0 +1,5 @@ +AM_CPPFLAGS= $(all_includes) + +noinst_LTLIBRARIES = libisofs.la + +libisofs_la_SOURCES = isofs.cpp diff --git a/libk3b/tools/libisofs/README b/libk3b/tools/libisofs/README new file mode 100644 index 0000000..3657861 --- /dev/null +++ b/libk3b/tools/libisofs/README @@ -0,0 +1,24 @@ +This is the 0.2 release of libisofs. For changes, see the ChangeLog. + +Libisofs implements the reading of the famous ISO-9660 (ECMA-167) file system, +found on CD-ROM media. It also supports the Rock Ridge Interchange Protocol and +Microsoft Joliet extensions. It allows user-mode programs to query the +filesystem volume descriptors and traverse through the directory structure. +Preliminary support for El-Torito boot CDs are added in version 0.2. + +To use it in your project, I recommend to copy bswap.h, isofs.h, iso_fs.h, +el_torito.h rock.h and isofs.c to your sources, and include isofs.h in the +appropriate places. + +Currently only the directory tables are parsed, the path tables are not. +(The path tables contain redundant information.) + +Also a sample program can be compiled with the supplied Makefile. Simply +execute 'make', it should create the executable file isofs. + +On big-endian systems, you need to define WORDS_BIGENDIAN (either in the +compiler command-line, or if you defined HAVE_CONFIG_H, in config.h) + + +Gyrgy Szombathelyi +http://libcdrom.sourceforge.net/libisofs.html diff --git a/libk3b/tools/libisofs/bswap.h b/libk3b/tools/libisofs/bswap.h new file mode 100644 index 0000000..96bd588 --- /dev/null +++ b/libk3b/tools/libisofs/bswap.h @@ -0,0 +1,94 @@ +/* From the mplayer project (www.mplayerhq.hu) */ + +#ifndef __BSWAP_H__ +#define __BSWAP_H__ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_BYTESWAP_H +#include +#else + +#ifdef ARCH_X86 +inline static unsigned short ByteSwap16(unsigned short x) +{ + __asm("xchgb %b0,%h0" : + "=q" (x) : + "0" (x)); + return x; +} +#define bswap_16(x) ByteSwap16(x) + +inline static unsigned int ByteSwap32(unsigned int x) +{ +#if defined(__CPU__) && (__CPU__ > 386) + __asm("bswap %0": + "=r" (x) : +#else + __asm("xchgb %b0,%h0\n" + " rorl $16,%0\n" + " xchgb %b0,%h0": + "=q" (x) : +#endif + "0" (x)); + return x; +} +#define bswap_32(x) ByteSwap32(x) + +inline static unsigned long long int ByteSwap64(unsigned long long int x) +{ + register union { __extension__ unsigned long long int __ll; + unsigned int __l[2]; } __x; + asm("xchgl %0,%1": + "=r"(__x.__l[0]),"=r"(__x.__l[1]): + "0"(bswap_32((unsigned long)x)),"1"(bswap_32((unsigned long)(x>>32)))); + return __x.__ll; +} +#define bswap_64(x) ByteSwap64(x) + +#else + +#define bswap_16(x) (((x) & 0x00ff) << 8 | ((x) & 0xff00) >> 8) + + +/* code from bits/byteswap.h (C) 1997, 1998 Free Software Foundation, Inc. */ +#define bswap_32(x) \ + ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \ + (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)) + +#define bswap_64(x) \ + (__extension__ \ + ({ union { __extension__ unsigned long long int __ll; \ + unsigned int __l[2]; } __w, __r; \ + __w.__ll = (x); \ + __r.__l[0] = bswap_32 (__w.__l[1]); \ + __r.__l[1] = bswap_32 (__w.__l[0]); \ + __r.__ll; })) +#endif /* !ARCH_X86 */ + +#endif /* !HAVE_BYTESWAP_H */ + +/* + be2me ... BigEndian to MachineEndian + le2me ... LittleEndian to MachineEndian +*/ + +#ifdef WORDS_BIGENDIAN +#define be2me_16(x) (x) +#define be2me_32(x) (x) +#define be2me_64(x) (x) +#define le2me_16(x) bswap_16(x) +#define le2me_32(x) bswap_32(x) +#define le2me_64(x) bswap_64(x) +#else +#define be2me_16(x) bswap_16(x) +#define be2me_32(x) bswap_32(x) +#define be2me_64(x) bswap_64(x) +#define le2me_16(x) (x) +#define le2me_32(x) (x) +#define le2me_64(x) (x) +#endif + +#endif diff --git a/libk3b/tools/libisofs/el_torito.h b/libk3b/tools/libisofs/el_torito.h new file mode 100644 index 0000000..cba83f7 --- /dev/null +++ b/libk3b/tools/libisofs/el_torito.h @@ -0,0 +1,63 @@ +#ifndef ELTORITO_H +#define ELTORITO_H 1 + +#include "iso_fs.h" + +#define EL_TORITO_ID "EL TORITO SPECIFICATION\0\0\0\0\0\0\0\0\0" + +struct el_torito_boot_descriptor { + char type [ISODCL ( 1, 1)]; /* 711 */ + char id [ISODCL ( 2, 6)]; + char version [ISODCL ( 7, 7)]; /* 711 */ + char system_id [ISODCL ( 8, 39)]; /* achars */ + char unused [ISODCL ( 40, 71)]; + char boot_catalog [ISODCL ( 72, 75)]; /* 731 */ +}; + +struct validation_entry { + char type [ISODCL ( 1, 1)]; /* 1 */ + char platform [ISODCL ( 2, 2)]; + char unused [ISODCL ( 3, 4)]; + char id [ISODCL ( 5, 28)]; + char cheksum [ISODCL ( 29, 30)]; + char key [ISODCL ( 31, 31)]; /* 0x55 */ + char key2 [ISODCL ( 32, 32)]; /* 0xaa */ +}; + +struct default_entry { + char bootid [ISODCL ( 1, 1)]; + char media [ISODCL ( 2, 2)]; + char loadseg [ISODCL ( 3, 4)]; + char systype [ISODCL ( 5, 5)]; + char unused [ISODCL ( 6, 6)]; + char seccount [ISODCL ( 7, 8)]; + char start [ISODCL ( 9, 12)]; + char unused2 [ISODCL ( 13, 32)]; +}; + +struct section_header { + char headerid [ISODCL ( 1, 1)]; + char platform [ISODCL ( 2, 2)]; + char entries [ISODCL ( 3, 4)]; + char id [ISODCL ( 5, 32)]; +}; + +struct section_entry { + char bootid [ISODCL ( 1, 1)]; + char media [ISODCL ( 2, 2)]; + char loadseg [ISODCL ( 3, 4)]; + char systype [ISODCL ( 5, 5)]; + char unused [ISODCL ( 6, 6)]; + char seccount [ISODCL ( 7, 8)]; + char start [ISODCL ( 9, 12)]; + char selcrit [ISODCL ( 13, 13)]; + char vendor_selcrit [ISODCL ( 14, 32)]; +}; + +struct section_entry_ext { + char extid [ISODCL ( 1, 1)]; + char extrec [ISODCL ( 2, 2)]; + char vendor_selcrit [ISODCL ( 3, 32)]; +}; + +#endif diff --git a/libk3b/tools/libisofs/iso_fs.h b/libk3b/tools/libisofs/iso_fs.h new file mode 100644 index 0000000..43353b0 --- /dev/null +++ b/libk3b/tools/libisofs/iso_fs.h @@ -0,0 +1,219 @@ +/* From the linux kernel */ + +#ifndef _ISO_FS_H +#define _ISO_FS_H 1 + +#include "bswap.h" + +/* + * The isofs filesystem constants/structures + */ + +/* This part borrowed from the bsd386 isofs */ +#define ISODCL(from, to) (to - from + 1) + +struct iso_volume_descriptor { + char type[ISODCL(1,1)]; /* 711 */ + char id[ISODCL(2,6)]; + char version[ISODCL(7,7)]; + char data[ISODCL(8,2048)]; +}; + +/* volume descriptor types */ +#define ISO_VD_BOOT 0 +#define ISO_VD_PRIMARY 1 +#define ISO_VD_SUPPLEMENTARY 2 +#define ISO_VD_END 255 + +#define ISO_STANDARD_ID "CD001" + +struct iso_primary_descriptor { + char type [ISODCL ( 1, 1)]; /* 711 */ + char id [ISODCL ( 2, 6)]; + char version [ISODCL ( 7, 7)]; /* 711 */ + char unused1 [ISODCL ( 8, 8)]; + char system_id [ISODCL ( 9, 40)]; /* achars */ + char volume_id [ISODCL ( 41, 72)]; /* dchars */ + char unused2 [ISODCL ( 73, 80)]; + char volume_space_size [ISODCL ( 81, 88)]; /* 733 */ + char unused3 [ISODCL ( 89, 120)]; + char volume_set_size [ISODCL (121, 124)]; /* 723 */ + char volume_sequence_number [ISODCL (125, 128)]; /* 723 */ + char logical_block_size [ISODCL (129, 132)]; /* 723 */ + char path_table_size [ISODCL (133, 140)]; /* 733 */ + char type_l_path_table [ISODCL (141, 144)]; /* 731 */ + char opt_type_l_path_table [ISODCL (145, 148)]; /* 731 */ + char type_m_path_table [ISODCL (149, 152)]; /* 732 */ + char opt_type_m_path_table [ISODCL (153, 156)]; /* 732 */ + char root_directory_record [ISODCL (157, 190)]; /* 9.1 */ + char volume_set_id [ISODCL (191, 318)]; /* dchars */ + char publisher_id [ISODCL (319, 446)]; /* achars */ + char preparer_id [ISODCL (447, 574)]; /* achars */ + char application_id [ISODCL (575, 702)]; /* achars */ + char copyright_file_id [ISODCL (703, 739)]; /* 7.5 dchars */ + char abstract_file_id [ISODCL (740, 776)]; /* 7.5 dchars */ + char bibliographic_file_id [ISODCL (777, 813)]; /* 7.5 dchars */ + char creation_date [ISODCL (814, 830)]; /* 8.4.26.1 */ + char modification_date [ISODCL (831, 847)]; /* 8.4.26.1 */ + char expiration_date [ISODCL (848, 864)]; /* 8.4.26.1 */ + char effective_date [ISODCL (865, 881)]; /* 8.4.26.1 */ + char file_structure_version [ISODCL (882, 882)]; /* 711 */ + char unused4 [ISODCL (883, 883)]; + char application_data [ISODCL (884, 1395)]; + char unused5 [ISODCL (1396, 2048)]; +}; + +/* Almost the same as the primary descriptor but two fields are specified */ +struct iso_supplementary_descriptor { + char type [ISODCL ( 1, 1)]; /* 711 */ + char id [ISODCL ( 2, 6)]; + char version [ISODCL ( 7, 7)]; /* 711 */ + char flags [ISODCL ( 8, 8)]; /* 853 */ + char system_id [ISODCL ( 9, 40)]; /* achars */ + char volume_id [ISODCL ( 41, 72)]; /* dchars */ + char unused2 [ISODCL ( 73, 80)]; + char volume_space_size [ISODCL ( 81, 88)]; /* 733 */ + char escape [ISODCL ( 89, 120)]; /* 856 */ + char volume_set_size [ISODCL (121, 124)]; /* 723 */ + char volume_sequence_number [ISODCL (125, 128)]; /* 723 */ + char logical_block_size [ISODCL (129, 132)]; /* 723 */ + char path_table_size [ISODCL (133, 140)]; /* 733 */ + char type_l_path_table [ISODCL (141, 144)]; /* 731 */ + char opt_type_l_path_table [ISODCL (145, 148)]; /* 731 */ + char type_m_path_table [ISODCL (149, 152)]; /* 732 */ + char opt_type_m_path_table [ISODCL (153, 156)]; /* 732 */ + char root_directory_record [ISODCL (157, 190)]; /* 9.1 */ + char volume_set_id [ISODCL (191, 318)]; /* dchars */ + char publisher_id [ISODCL (319, 446)]; /* achars */ + char preparer_id [ISODCL (447, 574)]; /* achars */ + char application_id [ISODCL (575, 702)]; /* achars */ + char copyright_file_id [ISODCL (703, 739)]; /* 7.5 dchars */ + char abstract_file_id [ISODCL (740, 776)]; /* 7.5 dchars */ + char bibliographic_file_id [ISODCL (777, 813)]; /* 7.5 dchars */ + char creation_date [ISODCL (814, 830)]; /* 8.4.26.1 */ + char modification_date [ISODCL (831, 847)]; /* 8.4.26.1 */ + char expiration_date [ISODCL (848, 864)]; /* 8.4.26.1 */ + char effective_date [ISODCL (865, 881)]; /* 8.4.26.1 */ + char file_structure_version [ISODCL (882, 882)]; /* 711 */ + char unused4 [ISODCL (883, 883)]; + char application_data [ISODCL (884, 1395)]; + char unused5 [ISODCL (1396, 2048)]; +}; + +#define HS_STANDARD_ID "CDROM" + +struct hs_volume_descriptor { + char foo [ISODCL ( 1, 8)]; /* 733 */ + char type [ISODCL ( 9, 9)]; /* 711 */ + char id [ISODCL ( 10, 14)]; + char version [ISODCL ( 15, 15)]; /* 711 */ + char data[ISODCL(16,2048)]; +}; + + +struct hs_primary_descriptor { + char foo [ISODCL ( 1, 8)]; /* 733 */ + char type [ISODCL ( 9, 9)]; /* 711 */ + char id [ISODCL ( 10, 14)]; + char version [ISODCL ( 15, 15)]; /* 711 */ + char unused1 [ISODCL ( 16, 16)]; /* 711 */ + char system_id [ISODCL ( 17, 48)]; /* achars */ + char volume_id [ISODCL ( 49, 80)]; /* dchars */ + char unused2 [ISODCL ( 81, 88)]; /* 733 */ + char volume_space_size [ISODCL ( 89, 96)]; /* 733 */ + char unused3 [ISODCL ( 97, 128)]; /* 733 */ + char volume_set_size [ISODCL (129, 132)]; /* 723 */ + char volume_sequence_number [ISODCL (133, 136)]; /* 723 */ + char logical_block_size [ISODCL (137, 140)]; /* 723 */ + char path_table_size [ISODCL (141, 148)]; /* 733 */ + char type_l_path_table [ISODCL (149, 152)]; /* 731 */ + char unused4 [ISODCL (153, 180)]; /* 733 */ + char root_directory_record [ISODCL (181, 214)]; /* 9.1 */ +}; + +/* We use this to help us look up the parent inode numbers. */ + +struct iso_path_table{ + char name_len[1]; /* 711 */ + char ext_attr_length[1]; /* 711 */ + char extent[4]; /* 731 */ + char parent[2]; /* 721 */ + char name[1]; +}; + +/* high sierra is identical to iso, except that the date is only 6 bytes, and + there is an extra reserved byte after the flags */ + +struct iso_directory_record { + char length [ISODCL (1, 1)]; /* 711 */ + char ext_attr_length [ISODCL (2, 2)]; /* 711 */ + char extent [ISODCL (3, 10)]; /* 733 */ + char size [ISODCL (11, 18)]; /* 733 */ + char date [ISODCL (19, 25)]; /* 7 by 711 */ + char flags [ISODCL (26, 26)]; + char file_unit_size [ISODCL (27, 27)]; /* 711 */ + char interleave [ISODCL (28, 28)]; /* 711 */ + char volume_sequence_number [ISODCL (29, 32)]; /* 723 */ + char name_len [ISODCL (33, 33)]; /* 711 */ + char name [1]; +}; + +/* 8 bit numbers */ +__inline unsigned char isonum_711(char *p); +__inline char isonum_712(char *p); + +/* 16 bit numbers */ +__inline unsigned short isonum_721(char *p); +__inline unsigned short isonum_722(char *p); +__inline unsigned short isonum_723(char *p); + +/* 32 bit numbers */ +__inline unsigned int isonum_731(char *p); +__inline unsigned int isonum_732(char *p); +__inline unsigned int isonum_733(char *p); + + +/* 8 bit numbers */ +__inline unsigned char isonum_711(char *p) +{ + return *(unsigned char *)p; +} +__inline char isonum_712(char *p) +{ + return *p; +} + +/* 16 bit numbers */ +__inline unsigned short isonum_721(char *p) +{ + return le2me_16(*(unsigned short *)p); +} +__inline unsigned short isonum_722(char *p) +{ + return be2me_16(*(unsigned short *)p); +} +__inline unsigned short isonum_723(char *p) +{ + /* Ignore bigendian datum due to broken mastering programs */ + return le2me_16(*(unsigned short *)p); +} + +/* 32 bit numbers */ +__inline unsigned int isonum_731(char *p) +{ + return le2me_32(*(unsigned int *)p); +} + +__inline unsigned int isonum_732(char *p) +{ + return be2me_32(*(unsigned int *)p); +} + +__inline unsigned int isonum_733(char *p) +{ + /* Ignore bigendian datum due to broken mastering programs */ + return le2me_32(*(unsigned int *)p); +} + +#endif /*_ISOFS_H*/ + diff --git a/libk3b/tools/libisofs/isofs.cpp b/libk3b/tools/libisofs/isofs.cpp new file mode 100644 index 0000000..e5c871b --- /dev/null +++ b/libk3b/tools/libisofs/isofs.cpp @@ -0,0 +1,878 @@ +/*************************************************************************** + isofs.c - libisofs implementation + ------------------- + begin : Oct 25 2002 + copyright : (C) 2002 by Szombathelyi Gyrgy + email : gyurco@users.sourceforge.net + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include +#include +#include + +#include "isofs.h" +#include "rock.h" + + + +/* internal function from the linux kernel (isofs fs) */ +static time_t getisotime(int year,int month,int day,int hour, + int minute,int second,int tz) { + + int days, i; + time_t crtime; + + year-=1970; + + if (year < 0) { + crtime = 0; + } else { + int monlen[12] = {31,28,31,30,31,30,31,31,30,31,30,31}; + + days = year * 365; + if (year > 2) + days += (year+1) / 4; + for (i = 1; i < month; i++) + days += monlen[i-1]; + if (((year+2) % 4) == 0 && month > 2) + days++; + days += day - 1; + crtime = ((((days * 24) + hour) * 60 + minute) * 60) + + second; + + /* sign extend */ + if (tz & 0x80) + tz |= (-1 << 8); + + /* + * The timezone offset is unreliable on some disks, + * so we make a sanity check. In no case is it ever + * more than 13 hours from GMT, which is 52*15min. + * The time is always stored in localtime with the + * timezone offset being what get added to GMT to + * get to localtime. Thus we need to subtract the offset + * to get to true GMT, which is what we store the time + * as internally. On the local system, the user may set + * their timezone any way they wish, of course, so GMT + * gets converted back to localtime on the receiving + * system. + * + * NOTE: mkisofs in versions prior to mkisofs-1.10 had + * the sign wrong on the timezone offset. This has now + * been corrected there too, but if you are getting screwy + * results this may be the explanation. If enough people + * complain, a user configuration option could be added + * to add the timezone offset in with the wrong sign + * for 'compatibility' with older discs, but I cannot see how + * it will matter that much. + * + * Thanks to kuhlmav@elec.canterbury.ac.nz (Volker Kuhlmann) + * for pointing out the sign error. + */ + if (-52 <= tz && tz <= 52) + crtime -= tz * 15 * 60; + } + return crtime; + +} + +/** + * Returns the Unix from the ISO9660 9.1.5 time format + */ +time_t isodate_915(char * p, int hs) { + + return getisotime(1900+p[0],p[1],p[2],p[3],p[4],p[5],hs==0 ? p[6] : 0); +} + +/** + * Returns the Unix from the ISO9660 8.4.26.1 time format + * BUG: hundredth of seconds are ignored, because Unix time_t has one second + * resolution (I think it's no problem at all) + */ +time_t isodate_84261(char * p, int hs) { + int year,month,day,hour,minute,second; + year=(p[0]-'0')*1000 + (p[1]-'0')*100 + (p[2]-'0')*10 + p[3]-'0'; + month=(p[4]-'0')*10 + (p[5]-'0'); + day=(p[6]-'0')*10 + (p[7]-'0'); + hour=(p[8]-'0')*10 + (p[9]-'0'); + minute=(p[10]-'0')*10 + (p[11]-'0'); + second=(p[12]-'0')*10 + (p[13]-'0'); + return getisotime(year,month,day,hour,minute,second,hs==0 ? p[16] : 0); +} + +void FreeBootTable(boot_head *boot) { + boot_entry *be,*next; + + be=boot->defentry; + while (be) { + next=be->next; + free(be); + be=next; + } + boot->defentry=NULL; +} + +int BootImageSize(readfunc* read,int media,sector_t start,int len,void* udata) { + int ret; + + switch(media & 0xf) { + case 0: + ret=len; /* No emulation */ + break; + case 1: + ret=80*2*15; /* 1.2 MB */ + break; + case 2: + ret=80*2*18; /* 1.44 MB */ + break; + case 3: + ret=80*2*36; /* 2.88 MB */ + break; + case 4: + /* FIXME!!! */ + ret=len; /* Hard Disk */ + break; + default: + ret=len; + } + return ret; +} + +static boot_entry *CreateBootEntry(char *be) { + boot_entry *entry; + + entry = (boot_entry*) malloc(sizeof(boot_entry)); + if (!entry) return NULL; + memset(entry, 0, sizeof(boot_entry)); + memcpy(entry->data,be,0x20); + return entry; +} + +int ReadBootTable(readfunc *read,sector_t sector, boot_head *head, void *udata) { + + char buf[2048], *c, *be; + int i,end=0; + unsigned short sum; + boot_entry *defcur=NULL,*deflast=NULL; + register struct validation_entry *ventry=NULL; + register struct default_entry *dentry=NULL; + register struct section_header *sheader=NULL; + register struct section_entry *sentry=NULL; + register struct section_entry_ext *extsentry=NULL; + + head->sections=NULL; + head->defentry=NULL; + while (1) { + be = (char*) &buf; + if ( read(be, sector, 1, udata) != 1 ) goto err; + + /* first entry needs to be a validation entry */ + if (!ventry) { + ventry=(struct validation_entry *) be; + if ( isonum_711(ventry->type) !=1 ) goto err; + sum=0; + c = (char*) ventry; + for (i=0;i<16;i++) { sum += isonum_721(c); c+=2; } + if (sum) goto err; + memcpy(&head->ventry,be,0x20); + be += 0x20; + } + + while (!end && (be < (buf+1))) { + switch (isonum_711(be)) { + case 0x88: + defcur=CreateBootEntry(be); + if (!defcur) goto err; + if (deflast) + deflast->next=defcur; + else + head->defentry=defcur; + defcur->prev=deflast; + deflast=defcur; + break; + case 0x90: + case 0x91: + break; + default: + end=1; + break; + } + be += 0x20; + } + if (end) break; + + sector ++; + } + + return 0; + +err: + FreeBootTable(head); + return -1; +} + + +/** + * Creates the linked list of the volume descriptors + */ +iso_vol_desc *ReadISO9660(readfunc *read,sector_t sector,void *udata) { + + int i; + struct iso_volume_descriptor buf; + iso_vol_desc *first=NULL,*current=NULL,*prev=NULL; + + for (i=0;i<100;i++) { + if (read( (char*) &buf, sector+i+16, 1, udata) != 1 ) { + FreeISO9660(first); + return NULL; + } + if (!memcmp(ISO_STANDARD_ID,&buf.id,5)) { + switch ( isonum_711(&buf.type[0]) ) { + + case ISO_VD_BOOT: + case ISO_VD_PRIMARY: + case ISO_VD_SUPPLEMENTARY: + current=(iso_vol_desc*) malloc(sizeof(iso_vol_desc)); + if (!current) { + FreeISO9660(first); + return NULL; + } + current->prev=prev; + current->next=NULL; + if (prev) prev->next=current; + memcpy(&(current->data),&buf,2048); + if (!first) first=current; + prev=current; + break; + + case ISO_VD_END: + return first; + break; + } + } else if (!memcmp(HS_STANDARD_ID,(struct hs_volume_descriptor*) &buf,5)) { + /* High Sierra format not supported (yet) */ + } + } + + return first; +} + +/** + * Frees the linked list of volume descriptors + */ +void FreeISO9660(iso_vol_desc *data) { + + iso_vol_desc *current; + + + while (data) { + current=data; + data=current->next; + free(current); + } +} + +/** + * Frees the strings in 'rrentry' + */ +void FreeRR(rr_entry *rrentry) { + if (rrentry->name) { + free(rrentry->name); + rrentry->name=NULL; + } + if (rrentry->sl) { + free(rrentry->sl); + rrentry->name=NULL; + } +} + +static int str_nappend(char **d,char *s,int n) { + int i=0; + char *c; + +/* i=strnlen(s,n)+1; */ + while (iname_len); + if (!(isonum_711(idr->name_len) & 1)) suspoffs++; + susplen=isonum_711(idr->length)-suspoffs; + r= & (((char*) idr)[suspoffs]); + rr = (struct rock_ridge*) r; + + memset(rrentry,0,sizeof(rr_entry)); + rrentry->len = sizeof(rr_entry); + + while (susplen > 0) { + if (isonum_711(&rr->len) > susplen || rr->len == 0) break; + if (rr->signature[0]=='N' && rr->signature[1]=='M') { + if (!(rr->u.NM.flags & 0x26) && rr->len>5 && !rrentry->name) { + + if (str_nappend(&rrentry->name,rr->u.NM.name,isonum_711(&rr->len)-5)) { + FreeRR(rrentry); return -ENOMEM; + } + ret++; + } + } else if (rr->signature[0]=='P' && rr->signature[1]=='X' && + (isonum_711(&rr->len)==44 || isonum_711(&rr->len)==36)) { + rrentry->mode=isonum_733(rr->u.PX.mode); + rrentry->nlink=isonum_733(rr->u.PX.n_links); + rrentry->uid=isonum_733(rr->u.PX.uid); + rrentry->gid=isonum_733(rr->u.PX.gid); + if (isonum_711(&rr->len)==44) rrentry->serno=isonum_733(rr->u.PX.serno); + ret++; + } else if (rr->signature[0]=='P' && rr->signature[1]=='N' && + isonum_711(&rr->len)==20) { + rrentry->dev_major=isonum_733(rr->u.PN.dev_high); + rrentry->dev_minor=isonum_733(rr->u.PN.dev_low); + ret++; + } else if (rr->signature[0]=='P' && rr->signature[1]=='L' && + isonum_711(&rr->len)==12) { + rrentry->pl=isonum_733(rr->u.PL.location); + ret++; + } else if (rr->signature[0]=='C' && rr->signature[1]=='L' && + isonum_711(&rr->len)==12) { + rrentry->cl=isonum_733(rr->u.CL.location); + ret++; + } else if (rr->signature[0]=='R' && rr->signature[1]=='E' && + isonum_711(&rr->len)==4) { + rrentry->re=1; + ret++; + } else if (rr->signature[0]=='S' && rr->signature[1]=='L' && + isonum_711(&rr->len)>7) { + i = isonum_711(&rr->len)-5; + c = (char*) rr; + c += 5; + while (i>0) { + switch(c[0] & ~1) { + case 0x2: + if (str_append(&rrentry->sl,".")) { + FreeRR(rrentry); return -ENOMEM; + } + break; + case 0x4: + if (str_append(&rrentry->sl,"..")) { + FreeRR(rrentry); return -ENOMEM; + } + break; + } + if ( (c[0] & 0x08) == 0x08 || (c[1] && rrentry->sl && + strlen(rrentry->sl)>1) ) { + if (str_append(&rrentry->sl,"/")) { + FreeRR(rrentry); return -ENOMEM; + } + } + + if ((unsigned char)c[1]>0) { + if (str_nappend(&rrentry->sl,c+2,(unsigned char)c[1])) { + FreeRR(rrentry); return -ENOMEM; + } + } + i -= ((unsigned char)c[1] + 2); + c += ((unsigned char)c[1] + 2); + } + ret++; + } else if (rr->signature[0]=='T' && rr->signature[1]=='F' && + isonum_711(&rr->len)>5) { + + i = isonum_711(&rr->len)-5; + f = rr->u.TF.flags; + c = (char*) rr; + c += 5; + + while (i >= rrtlen(f)) { + if (f & 1) { + rrentry->t_creat=rrctime(f,c); + f &= ~1; + } else if (f & 2) { + rrentry->rr_st_mtime=rrctime(f,c); + f &= ~2; + } else if (f & 4) { + rrentry->rr_st_atime=rrctime(f,c); + f &= ~4; + } else if (f & 8) { + rrentry->rr_st_ctime=rrctime(f,c); + f &= ~8; + } else if (f & 16) { + rrentry->t_backup=rrctime(f,c); + f &= ~16; + } else if (f & 32) { + rrentry->t_expire=rrctime(f,c); + f &= ~32; + } else if (f & 64) { + rrentry->t_effect=rrctime(f,c); + f &= ~64; + } + + i -= rrtlen(f); + c += rrtlen(f); + } + ret++; + + } else if (rr->signature[0]=='Z' && rr->signature[1]=='F' && + isonum_711(&rr->len)==16) { + /* Linux-specific extension: transparent decompression */ + rrentry->z_algo[0]=rr->u.ZF.algorithm[0]; + rrentry->z_algo[1]=rr->u.ZF.algorithm[1]; + rrentry->z_params[0]=rr->u.ZF.parms[0]; + rrentry->z_params[1]=rr->u.ZF.parms[1]; + rrentry->z_size=isonum_733(rr->u.ZF.real_size); + ret++; + } else { +/* printf("SUSP sign: %c%c\n",rr->signature[0],rr->signature[1]); */ + } + + susplen -= isonum_711(&rr->len); + r += isonum_711(&rr->len); + rr = (struct rock_ridge*) r; + } + + return ret; +} + +/** + * Iterates over the directory entries. The directory is in 'buf', + * the size of the directory is 'size'. 'callback' is called for each + * directory entry with the parameter 'udata'. + */ +int ProcessDir(readfunc *read,int extent,int size,dircallback *callback,void *udata) { + + int pos=0,ret=0,siz; + char *buf; + struct iso_directory_record *idr; + + if (size & 2047) { + siz=((size>>11)+1)<<11; + } else { + siz=size; + } + + buf=(char*) malloc(siz); + if (!buf) return -ENOMEM; + if (read(buf,extent,siz>>11,udata)!=siz>>11) { + free(buf); + return -EIO; + } + + while (size>0) { + idr=(struct iso_directory_record*) &buf[pos]; + if (isonum_711(idr->length)==0) { + size-=(2048 - (pos & 0x7ff)); + if (size<=2) break; + pos+=0x800; + pos&=0xfffff800; + idr=(struct iso_directory_record*) &buf[pos]; + } + pos+=isonum_711(idr->length); + pos+=isonum_711(idr->ext_attr_length); + size-=isonum_711(idr->length); + size-=isonum_711(idr->ext_attr_length); + if (size<0) break; + + if (isonum_711(idr->length) +<33 || + isonum_711(idr->length)<33+isonum_711(idr->name_len)) { + /* Invalid directory entry */ + continue; + } + if ((ret=callback(idr,udata))) break; + } + + free(buf); + return ret; +} + +/** + * returns the joliet level from the volume descriptor + */ +int JolietLevel(struct iso_volume_descriptor *ivd) { + int ret=0; + register struct iso_supplementary_descriptor *isd; + + isd = (struct iso_supplementary_descriptor *) ivd; + + if (isonum_711(ivd->type)==ISO_VD_SUPPLEMENTARY) { + if (isd->escape[0]==0x25 && + isd->escape[1]==0x2f) { + + switch (isd->escape[2]) { + case 0x40: + ret=1; + break; + case 0x43: + ret=2; + break; + case 0x45: + ret=3; + break; + } + } + } + return ret; +} + +/********************************************************************/ +#if 0 + +#include +#include +#include +#include +#include +#include +#include + +int level=0,joliet=0,dirs,files; +iconv_t iconv_d; +int fd; + +int readf(char *buf, int start, int len,void *udata) { + int ret; + + if ((ret=lseek(fd, start << 11, SEEK_SET))<0) return ret; + ret=read(fd, buf, len << 11); + if (ret<0) return ret; + return (ret >> 11); +} + +void dumpchars(char *c,int len) { + while (len>0) { + printf("%c",*c); + len--; + c++; + } +} + +void sp(int num) { + int i; + for (i=0;iname_len)==1) { + switch (dir->name[0]) { + case 0: + printf("."); + break; + case 1: + printf(".."); + break; + default: + printf("%c",dir->name[0]); + break; + } + } + dumpchardesc(dir->name,isonum_711(dir->name_len)); + printf(" size=%d",isonum_733(dir->size)); + printf(" extent=%d ",isonum_733(dir->extent)); + dumpflags(isonum_711(dir->flags)); + dumpiso915time((char*) &(dir->date),0); +} + +void dumprrentry(rr_entry *rr) { + printf(" NM=[%s] uid=%d gid=%d nlink=%d mode=%o ", + rr->name,rr->uid,rr->gid,rr->nlink,rr->mode); + if (S_ISCHR(rr->mode) || S_ISBLK(rr->mode)) + printf("major=%d minor=%d ",rr->dev_major,rr->dev_minor); + if (rr->mode & S_IFLNK && rr->sl) printf("slink=%s ",rr->sl); +/* + printf("\n"); + if (rr->t_creat) printf("t_creat: %s",ctime(&rr->t_creat)); + if (rr->rr_st_mtime) printf("rr_st_mtime: %s",ctime(&rr->rr_st_mtime)); + if (rr->rr_st_atime) printf("rr_st_atime: %s",ctime(&rr->rr_st_atime)); + if (rr->rr_st_ctime) printf("rr_st_ctime: %s",ctime(&rr->rr_st_ctime)); + if (rr->t_backup) printf("t_backup: %s",ctime(&rr->t_backup)); + if (rr->t_expire) printf("t_expire: %s",ctime(&rr->t_expire)); + if (rr->t_effect) printf("t_effect: %s",ctime(&rr->t_effect)); +*/ +} + +void dumpsusp(char *c, int len) { + dumpchars(c,len); +} + +void dumpboot(struct el_torito_boot_descriptor *ebd) { + printf("version: %d\n",isonum_711(ebd->version)); + printf("system id: ");dumpchars(ebd->system_id,ISODCL(8,39));printf("\n"); + printf("boot catalog start: %d\n",isonum_731(ebd->boot_catalog)); +} + +void dumpdefentry(struct default_entry *de) { + printf("Default entry: \n"); + printf(" bootid=%x\n",isonum_711(de->bootid)); + printf(" media emulation=%d (",isonum_711(de->media)); + switch(isonum_711(de->media) & 0xf) { + case 0: + printf("No emulation"); + break; + case 1: + printf("1.2 Mb floppy"); + break; + case 2: + printf("1.44 Mb floppy"); + break; + case 3: + printf("2.88 Mb floppy"); + break; + case 4: + printf("Hard Disk"); + break; + default: + printf("Unknown/Invalid"); + break; + } + printf(")\n"); + printf(" loadseg=%d\n",isonum_721(de->loadseg)); + printf(" systype=%d\n",isonum_711(de->systype)); + printf(" start lba=%d count=%d\n",isonum_731(de->start), + isonum_721(de->seccount)); +} + +void dumpbootcat(boot_head *bh) { + boot_entry *be; + + printf("System id: ");dumpchars(bh->ventry.id,ISODCL(28,5));printf("\n"); + be=bh->defentry; + while (be) { + dumpdefentry(be->data); + be=be->next; + } +} + +void dumpdesc(struct iso_primary_descriptor *ipd) { + + printf("system id: ");dumpchardesc(ipd->system_id,ISODCL(9,40));printf("\n"); + printf("volume id: ");dumpchardesc(ipd->volume_id,ISODCL(41,72));printf("\n"); + printf("volume space size: %d\n",isonum_733(ipd->volume_space_size)); + printf("volume set size: %d\n",isonum_723(ipd->volume_set_size)); + printf("volume seq num: %d\n",isonum_723(ipd->volume_set_size)); + printf("logical block size: %d\n",isonum_723(ipd->logical_block_size)); + printf("path table size: %d\n",isonum_733(ipd->path_table_size)); + printf("location of type_l path table: %d\n",isonum_731(ipd->type_l_path_table)); + printf("location of optional type_l path table: %d\n",isonum_731(ipd->opt_type_l_path_table)); + printf("location of type_m path table: %d\n",isonum_732(ipd->type_m_path_table)); + printf("location of optional type_m path table: %d\n",isonum_732(ipd->opt_type_m_path_table)); +/* + printf("Root dir record:\n");dumpdirrec((struct iso_directory_record*) &ipd->root_directory_record); +*/ + printf("Volume set id: ");dumpchardesc(ipd->volume_set_id,ISODCL(191,318));printf("\n"); + printf("Publisher id: ");dumpchardesc(ipd->publisher_id,ISODCL(319,446));printf("\n"); + printf("Preparer id: ");dumpchardesc(ipd->preparer_id,ISODCL(447,574));printf("\n"); + printf("Application id: ");dumpchardesc(ipd->application_id,ISODCL(575,702));printf("\n"); + printf("Copyright id: ");dumpchardesc(ipd->copyright_file_id,ISODCL(703,739));printf("\n"); + printf("Abstract file id: ");dumpchardesc(ipd->abstract_file_id,ISODCL(740,776));printf("\n"); + printf("Bibliographic file id: ");dumpchardesc(ipd->bibliographic_file_id,ISODCL(777,813));printf("\n"); + printf("Volume creation date: ");dumpiso84261time(ipd->creation_date,0);printf("\n"); + printf("Volume modification date: ");dumpiso84261time(ipd->modification_date,0);printf("\n"); + printf("Volume expiration date: ");dumpiso84261time(ipd->expiration_date,0);printf("\n"); + printf("Volume effective date: ");dumpiso84261time(ipd->effective_date,0);printf("\n"); + printf("File structure version: %d\n",isonum_711(ipd->file_structure_version)); +} + +int mycallb(struct iso_directory_record *idr,void *udata) { + rr_entry rrentry; + + sp(level);dumpdirrec(idr); + if (level==0) printf(" (Root directory) "); + printf("\n"); + + if (ParseRR(idr,&rrentry)>0) { + sp(level);printf(" ");dumprrentry(&rrentry);printf("\n"); + } + FreeRR(&rrentry); + if ( !(idr->flags[0] & 2) ) files++; + if ( (idr->flags[0] & 2) && (level==0 || isonum_711(idr->name_len)>1) ) { + level++; + dirs++; + ProcessDir(&readf,isonum_733(idr->extent),isonum_733(idr->size),&mycallb,udata); + level--; + } + return 0; +} + +/************************************************/ + +int main(int argc, char *argv[]) { + + int i=1,sector=0; + iso_vol_desc *desc; + boot_head boot; + + if (argc<2) { + fprintf(stderr,"\nUsage: %s iso-file-name or device [starting sector]\n\n",argv[0]); + return 0; + } + if (argc>=3) { + sector=atoi(argv[2]); + printf("Using starting sector number %d\n",sector); + } + fd=open(argv[1],O_RDONLY); + if (fd<0) { + fprintf(stderr,"open error\n"); + return -1; + } + iconv_d=iconv_open("ISO8859-2","UTF16BE"); + if (iconv_d==0) { + fprintf(stderr,"iconv open error\n"); + return -1; + } + + desc=ReadISO9660(&readf,sector,NULL); + if (!desc) { + printf("No volume descriptors\n"); + return -1; + } + while (desc) { + + printf("\n\n--------------- Volume descriptor (%d.) type %d: ---------------\n\n", + i,isonum_711(desc->data.type)); + switch (isonum_711(desc->data.type)) { + case ISO_VD_BOOT: { + + struct el_torito_boot_descriptor* bootdesc; + bootdesc=&(desc->data); + dumpboot(bootdesc); + if ( !memcmp(EL_TORITO_ID,bootdesc->system_id,ISODCL(8,39)) ) { + + if (ReadBootTable(&readf,isonum_731(bootdesc->boot_catalog),&boot,NULL)) { + printf("Boot Catalog Error\n"); + } else { + dumpbootcat(&boot); + FreeBootTable(&boot); + } + } + } + break; + + case ISO_VD_PRIMARY: + case ISO_VD_SUPPLEMENTARY: + joliet=0; + joliet = JolietLevel(&desc->data); + printf("Joliet level: %d\n",joliet); + dumpdesc((struct iso_primary_descriptor*) &desc->data); + printf("\n\n--------------- Directory structure: -------------------\n\n"); + dirs=0;files=0; + mycallb( &( ((struct iso_primary_descriptor*) &desc->data)->root_directory_record), NULL ); + printf("\nnumber of directories: %d\n",dirs); + printf("\nnumber of files: %d\n",files); + break; + + } + desc=desc->next; + i++; + } + iconv_close(iconv_d); + close(fd); + FreeISO9660(desc); + return 0; +} + +#endif diff --git a/libk3b/tools/libisofs/isofs.h b/libk3b/tools/libisofs/isofs.h new file mode 100644 index 0000000..f284903 --- /dev/null +++ b/libk3b/tools/libisofs/isofs.h @@ -0,0 +1,151 @@ +/*************************************************************************** + isofs.h - include this file to use libisofs + ------------------- + begin : Oct 25 2002 + copyright : (C) 2002 by Szombathelyi Gyrgy + email : gyurco@users.sourceforge.net + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef ISOFS_H +#define ISOFS_H + +#include + +#include "iso_fs.h" +#include "el_torito.h" + +typedef long sector_t; + +typedef struct _rr_entry { + int len; /* length of structure */ + char *name; /* Name from 'NM' */ + char *sl; /* symbolic link data */ + time_t t_creat; + time_t rr_st_mtime; + time_t rr_st_atime; + time_t rr_st_ctime; + time_t t_backup; + time_t t_expire; + time_t t_effect; + int mode; /* POSIX file modes */ + int nlink; + int uid; + int gid; + int serno; + int dev_major; + int dev_minor; + int pl; /* parent location */ + int cl; /* child location */ + int re; /* relocated */ + char z_algo[2]; /* zizofs algorithm */ + char z_params[2]; /* zizofs parameters */ + int z_size; /* zizofs real_size */ +} rr_entry; + +typedef struct _iso_vol_desc { + struct _iso_vol_desc *next; + struct _iso_vol_desc *prev; + struct iso_volume_descriptor data; +} iso_vol_desc; + +typedef struct _boot_entry { + struct _boot_entry *next; + struct _boot_entry *prev; + struct _boot_entry *parent; + struct _boot_entry *child; + char data[32]; +} boot_entry; + +typedef struct _boot_head { + struct validation_entry ventry; + struct _boot_entry *defentry; + struct _boot_entry *sections; +} boot_head; + +/** + * this callback function needs to read 'len' sectors from 'start' into 'buf' + */ +typedef int readfunc(char *buf,sector_t start, int len,void *); + +/** + * ProcessDir uses this callback + */ +typedef int dircallback(struct iso_directory_record *,void *); + +/** + * Returns the Unix from the ISO9660 9.1.5 (7 bytes) time format + * This function is from the linux kernel. + * Set 'hs' to non-zero if it's a HighSierra volume + */ +time_t isodate_915(char * p, int hs); + +/** + * Returns the Unix time from the ISO9660 8.4.26.1 (17 bytes) time format + * BUG: hundredth of seconds are ignored, because time_t has one second + * resolution (I think it's no problem at all) + * Set 'hs' to non-zero if it's a HighSierra volume + */ +time_t isodate_84261(char * p, int hs); + +/** + * Creates the linked list of the volume descriptors + * 'sector' is the starting sector number of where the filesystem start + * (starting sector of a session on a CD-ROM) + * If the function fails, returns NULL + * Don't forget to call FreeISO9660 after using the volume descriptor list! + */ +iso_vol_desc *ReadISO9660(readfunc *read,sector_t sector,void *udata); + +/** + * Frees the linked list of volume descriptors. + */ +void FreeISO9660(iso_vol_desc *data); + +/** + * Iterates over the directory entries. The directory is in 'buf', + * the size of the directory is 'size'. 'callback' is called for each + * directory entry with the parameter 'udata'. + */ +int ProcessDir(readfunc *read,int extent,int size,dircallback *callback,void *udata); + +/** + * Parses the System Use area and fills rr_entry with values + */ +int ParseRR(struct iso_directory_record *idr, rr_entry *rrentry); + +/** + * Frees the strings in 'rrentry' + */ +void FreeRR(rr_entry *rrentry); + +/** + * returns the joliet level from the volume descriptor + */ +int JolietLevel(struct iso_volume_descriptor *ivd); + +/** + * Returns the size of the boot image (in 512 byte sectors) + */ +int BootImageSize(readfunc *read,int media,sector_t start,int len,void *udata); + +/** + * Frees the boot catalog entries in 'boot'. If you ever called ReadBootTable, + * then don't forget to call FreeBootTable! + */ +void FreeBootTable(boot_head *boot); + +/** + * Reads the boot catalog into 'head'. Don't forget to call FreeBootTable! + */ +int ReadBootTable(readfunc *read,sector_t sector, boot_head *head, void *udata); + +#endif diff --git a/libk3b/tools/libisofs/rock.h b/libk3b/tools/libisofs/rock.h new file mode 100644 index 0000000..e859192 --- /dev/null +++ b/libk3b/tools/libisofs/rock.h @@ -0,0 +1,127 @@ +/* this header is from the linux kernel */ + +#ifndef ROCK_H +#define ROCK_H 1 + +/* These structs are used by the system-use-sharing protocol, in which the + Rock Ridge extensions are embedded. It is quite possible that other + extensions are present on the disk, and this is fine as long as they + all use SUSP */ + +struct SU_SP{ + unsigned char magic[2]; + unsigned char skip; +}; + +struct SU_CE{ + char extent[8]; + char offset[8]; + char size[8]; +}; + +struct SU_ER{ + unsigned char len_id; + unsigned char len_des; + unsigned char len_src; + unsigned char ext_ver; + char data[1]; +}; + +struct RR_RR{ + char flags[1]; +}; + +struct RR_PX{ + char mode[8]; + char n_links[8]; + char uid[8]; + char gid[8]; + char serno[8]; +}; + +struct RR_PN{ + char dev_high[8]; + char dev_low[8]; +}; + + +struct SL_component{ + unsigned char flags; + unsigned char len; + char text[1]; +}; + +struct RR_SL{ + unsigned char flags; + struct SL_component link; +}; + +struct RR_NM{ + unsigned char flags; + char name[1]; +}; + +struct RR_CL{ + char location[8]; +}; + +struct RR_PL{ + char location[8]; +}; + +struct stamp{ + char time[7]; +}; + +struct RR_TF{ + char flags; + struct stamp times[1]; /* Variable number of these beasts */ +}; + +/* Linux-specific extension for transparent decompression */ +struct RR_ZF{ + char algorithm[2]; + char parms[2]; + char real_size[8]; +}; + +/* These are the bits and their meanings for flags in the TF structure. */ +#define TF_CREATE 1 +#define TF_MODIFY 2 +#define TF_ACCESS 4 +#define TF_ATTRIBUTES 8 +#define TF_BACKUP 16 +#define TF_EXPIRATION 32 +#define TF_EFFECTIVE 64 +#define TF_LONG_FORM 128 + +struct rock_ridge{ + char signature[2]; + char len; /* 711 */ + char version; /* 711 */ + union{ + struct SU_SP SP; + struct SU_CE CE; + struct SU_ER ER; + struct RR_RR RR; + struct RR_PX PX; + struct RR_PN PN; + struct RR_SL SL; + struct RR_NM NM; + struct RR_CL CL; + struct RR_PL PL; + struct RR_TF TF; + struct RR_ZF ZF; + } u; +}; + +#define RR_PX 1 /* POSIX attributes */ +#define RR_PN 2 /* POSIX devices */ +#define RR_SL 4 /* Symbolic link */ +#define RR_NM 8 /* Alternate Name */ +#define RR_CL 16 /* Child link */ +#define RR_PL 32 /* Parent link */ +#define RR_RE 64 /* Relocation directory */ +#define RR_TF 128 /* Timestamps */ + +#endif /* ROCK_H */ diff --git a/libk3b/videodvd/Makefile.am b/libk3b/videodvd/Makefile.am new file mode 100644 index 0000000..0225117 --- /dev/null +++ b/libk3b/videodvd/Makefile.am @@ -0,0 +1,19 @@ +AM_CPPFLAGS = -I$(srcdir) \ + -I$(srcdir)/../core \ + -I$(srcdir)/../../libk3bdevice \ + -I$(srcdir)/../tools \ + -I$(srcdir)/../plugin \ + $(all_includes) + +METASOURCES = AUTO + +noinst_LTLIBRARIES = libvideodvd.la +libvideodvd_la_LIBADD = -ldvdread + +libvideodvd_la_SOURCES = k3bvideodvd.cpp k3bvideodvdtime.cpp \ + k3bvideodvdvideostream.cpp + +include_HEADERS = k3bvideodvd.h k3bvideodvdtitle.h \ + k3bvideodvdaudiostream.h k3bvideodvdsubpicturestream.h \ + k3bvideodvdvideostream.h k3bvideodvdtime.h \ + k3bvideodvdptt.h diff --git a/libk3b/videodvd/configure.in.bot b/libk3b/videodvd/configure.in.bot new file mode 100644 index 0000000..7ed988b --- /dev/null +++ b/libk3b/videodvd/configure.in.bot @@ -0,0 +1,11 @@ +echo "" + +echo "K3b - Include libdvdread (Video DVD ripping) support:" +if test "$have_libdvdread" = "yes"; then + echo "K3b - yes" +else + echo "K3b - no" + if test "$ac_cv_use_libdvdread" = "yes"; then + echo "K3b - You are missing the libdvdread library." + fi +fi diff --git a/libk3b/videodvd/configure.in.in b/libk3b/videodvd/configure.in.in new file mode 100644 index 0000000..f5ec969 --- /dev/null +++ b/libk3b/videodvd/configure.in.in @@ -0,0 +1,28 @@ +AC_ARG_WITH( + libdvdread, + AS_HELP_STRING( + [--without-libdvdread], + [build K3b without libdvdread (Video DVD ripping) support (default=no)]), + [ac_cv_use_libdvdread=$withval], + [ac_cv_use_libdvdread=yes] +) + +have_libdvdread=no +if test "$ac_cv_use_libdvdread" = "yes"; then + KDE_CHECK_HEADERS(dvdread/dvd_reader.h, + [ + AC_CHECK_LIB(dvdread, + DVDOpen, + [ + AC_DEFINE(HAVE_LIBDVDREAD,1,[Defined if you have libdvdread headers and libs installed.]) + have_libdvdread=yes + ] + ) + ]) +fi +AM_CONDITIONAL(include_videodvdrip, [test x$have_libdvdread = xyes]) + +#if test "$have_libdvdread" = "no"; then +# AC_MSG_ERROR([Could not find libdvdread. Please install.]) +# DO_NOT_COMPILE="$DO_NOT_COMPILE k3b" +#fi diff --git a/libk3b/videodvd/k3bvideodvd.cpp b/libk3b/videodvd/k3bvideodvd.cpp new file mode 100644 index 0000000..8692c04 --- /dev/null +++ b/libk3b/videodvd/k3bvideodvd.cpp @@ -0,0 +1,327 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS // needed for *_MAX macros in dvdread headers +#endif + +#include "k3bvideodvd.h" + +#include + +#include + +#include + +#include // needed by dvdreads headers +#include +#include +#include + + +// I don't get this stuff, I should read something about VideoDVD some day... +#define CONVERT_TIME(x) (((x & 0xf0) >> 3) * 5 + (x & 0x0f)) +#define CONVERT_FRAME(x) (((x & 0x30) >> 3) * 5 + (x & 0x0f)) + + +K3bVideoDVD::VideoDVD::VideoDVD() +{ +} + + +K3bVideoDVD::VideoDVD::~VideoDVD() +{ +} + + +bool K3bVideoDVD::VideoDVD::valid() const +{ + return ( m_device != 0 ); +} + + +bool K3bVideoDVD::VideoDVD::open( K3bDevice::Device* dev ) +{ + m_device = 0; + m_titles.clear(); + + // + // Initialize libdvdread + // + dvd_reader_t* dvdReaderT = DVDOpen( QFile::encodeName(dev->blockDeviceName()) ); + if( !dvdReaderT ) { + kdDebug() << "(K3bVideoDVD) Could not open device " << dev->blockDeviceName() << endl; + return false; + } + + // + // Read volume id + // + char v[33]; + if( DVDUDFVolumeInfo( dvdReaderT, v, 33, 0, 0 ) != 0 && + DVDISOVolumeInfo( dvdReaderT, v, 33, 0, 0 ) != 0 ) { + kdDebug() << "(K3bVideoDVD) Could not read volume info." << endl; + DVDClose( dvdReaderT ); + return false; + } + m_volumeIdentifier = QString::fromLatin1( v, 32 ); + + // + // Open the VMG info + // + ifo_handle_t* vmg = ifoOpen( dvdReaderT, 0 ); + if( !vmg ) { + kdDebug() << "(K3bVideoDVD) Can't open VMG info." << endl; + DVDClose( dvdReaderT ); + return false; + } + + // + // parse titles + // + m_titles.resize( vmg->tt_srpt->nr_of_srpts ); + for( unsigned int i = 0; i < vmg->tt_srpt->nr_of_srpts; ++i ) { + title_info_t& title = vmg->tt_srpt->title[i]; + + // m_titles[i].m_videoDVD = this; + + // + // general title info + // + m_titles[i].m_titleNum = i+1; + m_titles[i].m_numPTTs = title.nr_of_ptts; + m_titles[i].m_numAngles = title.nr_of_angles; + m_titles[i].m_titleSet = title.title_set_nr; + m_titles[i].m_ttn = title.vts_ttn; + + // + // Open the title set the current title is a part of + // + ifo_handle_t* titleIfo = ifoOpen( dvdReaderT, vmg->tt_srpt->title[i].title_set_nr ); + if( !titleIfo ) { + kdDebug() << "(K3bVideoDVD) Can't open Title ifo." << endl; + ifoClose( vmg ); + DVDClose( dvdReaderT ); + return false; + } + + // + // Length of this title + // + // the program chain number of the first partoftitle of the current title (FIXME: but a title may contain multiple pgcs) + int pgc_id = titleIfo->vts_ptt_srpt->title[ m_titles[i].ttn() - 1 ].ptt[0].pgcn; + // (first?) program chain of the first partoftitle of the current title + pgc_t* cur_pgc = titleIfo->vts_pgcit->pgci_srp[ pgc_id - 1 ].pgc; + + m_titles[i].m_playbackTime = Time( CONVERT_TIME(cur_pgc->playback_time.hour), + CONVERT_TIME(cur_pgc->playback_time.minute), + CONVERT_TIME(cur_pgc->playback_time.second), + CONVERT_FRAME(cur_pgc->playback_time.frame_u) ); + + // + // Video stream information + // + m_titles[i].m_videoStream.m_permittedDf = titleIfo->vtsi_mat->vts_video_attr.permitted_df; + m_titles[i].m_videoStream.m_displayAspectRatio = titleIfo->vtsi_mat->vts_video_attr.display_aspect_ratio; + m_titles[i].m_videoStream.m_videoFormat = titleIfo->vtsi_mat->vts_video_attr.video_format; + m_titles[i].m_videoStream.m_mpegVersion = titleIfo->vtsi_mat->vts_video_attr.mpeg_version; + m_titles[i].m_videoStream.m_filmMode = titleIfo->vtsi_mat->vts_video_attr.film_mode; + m_titles[i].m_videoStream.m_letterboxed = titleIfo->vtsi_mat->vts_video_attr.letterboxed; + m_titles[i].m_videoStream.m_pictureSize = titleIfo->vtsi_mat->vts_video_attr.picture_size; + m_titles[i].m_videoStream.m_bitRate = titleIfo->vtsi_mat->vts_video_attr.bit_rate; + + // + // Audio stream information + // + m_titles[i].m_audioStreams.resize( titleIfo->vtsi_mat->nr_of_vts_audio_streams ); + for( unsigned int j = 0; j < titleIfo->vtsi_mat->nr_of_vts_audio_streams; ++j ) { + m_titles[i].m_audioStreams[j].m_format = titleIfo->vtsi_mat->vts_audio_attr[j].audio_format; + m_titles[i].m_audioStreams[j].m_applicationMode = titleIfo->vtsi_mat->vts_audio_attr[j].application_mode; + m_titles[i].m_audioStreams[j].m_quantization = titleIfo->vtsi_mat->vts_audio_attr[j].quantization; + m_titles[i].m_audioStreams[j].m_sampleFrequency = titleIfo->vtsi_mat->vts_audio_attr[j].sample_frequency; + m_titles[i].m_audioStreams[j].m_codeExtension = titleIfo->vtsi_mat->vts_audio_attr[j].code_extension; + m_titles[i].m_audioStreams[j].m_multiChannelExt = titleIfo->vtsi_mat->vts_audio_attr[j].multichannel_extension; + m_titles[i].m_audioStreams[j].m_channels = titleIfo->vtsi_mat->vts_audio_attr[j].channels+1; + if( titleIfo->vtsi_mat->vts_audio_attr[j].lang_type == 1 ) + m_titles[i].m_audioStreams[j].m_langCode.sprintf( "%c%c", + titleIfo->vtsi_mat->vts_audio_attr[j].lang_code>>8, + titleIfo->vtsi_mat->vts_audio_attr[j].lang_code & 0xff ); + else + m_titles[i].m_audioStreams[j].m_langCode = QString::null; + } + + // + // SubPicture stream information + // + m_titles[i].m_subPictureStreams.resize( titleIfo->vtsi_mat->nr_of_vts_subp_streams ); + for( unsigned int j = 0; j < titleIfo->vtsi_mat->nr_of_vts_subp_streams; ++j ) { + m_titles[i].m_subPictureStreams[j].m_codeMode = titleIfo->vtsi_mat->vts_subp_attr[j].code_mode; + m_titles[i].m_subPictureStreams[j].m_codeExtension = titleIfo->vtsi_mat->vts_subp_attr[j].code_extension; + if( titleIfo->vtsi_mat->vts_subp_attr[j].type == 1 ) + m_titles[i].m_subPictureStreams[j].m_langCode.sprintf( "%c%c", + titleIfo->vtsi_mat->vts_subp_attr[j].lang_code>>8, + titleIfo->vtsi_mat->vts_subp_attr[j].lang_code & 0xff ); + else + m_titles[i].m_subPictureStreams[j].m_langCode = QString::null; + } + + // + // add chapter info + // + m_titles[i].m_ptts.resize( m_titles[i].numPTTs() ); + for( unsigned int j = 0; j < m_titles[i].numPTTs(); ++j ) { + m_titles[i].m_ptts[j].m_pttNum = j+1; + m_titles[i].m_ptts[j].m_playbackTime = Time( CONVERT_TIME(cur_pgc->cell_playback[j].playback_time.hour), + CONVERT_TIME(cur_pgc->cell_playback[j].playback_time.minute), + CONVERT_TIME(cur_pgc->cell_playback[j].playback_time.second), + CONVERT_FRAME(cur_pgc->cell_playback[j].playback_time.frame_u) ); + m_titles[i].m_ptts[j].m_firstSector = cur_pgc->cell_playback[j].first_sector; + m_titles[i].m_ptts[j].m_lastSector = cur_pgc->cell_playback[j].last_sector; + } + + ifoClose( titleIfo ); + } + + ifoClose( vmg ); + DVDClose( dvdReaderT ); + + // + // Setting the device makes this a valid instance + // + m_device = dev; + + return true; +} + + +const K3bVideoDVD::Title& K3bVideoDVD::VideoDVD::title( unsigned int num ) const +{ + return m_titles[num]; +} + + +const K3bVideoDVD::Title& K3bVideoDVD::VideoDVD::operator[]( unsigned int num ) const +{ + return title( num ); +} + + +void K3bVideoDVD::VideoDVD::debug() const +{ + kdDebug() << "VideoDVD information:" << endl + << "=====================" << endl + << "Volume ID: " << volumeIdentifier() << endl << endl; + + for( unsigned int i = 0; i < numTitles(); ++i ) { + kdDebug() << "Title " << title(i).titleNumber() << " (" << title(i).playbackTime().toString() << ")" << endl + << " Chapters: " << title(i).numPTTs() << endl + << " Angles: " << title(i).numAngles() << endl + << " VTS,TTN: " << title(i).titleSet() << "," << title(i).ttn() << endl + << " Audio Streams:" << endl; + for( unsigned int j = 0; j < title(i).numAudioStreams(); ++j ) + kdDebug() << " " << title(i).audioStream(j).langCode() << ": " + << audioFormatString( title(i).audioStream(j).format() ) << ", " + << audioCodeExtensionString( title(i).audioStream(j).codeExtension() ) << endl; + kdDebug() << " SubPicture Streams:" << endl; + for( unsigned int j = 0; j < title(i).numSubPictureStreams(); ++j ) + kdDebug() << " " << title(i).subPictureStream(j).langCode() << ": " + << subPictureCodeModeString( title(i).subPictureStream(j).codeMode() ) << ", " + << subPictureCodeExtensionString( title(i).subPictureStream(j).codeExtension() ) << endl; + } +} + + +QString K3bVideoDVD::audioFormatString( int format ) +{ + switch( format ) { + case AUDIO_FORMAT_AC3: + return i18n("AC3"); + case AUDIO_FORMAT_MPEG1: + return i18n("MPEG1"); + case AUDIO_FORMAT_MPEG2EXT: + return i18n("MPEG2 Extended"); + case AUDIO_FORMAT_LPCM: + return i18n("LPCM"); + case AUDIO_FORMAT_DTS: + return i18n("DTS"); + default: + return i18n("unknown audio format"); + } +} + + +QString K3bVideoDVD::audioCodeExtensionString( int ext ) +{ + switch( ext ) { + case AUDIO_CODE_EXT_UNSPECIFIED: + return i18n("Unspecified"); + case AUDIO_CODE_EXT_NORMAL: + return i18n("Normal"); + case AUDIO_CODE_EXT_VISUALLY_IMPAIRED: + return i18n("For the visually impaired"); + case AUDIO_CODE_EXT_DIR_COMMENTS_1: + return i18n("Director's comments 1"); + case AUDIO_CODE_EXT_DIR_COMMENTS_2: + return i18n("Director's comments 2"); + default: + return i18n("unknown audio code extension"); + } +} + + +QString K3bVideoDVD::subPictureCodeModeString( int mode ) +{ + switch( mode ) { + case SUBPIC_CODE_MODE_RLE: + return i18n("RLE"); + case SUBPIC_CODE_MODE_EXT: + return i18n("Extended"); + default: + return i18n("unknown coding mode"); + } +} + + +QString K3bVideoDVD::subPictureCodeExtensionString( int ext ) +{ + switch( ext ) { + case SUBPIC_CODE_EXT_UNSPECIFIED: + return i18n("Unspecified"); + case SUBPIC_CODE_EXT_CAPTION_NORMAL_SIZE: + return i18n("Caption with normal size character"); + case SUBPIC_CODE_EXT_CAPTION_BIGGER_SIZE: + return i18n("Caption with bigger size character"); + case SUBPIC_CODE_EXT_CAPTION_FOR_CHILDREN: + return i18n("Caption for children"); + case SUBPIC_CODE_EXT_CLOSED_CAPTION_NORMAL_SIZE: + return i18n("Closed caption with normal size character"); + case SUBPIC_CODE_EXT_CLOSED_CAPTION_BIGGER_SIZE: + return i18n("Closed caption with bigger size character"); + case SUBPIC_CODE_EXT_CLOSED_CAPTION_FOR_CHILDREN: + return i18n("Closed caption for children"); + case SUBPIC_CODE_EXT_FORCED_CAPTION: + return i18n("Forced caption"); + case SUBPIC_CODE_EXT_DIR_COMMENTS_NORMAL_SIZE: + return i18n("Director's comments with normal size characters"); + case SUBPIC_CODE_EXT_DIR_COMMENTS_BIGGER_SIZE: + return i18n("Director's comments with bigger size characters"); + case SUBPIC_CODE_EXT_DIR_COMMENTS_FOR_CHILDREN: + return i18n("Director's comments for children"); + default: + return i18n("unknown code extension"); + } +} + diff --git a/libk3b/videodvd/k3bvideodvd.h b/libk3b/videodvd/k3bvideodvd.h new file mode 100644 index 0000000..180a6f5 --- /dev/null +++ b/libk3b/videodvd/k3bvideodvd.h @@ -0,0 +1,91 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_VIDEOVD_H_ +#define _K3B_VIDEOVD_H_ + +#include + +#include + +#include +#include + + +namespace K3bDevice { + class Device; +} + +/** + * The K3bVideoDVD classes do not provide a complete playback frontend to + * libdvdread but are merely intended for Video DVD analysis. + * + * They are title based and thus treat a Video DVD to be a set of titles. + * Additional Video DVD constructs such as title sets, parts of titles (chapters), + * program chanins, or cells are not handled explicitly. + * + * The usage is very simple. One creates a VideoDVD instance and calls the open() + * method with a device containing a Video DVD. If the method returns true the + * analysis was successful and the structures are filled. + * + * After open() has returned the device has already been closed. + */ +namespace K3bVideoDVD +{ + /** + * libdvdread wrapper class + */ + class LIBK3B_EXPORT VideoDVD + { + public: + VideoDVD(); + ~VideoDVD(); + + /** + * \return true if a Video DVD was successfully opened via open() + */ + bool valid() const; + + /** + * Open a video dvd and parse it's contents. The device will be closed after this + * method returns, regardless of it's success. + */ + bool open( K3bDevice::Device* dev ); + + K3bDevice::Device* device() const { return m_device; } + const QString& volumeIdentifier() const { return m_volumeIdentifier; } + unsigned int numTitles() const { return m_titles.count(); } + + /** + * Get a title from the Video DVD. Index starts at 0. + */ + const Title& title( unsigned int num ) const; + const Title& operator[]( unsigned int num ) const; + + void debug() const; + + private: + K3bDevice::Device* m_device; + QValueVector m_titles; + QString m_volumeIdentifier; + }; + + LIBK3B_EXPORT QString audioFormatString( int format ); + LIBK3B_EXPORT QString audioCodeExtensionString( int ext ); + LIBK3B_EXPORT QString subPictureCodeModeString( int mode ); + LIBK3B_EXPORT QString subPictureCodeExtensionString( int ext ); +} + +#endif diff --git a/libk3b/videodvd/k3bvideodvdaudiostream.h b/libk3b/videodvd/k3bvideodvdaudiostream.h new file mode 100644 index 0000000..78068f0 --- /dev/null +++ b/libk3b/videodvd/k3bvideodvdaudiostream.h @@ -0,0 +1,112 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_VIDEODVD_AUDIO_STREAM_H_ +#define _K3B_VIDEODVD_AUDIO_STREAM_H_ + +#include <k3b_export.h> + +#include <qstring.h> + + +namespace K3bVideoDVD +{ + enum AudioFormat { + AUDIO_FORMAT_AC3 = 0, + AUDIO_FORMAT_MPEG1 = 2, + AUDIO_FORMAT_MPEG2EXT = 3, + AUDIO_FORMAT_LPCM = 4, + AUDIO_FORMAT_DTS = 6 + }; + + enum AudioApplicationMode { + AUDIO_APPLICATION_KARAOKE = 1, + AUDIO_APPLICATION_SURROUND = 2 + }; + + enum AudioQuantization { + AUDIO_QUANTIZATION_16BIT = 0, + AUDIO_QUANTIZATION_20BIT = 1, + AUDIO_QUANTIZATION_24BIT = 2 + }; + + enum AudioSampleFrequency { + AUDIO_SAMPLE_FREQ_48HZ = 0, + AUDIO_SAMPLE_FREQ_96HZ = 1 + }; + + enum AudioCodeExtension { + AUDIO_CODE_EXT_UNSPECIFIED = 0, + AUDIO_CODE_EXT_NORMAL = 1, + AUDIO_CODE_EXT_VISUALLY_IMPAIRED = 2, + AUDIO_CODE_EXT_DIR_COMMENTS_1 = 3, + AUDIO_CODE_EXT_DIR_COMMENTS_2 = 4 + }; + + class LIBK3B_EXPORT AudioStream + { + public: + AudioStream() {} + + /** + * \return A two chars language code or the empty string + * if the language is undefined. + */ + const QString& langCode() const { return m_langCode; } + + /** + * \see AudioFormat + */ + unsigned short format() const { return m_format; } + + /** + * \see AudioApplicationMode + */ + unsigned short applicationMode() const { return m_applicationMode; } + + /** + * \see AudioQuantization + */ + unsigned short quantization() const { return m_quantization; } + + /** + * \see AudioSampleFrequency + */ + unsigned short sampleFrequency() const { return m_sampleFrequency; } + + /** + * \see AudioCodeExtension + */ + unsigned short codeExtension() const { return m_codeExtension; } + + bool multiChannelExt() const { return m_multiChannelExt; } + + unsigned short channels() const { return m_channels; } + + private: + unsigned short m_format:3; + unsigned short m_applicationMode:2; + unsigned short m_quantization:2; + unsigned short m_sampleFrequency:2; + unsigned short m_codeExtension; + bool m_multiChannelExt; + unsigned short m_channels:3; + QString m_langCode; + + friend class VideoDVD; + }; +} + +#endif diff --git a/libk3b/videodvd/k3bvideodvdptt.h b/libk3b/videodvd/k3bvideodvdptt.h new file mode 100644 index 0000000..f0dca91 --- /dev/null +++ b/libk3b/videodvd/k3bvideodvdptt.h @@ -0,0 +1,50 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_VIDEODVD_PTT_H_ +#define _K3B_VIDEODVD_PTT_H_ + +#include <k3b_export.h> + +#include <k3bvideodvd.h> +#include <k3bvideodvdtime.h> + + +namespace K3bVideoDVD +{ + class LIBK3B_EXPORT PTT + { + public: + PTT() {} + + unsigned int pttNumber() const { return m_pttNum; } + + const Time& playbackTime() const { return m_playbackTime; } + + unsigned int firstSector() const { return m_firstSector; } + unsigned int lastSector() const { return m_lastSector; } + + private: + unsigned int m_pttNum; + Time m_playbackTime; + + unsigned int m_firstSector; + unsigned int m_lastSector; + + friend class VideoDVD; + }; +} + +#endif diff --git a/libk3b/videodvd/k3bvideodvdsubpicturestream.h b/libk3b/videodvd/k3bvideodvdsubpicturestream.h new file mode 100644 index 0000000..b32407d --- /dev/null +++ b/libk3b/videodvd/k3bvideodvdsubpicturestream.h @@ -0,0 +1,68 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_VIDEODVD_SUBPICTURE_STREAM_H_ +#define _K3B_VIDEODVD_SUBPICTURE_STREAM_H_ + +#include <k3b_export.h> + +#include <qstring.h> + + +namespace K3bVideoDVD +{ + enum SubPictureCodeMode { + SUBPIC_CODE_MODE_RLE = 0, + SUBPIC_CODE_MODE_EXT = 1 + }; + + enum SubPictureCodeExtension { + SUBPIC_CODE_EXT_UNSPECIFIED = 0, + SUBPIC_CODE_EXT_CAPTION_NORMAL_SIZE = 1, + SUBPIC_CODE_EXT_CAPTION_BIGGER_SIZE = 2, + SUBPIC_CODE_EXT_CAPTION_FOR_CHILDREN = 3, + SUBPIC_CODE_EXT_CLOSED_CAPTION_NORMAL_SIZE = 5, + SUBPIC_CODE_EXT_CLOSED_CAPTION_BIGGER_SIZE = 6, + SUBPIC_CODE_EXT_CLOSED_CAPTION_FOR_CHILDREN = 7, + SUBPIC_CODE_EXT_FORCED_CAPTION = 9, + SUBPIC_CODE_EXT_DIR_COMMENTS_NORMAL_SIZE = 13, + SUBPIC_CODE_EXT_DIR_COMMENTS_BIGGER_SIZE = 14, + SUBPIC_CODE_EXT_DIR_COMMENTS_FOR_CHILDREN = 15 + }; + + class LIBK3B_EXPORT SubPictureStream + { + public: + SubPictureStream() {} + + unsigned int codeMode() const { return m_codeMode; } + unsigned int codeExtension() const { return m_codeExtension; } + + /** + * \return A two chars language code or the empty string + * if the language is undefined. + */ + const QString& langCode() const { return m_langCode; } + + private: + unsigned int m_codeMode:3; + QString m_langCode; + unsigned int m_codeExtension; + + friend class VideoDVD; + }; +} + +#endif diff --git a/libk3b/videodvd/k3bvideodvdtime.cpp b/libk3b/videodvd/k3bvideodvdtime.cpp new file mode 100644 index 0000000..acc6aec --- /dev/null +++ b/libk3b/videodvd/k3bvideodvdtime.cpp @@ -0,0 +1,106 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bvideodvdtime.h" + +K3bVideoDVD::Time::Time() + : m_hour(0), + m_minute(0), + m_second(0), + m_frame(0) +{ +} + + +K3bVideoDVD::Time::Time( unsigned short hour, + unsigned short min, + unsigned short sec, + unsigned short frame ) + : m_hour(hour), + m_minute(min), + m_second(sec), + m_frame(frame) +{ +} + + +double K3bVideoDVD::Time::totalSeconds() const +{ + double s = (double)second(); + s += 60.0 * (double)minute(); + s += 3600.0 * (double)hour(); + + return s + (double)( frame() / frameRate() ); +} + + +unsigned int K3bVideoDVD::Time::totalFrames() const +{ + double f = (double)second(); + f += 60.0 * (double)minute(); + f += 3600.0 * (double)hour(); + + return (int)( f * frameRate() ) + frame(); +} + + +double K3bVideoDVD::Time::frameRate() const +{ + // + // This is how it is done in libdvdread + // I don't really understand it, though... :( + // + switch( (frame() & 0xc0) >> 6 ) { + case 1: + // PAL? + return 25.0; + case 3: + // NTSC? + return 29.97; + default: + // should only happen for time == 0? + return 0.0; + } +} + + +QString K3bVideoDVD::Time::toString( bool includeFrames ) const +{ + // FIXME: use a d-pointer + const_cast<K3bVideoDVD::Time*>(this)->makeValid(); + + if( includeFrames ) + return QString().sprintf( "%02d:%02d:%02d.%02d", + m_hour, + m_minute, + m_second, + m_frame & 0x3f ); + else + return QString().sprintf( "%02d:%02d:%02d", + m_hour, + m_minute, + m_second + ( m_frame > 0 ? 1 : 0 ) ); +} + + +void K3bVideoDVD::Time::makeValid() +{ + // FIXME: how to handle the frames? + + m_minute += m_second/60; + m_second = m_second % 60; + m_hour += m_minute/60; + m_minute = m_minute % 60; +} diff --git a/libk3b/videodvd/k3bvideodvdtime.h b/libk3b/videodvd/k3bvideodvdtime.h new file mode 100644 index 0000000..f486741 --- /dev/null +++ b/libk3b/videodvd/k3bvideodvdtime.h @@ -0,0 +1,59 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_VIDEODVD_TIME_H_ +#define _K3B_VIDEODVD_TIME_H_ + +#include <k3b_export.h> + +#include <qstring.h> + +/** + * This should not be confused with K3b::Msf + */ +namespace K3bVideoDVD +{ + class LIBK3B_EXPORT Time + { + public: + Time(); + Time( unsigned short hour, + unsigned short min, + unsigned short sec, + unsigned short frame ); + + unsigned short hour() const { return m_hour; } + unsigned short minute() const { return m_minute; } + unsigned short second() const { return m_second; } + unsigned short frame() const { return m_frame; } + + double totalSeconds() const; + unsigned int totalFrames() const; + + // FIXME: is this useful? + double frameRate() const; + + QString toString( bool includeFrames = true ) const; + + private: + void makeValid(); + + unsigned int m_hour; + unsigned int m_minute; + unsigned int m_second; + unsigned int m_frame; + }; + } +#endif diff --git a/libk3b/videodvd/k3bvideodvdtitle.h b/libk3b/videodvd/k3bvideodvdtitle.h new file mode 100644 index 0000000..17f31a3 --- /dev/null +++ b/libk3b/videodvd/k3bvideodvdtitle.h @@ -0,0 +1,112 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_VIDEODVD_TITLE_H_ +#define _K3B_VIDEODVD_TITLE_H_ + +#include <k3b_export.h> + +#include <k3bvideodvdtime.h> +#include <k3bvideodvdvideostream.h> +#include <k3bvideodvdaudiostream.h> +#include <k3bvideodvdsubpicturestream.h> +#include <k3bvideodvdptt.h> + +#include <qvaluevector.h> + + +namespace K3bVideoDVD +{ + class LIBK3B_EXPORT Title + { + public: + Title() {} + + unsigned int titleNumber() const { return m_titleNum; } + + /** + * \return The number of PTTs (Part of Title), commonly known + * as chapters + */ + unsigned int numPTTs() const { return m_numPTTs; } + + /** + * This method is just here for convenience. It returns the same as the above. + */ + unsigned int numChapters() const { return m_numPTTs; } + unsigned int numAngles() const { return m_numAngles; } + + /** + * \return The number of the titleset this title is a part of. + */ + unsigned int titleSet() const { return m_titleSet; } + + /** + * \return Number of the title in it's titleset. + */ + unsigned int ttn() const { return m_ttn; } + + unsigned int numAudioStreams() const { return m_audioStreams.count(); } + unsigned int numSubPictureStreams() const { return m_subPictureStreams.count(); } + + const VideoStream& videoStream() const { return m_videoStream; } + const AudioStream& audioStream( unsigned int i ) const { return m_audioStreams[i]; } + const SubPictureStream& subPictureStream( unsigned int i ) const { return m_subPictureStreams[i]; } + + /** + * Access to the PTTs of the title + */ + const PTT& operator[]( int i ) const { return ptt( i ); } + + /** + * Access to the PTTs of the title + */ + const PTT& ptt( int i ) const { return m_ptts[i]; } + + /** + * Access to the PTTs (chapters) of the title + */ + const PTT& chapter( int i ) const { return ptt( i ); } + + const Time& playbackTime() const { return m_playbackTime; } + + /** + * \return A video capture + */ + // QBitmap videoCapture( const Time& ) const; + + private: + unsigned int m_titleNum; + unsigned int m_numPTTs; + unsigned int m_titleSet; + // FIXME: find a proper name for ttn + unsigned int m_ttn; + unsigned int m_numAngles; + + Time m_playbackTime; + + VideoStream m_videoStream; + QValueVector<AudioStream> m_audioStreams; + QValueVector<SubPictureStream> m_subPictureStreams; + + QValueVector<PTT> m_ptts; + + // VideoDVD* m_videoDVD; + + friend class VideoDVD; + }; +} + +#endif diff --git a/libk3b/videodvd/k3bvideodvdvideostream.cpp b/libk3b/videodvd/k3bvideodvdvideostream.cpp new file mode 100644 index 0000000..e7b6e9e --- /dev/null +++ b/libk3b/videodvd/k3bvideodvdvideostream.cpp @@ -0,0 +1,60 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bvideodvdvideostream.h" + +unsigned int K3bVideoDVD::VideoStream::pictureWidth() const +{ + switch( pictureSize() ) { + case VIDEO_PICTURE_SIZE_720: + return 720; + case VIDEO_PICTURE_SIZE_704: + return 704; + case VIDEO_PICTURE_SIZE_352: + case VIDEO_PICTURE_SIZE_352_2: + return 352; + default: + return 0; + } +} + + +unsigned int K3bVideoDVD::VideoStream::pictureHeight() const +{ + int height = 480; + if( format() != 0 ) + height = 576; + if( pictureSize() == VIDEO_PICTURE_SIZE_352_2 ) + height /= 2; + + return height; +} + + +unsigned int K3bVideoDVD::VideoStream::realPictureWidth() const +{ + double aspectRatio = 0.0; + if( displayAspectRatio() == K3bVideoDVD::VIDEO_ASPECT_RATIO_4_3 ) + aspectRatio = 4.0/3.0; + else + aspectRatio = 16.0/9.0; + return (int)(aspectRatio * (double)realPictureHeight()); +} + + +unsigned int K3bVideoDVD::VideoStream::realPictureHeight() const +{ + return pictureHeight(); +} diff --git a/libk3b/videodvd/k3bvideodvdvideostream.h b/libk3b/videodvd/k3bvideodvdvideostream.h new file mode 100644 index 0000000..c6c9d95 --- /dev/null +++ b/libk3b/videodvd/k3bvideodvdvideostream.h @@ -0,0 +1,107 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_VIDEODVD_VIDEO_STREAM_H_ +#define _K3B_VIDEODVD_VIDEO_STREAM_H_ + +#include <k3b_export.h> + +namespace K3bVideoDVD +{ + enum VideoMPEGVersion { + MPEG1 = 0, + MPEG2 = 1 + }; + + enum VideoFormat { + VIDEO_FORMAT_NTSC = 0, + VIDEO_FORMAT_PAL = 1 + }; + + enum VideoAspectRatio { + VIDEO_ASPECT_RATIO_4_3 = 0, + VIDEO_ASPECT_RATIO_16_9 = 1 + }; + + enum VideoPermitedDf { + VIDEO_PERMITTED_DF_BOTH = 0, + VIDEO_PERMITTED_DF_PAN_SCAN = 1, + VIDEO_PERMITTED_DF_LETTERBOXED = 2, + VIDEO_PERMITTED_DF_UNSPECIFIED = 3 + }; + + enum VideoBitRate { + VIDEO_BITRATE_VARIABLE = 0, + VIDEO_BITRATE_CONSTANT = 1 + }; + + enum VideoPicureSize { + VIDEO_PICTURE_SIZE_720 = 0, + VIDEO_PICTURE_SIZE_704 = 1, + VIDEO_PICTURE_SIZE_352 = 2, + VIDEO_PICTURE_SIZE_352_2 = 3 + }; + + class LIBK3B_EXPORT VideoStream + { + public: + VideoStream() {} + + unsigned int permittedDf() const { return m_permittedDf; } + unsigned int displayAspectRatio() const { return m_displayAspectRatio; } + unsigned int format() const { return m_videoFormat; } + unsigned int mpegVersion() const { return m_mpegVersion; } + unsigned int filmMode() const { return m_filmMode; } + unsigned int letterboxed() const { return m_letterboxed; } + unsigned int pictureSize() const { return m_pictureSize; } + unsigned int bitRate() const { return m_bitRate; } + + /** + * The picture width of the video stream + */ + unsigned int pictureWidth() const; + + /** + * The picture height of the video stream + */ + unsigned int pictureHeight() const; + + /** + * The width of the "real" video after applying aspect ratio + * correction + */ + unsigned int realPictureWidth() const; + + /** + * The height of the "real" video after applying aspect ratio + * correction + */ + unsigned int realPictureHeight() const; + + private: + unsigned int m_permittedDf:2; + unsigned int m_displayAspectRatio:2; + unsigned int m_videoFormat:2; + unsigned int m_mpegVersion:2; + unsigned int m_filmMode:1; + unsigned int m_letterboxed:1; + unsigned int m_pictureSize:2; + unsigned int m_bitRate:1; + + friend class VideoDVD; + }; +} + +#endif diff --git a/libk3bdevice/Makefile.am b/libk3bdevice/Makefile.am new file mode 100644 index 0000000..bd6aaf8 --- /dev/null +++ b/libk3bdevice/Makefile.am @@ -0,0 +1,34 @@ +AM_CPPFLAGS= -I$(srcdir)/libk3bdevice -I$(srcdir) $(all_includes) $(HAL_INCS) $(DBUS_INCS) $(DBUSQT_INCS) + +KDE_CXXFLAGS = $(ENABLE_PERMISSIVE_FLAG) + +METASOURCES = AUTO + +lib_LTLIBRARIES = libk3bdevice.la + +libk3bdevice_la_LIBADD = $(LIB_KIO) $(RESMGR_LIB) $(CAM_LIB) $(HAL_DBUS_LIBS) + +# lib version 5 for K3b 1.0 +libk3bdevice_la_LDFLAGS = $(all_libraries) -version-info 5:0:0 -no-undefined + +if include_HAL +libk3bdevice_la_SOURCES = k3bdevice.cpp k3bdevice_mmc.cpp k3bscsicommand.cpp \ +k3btrack.cpp k3btoc.cpp k3bdevicemanager.cpp k3bmsf.cpp k3bdiskinfo.cpp \ +k3bdeviceglobals.cpp k3bcrc.cpp k3bcdtext.cpp k3bhalconnection.cpp \ +k3bdebug.cpp + +include_HEADERS = k3bdevicemanager.h k3bdevice.h k3btoc.h k3btrack.h \ +k3bdeviceglobals.h k3bdiskinfo.h k3bcdtext.h k3bmsf.h k3bdevicetypes.h \ +k3bdevice_export.h k3bhalconnection.h k3bdebug.h +else +libk3bdevice_la_SOURCES = k3bdevice.cpp k3bdevice_mmc.cpp k3bscsicommand.cpp \ +k3btrack.cpp k3btoc.cpp k3bdevicemanager.cpp k3bmsf.cpp k3bdiskinfo.cpp \ +k3bdeviceglobals.cpp k3bcrc.cpp k3bcdtext.cpp k3bdebug.cpp + +include_HEADERS = k3bdevicemanager.h k3bdevice.h k3btoc.h k3btrack.h \ +k3bdeviceglobals.h k3bdiskinfo.h k3bcdtext.h k3bmsf.h k3bdevicetypes.h \ +k3bdevice_export.h k3bdebug.h +endif + +messages: rc.cpp + $(XGETTEXT) `find -name "*.cpp" -or -name "*.h"` -o $(podir)/libk3bdevice.pot diff --git a/libk3bdevice/configure.in.bot b/libk3bdevice/configure.in.bot new file mode 100644 index 0000000..fbb068d --- /dev/null +++ b/libk3bdevice/configure.in.bot @@ -0,0 +1,20 @@ +echo "" + +if test -n "$RESMGR_LIB"; then + echo "K3b - Resmgr support: yes" +else + echo "K3b - Resmgr support: no" +fi + +echo "" + + +if test x$have_hal = xyes; then + echo "K3b - Compile HAL support yes" +else + echo "K3b - Compile HAL support no" +if test "x$ac_cv_use_hal" = "xyes" ; then + echo "K3b - You are missing the HAL >= 0.5 headers and libraries" + echo "K3b - or the DBus Qt bindings." +fi +fi diff --git a/libk3bdevice/configure.in.in b/libk3bdevice/configure.in.in new file mode 100644 index 0000000..5cabeec --- /dev/null +++ b/libk3bdevice/configure.in.in @@ -0,0 +1,212 @@ +dnl FIXME: only make the linux header check on linux systems. + +linux_scsi=no +AC_MSG_CHECKING(for linux scsi headers) +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +AC_TRY_COMPILE([ + #include <linux/version.h> + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,50) + typedef unsigned char u8; + #endif + #include <sys/types.h> + #include <linux/../scsi/scsi.h> /* cope with silly includes */ + ], + [], + [linux_scsi=yes]) +AC_MSG_RESULT($linux_scsi) + +case "$host_os" in +freebsd*|dragonfly*) + # I'll be damned if lousy coding prevents us from running + # this application. + linux_scsi=yes + ;; +esac + +if test "x$linux_scsi" = "xno" ; then + DO_NOT_COMPILE="$DO_NOT_COMPILE k3b" +fi +AC_LANG_RESTORE + +dnl - find the cam_* functions +AC_CHECK_FUNC(cam_close_device, + [CAM_LIB=""], + [AC_CHECK_LIB(cam, cam_close_device, [CAM_LIB=-lcam], [CAM_LIB=""])] + ) +AC_SUBST(CAM_LIB) + + + +dnl === check for resmgr - begin ============ +AC_ARG_WITH( + resmgr, + AS_HELP_STRING([--without-resmgr], [build K3b without ResMgr support (default=no)]), + [ac_cv_use_resmgr=$withval], + [ac_cv_use_resmgr=yes] +) + +if test "$ac_cv_use_resmgr" = "yes"; then + RESMGR_LIB="" + KDE_CHECK_HEADERS(resmgr.h, [ + KDE_CHECK_LIB(resmgr,rsm_open_device,[ + RESMGR_LIB="-lresmgr" + AC_DEFINE(HAVE_RESMGR,1,[defined if you have resmgr libraries and headers]) + ]) + ]) + AC_SUBST(RESMGR_LIB) +fi +dnl === check for resmgr - end ============ + + + + + +# HAL check from kdebase/kioslave/media + +AC_ARG_WITH( + hal, + AS_HELP_STRING( + [--without-hal], + [build K3b without HAL support (default=no)]), + [ac_cv_use_hal=$withval], + [ac_cv_use_hal=yes] +) + +if test "x$ac_cv_use_hal" = "xyes" ; then + +########### Check for the HAL + + AC_MSG_CHECKING(for the HAL) + + hal_inc=NOTFOUND + hal_lib=NOTFOUND + hal=NOTFOUND + + search_incs="$kde_includes /usr/include /usr/include/hal /usr/local/include /usr/local/include/hal" + AC_FIND_FILE(libhal.h libhal-storage.h, $search_incs, hal_incdir) + + if [test -r $hal_incdir/libhal.h] ; then + HAL_INCS="-I$hal_incdir" + hal_inc=FOUND + fi + + if test -r $hal_incdir/libhal-storage.h ; then + hal_storage_version=4 + grep LibHalVolume $hal_incdir/libhal-storage.h \ + > /dev/null 2>&1 && hal_storage_version=5 + if test $hal_storage_version = 4 ; then + AC_DEFINE(HAL_0_4, , [HAL API version 0.4]) + fi + fi + + search_libs="$kde_libraries /usr/lib64 /usr/lib /usr/local/lib /lib /lib64" + AC_FIND_FILE(libhal.so, $search_libs, hal_libdir) + + if [test -r $hal_libdir/libhal.so] ; then + HAL_LIBS="-L$hal_libdir -lhal" + hal_lib=FOUND + fi + + + if [test $hal_inc = FOUND] && [test $hal_lib = FOUND] ; then + AC_MSG_RESULT(headers $hal_incdir libraries $hal_libdir) + hal=FOUND + else + AC_MSG_RESULT(searched but not found) + fi + + AC_SUBST(HAL_INCS) + AC_SUBST(HAL_LIBS) + + +########### Check for DBus + + AC_MSG_CHECKING(for DBus) + + dbus_inc=NOTFOUND + dbus_lib=NOTFOUND + dbus=NOTFOUND + + search_incs="$kde_includes /usr/include /usr/include/dbus-1.0 /usr/local/include /usr/local/include/dbus-1.0" + AC_FIND_FILE(dbus/dbus.h, $search_incs, dbus_incdir) + + search_incs_arch_deps="$kde_includes /usr/lib64/dbus-1.0/include /usr/lib/dbus-1.0/include /usr/local/lib/dbus-1.0/include" + AC_FIND_FILE(dbus/dbus-arch-deps.h, $search_incs_arch_deps, dbus_incdir_arch_deps) + + if [test -r $dbus_incdir/dbus/dbus.h] && [test -r $dbus_incdir_arch_deps/dbus/dbus-arch-deps.h] ; then + DBUS_INCS="-I$dbus_incdir -I$dbus_incdir_arch_deps" + dbus_inc=FOUND + fi + + search_libs="$kde_libraries /usr/lib64 /usr/lib /usr/local/lib /lib /lib64" + AC_FIND_FILE(libdbus-1.so, $search_libs, dbus_libdir) + + if test -r $dbus_libdir/libdbus-1.so ; then + DBUS_LIBS="-L$dbus_libdir -ldbus-1" + dbus_lib=FOUND + fi + + if [test $dbus_inc = FOUND] && [test $dbus_lib = FOUND] ; then + AC_MSG_RESULT(headers $dbus_incdir $dbus_incdir_arch_deps libraries $dbus_libdir) + dbus=FOUND + else + AC_MSG_RESULT(searched but not found) + fi + + AC_SUBST(DBUS_INCS) + AC_SUBST(DBUS_LIBS) + +########### Check for DBus-Qt bindings + + AC_MSG_CHECKING(for DBus-Qt bindings) + + dbusqt_inc=NOTFOUND + dbusqt_lib=NOTFOUND + dbusqt=NOTFOUND + + search_incs="$kde_includes /usr/include /usr/include/dbus-1.0 /usr/local/include /usr/local/include/dbus-1.0" + AC_FIND_FILE(dbus/connection.h, $search_incs, dbusqt_incdir) + + if test -r $dbusqt_incdir/dbus/connection.h ; then + have_qt_patch=0 + grep dbus_connection_setup_with_qt_main $dbusqt_incdir/dbus/connection.h \ + > /dev/null 2>&1 && have_qt_patch=1 + if test $have_qt_patch = 1 ; then + DBUSQT_INCS="-I$dbusqt_incdir" + dbusqt_inc=FOUND + fi + fi + + search_libs="$kde_libraries /usr/lib /usr/lib64 /usr/local/lib" + AC_FIND_FILE(libdbus-qt-1.so, $search_libs, dbusqt_libdir) + + if test -r $dbusqt_libdir/libdbus-qt-1.so ; then + DBUSQT_LIBS="-L$dbusqt_libdir -ldbus-qt-1" + dbusqt_lib=FOUND + fi + + if [test $dbusqt_inc = FOUND] && [test $dbusqt_lib = FOUND] ; then + AC_MSG_RESULT(headers $dbusqt_incdir libraries $dbusqt_libdir) + dbusqt=FOUND + else + AC_MSG_RESULT(searched but not found) + fi + + AC_SUBST(DBUSQT_INCS) + AC_SUBST(DBUSQT_LIBS) +fi + +########### Check if media HAL backend sould be compiled + +have_hal=no +HAL_DBUS_LIBS="" +if [test "x$hal" = "xFOUND"] && [test "x$dbus" = "xFOUND"] && [test "x$dbusqt" = "xFOUND"] && [ test $hal_storage_version = 5 ] ; then + AC_DEFINE(HAVE_HAL, , [compile in HAL support]) + have_hal=yes + HAL_DBUS_LIBS="$HAL_LIBS $DBUS_LIBS $DBUSQT_LIBS" +fi + +AM_CONDITIONAL(include_HAL, [test x$have_hal = xyes]) +AC_SUBST(HAL_DBUS_LIBS) + diff --git a/libk3bdevice/k3bcdtext.cpp b/libk3bdevice/k3bcdtext.cpp new file mode 100644 index 0000000..713f7dd --- /dev/null +++ b/libk3bdevice/k3bcdtext.cpp @@ -0,0 +1,685 @@ +/* + * + * $Id: k3bcdtext.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include <config.h> + +#include "k3bcdtext.h" +#include "k3bcrc.h" + +#include <k3bdebug.h> + +#include <qtextcodec.h> + +#include <string.h> + + +namespace K3bDevice { + + struct cdtext_pack { + unsigned char id1; + unsigned char id2; + unsigned char id3; +#ifdef WORDS_BIGENDIAN // __BYTE_ORDER == __BIG_ENDIAN + unsigned char dbcc: 1; + unsigned char blocknum: 3; + unsigned char charpos: 4; +#else + unsigned char charpos: 4; + unsigned char blocknum: 3; + unsigned char dbcc: 1; +#endif + unsigned char data[12]; + unsigned char crc[2]; + }; + + /** + * This one is taken from cdrecord + */ + struct text_size_block { + char charcode; + char first_track; + char last_track; + char copyr_flags; + char pack_count[16]; + char last_seqnum[8]; + char language_codes[8]; + }; + + void debugRawTextPackData( const unsigned char* data, int dataLen ) + { + k3bDebug() << endl << " id1 | id2 | id3 | charps | blockn | dbcc | data | crc |" << endl; + + cdtext_pack* pack = (cdtext_pack*)data; + + for( int i = 0; i < dataLen/18; ++i ) { + QString s; + s += QString( " %1 |" ).arg( pack[i].id1, 6, 16 ); + s += QString( " %1 |" ).arg( pack[i].id2, 6 ); + s += QString( " %1 |" ).arg( pack[i].id3, 6 ); + s += QString( " %1 |" ).arg( pack[i].charpos, 6 ); + s += QString( " %1 |" ).arg( pack[i].blocknum, 6 ); + s += QString( " %1 |" ).arg( pack[i].dbcc, 4 ); +// char str[12]; +// sprintf( str, "%c%c%c%c%c%c%c%c%c%c%c%c", +// pack[i].data[0] == '\0' ? '' : pack[i].data[0], +// pack[i].data[1] == '\0' ? '' : pack[i].data[1], +// pack[i].data[2] == '\0' ? '' : pack[i].data[2], +// pack[i].data[3] == '\0' ? '' : pack[i].data[3], +// pack[i].data[4] == '\0' ? '' : pack[i].data[4], +// pack[i].data[5] == '\0' ? '' : pack[i].data[5], +// pack[i].data[6] == '\0' ? '' : pack[i].data[6], +// pack[i].data[7] == '\0' ? '' : pack[i].data[7], +// pack[i].data[8] == '\0' ? '' : pack[i].data[8], +// pack[i].data[9] == '\0' ? '' : pack[i].data[9], +// pack[i].data[10] == '\0' ? '' : pack[i].data[10], +// pack[i].data[11] == '\0' ? '' : pack[i].data[11] ); +// s += QString( " %1 |" ).arg( "'" + QCString(str,13) + "'", 14 ); +// Q_UINT16 crc = pack[i].crc[0]<<8|pack[i].crc[1]; +// s += QString( " %1 |" ).arg( crc ); + k3bDebug() << s << endl; + } + } + +} + + + +K3bDevice::CdText::CdText() +{ +} + + +K3bDevice::CdText::CdText( const K3bDevice::CdText& text ) + : QValueVector<K3bDevice::TrackCdText>( text ), + m_title( text.title() ), + m_performer( text.performer() ), + m_songwriter( text.songwriter() ), + m_composer( text.composer() ), + m_arranger( text.arranger() ), + m_message( text.message() ), + m_discId( text.discId() ), + m_upcEan( text.upcEan() ) +{ +} + + +K3bDevice::CdText::CdText( const unsigned char* data, int len ) +{ + setRawPackData( data, len ); +} + + +K3bDevice::CdText::CdText( const QByteArray& b ) +{ + setRawPackData( b ); +} + + +K3bDevice::CdText::CdText( int size ) +{ + resize( size ); +} + + +void K3bDevice::CdText::clear() +{ + QValueVector<TrackCdText>::clear(); + + m_title.setLength(0); + m_performer.setLength(0); + m_songwriter.setLength(0); + m_composer.setLength(0); + m_arranger.setLength(0); + m_message.setLength(0); + m_discId.setLength(0); + m_upcEan.setLength(0); +} + + +void K3bDevice::CdText::setRawPackData( const unsigned char* data, int len ) +{ + clear(); + + int r = len%18; + if( r > 0 && r != 4 ) { + k3bDebug() << "(K3bDevice::CdText) invalid cdtext size: " << len << endl; + } + else if( len-r > 0 ) { + debugRawTextPackData( &data[r], len-r ); + + cdtext_pack* pack = (cdtext_pack*)&data[r]; + + + for( int i = 0; i < (len-r)/18; ++i ) { + + if( pack[i].dbcc ) { + k3bDebug() << "(K3bDevice::CdText) Double byte code not supported" << endl; + return; + } + + // + // For some reason all crc bits are inverted. + // + pack[i].crc[0] ^= 0xff; + pack[i].crc[1] ^= 0xff; + + Q_UINT16 crc = calcX25( reinterpret_cast<unsigned char*>(&pack[i]), 18 ); + + pack[i].crc[0] ^= 0xff; + pack[i].crc[1] ^= 0xff; + + if( crc != 0x0000 ) + k3bDebug() << "(K3bDevice::CdText) CRC invalid!" << endl; + + + // + // pack.data has a length of 12 + // + // id1 tells us the tracknumber of the data (0 for global) + // data may contain multiple \0. In that case after every \0 the track number increases 1 + // + + char* nullPos = (char*)pack[i].data - 1; + + unsigned int trackNo = pack[i].id2; + + while( nullPos ) { + if( count() < trackNo ) + resize( trackNo ); + + char* nextNullPos = (char*)::memchr( nullPos+1, '\0', 11 - (nullPos - (char*)pack[i].data) ); + QString txtstr; + if( nextNullPos ) // take all chars up to the next null + txtstr = QString::fromLatin1( (char*)nullPos+1, nextNullPos - nullPos - 1 ); + else // take all chars to the end of the pack data (12 bytes) + txtstr = QString::fromLatin1( (char*)nullPos+1, 11 - (nullPos - (char*)pack[i].data) ); + + // + // a tab character means to use the same as for the previous track + // + if( txtstr == "\t" ) + txtstr = textForPackType( pack[i].id1, trackNo-1 ); + + switch( pack[i].id1 ) { + case 0x80: // Title + if( trackNo == 0 ) + m_title.append( txtstr ); + else + at(trackNo-1).m_title.append( txtstr ); + break; + + case 0x81: // Performer + if( trackNo == 0 ) + m_performer.append( txtstr ); + else + at(trackNo-1).m_performer.append( txtstr ); + break; + + case 0x82: // Writer + if( trackNo == 0 ) + m_songwriter.append( txtstr ); + else + at(trackNo-1).m_songwriter.append( txtstr ); + break; + + case 0x83: // Composer + if( trackNo == 0 ) + m_composer.append( txtstr ); + else + at(trackNo-1).m_composer.append( txtstr ); + break; + + case 0x84: // Arranger + if( trackNo == 0 ) + m_arranger.append( txtstr ); + else + at(trackNo-1).m_arranger.append( txtstr ); + break; + + case 0x85: // Message + if( trackNo == 0 ) + m_message.append( txtstr ); + else + at(trackNo-1).m_message.append( txtstr ); + break; + + case 0x86: // Disc identification + // only global + if( trackNo == 0 ) + m_discId.append( txtstr ); + break; + + case 0x8e: // Upc or isrc + if( trackNo == 0 ) + m_upcEan.append( txtstr ); + else + at(trackNo-1).m_isrc.append( txtstr ); + break; + + // TODO: support for binary data + // 0x88: TOC + // 0x89: second TOC + // 0x8f: Size information + + default: + break; + } + + trackNo++; + nullPos = nextNullPos; + } + } + + // remove empty fields at the end + unsigned int i = count(); + while( i > 0 && at(i-1).isEmpty() ) + --i; + resize( i ); + } + else + k3bDebug() << "(K3bDevice::CdText) zero-sized CD-TEXT: " << len << endl; +} + + +void K3bDevice::CdText::setRawPackData( const QByteArray& b ) +{ + setRawPackData( reinterpret_cast<const unsigned char*>(b.data()), b.size() ); +} + +QByteArray K3bDevice::CdText::rawPackData() const +{ + // FIXME: every pack block may only consist of up to 255 packs. + + unsigned int pc = 0; + unsigned int alreadyCountedPacks = 0; + + + // + // prepare the size information block + // + text_size_block tsize; + ::memset( &tsize, 0, sizeof(text_size_block) ); + tsize.charcode = 0; // ISO 8859-1 + tsize.first_track = 1; + tsize.last_track = count(); + tsize.pack_count[0xF] = 3; + tsize.language_codes[0] = 0x09; // English (from cdrecord) + + + // + // create the CD-Text packs + // + QByteArray data(0); + for( int i = 0; i <= 6; ++i ) { + if( textLengthForPackType( 0x80 | i ) ) { + appendByteArray( data, createPackData( 0x80 | i, pc ) ); + tsize.pack_count[i] = pc - alreadyCountedPacks; + alreadyCountedPacks = pc; + } + } + if( textLengthForPackType( 0x8E ) ) { + appendByteArray( data, createPackData( 0x8E, pc ) ); + tsize.pack_count[0xE] = pc - alreadyCountedPacks; + alreadyCountedPacks = pc; + } + + + // pc is the number of the next pack and we add 3 size packs + tsize.last_seqnum[0] = pc + 2; + + + // + // create the size info packs + // + unsigned int dataFill = data.size(); + data.resize( data.size() + 3 * sizeof(cdtext_pack) ); + for( int i = 0; i < 3; ++i ) { + cdtext_pack pack; + ::memset( &pack, 0, sizeof(cdtext_pack) ); + pack.id1 = 0x8F; + pack.id2 = i; + pack.id3 = pc+i; + ::memcpy( pack.data, &reinterpret_cast<char*>(&tsize)[i*12], 12 ); + savePack( &pack, data, dataFill ); + } + + // + // add MMC header + // + QByteArray a( 4 ); + a[0] = (data.size()+2)>>8 & 0xff; + a[1] = (data.size()+2) & 0xff; + a[2] = a[3] = 0; + appendByteArray( a, data ); + + return a; +} + + +void K3bDevice::CdText::appendByteArray( QByteArray& a, const QByteArray& b ) const +{ + unsigned int oldSize = a.size(); + a.resize( oldSize + b.size() ); + ::memcpy( &a.data()[oldSize], b.data(), b.size() ); +} + + +// this method also creates completely empty packs +QByteArray K3bDevice::CdText::createPackData( int packType, unsigned int& packCount ) const +{ + QByteArray data; + unsigned int dataFill = 0; + QCString text = encodeCdText( textForPackType( packType, 0 ) ); + unsigned int currentTrack = 0; + unsigned int textPos = 0; + unsigned int packPos = 0; + + // + // initialize the first pack + // + cdtext_pack pack; + ::memset( &pack, 0, sizeof(cdtext_pack) ); + pack.id1 = packType; + pack.id3 = packCount; + + // + // We break this loop when all texts have been packed + // + while( 1 ) { + // + // Copy as many bytes as possible into the pack + // + int copyBytes = QMIN( 12-packPos, text.length()-textPos ); + ::memcpy( reinterpret_cast<char*>(&pack.data[packPos]), &text.data()[textPos], copyBytes ); + textPos += copyBytes; + packPos += copyBytes; + + + // + // Check if the packdata is full + // + if( packPos > 11 ) { + + savePack( &pack, data, dataFill ); + ++packCount; + + // + // reset the pack + // + ::memset( &pack, 0, sizeof(cdtext_pack) ); + pack.id1 = packType; + pack.id2 = currentTrack; + pack.id3 = packCount; + packPos = 0; + + // update the charpos in case we continue a text in the next pack + if( textPos <= text.length() ) + pack.charpos = ( textPos > 15 ? 15 : textPos ); + } + + + // + // Check if we have no text data left + // + if( textPos >= text.length() ) { + + // add one zero spacer byte + ++packPos; + + ++currentTrack; + + // Check if all texts have been packed + if( currentTrack > count() ) { + savePack( &pack, data, dataFill ); + ++packCount; + + data.resize( dataFill ); + return data; + } + + // next text block + text = encodeCdText( textForPackType( packType, currentTrack ) ); + textPos = 0; + } + } +} + + +void K3bDevice::CdText::savePack( cdtext_pack* pack, QByteArray& data, unsigned int& dataFill ) const +{ + // create CRC + Q_UINT16 crc = calcX25( reinterpret_cast<unsigned char*>(pack), sizeof(cdtext_pack)-2 ); + + // invert for Redbook compliance + crc ^= 0xffff; + + pack->crc[0] = (crc>>8) & 0xff; + pack->crc[1] = crc & 0xff; + + + // append the pack to data + if( data.size() < dataFill + sizeof(cdtext_pack) ) + data.resize( dataFill + sizeof(cdtext_pack), QGArray::SpeedOptim ); + + ::memcpy( &data.data()[dataFill], reinterpret_cast<char*>( pack ), sizeof(cdtext_pack) ); + + dataFill += sizeof(cdtext_pack); +} + + +// track 0 means global cdtext +const QString& K3bDevice::CdText::textForPackType( int packType, unsigned int track ) const +{ + switch( packType ) { + default: + case 0x80: + if( track == 0 ) + return title(); + else + return at(track-1).title(); + + case 0x81: + if( track == 0 ) + return performer(); + else + return at(track-1).performer(); + + case 0x82: + if( track == 0 ) + return songwriter(); + else + return at(track-1).songwriter(); + + case 0x83: + if( track == 0 ) + return composer(); + else + return at(track-1).composer(); + + case 0x84: + if( track == 0 ) + return arranger(); + else + return at(track-1).arranger(); + + case 0x85: + if( track == 0 ) + return message(); + else + return at(track-1).message(); + + case 0x86: + if( track == 0 ) + return discId(); + else + return QString::null; + +// case 0x87: +// if( track == 0 ) +// return genre(); +// else +// return at(track-1).title(); + + case 0x8E: + if( track == 0 ) + return upcEan(); + else + return at(track-1).isrc(); + } +} + + +// count the overall length of a certain packtype texts +unsigned int K3bDevice::CdText::textLengthForPackType( int packType ) const +{ + unsigned int len = 0; + for( unsigned int i = 0; i <= count(); ++i ) + len += encodeCdText( textForPackType( packType, i ) ).length(); + return len; +} + + +QCString K3bDevice::encodeCdText( const QString& s, bool* illegalChars ) +{ + if( illegalChars ) + *illegalChars = false; + + // TODO: do this without QT + QTextCodec* codec = QTextCodec::codecForName("ISO8859-1"); + if( codec ) { + QCString encoded = codec->fromUnicode( s ); + return encoded; + } + else { + QCString r(s.length()+1); + + for( unsigned int i = 0; i < s.length(); ++i ) { + if( s[i].latin1() == 0 ) { // non-ASCII character + r[i] = ' '; + if( illegalChars ) + *illegalChars = true; + } + else + r[i] = s[i].latin1(); + } + + return r; + } +} + + +bool K3bDevice::CdText::checkCrc( const QByteArray& rawData ) +{ + return checkCrc( reinterpret_cast<const unsigned char*>(rawData.data()), rawData.size() ); +} + + +bool K3bDevice::CdText::checkCrc( const unsigned char* data, int len ) +{ + int r = len%18; + if( r > 0 && r != 4 ) { + k3bDebug() << "(K3bDevice::CdText) invalid cdtext size: " << len << endl; + return false; + } + else { + len -= r; + + // TODO: what if the crc field is not used? All zeros? + + for( int i = 0; i < (len-r)/18; ++i ) { + cdtext_pack* pack = (cdtext_pack*)&data[r]; + + // + // For some reason all crc bits are inverted. + // + pack[i].crc[0] ^= 0xff; + pack[i].crc[1] ^= 0xff; + + int crc = calcX25( reinterpret_cast<unsigned char*>(&pack[i]), 18 ); + + pack[i].crc[0] ^= 0xff; + pack[i].crc[1] ^= 0xff; + + if( crc != 0x0000 ) + return false; + } + + return true; + } +} + + +void K3bDevice::CdText::debug() const +{ + // debug the stuff + k3bDebug() << "CD-TEXT data:" << endl + << "Global:" << endl + << " Title: '" << title() << "'" << endl + << " Performer: '" << performer() << "'" << endl + << " Songwriter: '" << songwriter() << "'" << endl + << " Composer: '" << composer() << "'" << endl + << " Arranger: '" << arranger() << "'" << endl + << " Message: '" << message() << "'" << endl + << " Disc ID: '" << discId() << "'" << endl + << " Upc Ean: '" << upcEan() << "'" << endl; + for( unsigned int i = 0; i < count(); ++i ) { + k3bDebug() << "Track " << (i+1) << ":" << endl + << " Title: '" << at(i).title() << "'" << endl + << " Performer: '" << at(i).performer() << "'" << endl + << " Songwriter: '" << at(i).songwriter() << "'" << endl + << " Composer: '" << at(i).composer() << "'" << endl + << " Arranger: '" << at(i).arranger() << "'" << endl + << " Message: '" << at(i).message() << "'" << endl + << " Isrc: '" << at(i).isrc() << "'" << endl; + } +} + + +bool K3bDevice::TrackCdText::operator==( const K3bDevice::TrackCdText& other ) const +{ + return( m_title == other.m_title && + m_performer == other.m_performer && + m_songwriter == other.m_songwriter && + m_composer == other.m_composer && + m_arranger == other.m_arranger && + m_message == other.m_message && + m_isrc == other.m_isrc ); +} + + +bool K3bDevice::TrackCdText::operator!=( const K3bDevice::TrackCdText& other ) const +{ + return !operator==( other ); +} + + +bool K3bDevice::CdText::operator==( const K3bDevice::CdText& other ) const +{ + return( m_title == other.m_title && + m_performer == other.m_performer && + m_songwriter == other.m_songwriter && + m_composer == other.m_composer && + m_arranger == other.m_arranger && + m_message == other.m_message && + m_discId == other.m_discId && + m_upcEan == other.m_upcEan && + QValueVector<TrackCdText>::operator==( other ) ); +} + + +bool K3bDevice::CdText::operator!=( const K3bDevice::CdText& other ) const +{ + return !operator==( other ); +} diff --git a/libk3bdevice/k3bcdtext.h b/libk3bdevice/k3bcdtext.h new file mode 100644 index 0000000..10f6c82 --- /dev/null +++ b/libk3bdevice/k3bcdtext.h @@ -0,0 +1,201 @@ +/* + * + * $Id: k3bcdtext.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_CDTEXT_H_ +#define _K3B_CDTEXT_H_ + +#include <qstring.h> +#include <qvaluevector.h> +#include "k3bdevice_export.h" + +namespace K3bDevice +{ + struct cdtext_pack; + + class TrackCdText + { + friend class Device; + + public: + TrackCdText() { + } + + void clear() { + m_title.truncate(0); + m_performer.truncate(0); + m_songwriter.truncate(0); + m_composer.truncate(0); + m_arranger.truncate(0); + m_message.truncate(0); + m_isrc.truncate(0); + } + + const QString& title() const { return m_title; } + const QString& performer() const { return m_performer; } + const QString& songwriter() const { return m_songwriter; } + const QString& composer() const { return m_composer; } + const QString& arranger() const { return m_arranger; } + const QString& message() const { return m_message; } + const QString& isrc() const { return m_isrc; } + + // TODO: use the real CD-TEXT charset (a modified ISO8859-1) + void setTitle( const QString& s ) { m_title = s; fixup(m_title); } + void setPerformer( const QString& s ) { m_performer = s; fixup(m_performer); } + void setSongwriter( const QString& s ) { m_songwriter = s; fixup(m_songwriter); } + void setComposer( const QString& s ) { m_composer = s; fixup(m_composer); } + void setArranger( const QString& s ) { m_arranger = s; fixup(m_arranger); } + void setMessage( const QString& s ) { m_message = s; fixup(m_message); } + void setIsrc( const QString& s ) { m_isrc = s; fixup(m_isrc); } + + bool isEmpty() const { + if( !m_title.isEmpty() ) + return false; + if( !m_performer.isEmpty() ) + return false; + if( !m_songwriter.isEmpty() ) + return false; + if( !m_composer.isEmpty() ) + return false; + if( !m_arranger.isEmpty() ) + return false; + if( !m_message.isEmpty() ) + return false; + if( !m_isrc.isEmpty() ) + return false; + + return true; + } + + bool operator==( const TrackCdText& ) const; + bool operator!=( const TrackCdText& ) const; + + private: + // TODO: remove this (see above) + void fixup( QString& s ) { s.replace( '/', "_" ); s.replace( '\"', "_" ); } + + QString m_title; + QString m_performer; + QString m_songwriter; + QString m_composer; + QString m_arranger; + QString m_message; + QString m_isrc; + + friend class CdText; + }; + + class LIBK3BDEVICE_EXPORT CdText : public QValueVector<TrackCdText> + { + friend class Device; + + public: + CdText(); + CdText( const unsigned char* data, int len ); + CdText( const QByteArray& ); + CdText( int size ); + CdText( const CdText& ); + + void setRawPackData( const unsigned char*, int ); + void setRawPackData( const QByteArray& ); + + QByteArray rawPackData() const; + + bool empty() const { + if( !m_title.isEmpty() ) + return false; + if( !m_performer.isEmpty() ) + return false; + if( !m_songwriter.isEmpty() ) + return false; + if( !m_composer.isEmpty() ) + return false; + if( !m_arranger.isEmpty() ) + return false; + if( !m_message.isEmpty() ) + return false; + if( !m_discId.isEmpty() ) + return false; + if( !m_upcEan.isEmpty() ) + return false; + + for( unsigned int i = 0; i < count(); ++i ) + if( !at(i).isEmpty() ) + return false; + + return true; + } + + bool isEmpty() const { + return empty(); + } + + void clear(); + + const QString& title() const { return m_title; } + const QString& performer() const { return m_performer; } + const QString& songwriter() const { return m_songwriter; } + const QString& composer() const { return m_composer; } + const QString& arranger() const { return m_arranger; } + const QString& message() const { return m_message; } + const QString& discId() const { return m_discId; } + const QString& upcEan() const { return m_upcEan; } + + // TODO: use the real CD-TEXT charset (a modified ISO8859-1) + void setTitle( const QString& s ) { m_title = s; fixup(m_title); } + void setPerformer( const QString& s ) { m_performer = s; fixup(m_performer); } + void setSongwriter( const QString& s ) { m_songwriter = s; fixup(m_songwriter); } + void setComposer( const QString& s ) { m_composer = s; fixup(m_composer); } + void setArranger( const QString& s ) { m_arranger = s; fixup(m_arranger); } + void setMessage( const QString& s ) { m_message = s; fixup(m_message); } + void setDiscId( const QString& s ) { m_discId = s; fixup(m_discId); } + void setUpcEan( const QString& s ) { m_upcEan = s; fixup(m_upcEan); } + + void debug() const; + + /** + * Returns false if found a crc error in the raw cdtext block or it has a + * wrong length. + */ + static bool checkCrc( const unsigned char*, int ); + static bool checkCrc( const QByteArray& ); + + bool operator==( const CdText& ) const; + bool operator!=( const CdText& ) const; + + private: + // TODO: remove this (see above) + void fixup( QString& s ) { s.replace( '/', "_" ); s.replace( '\"', "_" ); } + + const QString& textForPackType( int packType, unsigned int track ) const; + unsigned int textLengthForPackType( int packType ) const; + QByteArray createPackData( int packType, unsigned int& ) const; + void savePack( cdtext_pack* pack, QByteArray& data, unsigned int& dataFill ) const; + void appendByteArray( QByteArray& a, const QByteArray& b ) const; + + QString m_title; + QString m_performer; + QString m_songwriter; + QString m_composer; + QString m_arranger; + QString m_message; + QString m_discId; + QString m_upcEan; + }; + + QCString encodeCdText( const QString& s, bool* illegalChars = 0 ); +} + +#endif diff --git a/libk3bdevice/k3bcrc.cpp b/libk3bdevice/k3bcrc.cpp new file mode 100644 index 0000000..f533ae7 --- /dev/null +++ b/libk3bdevice/k3bcrc.cpp @@ -0,0 +1,80 @@ +/* + * + * $Id: k3bcrc.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bcrc.h" + +#include <k3bdebug.h> + + +static Q_UINT16 g_x25Table[1<<8] = { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0, +}; + + +Q_UINT16 K3bDevice::calcX25( unsigned char* message, unsigned int len, Q_UINT16 crc ) +{ + while( len-- ) { + crc = (crc<<8) ^ g_x25Table[(crc>>8) ^ (*message++)]; + } + + return crc; +} + + +bool K3bDevice::checkQCrc( unsigned char* subdata ) +{ + // Red Book for some reason inverts the CRC bytes + subdata[10] ^= 0xff; + subdata[11] ^= 0xff; + + Q_UINT16 crc = calcX25( subdata, 12 ); + + // correct the data + subdata[10] ^= 0xff; + subdata[11] ^= 0xff; + + return( crc == 0x0000 ); +} diff --git a/libk3bdevice/k3bcrc.h b/libk3bdevice/k3bcrc.h new file mode 100644 index 0000000..ee7d6a6 --- /dev/null +++ b/libk3bdevice/k3bcrc.h @@ -0,0 +1,35 @@ +/* + * + * $Id: k3bcrc.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_CRC_H_ +#define _K3B_CRC_H_ + +#include <qglobal.h> + +namespace K3bDevice +{ + // static K3bCrc* x25(); + + // bool check( unsigned char* message, unsigned int len, unsigned char* crc, unsigned int crcLen ); + + Q_UINT16 calcX25( unsigned char* message, unsigned int len, Q_UINT16 start = 0x0000 ); + + /** + * subdata is 12 bytes in long. + */ + bool checkQCrc( unsigned char* subdata ); +}; + +#endif diff --git a/libk3bdevice/k3bdebug.cpp b/libk3bdevice/k3bdebug.cpp new file mode 100644 index 0000000..40774aa --- /dev/null +++ b/libk3bdevice/k3bdebug.cpp @@ -0,0 +1,137 @@ +/* + * + * $Id: k3bemptydiscwaiter.cpp 606691 2006-11-21 12:15:21Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bdebug.h" + +#include <stdio.h> + + +K3bDebug::K3bDebug() +{ +} + + +K3bDebug::~K3bDebug() +{ +} + + +K3bDebug& K3bDebug::operator<<( int i ) +{ + fprintf( stderr, "%i", i ); + return *this; +} + + +K3bDebug& K3bDebug::operator<<( long l ) +{ + fprintf( stderr, "%li", l ); + return *this; +} + + +K3bDebug& K3bDebug::operator<<( unsigned int i ) +{ + fprintf( stderr, "%u", i ); + return *this; +} + + +K3bDebug& K3bDebug::operator<<( unsigned long l ) +{ + fprintf( stderr, "%lu", l ); + return *this; +} + + +K3bDebug& K3bDebug::operator<<( unsigned long long l ) +{ + fprintf( stderr, "%llu", l ); + return *this; +} + + +K3bDebug& K3bDebug::operator<<( char c ) +{ + fprintf( stderr, "%c", c ); + return *this; +} + + +K3bDebug& K3bDebug::operator<<( float f ) +{ + fprintf( stderr, "%f", f ); + return *this; +} + + +K3bDebug& K3bDebug::operator<<( double d ) +{ + fprintf( stderr, "%f", d ); + return *this; +} + + +K3bDebug& K3bDebug::operator<<( const QString& s ) +{ + fprintf( stderr, "%s", s.utf8().data() ); + return *this; +} + + +K3bDebug& K3bDebug::operator<<( const QCString& s ) +{ + fprintf( stderr, "%s", s.data() ); + return *this; +} + + +K3bDebug& K3bDebug::operator<<( const char* s ) +{ + fprintf( stderr, "%s", s ); + return *this; +} + + +K3bDebug& K3bDebug::operator<<( const K3b::Msf& msf ) +{ + return *this << msf.toString(); +} + + +K3bDebug& K3bDebug::operator<<( K3BDBGFUNC f ) +{ + return f( *this ); +} + + +K3bDebug& K3bDebug::k3bDebug() +{ + static K3bDebug s_debug; + return s_debug; +} + + + +K3bDebug& k3bDebug() +{ + return K3bDebug::k3bDebug(); +} + + +K3bDebug& endl( K3bDebug& s ) +{ + return s << '\n'; +} diff --git a/libk3bdevice/k3bdebug.h b/libk3bdevice/k3bdebug.h new file mode 100644 index 0000000..8bdd374 --- /dev/null +++ b/libk3bdevice/k3bdebug.h @@ -0,0 +1,63 @@ +/* + * + * $Id: k3bemptydiscwaiter.cpp 606691 2006-11-21 12:15:21Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_DEBUG_H_ +#define _K3B_DEBUG_H_ + +#include <qstring.h> + +#include <k3bmsf.h> +#include <k3bdevice_export.h> + +class K3bDebug; + +typedef K3bDebug& (*K3BDBGFUNC)( K3bDebug& ); + +/** + * K3bDebug as compared to KDebug does not need anything. No KInstance or whatever + * and does not use anything except fprintf. + * Thus, K3bDebug is fully thread-safe and safe in general + */ +class LIBK3BDEVICE_EXPORT K3bDebug +{ + public: + ~K3bDebug(); + + K3bDebug& operator<<( int ); + K3bDebug& operator<<( long ); + K3bDebug& operator<<( unsigned int ); + K3bDebug& operator<<( unsigned long ); + K3bDebug& operator<<( unsigned long long ); + K3bDebug& operator<<( char ); + K3bDebug& operator<<( float ); + K3bDebug& operator<<( double ); + K3bDebug& operator<<( const QString& ); + K3bDebug& operator<<( const QCString& ); + K3bDebug& operator<<( const char* ); + K3bDebug& operator<<( const K3b::Msf& ); + + K3bDebug& operator<<( K3BDBGFUNC ); + + static K3bDebug& k3bDebug(); + + private: + K3bDebug(); +}; + +LIBK3BDEVICE_EXPORT K3bDebug& k3bDebug(); +LIBK3BDEVICE_EXPORT K3bDebug& endl( K3bDebug& ); + +#endif diff --git a/libk3bdevice/k3bdevice.cpp b/libk3bdevice/k3bdevice.cpp new file mode 100644 index 0000000..45ba7bf --- /dev/null +++ b/libk3bdevice/k3bdevice.cpp @@ -0,0 +1,3650 @@ +/* + * + * $Id: k3bdevice.cpp 732002 2007-11-02 14:13:14Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include <config.h> + + +#include "k3bdevice.h" +#include "k3bdeviceglobals.h" +#include "k3btrack.h" +#include "k3btoc.h" +#include "k3bdiskinfo.h" +#include "k3bmmc.h" +#include "k3bscsicommand.h" +#include "k3bcrc.h" + +#include <qstringlist.h> +#include <qfile.h> +#include <qglobal.h> +#include <qvaluevector.h> +#include <qmutex.h> + +#include <k3bdebug.h> + +#include <sys/types.h> +#include <sys/ioctl.h> + +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <sys/stat.h> +#include <math.h> +#include <stdarg.h> + + +#ifdef Q_OS_LINUX + +#include <linux/version.h> +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,70) +typedef unsigned char u8; +#endif + +#undef __STRICT_ANSI__ +#include <linux/cdrom.h> +#define __STRICT_ANSI__ + +#endif // Q_OS_LINUX + +#ifdef Q_OS_FREEBSD +#include <stdio.h> +#include <camlib.h> +#define CD_FRAMESIZE_RAW 2352 +#endif + +#ifdef Q_OS_NETBSD +#include <sys/cdio.h> +#endif + +#ifdef HAVE_RESMGR +extern "C" { +#include <resmgr.h> +} +#endif + + +// +// Very evil hacking: force the speed values to be acurate +// as long as "they" do not introduce other "broken" DVD +// speeds like 2.4 this works fine +// +static int fixupDvdWritingSpeed( int speed ) +{ + // + // Some writers report their speeds in 1000 bytes per second instead of 1024. + // + if( speed % 1385 == 0 ) + return speed; + + else if( speed % 1352 == 0 ) + return speed*1385/1352; + + // has to be 2.4x speed + else + return 3324; +} + + +const char* K3bDevice::Device::cdrdao_drivers[] = + { "auto", "plextor", "plextor-scan", "cdd2600", "generic-mmc", + "generic-mmc-raw", "ricoh-mp6200", "sony-cdu920", + "sony-cdu948", "taiyo-yuden", "teac-cdr55", "toshiba", + "yamaha-cdr10x", 0 + }; + + +#if defined(Q_OS_LINUX) || defined(Q_OS_NETBSD) +int K3bDevice::openDevice( const char* name, bool write ) +{ + int fd = -1; + int flags = O_NONBLOCK; + if( write ) + flags |= O_RDWR; + else + flags |= O_RDONLY; + +#ifdef HAVE_RESMGR + // first try resmgr + fd = ::rsm_open_device( name, flags ); + // k3bDebug() << "(K3bDevice::Device) resmgr open: " << fd << endl; +#endif + + if( fd < 0 ) + fd = ::open( name, flags ); + + if( fd < 0 ) { + k3bDebug() << "(K3bDevice::Device) could not open device " + << name << ( write ? " for writing" : " for reading" ) << endl; + k3bDebug() << " (" << strerror(errno) << ")" << endl; + fd = -1; + + // at least open it read-only (which is sufficient for kernels < 2.6.8 anyway) + if( write ) + return openDevice( name, false ); + } + + return fd; +} +#endif + + +class K3bDevice::Device::Private +{ +public: + Private() + : supportedProfiles(0), +#ifdef Q_OS_LINUX + deviceFd(-1), +#endif +#ifdef Q_OS_NETBSD + deviceFd(-1), +#endif +#ifdef Q_OS_FREEBSD + cam(0), +#endif + openedReadWrite(false), + burnfree(false) { + } + + int readCapabilities; + int writeCapabilities; + int supportedProfiles; + QStringList allNodes; +#ifdef Q_OS_LINUX + int deviceFd; +#endif +#ifdef Q_OS_NETBSD + int deviceFd; +#endif +#ifdef Q_OS_FREEBSD + struct cam_device *cam; +#endif + bool openedReadWrite; + bool burnfree; + + QMutex mutex; + QMutex openCloseMutex; +}; + + +K3bDevice::Device::Device( const QString& devname ) + : m_bus(-1), + m_target(-1), + m_lun(-1), + m_writeModes(0) +{ + d = new Private; + + m_blockDevice = devname; + d->allNodes.append(devname); + + m_cdrdaoDriver = "auto"; + m_cdTextCapable = 0; + m_maxWriteSpeed = 0; + m_maxReadSpeed = 0; + d->burnfree = false; + m_dvdMinusTestwrite = true; + m_bufferSize = 0; +} + + +K3bDevice::Device::~Device() +{ + close(); + delete d; +} + + +bool K3bDevice::Device::init( bool bCheckWritingModes ) +{ + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << ": init()" << endl; + + // + // they all should read CD-ROM. + // + d->readCapabilities = MEDIA_CD_ROM; + d->writeCapabilities = 0; + d->supportedProfiles = 0; + + if( !open() ) + return false; + + // + // inquiry + // use a 36 bytes buffer since not all devices return the full inquiry struct + // + ScsiCommand cmd( this ); + unsigned char buf[36]; + cmd.clear(); + ::memset( buf, 0, sizeof(buf) ); + struct inquiry* inq = (struct inquiry*)buf; + cmd[0] = MMC_INQUIRY; + cmd[4] = sizeof(buf); + cmd[5] = 0; + if( cmd.transport( TR_DIR_READ, buf, sizeof(buf) ) ) { + kdError() << "(K3bDevice::Device) Unable to do inquiry." << endl; + close(); + return false; + } + else { + m_vendor = QString::fromLatin1( (char*)(inq->vendor), 8 ).stripWhiteSpace(); + m_description = QString::fromLatin1( (char*)(inq->product), 16 ).stripWhiteSpace(); + m_version = QString::fromLatin1( (char*)(inq->revision), 4 ).stripWhiteSpace(); + } + + if( m_vendor.isEmpty() ) + m_vendor = "UNKNOWN"; + if( m_description.isEmpty() ) + m_description = "UNKNOWN"; + + // + // We probe all features of the device. Since not all devices support the GET CONFIGURATION command + // we also query the mode page 2A and use the cdrom.h stuff to get as much information as possible + // + checkFeatures(); + + // + // Check the supported write modes (WRITINGMODE_TAO, WRITINGMODE_SAO, WRITINGMODE_RAW) by trying to set them + // We do this before checking mode page 2A in case some readers allow changin + // the write parameter page + // + if( bCheckWritingModes ) + checkWritingModes(); + + // + // Most current drives support the 2A mode page + // Here we can get some more information (cdrecord -prcap does exactly this) + // + checkFor2AFeatures(); + + m_maxWriteSpeed = determineMaximalWriteSpeed(); + + // + // Check Just-Link via Ricoh mode page 0x30 + // + if( !d->burnfree ) + checkForJustLink(); + + // + // Support for some very old drives + // + checkForAncientWriters(); + + // + // If it can be written it can also be read + // + d->readCapabilities |= d->writeCapabilities; + + close(); + + return furtherInit(); +} + + +bool K3bDevice::Device::furtherInit() +{ +#ifdef Q_OS_LINUX + + // + // Since all CDR drives at least support WRITINGMODE_TAO, all CDRW drives should support + // mode page 2a and all DVD writer should support mode page 2a or the GET CONFIGURATION + // command this is redundant and may be removed for BSD ports or even completely + // + // We just keep it here because of the "should" in the sentence above. If someone can tell me + // that the linux driver does nothing more we can remove it completely. + // + open(); + int drivetype = ::ioctl( handle(), CDROM_GET_CAPABILITY, CDSL_CURRENT ); + if( drivetype < 0 ) { + k3bDebug() << "Error while retrieving capabilities." << endl; + close(); + return false; + } + + d->readCapabilities |= DEVICE_CD_ROM; + + if( drivetype & CDC_CD_R ) + d->writeCapabilities |= MEDIA_CD_R; + if( drivetype & CDC_CD_RW ) + d->writeCapabilities |= MEDIA_CD_RW; + if( drivetype & CDC_DVD_R ) + d->writeCapabilities |= MEDIA_DVD_R; + if( drivetype & CDC_DVD ) + d->readCapabilities |= MEDIA_DVD_ROM; + + close(); + +#endif // Q_OS_LINUX + return true; +} + + +void K3bDevice::Device::checkForAncientWriters() +{ + // TODO: add a boolean which determines if this device is non-MMC so we may warn the user at K3b startup about it + + // + // There are a lot writers out there which behave like the TEAC R5XS + // + if( ( vendor().startsWith("TEAC") && ( description().startsWith("CD-R50S") || + description().startsWith("CD-R55S") ) ) + || + ( vendor().startsWith("SAF") && ( description().startsWith("CD-R2006PLUS") || + description().startsWith("CD-RW226") || + description().startsWith("CD-R4012") ) ) + || + ( vendor().startsWith("JVC") && ( description().startsWith("XR-W2001") || + description().startsWith("XR-W2010") || + description().startsWith("R2626") ) ) + || + ( vendor().startsWith("PINNACLE") && ( description().startsWith("RCD-1000") || + description().startsWith("RCD5020") || + description().startsWith("RCD5040") || + description().startsWith("RCD 4X4") ) ) + || + ( vendor().startsWith("Traxdata") && description().startsWith("CDR4120") ) ) { + m_writeModes = WRITINGMODE_TAO; + d->readCapabilities = MEDIA_CD_ROM|MEDIA_CD_R; + d->writeCapabilities = MEDIA_CD_ROM|MEDIA_CD_R; + m_maxWriteSpeed = 4; + m_maxReadSpeed = 12; + m_bufferSize = 1024; + d->burnfree = false; + } + else if( vendor().startsWith("TEAC") ) { + if( description().startsWith("CD-R56S") ) { + m_writeModes |= TAO; + d->readCapabilities = MEDIA_CD_ROM|MEDIA_CD_R; + d->writeCapabilities = MEDIA_CD_ROM|MEDIA_CD_R; + m_maxWriteSpeed = 6; + m_maxReadSpeed = 24; + m_bufferSize = 1302; + d->burnfree = false; + } + if( description().startsWith("CD-R58S") ) { + m_writeModes |= TAO; + d->readCapabilities = MEDIA_CD_ROM|MEDIA_CD_R; + d->writeCapabilities = MEDIA_CD_ROM|MEDIA_CD_R; + m_maxWriteSpeed = 8; + m_maxReadSpeed = 24; + m_bufferSize = 4096; + d->burnfree = false; + } + } + else if( vendor().startsWith("MATSHITA") ) { + if( description().startsWith("CD-R CW-7501") ) { + m_writeModes = WRITINGMODE_TAO|WRITINGMODE_SAO; + d->readCapabilities = MEDIA_CD_ROM|MEDIA_CD_R; + d->writeCapabilities = MEDIA_CD_ROM|MEDIA_CD_R; + m_maxWriteSpeed = 2; + m_maxReadSpeed = 4; + m_bufferSize = 1024; + d->burnfree = false; + } + if( description().startsWith("CD-R CW-7502") ) { + m_writeModes = WRITINGMODE_TAO|WRITINGMODE_SAO; + d->readCapabilities = MEDIA_CD_ROM|MEDIA_CD_R; + d->writeCapabilities = MEDIA_CD_ROM|MEDIA_CD_R; + m_maxWriteSpeed = 4; + m_maxReadSpeed = 8; + m_bufferSize = 1024; + d->burnfree = false; + } + else if( description().startsWith("CD-R56S") ) { + m_writeModes |= WRITINGMODE_TAO; + d->readCapabilities = MEDIA_CD_ROM|MEDIA_CD_R; + d->writeCapabilities = MEDIA_CD_ROM|MEDIA_CD_R; + m_maxWriteSpeed = 6; + m_maxReadSpeed = 24; + m_bufferSize = 1302; + d->burnfree = false; + } + } + else if( vendor().startsWith("HP") ) { + if( description().startsWith("CD-Writer 6020") ) { + m_writeModes = WRITINGMODE_TAO; + d->readCapabilities = MEDIA_CD_ROM|MEDIA_CD_R; + d->writeCapabilities = MEDIA_CD_ROM|MEDIA_CD_R; + m_maxWriteSpeed = 2; + m_maxReadSpeed = 6; + m_bufferSize = 1024; + d->burnfree = false; + } + } + else if( vendor().startsWith( "PHILIPS" ) ) { + if( description().startsWith( "CDD2600" ) ) { + m_writeModes = WRITINGMODE_TAO|WRITINGMODE_SAO; + d->readCapabilities = MEDIA_CD_ROM|MEDIA_CD_R; + d->writeCapabilities = MEDIA_CD_ROM|MEDIA_CD_R; + m_maxWriteSpeed = 2; + m_maxReadSpeed = 6; + m_bufferSize = 1024; + d->burnfree = false; + } + } +} + + +K3bDevice::Interface K3bDevice::Device::interfaceType() const +{ + if( m_bus != -1 && m_target != -1 && m_lun != -1 ) + return SCSI; + else + return IDE; +} + + +bool K3bDevice::Device::dao() const +{ + return m_writeModes & WRITINGMODE_SAO; +} + + +bool K3bDevice::Device::supportsRawWriting() const +{ + return( writingModes() & (WRITINGMODE_RAW|WRITINGMODE_RAW_R16|WRITINGMODE_RAW_R96P|WRITINGMODE_RAW_R96R) ); +} + + +bool K3bDevice::Device::writesCd() const +{ + return ( d->writeCapabilities & MEDIA_CD_R ) && ( m_writeModes & WRITINGMODE_TAO ); +} + + +bool K3bDevice::Device::burner() const +{ + return ( writesCd() || writesDvd() ); +} + + +bool K3bDevice::Device::writesCdrw() const +{ + return d->writeCapabilities & MEDIA_CD_RW; +} + + +bool K3bDevice::Device::writesDvd() const +{ + return ( writesDvdPlus() || writesDvdMinus() ); +} + + +bool K3bDevice::Device::writesDvdPlus() const +{ + return d->writeCapabilities & (MEDIA_DVD_PLUS_R|MEDIA_DVD_PLUS_RW); +} + + +bool K3bDevice::Device::writesDvdMinus() const +{ + return d->writeCapabilities & (MEDIA_DVD_R|MEDIA_DVD_RW); +} + + +bool K3bDevice::Device::readsDvd() const +{ + return d->readCapabilities & MEDIA_DVD_ROM; +} + + +int K3bDevice::Device::type() const +{ + int r = 0; + if( readCapabilities() & MEDIA_CD_ROM ) + r |= DEVICE_CD_ROM; + if( writeCapabilities() & MEDIA_CD_R ) + r |= DEVICE_CD_R; + if( writeCapabilities() & MEDIA_CD_RW ) + r |= DEVICE_CD_RW; + if( readCapabilities() & MEDIA_DVD_ROM ) + r |= DEVICE_DVD_ROM; + if( writeCapabilities() & MEDIA_DVD_RAM ) + r |= DEVICE_DVD_RAM; + if( writeCapabilities() & MEDIA_DVD_R ) + r |= DEVICE_DVD_R; + if( writeCapabilities() & MEDIA_DVD_RW ) + r |= DEVICE_DVD_RW; + if( writeCapabilities() & MEDIA_DVD_R_DL ) + r |= DEVICE_DVD_R_DL; + if( writeCapabilities() & MEDIA_DVD_PLUS_R ) + r |= DEVICE_DVD_PLUS_R; + if( writeCapabilities() & MEDIA_DVD_PLUS_RW ) + r |= DEVICE_DVD_PLUS_RW; + if( writeCapabilities() & MEDIA_DVD_PLUS_R_DL ) + r |= DEVICE_DVD_PLUS_R_DL; + if( readCapabilities() & MEDIA_HD_DVD_ROM ) + r |= DEVICE_HD_DVD_ROM; + if( writeCapabilities() & MEDIA_HD_DVD_R ) + r |= DEVICE_HD_DVD_R; + if( writeCapabilities() & MEDIA_HD_DVD_RAM ) + r |= DEVICE_HD_DVD_RAM; + if( readCapabilities() & MEDIA_BD_ROM ) + r |= DEVICE_BD_ROM; + if( writeCapabilities() & MEDIA_BD_R ) + r |= DEVICE_BD_R; + if( writeCapabilities() & MEDIA_BD_RE ) + r |= DEVICE_BD_RE; + + return r; +} + + +int K3bDevice::Device::readCapabilities() const +{ + return d->readCapabilities; +} + + +int K3bDevice::Device::writeCapabilities() const +{ + return d->writeCapabilities; +} + + +const QString& K3bDevice::Device::devicename() const +{ + return blockDeviceName(); +} + + +QString K3bDevice::Device::busTargetLun() const +{ + return QString("%1,%2,%3").arg(m_bus).arg(m_target).arg(m_lun); +} + + +int K3bDevice::Device::cdTextCapable() const +{ + if( cdrdaoDriver() == "auto" ) + return 0; + else + return m_cdTextCapable; +} + + +void K3bDevice::Device::setCdTextCapability( bool b ) +{ + m_cdTextCapable = ( b ? 1 : 2 ); +} + + +bool K3bDevice::Device::burnproof() const +{ + return burnfree(); +} + + +bool K3bDevice::Device::burnfree() const +{ + return d->burnfree; +} + + +bool K3bDevice::Device::isDVD() const +{ + if( readsDvd() ) + return( mediaType() & MEDIA_DVD_ALL ); + else + return false; +} + + +int K3bDevice::Device::isEmpty() const +{ + // if the device is already opened we do not close it + // to allow fast multiple method calls in a row + bool needToClose = !isOpen(); + + int ret = STATE_UNKNOWN; + if( !open() ) + return STATE_UNKNOWN; + + if( !testUnitReady() ) + return STATE_NO_MEDIA; + + unsigned char* data = 0; + unsigned int dataLen = 0; + + if( readDiscInformation( &data, dataLen ) ) { + disc_info_t* inf = (disc_info_t*)data; + switch( inf->status ) { + case 0: + ret = STATE_EMPTY; + break; + case 1: + ret = STATE_INCOMPLETE; + break; + case 2: + ret = STATE_COMPLETE; + break; + default: + ret = STATE_UNKNOWN; + break; + } + + delete [] data; + } + + if( needToClose ) + close(); + + return ret; +} + + +int K3bDevice::Device::numSessions() const +{ + // + // Session Info + // ============ + // Byte 0-1: Data Length + // Byte 2: First Complete Session Number (Hex) - always 1 + // Byte 3: Last Complete Session Number (Hex) + // + + int ret = -1; + + unsigned char* data = 0; + unsigned int len = 0; + + if( mediaType() & MEDIA_CD_ALL ) { + // + // Althought disk_info should get the real value without ide-scsi + // I keep getting wrong values (the value is too high. I think the leadout + // gets counted as session sometimes :() + // + if( readTocPmaAtip( &data, len, 1, 0, 0 ) ) { + ret = data[3]; + + delete [] data; + } + else { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << ": could not get session info !" << endl; + } + } + else { + if( readDiscInformation( &data, len ) ) { + ret = (int)( data[9]<<8 | data[4] ); + + // do only count complete sessions + if( (data[2]>>2) != 3 ) + ret--; + + delete [] data; + } + } + + return ret; +} + + +int K3bDevice::Device::getDataMode( const K3b::Msf& sector ) const +{ + bool needToClose = !isOpen(); + + int ret = Track::UNKNOWN; + + if( !open() ) + return ret; + + // we use readCdMsf here since it's defined mandatory in MMC1 and + // we only use this method for CDs anyway + unsigned char data[2352]; + bool readSuccess = readCdMsf( data, 2352, + 0, // all sector types + false, // no dap + sector, + sector+1, + true, // SYNC + true, // HEADER + true, // SUBHEADER + true, // USER DATA + true, // EDC/ECC + 0, // no c2 info + 0 ); + + if( readSuccess ) { + if ( data[15] == 0x1 ) + ret = Track::MODE1; + else if ( data[15] == 0x2 ) + ret = Track::MODE2; + if ( ret == Track::MODE2 ) { + if ( data[16] == data[20] && + data[17] == data[21] && + data[18] == data[22] && + data[19] == data[23] ) { + if ( data[18] & 0x20 ) + ret = Track::XA_FORM2; + else + ret = Track::XA_FORM1; + } + } + } + + if( needToClose ) + close(); + + return ret; +} + + + +int K3bDevice::Device::getTrackDataMode( const K3bDevice::Track& track ) const +{ + return getDataMode( track.firstSector() ); +} + + +K3bDevice::Toc K3bDevice::Device::readToc() const +{ + // if the device is already opened we do not close it + // to allow fast multiple method calls in a row + bool needToClose = !isOpen(); + + Toc toc; + + if( !open() ) + return toc; + + int mt = mediaType(); + + // + // Use the profile if available because DVD-ROM units need to treat DVD+-R(W) media as DVD-ROM + // if supported at all + // + if( currentProfile() == MEDIA_DVD_ROM ) + mt = MEDIA_DVD_ROM; + + if( mt & (MEDIA_DVD_MINUS_ALL|MEDIA_DVD_PLUS_RW|MEDIA_DVD_ROM) ) { + if( !readFormattedToc( toc, mt ) ) { + K3b::Msf size; + if( readCapacity( size ) ) { + Track track; + track.m_firstSector = 0; + track.m_lastSector = size.lba(); + track.m_session = 1; + track.m_type = Track::DATA; + track.m_mode = Track::DVD; + track.m_copyPermitted = ( mt != MEDIA_DVD_ROM ); + track.m_preEmphasis = ( mt != MEDIA_DVD_ROM ); + + toc.append( track ); + } + else + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() + << "READ CAPACITY for toc failed." << endl; + } + } + + else if( mt & (MEDIA_DVD_PLUS_R|MEDIA_DVD_PLUS_R_DL) ) { + // + // a DVD+R disk may have multiple sessions + // every session may contain up to 16 fragments + // if the disk is open there is one open session + // every closed session is viewed as a track whereas + // every fragment of the open session is viewed as a track + // + // We may use + // READ DISK INFORMATION + // READ TRACK INFORMATION: track number FFh, however, does not refer to the invisible track + // READ TOC/PMA/ATIP: form 0 refers to all closed sessions + // form 1 refers to the last closed session + // + readFormattedToc( toc, mt ); + } + + else if( mt & MEDIA_BD_ALL ) { + readFormattedToc( toc, mt ); + } + + else if( mt == MEDIA_DVD_RAM ) { + k3bDebug() << "(K3bDevice::readDvdToc) no dvdram support" << endl; + } + + + else if( mt & MEDIA_CD_ALL ) { + bool success = readRawToc( toc ); + if( !success ) { + success = readFormattedToc( toc, mt ); + +#ifdef Q_OS_LINUX + if( !success ) { + k3bDebug() << "(K3bDevice::Device) MMC READ TOC failed. falling back to cdrom.h." << endl; + readTocLinux(toc); + } +#endif + + if( success ) + fixupToc( toc ); + } + } + + if( needToClose ) + close(); + + return toc; +} + + +void K3bDevice::Device::readIsrcMcn( K3bDevice::Toc& toc ) const +{ + // read MCN and ISRC of all tracks + QCString mcn; + if( readMcn( mcn ) ) { + toc.setMcn( mcn ); + k3bDebug() << "(K3bDevice::Device) found MCN: " << mcn << endl; + } + else + k3bDebug() << "(K3bDevice::Device) no MCN found." << endl; + + for( unsigned int i = 1; i <= toc.count(); ++i ) { + QCString isrc; + if( toc[i-1].type() == Track::AUDIO ) { + if( readIsrc( i, isrc ) ) { + k3bDebug() << "(K3bDevice::Device) found ISRC for track " << i << ": " << isrc << endl; + toc[i-1].setIsrc( isrc ); + } + else + k3bDebug() << "(K3bDevice::Device) no ISRC found for track " << i << endl; + } + } +} + + +bool K3bDevice::Device::readFormattedToc( K3bDevice::Toc& toc, int mt ) const +{ + // if the device is already opened we do not close it + // to allow fast multiple method calls in a row + bool needToClose = !isOpen(); + + bool success = false; + + toc.clear(); + + unsigned int lastTrack = 0; + + unsigned char* data = 0; + unsigned int dataLen = 0; + if( !(mt & MEDIA_CD_ALL) ) { + // + // on DVD-R(W) multisession disks only two sessions are represented as tracks in the readTocPmaAtip + // response (fabricated TOC). Thus, we use readDiscInformation for DVD media to get the proper number of tracks + // + if( readDiscInformation( &data, dataLen ) ) { + lastTrack = (int)( data[11]<<8 | data[6] ); + + delete [] data; + + if( readTrackInformation( &data, dataLen, 1, lastTrack ) ) { + track_info_t* trackInfo = (track_info_t*)data; + + if( trackInfo->blank ) { + lastTrack--; + } + + delete [] data; + + success = true; + } + else + return false; + } + else + return false; + } + else { + if( readTocPmaAtip( &data, dataLen, 0, 0, 1 ) ) { + + if( dataLen < 4 ) { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << ": formatted toc data too small." << endl; + } + else if( dataLen != ( (unsigned int)sizeof(toc_track_descriptor) * ((unsigned int)data[3]+1) ) + 4 ) { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << ": invalid formatted toc data length: " + << (dataLen-2) << endl; + } + else { + lastTrack = data[3]; + toc_track_descriptor* td = (toc_track_descriptor*)&data[4]; + for( unsigned int i = 0; i < lastTrack; ++i ) { + + Track track; + unsigned int control = 0; + + // + // In case READ TRACK INFORMATION fails: + // no session number info + // no track length and thus possibly incorrect last sector for + // multisession disks + // + track.m_firstSector = from4Byte( td[i].start_adr ); + track.m_lastSector = from4Byte( td[i+1].start_adr ) - 1; + control = td[i].control; + + track.m_type = (control & 0x4) ? Track::DATA : Track::AUDIO; + track.m_mode = getTrackDataMode( track ); + track.m_copyPermitted = ( control & 0x2 ); + track.m_preEmphasis = ( control & 0x1 ); + + toc.append( track ); + } + + success = true; + } + + delete [] data; + } + } + + + // + // Try to get information for all the tracks + // + for( unsigned int i = 0; i < lastTrack; ++i ) { + if( toc.count() < i+1 ) + toc.append( Track() ); + + unsigned char* trackData = 0; + unsigned int trackDataLen = 0; + if( readTrackInformation( &trackData, trackDataLen, 1, i+1 ) ) { + track_info_t* trackInfo = (track_info_t*)trackData; + + toc[i].m_firstSector = from4Byte( trackInfo->track_start ); + + if( i > 0 && toc[i-1].m_lastSector == 0 ) + toc[i-1].m_lastSector = toc[i].m_firstSector - 1; + + // There are drives that return 0 track length here! + // Some drives even return an invalid length here. :( + if( from4Byte( trackInfo->track_size ) > 0 ) + toc[i].m_lastSector = toc[i].m_firstSector + from4Byte( trackInfo->track_size ) - 1; + + if( trackInfo->nwa_v ) { + toc[i].m_nextWritableAddress = from4Byte( trackInfo->next_writable ); + toc[i].m_freeBlocks = from4Byte( trackInfo->free_blocks ); + } + + toc[i].m_session = (int)(trackInfo->session_number_m<<8 & 0xf0 | + trackInfo->session_number_l & 0x0f); //FIXME: is this BCD? + + int control = trackInfo->track_mode; + + if( mt & MEDIA_CD_ALL ) { + toc[i].m_type = (control & 0x4) ? Track::DATA : Track::AUDIO; + toc[i].m_mode = getTrackDataMode( toc[i] ); + } + else { + toc[i].m_type = Track::DATA; + toc[i].m_mode = Track::DVD; + } + toc[i].m_copyPermitted = ( control & 0x2 ); + toc[i].m_preEmphasis = ( control & 0x1 ); + + delete [] trackData; + } + else if( !(mt & MEDIA_CD_ALL) ) { + success = false; + } + } + + // this can only happen with DVD media + if( !toc.isEmpty() && toc.last().lastSector() == 0 ) { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << " no track length for the last non-empty track." << endl; + unsigned char* trackData = 0; + unsigned int trackDataLen = 0; + if( readTrackInformation( &trackData, trackDataLen, 1, lastTrack+1 ) ) { + track_info_t* trackInfo = (track_info_t*)trackData; + + toc.last().m_lastSector = from4Byte( trackInfo->track_start ) - 1; + + delete [] trackData; + } + } + + + if( needToClose ) + close(); + + return success; +} + + +bool K3bDevice::Device::readRawToc( K3bDevice::Toc& toc ) const +{ + // if the device is already opened we do not close it + // to allow fast multiple method calls in a row + bool needToClose = !isOpen(); + + bool success = false; + + toc.clear(); + + if( open() ) { + // + // Read Raw TOC (format: 0010b) + // + // For POINT from 01h-63h we get all the tracks + // POINT a1h gices us the last track number in the session in PMIN + // POINT a2h gives the start of the session lead-out in PMIN,PSEC,PFRAME + // + + unsigned char* data = 0; + unsigned int dataLen = 0; + + if( readTocPmaAtip( &data, dataLen, 2, false, 1 ) ) { + if( dataLen > 4 ) { + success = true; + + toc_raw_track_descriptor* tr = (toc_raw_track_descriptor*)&data[4]; + + // + // debug the raw toc data + // + k3bDebug() << "Session | ADR | CONTROL| TNO | POINT | Min | Sec | Frame | Zero | PMIN | PSEC | PFRAME |" << endl; + for( unsigned int i = 0; i < (dataLen-4)/(int)sizeof(toc_raw_track_descriptor); ++i ) { + QString s; + s += QString( " %1 |" ).arg( (int)tr[i].session_number, 6 ); + s += QString( " %1 |" ).arg( (int)tr[i].adr, 6 ); + s += QString( " %1 |" ).arg( (int)tr[i].control, 6 ); + s += QString( " %1 |" ).arg( (int)tr[i].tno, 6 ); + s += QString( " %1 |" ).arg( (int)tr[i].point, 6, 16 ); + s += QString( " %1 |" ).arg( (int)tr[i].min, 6 ); + s += QString( " %1 |" ).arg( (int)tr[i].sec, 6 ); + s += QString( " %1 |" ).arg( (int)tr[i].frame, 6 ); + s += QString( " %1 |" ).arg( (int)tr[i].zero, 6, 16 ); + s += QString( " %1 |" ).arg( (int)tr[i].p_min, 6 ); + s += QString( " %1 |" ).arg( (int)tr[i].p_sec, 6 ); + s += QString( " %1 |" ).arg( (int)tr[i].p_frame, 6 ); + k3bDebug() << s << endl; + } + + // + // First we try to determine if the raw toc data uses BCD values + // + int isBcd = rawTocDataWithBcdValues( data, dataLen ); + if( isBcd == -1 ) { + delete [] data; + return false; + } + + K3b::Msf sessionLeadOut; + + for( unsigned int i = 0; i < (dataLen-4)/(unsigned int)sizeof(toc_raw_track_descriptor); ++i ) { + if( tr[i].adr == 1 && tr[i].point <= 0x63 ) { + // track + K3bTrack track; + track.m_session = tr[i].session_number; + + // :( We use 00:00:00 == 0 lba) + if( isBcd ) + track.m_firstSector = K3b::Msf( K3bDevice::fromBcd(tr[i].p_min), + K3bDevice::fromBcd(tr[i].p_sec), + K3bDevice::fromBcd(tr[i].p_frame) ) - 150; + else + track.m_firstSector = K3b::Msf( tr[i].p_min, tr[i].p_sec, tr[i].p_frame ) - 150; + + track.m_type = ( tr[i].control & 0x4 ? Track::DATA : Track::AUDIO ); + track.m_mode = ( track.type() == Track::DATA ? getTrackDataMode(track) : Track::UNKNOWN ); + track.m_copyPermitted = ( tr[i].control & 0x2 ); + track.m_preEmphasis = ( tr[i].control & 0x1 ); + + // + // only do this within a session because otherwise we already set the last sector with the session leadout + // + if( !toc.isEmpty() ) + if( toc[toc.count()-1].session() == track.session() ) + toc[toc.count()-1].m_lastSector = track.firstSector() - 1; + + toc.append(track); + } + else if( tr[i].point == 0xa2 ) { + // + // since the session is always reported before the tracks this is where we do this: + // set the previous session's last tracks's last sector to the first sector of the + // session leadout (which was reported before the tracks) + // + // This only happens on multisession CDs + // + if( !toc.isEmpty() ) + toc[toc.count()-1].m_lastSector = sessionLeadOut - 1; + + // this is save since the descriptors are reported in ascending order of the session number + // :( We use 00:00:00 == 0 lba) + if( isBcd ) + sessionLeadOut = K3b::Msf( K3bDevice::fromBcd(tr[i].p_min), + K3bDevice::fromBcd(tr[i].p_sec), + K3bDevice::fromBcd(tr[i].p_frame) ) - 150; + else + sessionLeadOut = K3b::Msf( tr[i].p_min, tr[i].p_sec, tr[i].p_frame ) - 150; + } + } + + k3bDebug() << blockDeviceName() << ": setting last sector of last track to " << (sessionLeadOut-1).lba() << endl; + + // set the last track's last sector + if( !toc.isEmpty() ) + toc[toc.count()-1].m_lastSector = sessionLeadOut - 1; + } + else + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << " empty raw toc." << endl; + + delete [] data; + } + } + + if( needToClose ) + close(); + + return success; +} + + +int K3bDevice::Device::rawTocDataWithBcdValues( unsigned char* data, unsigned int dataLen ) const +{ + toc_raw_track_descriptor* tr = (toc_raw_track_descriptor*)&data[4]; + + bool notBcd = false; + bool notHex = false; + + // + // in most cases this will already tell us if a drive does not provide bcd numbers + // (which should be all newer MMC drives) + // + for( unsigned int i = 0; i < (dataLen-4)/(unsigned int)sizeof(toc_raw_track_descriptor); ++i ) { + if( tr[i].adr == 1 && tr[i].point <= 0xa2) { + if( !K3bDevice::isValidBcd(tr[i].p_min) || + !K3bDevice::isValidBcd(tr[i].p_sec) || + !K3bDevice::isValidBcd(tr[i].p_frame) ) { + notBcd = true; + break; + } + + // we only need to check sec and frame since min needs to be <= 99 + // and bcd values are never bigger than 99. + else if( (int)K3bDevice::fromBcd(tr[i].p_sec) >= 60 || + (int)K3bDevice::fromBcd(tr[i].p_frame) >= 75 ) { + notBcd = true; + break; + } + } + } + + + // + // all values are valid bcd values but we still don't know for sure if they are really + // used as bcd. So we also check the HEX values. + // + for( unsigned int i = 0; i < (dataLen-4)/(unsigned int)sizeof(toc_raw_track_descriptor); ++i ) { + if( tr[i].adr == 1 && tr[i].point <= 0xa2 ) { + if( (int)tr[i].p_min > 99 || + (int)tr[i].p_sec >= 60 || + (int)tr[i].p_frame >= 75 ) { + notHex = true; + break; + } + } + } + + + // + // If all values are valid bcd and valid hex we check the start sectors of the tracks. + // + if( !notHex || !notBcd ) { + K3b::Msf sessionLeadOutHex, sessionLeadOutBcd; + K3b::Msf lastTrackHex, lastTrackBcd; + + for( unsigned int i = 0; i < (dataLen-4)/(unsigned int)sizeof(toc_raw_track_descriptor); ++i ) { + + if( tr[i].adr == 1 ) { + if( tr[i].point < 0x64 ) { + + // check hex values + if( K3b::Msf( tr[i].p_min, tr[i].p_sec, tr[i].p_frame ) < + lastTrackHex ) + notHex = true; + + // check bcd values + if( K3b::Msf( K3bDevice::fromBcd(tr[i].p_min), K3bDevice::fromBcd(tr[i].p_sec), K3bDevice::fromBcd(tr[i].p_frame) ) < + lastTrackBcd ) + notBcd = true; + + lastTrackBcd = K3b::Msf( K3bDevice::fromBcd(tr[i].p_min), K3bDevice::fromBcd(tr[i].p_sec), K3bDevice::fromBcd(tr[i].p_frame) ); + lastTrackHex = K3b::Msf( tr[i].p_min, tr[i].p_sec, tr[i].p_frame ); + } + else if( tr[i].point == 0xa2 ) { + if( sessionLeadOutHex < lastTrackHex ) + notHex = true; + if( sessionLeadOutBcd < lastTrackBcd ) + notBcd = true; + + sessionLeadOutHex = K3b::Msf( tr[i].p_min, tr[i].p_sec, tr[i].p_frame ); + sessionLeadOutBcd = K3b::Msf( K3bDevice::fromBcd(tr[i].p_min), K3bDevice::fromBcd(tr[i].p_sec), K3bDevice::fromBcd(tr[i].p_frame) ); + } + } + } + + // check the last track + if( sessionLeadOutHex < lastTrackHex ) + notHex = true; + if( sessionLeadOutBcd < lastTrackBcd ) + notBcd = true; + } + + + if( !notBcd && !notHex ) { + k3bDebug() << "(K3bDevice::Device) need to compare raw toc to formatted toc. :(" << endl; + // + // All values are valid bcd and valid HEX values so we compare with the formatted toc. + // This slows us down a lot but in most cases this should not be reached anyway. + // + // TODO: also check the bcd values + // + K3bDevice::Toc formattedToc; + if( readFormattedToc( formattedToc, MEDIA_CD_ROM ) ) { + for( unsigned int i = 0; i < (dataLen-4)/(unsigned int)sizeof(toc_raw_track_descriptor); ++i ) { + if( tr[i].adr == 1 && tr[i].point < 0x64 ) { + unsigned int track = (int)tr[i].point; + + // FIXME: do bcd drive also encode the track number in bcd? If so test it, too. + + if( track > formattedToc.count() ) { + notHex = true; + break; + } + + K3b::Msf posHex( tr[i].p_min, + tr[i].p_sec, + tr[i].p_frame ); + K3b::Msf posBcd( K3bDevice::fromBcd(tr[i].p_min), + K3bDevice::fromBcd(tr[i].p_sec), + K3bDevice::fromBcd(tr[i].p_frame) ); + posHex -= 150; + posBcd -= 150; + if( posHex != formattedToc[track-1].firstSector() ) + notHex = true; + if( posBcd != formattedToc[track-1].firstSector() ) + notBcd = true; + } + } + } + } + + if( notBcd ) + k3bDebug() << "(K3bDevice::Device) found invalid bcd values. No bcd toc." << endl; + if( notHex ) + k3bDebug() << "(K3bDevice::Device) found invalid hex values. No hex toc." << endl; + + if( notBcd == notHex ) { + k3bDebug() << "(K3bDevice::Device) unable to determine if hex (" << notHex << ") or bcd (" << notBcd << ")." << endl; + if( !notHex ) { + k3bDebug() << "Assuming hex encoding in favor of newer drives and the more reliable raw toc." << endl; + return 0; + } + return -1; + } + else if( notBcd ) + return 0; + else + return 1; +} + + +K3bDevice::CdText K3bDevice::Device::readCdText() const +{ + // if the device is already opened we do not close it + // to allow fast multiple method calls in a row + bool needToClose = !isOpen(); + + K3bDevice::CdText textData; + + if( open() ) { + unsigned char* data = 0; + unsigned int dataLen = 0; + + if( readTocPmaAtip( &data, dataLen, 5, false, 0 ) ) { + textData.setRawPackData( data, dataLen ); + + delete [] data; + } + + if( needToClose ) + close(); + } + + return textData; +} + + +#ifdef Q_OS_LINUX +// fallback +bool K3bDevice::Device::readTocLinux( K3bDevice::Toc& toc ) const +{ + // if the device is already opened we do not close it + // to allow fast multiple method calls in a row + bool needToClose = !isOpen(); + + bool success = true; + + toc.clear(); + + struct cdrom_tochdr tochdr; + struct cdrom_tocentry tocentry; + + usageLock(); + if( open() ) { + // + // CDROMREADTOCHDR ioctl returns: + // cdth_trk0: First Track Number + // cdth_trk1: Last Track Number + // + if( ::ioctl( d->deviceFd, CDROMREADTOCHDR, &tochdr ) ) { + k3bDebug() << "(K3bDevice::Device) could not get toc header !" << endl; + success = false; + } + else { + Track lastTrack; + for (int i = tochdr.cdth_trk0; i <= tochdr.cdth_trk1 + 1; i++) { + ::memset(&tocentry,0,sizeof (struct cdrom_tocentry)); + // get Lead-Out Information too + tocentry.cdte_track = (i<=tochdr.cdth_trk1) ? i : CDROM_LEADOUT; + tocentry.cdte_format = CDROM_LBA; + // + // CDROMREADTOCENTRY ioctl returns: + // cdte_addr.lba: Start Sector Number (LBA Format requested) + // cdte_ctrl: 4 ctrl bits + // 00x0b: 2 audio Channels(no pre-emphasis) + // 00x1b: 2 audio Channels(pre-emphasis) + // 10x0b: audio Channels(no pre-emphasis),reserved in cd-rw + // 10x1b: audio Channels(pre-emphasis),reserved in cd-rw + // 01x0b: data track, recorded uninterrupted + // 01x1b: data track, recorded incremental + // 11xxb: reserved + // xx0xb: digital copy prohibited + // xx1xb: digital copy permitted + // cdte_addr: 4 addr bits (type of Q-Subchannel data) + // 0000b: no Information + // 0001b: current position data + // 0010b: MCN + // 0011b: ISRC + // 0100b-1111b: reserved + // cdte_datamode: 0: Data Mode1 + // 1: CD-I + // 2: CD-XA Mode2 + // + + if( ::ioctl( d->deviceFd, CDROMREADTOCENTRY, &tocentry ) ) { + k3bDebug() << "(K3bDevice::Device) error reading tocentry " << i << endl; + success = false; + break; + } + + int startSec = tocentry.cdte_addr.lba; + int control = tocentry.cdte_ctrl & 0x0f; + int mode = tocentry.cdte_datamode; + if( i > tochdr.cdth_trk0 ) { + Track track( lastTrack.firstSector(), startSec-1, lastTrack.type(), lastTrack.mode() ); + track.m_preEmphasis = control & 0x1; + track.m_copyPermitted = control & 0x2; + toc.append( track ); + } + int trackType = 0; + int trackMode = Track::UNKNOWN; + if( (control & 0x04 ) && (tocentry.cdte_track != CDROM_LEADOUT) ) { + trackType = Track::DATA; + if( mode == 1 ) + trackMode = Track::MODE1; + else if( mode == 2 ) + trackMode = Track::MODE2; + + mode = getDataMode(startSec); + if( mode != Track::UNKNOWN ) + trackMode = mode; + } + else + trackType = Track::AUDIO; + + lastTrack = Track( startSec, startSec, trackType, trackMode ); + } + } + + if( needToClose ) + close(); + } + else + success = false; + + usageUnlock(); + + return success; +} +#endif // Q_OS_LINUX + + +bool K3bDevice::Device::fixupToc( K3bDevice::Toc& toc ) const +{ + bool success = false; + + // + // This is a very lame method of fixing the TOC of an Advanced Audio CD + // (a CD with two sessions: one with audio tracks and one with the data track) + // If a drive does not support reading raw toc or reading track info we only + // get every track's first sector. But between sessions there is a gap which is used + // for ms stuff. In this case it's 11400 sectors in size. When ripping ausio we would + // include these 11400 sectors which would result in a strange ending audio file. + // + if( numSessions() > 1 || toc.contentType() == MIXED ) { + k3bDebug() << "(K3bDevice::Device) fixup multisession toc..." << endl; + + // + // we need to update the last sector of every last track in every session + // for now we only update the track before the last session... + // This is the most often case: Advanced Audio CD + // + + unsigned char* data = 0; + unsigned int dataLen = 0; + if( readTocPmaAtip( &data, dataLen, 1, false, 0 ) ) { + + // + // data[6] - first track number in last complete session + // data[8-11] - start address of first track in last session + // + + toc[(unsigned int)data[6]-2].m_lastSector = from4Byte( &data[8] ) - 11400 - 1; + + delete [] data; + success = true; + } + else + k3bDebug() << "(K3bDevice::Device) FIXUP TOC failed." << endl; + } + + return success; +} + + +bool K3bDevice::Device::block( bool b ) const +{ + // + // For some reason the Scsi Command does not work here. + // So we use the ioctl on Linux systems + // +#if defined(Q_OS_LINUX) + bool success = false; + bool needToClose = !isOpen(); + usageLock(); + if( open() ) { + success = ( ::ioctl( d->deviceFd, CDROM_LOCKDOOR, b ? 1 : 0 ) == 0 ); + if( needToClose ) + close(); + } + usageUnlock(); + if ( success ) + return success; +#elif defined(Q_OS_NETBSD) + bool success = false; + bool needToClose = !isOpen(); + int arg = b ? 1 : 0; + usageLock(); + if( open() ) { + success = ( ::ioctl( d->deviceFd, DIOCLOCK, &arg ) == 0 ); + if( needToClose ) + close(); + } + usageUnlock(); + if ( success ) + return success; +#endif + + ScsiCommand cmd( this ); + cmd[0] = MMC_PREVENT_ALLOW_MEDIUM_REMOVAL; + cmd[5] = 0; // Necessary to set the proper command length + if( b ) + cmd[4] = 0x01; + int r = cmd.transport( TR_DIR_WRITE ); + + if( r ) + k3bDebug() << "(K3bDevice::Device) MMC ALLOW MEDIA REMOVAL failed." << endl; + + return ( r == 0 ); +} + +bool K3bDevice::Device::rewritable() const +{ + unsigned char* data = 0; + unsigned int dataLen = 0; + + if( readDiscInformation( &data, dataLen ) ) { + disc_info_t* inf = (disc_info_t*)data; + bool e = inf->erasable; + + delete [] data; + + return e; + } + else + return false; +} + + +bool K3bDevice::Device::eject() const +{ +#ifdef Q_OS_NETBSD + bool success = false; + bool needToClose = !isOpen(); + int arg = 0; + + usageLock(); + if( open() ) { + if ( ::ioctl( d->deviceFd, DIOCEJECT, &arg ) >= 0) + success = true; + if( needToClose ) + close(); + } + usageUnlock(); + if ( success ) + return success; +#elif defined(Q_OS_LINUX) + bool success = false; + bool needToClose = !isOpen(); + + usageLock(); + if( open() ) { + if( ::ioctl( d->deviceFd, CDROMEJECT ) >= 0 ) + success = true; + if( needToClose ) + close(); + } + usageUnlock(); + if ( success ) + return success; +#endif + + ScsiCommand cmd( this ); + cmd[0] = MMC_PREVENT_ALLOW_MEDIUM_REMOVAL; + cmd[5] = 0; // Necessary to set the proper command length + cmd.transport(); + + cmd[0] = MMC_START_STOP_UNIT; + cmd[5] = 0; // Necessary to set the proper command length + cmd[4] = 0x1; // Start unit + cmd.transport(); + + cmd[4] = 0x2; // LoEj = 1, Start = 0 + + return !cmd.transport(); +} + + +bool K3bDevice::Device::load() const +{ +#ifdef Q_OS_NETBSD + bool success = false; + bool needToClose = !isOpen(); + int arg = 0; + + usageLock(); + if( open() ) { + if ( ::ioctl( d->deviceFd, CDIOCCLOSE, &arg ) >= 0) + success = true; + if( needToClose ) + close(); + } + usageUnlock(); + if ( success ) + return success; +#elif defined(Q_OS_LINUX) + bool success = false; + bool needToClose = !isOpen(); + + usageLock(); + if( open() ) { + if( ::ioctl( d->deviceFd, CDROMCLOSETRAY ) >= 0 ) + success = true; + if( needToClose ) + close(); + } + usageUnlock(); + if ( success ) + return success; +#endif + + ScsiCommand cmd( this ); + cmd[0] = MMC_START_STOP_UNIT; + cmd[4] = 0x3; // LoEj = 1, Start = 1 + cmd[5] = 0; // Necessary to set the proper command length + return !cmd.transport(); +} + + +bool K3bDevice::Device::setAutoEjectEnabled( bool enabled ) const +{ + bool success = false; +#ifdef Q_OS_LINUX + + bool needToClose = !isOpen(); + usageLock(); + if ( open() ) { + success = ( ::ioctl( d->deviceFd, CDROMEJECT_SW, enabled ? 1 : 0 ) == 0 ); + if ( needToClose ) { + close(); + } + } + usageUnlock(); +#endif + return success; +} + + +void K3bDevice::Device::addDeviceNode( const QString& n ) +{ + if( !d->allNodes.contains( n ) ) + d->allNodes.append( n ); +} + + +const QStringList& K3bDevice::Device::deviceNodes() const +{ + return d->allNodes; +} + + +K3bDevice::Device::Handle K3bDevice::Device::handle() const +{ +#ifdef Q_OS_FREEBSD + return d->cam; +#else + return d->deviceFd; +#endif +} + + +bool K3bDevice::Device::open( bool write ) const +{ + if( d->openedReadWrite != write ) + close(); + + QMutexLocker ml( &d->openCloseMutex ); + + d->openedReadWrite = write; + +#ifdef Q_OS_FREEBSD + if( !d->cam ) { + d->cam = cam_open_pass (m_passDevice.latin1(), O_RDWR,0 /* NULL */); + k3bDebug() << "(K3bDevice::openDevice) open device " << m_passDevice + << ((d->cam)?" succeeded.":" failed.") << endl; + } + + return (d->cam != 0); +#endif +#if defined(Q_OS_LINUX) || defined(Q_OS_NETBSD) + if( d->deviceFd == -1 ) + d->deviceFd = openDevice( QFile::encodeName(devicename()), write ); + + return ( d->deviceFd != -1 ); +#endif +} + + +void K3bDevice::Device::close() const +{ + QMutexLocker ml( &d->openCloseMutex ); + +#ifdef Q_OS_FREEBSD + if( d->cam ) { + cam_close_device(d->cam); + d->cam = 0; + } +#endif +#if defined(Q_OS_LINUX) || defined(Q_OS_NETBSD) + if( d->deviceFd != -1 ) { + ::close( d->deviceFd ); + d->deviceFd = -1; + } +#endif +} + + +bool K3bDevice::Device::isOpen() const +{ +#ifdef Q_OS_FREEBSD + return d->cam; +#endif +#if defined(Q_OS_LINUX) || defined(Q_OS_NETBSD) + return ( d->deviceFd != -1 ); +#endif +} + + +int K3bDevice::Device::supportedProfiles() const +{ + return d->supportedProfiles; +} + + +int K3bDevice::Device::currentProfile() const +{ + unsigned char profileBuf[8]; + ::memset( profileBuf, 0, 8 ); + + ScsiCommand cmd( this ); + cmd[0] = MMC_GET_CONFIGURATION; + cmd[1] = 1; + cmd[8] = 8; + cmd[9] = 0; // Necessary to set the proper command length + + if( cmd.transport( TR_DIR_READ, profileBuf, 8 ) ) { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() + << " GET_CONFIGURATION failed." << endl; + return MEDIA_UNKNOWN; + } + else { + short profile = from2Byte( &profileBuf[6] ); + + // + // Plextor drives might not set a current profile + // In that case we get the list of all current profiles + // and simply use the first one in that list. + // + if( profile == 0x00 ) { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() + << " current profile 0. Checking current profile list instead." << endl; + unsigned char* data; + unsigned int len = 0; + if( getFeature( &data, len, FEATURE_PROFILE_LIST ) ) { + int featureLen( data[11] ); + for( int j = 0; j < featureLen; j+=4 ) { + // use the first current profile we encounter + if( data[12+j+2] & 0x1 ) { + profile = from2Byte( &data[12+j] ); + break; + } + } + + delete[] data; + } + } + + switch (profile) { + case 0x00: return MEDIA_NONE; + case 0x08: return MEDIA_CD_ROM; + case 0x09: return MEDIA_CD_R; + case 0x0A: return MEDIA_CD_RW; + case 0x10: return MEDIA_DVD_ROM; + case 0x11: return MEDIA_DVD_R_SEQ; + case 0x12: return MEDIA_DVD_RAM; + case 0x13: return MEDIA_DVD_RW_OVWR; + case 0x14: return MEDIA_DVD_RW_SEQ; + case 0x15: return MEDIA_DVD_R_DL_SEQ; + case 0x16: return MEDIA_DVD_R_DL_JUMP; + case 0x1A: return MEDIA_DVD_PLUS_RW; + case 0x1B: return MEDIA_DVD_PLUS_R; + case 0x2B: return MEDIA_DVD_PLUS_R_DL; + case 0x40: return MEDIA_BD_ROM; + case 0x41: { + if( featureCurrent( FEATURE_BD_PSEUDO_OVERWRITE ) == 1 ) + return MEDIA_BD_R_SRM_POW; + else + return MEDIA_BD_R_SRM; + } + case 0x42: return MEDIA_BD_R_RRM; + case 0x43: return MEDIA_BD_RE; + case 0x50: return MEDIA_HD_DVD_ROM; + case 0x51: return MEDIA_HD_DVD_R; + case 0x52: return MEDIA_HD_DVD_RAM; + default: return MEDIA_UNKNOWN; + } + } +} + + +K3bDevice::DiskInfo K3bDevice::Device::diskInfo() const +{ + DiskInfo inf; + + // if the device is already opened we do not close it + // to allow fast multiple method calls in a row + bool needToClose = !isOpen(); + + if( open() ) { + + unsigned char* data = 0; + unsigned int dataLen = 0; + + // + // The first thing to do should be: checking if a media is loaded + // We cannot rely on the profile here since at least some Plextor + // drives return the NO MEDIUM profile for CD media + // + if( !testUnitReady() ) { + // no disk or tray open + inf.m_diskState = STATE_NO_MEDIA; + inf.m_mediaType = MEDIA_NONE; + inf.m_currentProfile = MEDIA_NONE; + } + else + inf.m_currentProfile = currentProfile(); + + if( inf.diskState() != STATE_NO_MEDIA ) { + + if( readDiscInformation( &data, dataLen ) ) { + disc_info_t* dInf = (disc_info_t*)data; + // + // Copy the needed values from the disk_info struct + // + switch( dInf->status ) { + case 0: + inf.m_diskState = STATE_EMPTY; + break; + case 1: + inf.m_diskState = STATE_INCOMPLETE; + break; + case 2: + inf.m_diskState = STATE_COMPLETE; + break; + default: + inf.m_diskState = STATE_UNKNOWN; + break; + } + + switch( dInf->border ) { + case 0: + inf.m_lastSessionState = STATE_EMPTY; + break; + case 1: + inf.m_lastSessionState = STATE_INCOMPLETE; + break; + case 2: + inf.m_lastSessionState = STATE_COMPLETE; + break; + default: + inf.m_lastSessionState = STATE_UNKNOWN; + break; + } + + switch( dInf->bg_f_status&0x3 ) { + case 0x0: + inf.m_bgFormatState = BG_FORMAT_NONE; + break; + case 0x1: + inf.m_bgFormatState = BG_FORMAT_INCOMPLETE; + break; + case 0x2: + inf.m_bgFormatState = BG_FORMAT_IN_PROGRESS; + break; + case 0x3: + inf.m_bgFormatState = BG_FORMAT_COMPLETE; + break; + } + + inf.m_numTracks = (dInf->last_track_l & 0xff) | (dInf->last_track_m<<8 & 0xff00); + if( inf.diskState() == STATE_EMPTY ) + inf.m_numTracks = 0; + + // FIXME: I am not sure if this is accurate. Better test the last track's RT field + else if( inf.diskState() == STATE_INCOMPLETE ) + inf.m_numTracks--; // do not count the invisible track + + inf.m_rewritable = dInf->erasable; + + // + // This is the Last Possible Lead-Out Start Address in HMSF format + // This is only valid for CD-R(W) and DVD+R media. + // For complete media this shall be filled with 0xff + // + if( dInf->lead_out_m != 0xff && + dInf->lead_out_r != 0xff && + dInf->lead_out_s != 0xff && + dInf->lead_out_f != 0xff ) + inf.m_capacity = K3b::Msf( dInf->lead_out_m + dInf->lead_out_r*60, + dInf->lead_out_s, + dInf->lead_out_f ) - 150; + + // + // This is the position where the next Session shall be recorded in HMSF format + // This is only valid for CD-R(W) and DVD+R media. + // For complete media this shall be filled with 0xff + // + if( dInf->lead_in_m != 0xff && + dInf->lead_in_r != 0xff && + dInf->lead_in_s != 0xff && + dInf->lead_in_f != 0xff ) + inf.m_usedCapacity = K3b::Msf( dInf->lead_in_m + dInf->lead_in_r*60, + dInf->lead_in_s, + dInf->lead_in_f ) - 4500; + + delete [] data; + } + else { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() + << " fabricating disk information for a stupid device." << endl; + Toc toc = readToc(); + if( !toc.isEmpty() ) { + inf.m_diskState = STATE_COMPLETE; + inf.m_lastSessionState = STATE_COMPLETE; + inf.m_numTracks = toc.count(); + inf.m_capacity = inf.m_usedCapacity = toc.length(); + } + } + + + // + // The mediatype needs to be set + // + inf.m_mediaType = mediaType(); + + // At least some Plextor drives return profile NONE for CD media + // or CD_ROM for writable media + if( inf.m_mediaType & (MEDIA_UNKNOWN|MEDIA_NONE|MEDIA_CD_ROM) ) { + // probably it is a CD + if( inf.rewritable() ) + inf.m_mediaType = MEDIA_CD_RW; + else if( inf.empty() || inf.appendable() ) + inf.m_mediaType = MEDIA_CD_R; + else + inf.m_mediaType = MEDIA_CD_ROM; + } + + if( inf.m_mediaType & MEDIA_DVD_ALL ) { + if( readDvdStructure( &data, dataLen ) ) { + // some debugging stuff + K3b::Msf sda, eda, ea0; + sda = ( data[4+5]<<16 | data[4+6] << 8 | data[4+7] ); + eda = ( data[4+9]<<16 | data[4+10] << 8 | data[4+11] ); + ea0 = ( data[4+13]<<16 | data[4+14] << 8 | data[4+15] ); + + k3bDebug() << "First sec data area: " << sda.toString() + << " (LBA " << QString::number(sda.lba()) + << ") (" << QString::number(sda.mode1Bytes()) << endl; + k3bDebug() << "Last sec data area: " << eda.toString() + << " (LBA " << QString::number(eda.lba()) + << ") (" << QString::number(eda.mode1Bytes()) << " Bytes)" << endl; + k3bDebug() << "Last sec layer 1: " << ea0.toString() + << " (LBA " << QString::number(ea0.lba()) + << ") (" << QString::number(ea0.mode1Bytes()) << " Bytes)" << endl; + + + K3b::Msf da0 = ea0 - sda + 1; + K3b::Msf da1 = eda - ea0; + k3bDebug() << "Layer 1 length: " << da0.toString() + << " (LBA " << QString::number(da0.lba()) + << ") (" << QString::number(da0.mode1Bytes()) << " Bytes)" << endl; + k3bDebug() << "Layer 2 length: " << da1.toString() + << " (LBA " << QString::number(da1.lba()) + << ") (" << QString::number(da1.mode1Bytes()) << " Bytes)" << endl; + + inf.m_numLayers = ((data[6]&0x60) == 0 ? 1 : 2); + + bool otp = (data[4+2] & 0xF); + + // ea0 is 0 if the medium does not use Opposite track path + if( otp && ea0 > 0 ) + inf.m_firstLayerSize = da0; + else + inf.m_firstLayerSize = 0; + + delete [] data; + } + else { + k3bDebug() << "(K3bDevice::Device) Unable to read DVD structure for num of layers." << endl; + inf.m_numLayers = ( (inf.m_mediaType & MEDIA_WRITABLE_DVD_DL) ? 2 : 1 ); + } + } + + + // + // Number of sessions for non-empty disks + // + if( inf.diskState() != STATE_EMPTY ) { + int sessions = numSessions(); + if( sessions >= 0 ) + inf.m_numSessions = sessions; + else + k3bDebug() << "(K3bDevice::Device) could not get session info via READ TOC/PMA/ATIP." << endl; + } + else + inf.m_numSessions = 0; + + inf.m_mediaId = mediaId( inf.mediaType() ); + + // + // Now we determine the size: + + // for all empty and appendable media READ FORMAT CAPACITIES should return the proper unformatted size + // for complete disks we may use the READ_CAPACITY command or the start sector from the leadout + // + int media = inf.mediaType(); + // + // Use the profile if available because DVD-ROM units need to treat DVD+-R(W) media as DVD-ROM + // if supported at all + // + if( inf.currentProfile() == MEDIA_DVD_ROM ) + media = MEDIA_DVD_ROM; + + switch( media ) { + case MEDIA_CD_R: + case MEDIA_CD_RW: + if( inf.m_capacity == 0 ) { + if( readTocPmaAtip( &data, dataLen, 0x4, true, 0 ) ) { + + struct atip_descriptor* atip = (struct atip_descriptor*)data; + + if( dataLen >= 11 ) { + inf.m_capacity = K3b::Msf( atip->lead_out_m, atip->lead_out_s, atip->lead_out_f ) - 150; + debugBitfield( &atip->lead_out_m, 3 ); + k3bDebug() << blockDeviceName() << ": ATIP capacity: " << inf.m_capacity.toString() << endl; + } + + delete [] data; + } + } + + // + // for empty and appendable media capacity and usedCapacity should be filled in from + // diskinfo above. If not they are both still 0 + // + if( inf.m_capacity != 0 && + ( inf.diskState() == STATE_EMPTY || inf.m_usedCapacity != 0 ) ) { + // done. + break; + } + + default: + case MEDIA_CD_ROM: + if( inf.m_capacity > 0 && inf.m_usedCapacity == 0 ) + inf.m_usedCapacity = inf.m_capacity; + + if( inf.m_usedCapacity == 0 ) { + K3b::Msf readCap; + if( readCapacity( readCap ) ) { + k3bDebug() << "(K3bDevice::Device) READ CAPACITY: " << readCap.toString() + << " other capacity: " << inf.m_capacity.toString() << endl; + // + // READ CAPACITY returns the last written sector + // that means the size is actually readCap + 1 + // + inf.m_usedCapacity = readCap + 1; + } + else { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() + << " Falling back to readToc for capacity." << endl; + inf.m_usedCapacity = readToc().length(); + } + } + + case MEDIA_DVD_ROM: { + K3b::Msf readCap; + if( readCapacity( readCap ) ) { + k3bDebug() << "(K3bDevice::Device) READ CAPACITY: " << readCap.toString() + << " other capacity: " << inf.m_capacity.toString() << endl; + // + // READ CAPACITY returns the last written sector + // that means the size is actually readCap + 1 + // + inf.m_usedCapacity = readCap + 1; + } + else { + // + // Only one track, use it's size + // + if( readTrackInformation( &data, dataLen, 0x1, 0x1 ) ) { + track_info_t* trackInfo = (track_info_t*)data; + inf.m_usedCapacity = from4Byte( trackInfo->track_size ); + delete [] data; + } + else + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() + << "READ TRACK INFORMATION for DVD-ROM failed." << endl; + } + + break; + } + + case MEDIA_DVD_PLUS_R: + case MEDIA_DVD_PLUS_R_DL: + if( inf.appendable() || inf.empty() ) { + // + // get remaining space via the invisible track + // + if( readTrackInformation( &data, dataLen, 0x1, /*0xff*/ inf.numTracks()+1 ) ) { + track_info_t* trackInfo = (track_info_t*)data; + inf.m_usedCapacity = from4Byte( trackInfo->track_start ); + inf.m_capacity = from4Byte( trackInfo->track_start ) + from4Byte( trackInfo->track_size ); + delete [] data; + } + } + else { + if( readTrackInformation( &data, dataLen, 0x1, inf.numTracks() ) ) { + track_info_t* trackInfo = (track_info_t*)data; + inf.m_capacity = inf.m_usedCapacity + = from4Byte( trackInfo->track_start ) + from4Byte( trackInfo->track_size ); + delete [] data; + } + } + break; + + case MEDIA_DVD_R: + case MEDIA_DVD_R_SEQ: + case MEDIA_DVD_R_DL: + case MEDIA_DVD_R_DL_JUMP: + case MEDIA_DVD_R_DL_SEQ: + // + // get data from the incomplete track (which is NOT the invisible track 0xff) + // This will fail in case the media is complete! + // + if( readTrackInformation( &data, dataLen, 0x1, inf.numTracks()+1 ) ) { + track_info_t* trackInfo = (track_info_t*)data; + inf.m_usedCapacity = from4Byte( trackInfo->track_start ); + inf.m_capacity = from4Byte( trackInfo->free_blocks ) + from4Byte( trackInfo->track_start ); + delete [] data; + } + + // + // Get the "really" used space without border-out + // + if( !inf.empty() ) { + K3b::Msf readCap; + if( readCapacity( readCap ) ) { + // + // READ CAPACITY returns the last written sector + // that means the size is actually readCap + 1 + // + inf.m_usedCapacity = readCap + 1; + } + else + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() + << " READ CAPACITY for DVD-R failed." << endl; + } + + break; + + case MEDIA_DVD_RW_OVWR: + inf.m_numSessions = 1; + case MEDIA_DVD_RW: + case MEDIA_DVD_RW_SEQ: + // only one track on a DVD-RW media + if( readTrackInformation( &data, dataLen, 0x1, 0x1 ) ) { + track_info_t* trackInfo = (track_info_t*)data; + inf.m_capacity = from4Byte( trackInfo->track_size ); + if( !inf.empty() ) { + if( readFormatCapacity( 0x10, inf.m_capacity ) ) + k3bDebug() << blockDeviceName() << ": Format capacity 0x10: " << inf.m_capacity.toString() << endl; + + inf.m_usedCapacity = from4Byte( trackInfo->track_size ); + } + + delete [] data; + } + break; + + case MEDIA_DVD_PLUS_RW: { + K3b::Msf currentMax; + int currentMaxFormat = 0; + if( readFormatCapacity( 0x26, inf.m_capacity, ¤tMax, ¤tMaxFormat ) ) { + if( currentMaxFormat == 0x1 ) { // unformatted or blank media + inf.m_usedCapacity = 0; + inf.m_capacity = currentMax; + } + else { + inf.m_usedCapacity = currentMax; + // Plextor drives tend to screw things up and report invalid values + // for the max format capacity of 1.4 GB DVD media + if ( inf.bgFormatState() == BG_FORMAT_COMPLETE ) { + inf.m_capacity = currentMax; + } + } + } + else + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() + << " READ FORMAT CAPACITIES for DVD+RW failed." << endl; + + break; + } + + case MEDIA_BD_R: + case MEDIA_BD_R_SRM: + case MEDIA_BD_R_SRM_POW: + case MEDIA_BD_R_RRM: + case MEDIA_BD_RE: + // + // get the invisible track's first sector + // or the next writable address of the last open track + // + if( readDiscInformation( &data, dataLen ) ) { + int lastTrack = (int)( data[11]<<8 | data[6] ); + delete [] data; + + if( readTrackInformation( &data, dataLen, 1, lastTrack ) ) { + + // capacity: last track's start address + last track's size + inf.m_capacity = from4Byte( data+8 ) + from4Byte( data+24 ); + + if( data[6] & 0x80 ) + inf.m_usedCapacity = from4Byte( data+8 ); + else if( data[7] & 0x1 ) + inf.m_usedCapacity = from4Byte( data+12 ); + delete [] data; + } + } + break; + + case MEDIA_BD_ROM: { + K3b::Msf readCap; + if( readCapacity( readCap ) ) { + // + // READ CAPACITY returns the last written sector + // that means the size is actually readCap + 1 + // + inf.m_usedCapacity = readCap + 1; + } + + break; + } + } + } + + if( needToClose ) + close(); + } + + return inf; +} + + +int K3bDevice::Device::mediaType() const +{ + int m = MEDIA_UNKNOWN; + + if( testUnitReady() ) { + + m = currentProfile(); + + if( m & (MEDIA_UNKNOWN|MEDIA_DVD_ROM|MEDIA_HD_DVD_ROM) ) { + // + // We prefere the mediatype as reported by the media since this way + // even ROM drives may report the correct type of writable media. + // + + // 4 bytes header + 2048 bytes layer descriptor + unsigned char* data = 0; + unsigned int dataLen = 0; + if( readDvdStructure( &data, dataLen ) ) { + switch( data[4]&0xF0 ) { + case 0x00: m = MEDIA_DVD_ROM; break; + case 0x10: m = MEDIA_DVD_RAM; break; + case 0x20: m = MEDIA_DVD_R; break; // there seems to be no value for DVD-R DL, it reports DVD-R + case 0x30: m = MEDIA_DVD_RW; break; + case 0x40: m = MEDIA_HD_DVD_ROM; break; + case 0x50: m = MEDIA_HD_DVD_R; break; + case 0x60: m = MEDIA_HD_DVD_RAM; break; + case 0x90: m = MEDIA_DVD_PLUS_RW; break; + case 0xA0: m = MEDIA_DVD_PLUS_R; break; + case 0xE0: m = MEDIA_DVD_PLUS_R_DL; break; + default: + k3bDebug() << "(K3bDevice::Device) unknown dvd media type: " << QString::number(data[4]&0xF0, 8) << endl; + break; // unknown + } + + delete [] data; + } + } + + if( m & (MEDIA_UNKNOWN|MEDIA_BD_ROM) ) { + // + // We prefere the mediatype as reported by the media since this way + // even ROM drives may report the correct type of writable media. + // + + unsigned char* data = 0; + unsigned int dataLen = 0; + if( readDiscStructure( &data, dataLen, 1, 0 ) ) { + if( dataLen > 4+12 && + data[4+8] == 'B' && data[4+9] == 'D' ) { + switch( data[4+10] ) { + case 'O': m = MEDIA_BD_ROM; break; + case 'W': m = MEDIA_BD_RE; break; + case 'R': m = MEDIA_BD_R; break; + } + } + + delete [] data; + } + } + + // + // Only old CD or DVD devices do not report a current profile + // or report CD-ROM profile for all CD types + // + if( m & (MEDIA_UNKNOWN|MEDIA_CD_ROM) ) { + unsigned char* data = 0; + unsigned int dataLen = 0; + if( readTocPmaAtip( &data, dataLen, 4, false, 0 ) ) { + if( (data[6]>>6)&1 ) + m = MEDIA_CD_RW; + else + m = MEDIA_CD_R; + + delete [] data; + } + else + m = MEDIA_CD_ROM; + } + } + + return m; +} + + +bool K3bDevice::Device::readSectorsRaw( unsigned char *buf, int start, int count ) const +{ + return readCd( buf, count*2352, + 0, // all sector types + false, // no dap + start, + count, + true, // SYNC + true, // HEADER + true, // SUBHEADER + true, // USER DATA + true, // EDC/ECC + 0, // no c2 info + 0 ); +} + + + +void K3bDevice::Device::checkForJustLink() +{ + unsigned char* ricoh = 0; + unsigned int ricohLen = 0; + if( modeSense( &ricoh, ricohLen, 0x30 ) ) { + + // + // 8 byte mode header + 6 byte page data + // + + if( ricohLen >= 14 ) { + ricoh_mode_page_30* rp = (ricoh_mode_page_30*)(ricoh+8); + d->burnfree = rp->BUEFS; + } + + delete [] ricoh; + } +} + + +void K3bDevice::Device::checkFeatures() +{ + unsigned char header[1024]; + ::memset( header, 0, 1024 ); + + ScsiCommand cmd( this ); + cmd[0] = MMC_GET_CONFIGURATION; + cmd[1] = 2; + cmd[9] = 0; // Necessary to set the proper command length + + + // + // CD writing features + // + cmd[2] = FEATURE_CD_MASTERING>>8; + cmd[3] = FEATURE_CD_MASTERING; + cmd[8] = 8+8; + if( !cmd.transport( TR_DIR_READ, header, 16 ) ) { + unsigned int len = from4Byte( header ); + if( len >= 12 ) { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << " feature: " << "CD Mastering" << endl; +#ifdef WORDS_BIGENDIAN + struct cd_mastering_feature { + unsigned char reserved1 : 1; + unsigned char BUF : 1; // Burnfree + unsigned char SAO : 1; // Session At Once writing + unsigned char raw_ms : 1; // Writing Multisession in Raw Writing Mode + unsigned char raw : 1; // Writing in WRITINGMODE_RAW mode + unsigned char testwrite : 1; // Simulation write support + unsigned char cd_rw : 1; // CD-RW support + unsigned char rw_sub : 1; // Write R-W sub channels with user data + unsigned char max_cue_length[3]; + }; +#else + struct cd_mastering_feature { + unsigned char rw_sub : 1; // Write R-W sub channels with user data + unsigned char cd_rw : 1; // CD-RW support + unsigned char testwrite : 1; // Simulation write support + unsigned char raw : 1; // Writing in WRITINGMODE_RAW mode + unsigned char raw_ms : 1; // Writing Multisession in Raw Writing Mode + unsigned char SAO : 1; // Session At Once writing + unsigned char BUF : 1; // Burnfree + unsigned char reserved1 : 1; + unsigned char max_cue_length[3]; + }; +#endif + + struct cd_mastering_feature* p = (struct cd_mastering_feature*)&header[12]; + if( p->BUF ) d->burnfree = true; + d->writeCapabilities |= MEDIA_CD_R; + if( p->cd_rw ) + d->writeCapabilities |= MEDIA_CD_RW; +// if( p->WRITINGMODE_SAO ) m_writeModes |= WRITINGMODE_SAO; +// if( p->raw || p->raw_ms ) m_writeModes |= WRITINGMODE_RAW; // WRITINGMODE_RAW16 always supported when raw is supported? + } + } + + cmd[2] = FEATURE_CD_TRACK_AT_ONCE>>8; + cmd[3] = FEATURE_CD_TRACK_AT_ONCE; + cmd[8] = 8+8; + if( !cmd.transport( TR_DIR_READ, header, 16 ) ) { + unsigned int len = from4Byte( header ); + if( len >= 12 ) { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << " feature: " << "CD Track At Once" << endl; +#ifdef WORDS_BIGENDIAN + struct cd_track_at_once_feature { + unsigned char reserved1 : 1; + unsigned char BUF : 1; // Burnfree + unsigned char reserved2 : 1; + unsigned char rw_raw : 1; // Writing R-W subcode in Raw mode + unsigned char rw_pack : 1; // Writing R-W subcode in Packet mode + unsigned char testwrite : 1; // Simulation write support + unsigned char cd_rw : 1; // CD-RW support + unsigned char rw_sub : 1; // Write R-W sub channels with user data + unsigned char reserved3; + unsigned char data_type[2]; + }; +#else + struct cd_track_at_once_feature { + unsigned char rw_sub : 1; // Write R-W sub channels with user data + unsigned char cd_rw : 1; // CD-RW support + unsigned char testwrite : 1; // Simulation write support + unsigned char rw_pack : 1; // Writing R-W subcode in Packet mode + unsigned char rw_raw : 1; // Writing R-W subcode in Raw mode + unsigned char reserved2 : 1; + unsigned char BUF : 1; // Burnfree + unsigned char reserved1 : 1; + unsigned char reserved3; + unsigned char data_type[2]; + }; +#endif + + struct cd_track_at_once_feature* p = (struct cd_track_at_once_feature*)&header[12]; + m_writeModes |= WRITINGMODE_TAO; + if( p->BUF ) d->burnfree = true; + d->writeCapabilities |= MEDIA_CD_R; + if( p->cd_rw ) + d->writeCapabilities |= MEDIA_CD_RW; + + // is the following correct? What exactly does rw_sub tell us? +// if( m_writeModes & WRITINGMODE_RAW ) { +// if( p->rw_raw ) m_writeModes |= WRITINGMODE_RAW_R96R; +// if( p->rw_pack ) m_writeModes |= WRITINGMODE_RAW_R96P; +// } + +// // check the data types for 1, 2, and 3 (raw16, raw96p, and raw96r) +// debugBitfield( p->data_type, 2 ); +// if( m_writeModes & WRITINGMODE_RAW ) { +// if( p->data_type[1] & 0x20 ) m_writeModes |= WRITINGMODE_RAW_R16; +// if( p->data_type[1] & 0x40 ) m_writeModes |= WRITINGMODE_RAW_R96P; +// if( p->data_type[1] & 0x80 ) m_writeModes |= WRITINGMODE_RAW_R96R; +// } + } + } + + cmd[2] = FEATURE_CD_RW_MEDIA_WRITE_SUPPORT>>8; + cmd[3] = FEATURE_CD_RW_MEDIA_WRITE_SUPPORT; + cmd[8] = 8+8; + if( !cmd.transport( TR_DIR_READ, header, 16 ) ) { + unsigned int len = from4Byte( header ); + if( len >= 12 ) { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << " feature: " << "CD-RW Media Write Support" << endl; + d->writeCapabilities |= (MEDIA_CD_R|MEDIA_CD_RW); + } + } + + + // + // DVD-ROM + // + // FIXME: since MMC5 the feature descr. is 8 bytes in length including a dvd dl read bit at byte 6 + cmd[2] = FEATURE_DVD_READ>>8; + cmd[3] = FEATURE_DVD_READ; + cmd[8] = 8+8; + if( !cmd.transport( TR_DIR_READ, header, 16 ) ) { + unsigned int len = from4Byte( header ); + if( len >= 12 ) { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << " feature: " << "DVD Read (MMC5)" << endl; + d->readCapabilities |= MEDIA_DVD_ROM; + if( header[8+6] & 0x1 ) + d->readCapabilities |= MEDIA_WRITABLE_DVD_DL; + } + } + else { + // retry with pre-MMC5 length + cmd[8] = 8+4; + if( !cmd.transport( TR_DIR_READ, header, 12 ) ) { + unsigned int len = from4Byte( header ); + if( len >= 8 ) { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << " feature: " << "DVD Read (pre-MMC5)" << endl; + d->readCapabilities |= MEDIA_DVD_ROM; + } + } + } + + // + // DVD+R(W) writing features + // + cmd[2] = FEATURE_DVD_PLUS_R>>8; + cmd[3] = FEATURE_DVD_PLUS_R; + cmd[8] = 8+8; + if( !cmd.transport( TR_DIR_READ, header, 16 ) ) { + unsigned int len = from4Byte( header ); + if( len >= 12 ) { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << " feature: " << "DVD+R" << endl; + d->readCapabilities |= MEDIA_DVD_PLUS_R; + if( header[12] & 0x1 ) + d->writeCapabilities |= MEDIA_DVD_PLUS_R; + } + } + + cmd[2] = FEATURE_DVD_PLUS_RW>>8; + cmd[3] = FEATURE_DVD_PLUS_RW; + cmd[8] = 8+8; + if( !cmd.transport( TR_DIR_READ, header, 16 ) ) { + unsigned int len = from4Byte( header ); + if( len >= 12 ) { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << " feature: " << "DVD+RW" << endl; +#ifdef WORDS_BIGENDIAN + struct dvd_plus_rw_feature { + unsigned char reserved1 : 7; + unsigned char write : 1; + unsigned char reserved2 : 6; + unsigned char quick_start : 1; + unsigned char close_only : 1; + // and some stuff we do not use here... + }; +#else + struct dvd_plus_rw_feature { + unsigned char write : 1; + unsigned char reserved1 : 7; + unsigned char close_only : 1; + unsigned char quick_start : 1; + unsigned char reserved2 : 6; + // and some stuff we do not use here... + }; +#endif + + struct dvd_plus_rw_feature* p = (struct dvd_plus_rw_feature*)&header[12]; + d->readCapabilities |= MEDIA_DVD_PLUS_RW; + if( p->write ) + d->writeCapabilities |= MEDIA_DVD_PLUS_RW; + } + } + + + // some older DVD-ROM drives claim to support DVD+R DL + if( d->writeCapabilities & MEDIA_DVD_PLUS_R ) { + cmd[2] = FEATURE_DVD_PLUS_RW_DUAL_LAYER>>8; + cmd[3] = FEATURE_DVD_PLUS_RW_DUAL_LAYER; + cmd[8] = 8+8; + if( !cmd.transport( TR_DIR_READ, header, 16 ) ) { + unsigned int len = from4Byte( header ); + if( len >= 12 ) { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << " feature: " << "DVD+RW Double Layer" << endl; + d->readCapabilities |= MEDIA_DVD_PLUS_RW_DL; + if( header[12] & 0x1 ) + d->writeCapabilities |= MEDIA_DVD_PLUS_RW_DL; + } + } + + cmd[2] = FEATURE_DVD_PLUS_R_DUAL_LAYER>>8; + cmd[3] = FEATURE_DVD_PLUS_R_DUAL_LAYER; + cmd[8] = 8+8; + if( !cmd.transport( TR_DIR_READ, header, 16 ) ) { + unsigned int len = from4Byte( header ); + if( len >= 12 ) { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << " feature: " << "DVD+R Double Layer" << endl; + d->readCapabilities |= MEDIA_DVD_PLUS_R_DL; + if( header[12] & 0x1 ) + d->writeCapabilities |= MEDIA_DVD_PLUS_R_DL; + } + } + } + + + // + // Blue Ray + // + // We do not care for the different BD classes and versions here + // + cmd[2] = FEATURE_BD_READ>>8; + cmd[3] = FEATURE_BD_READ; + cmd[8] = 8+32; + if( !cmd.transport( TR_DIR_READ, header, 40 ) ) { + unsigned int len = from4Byte( header ); + if( len >= 36 ) { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << " feature: " << "BD Read" << endl; + if( header[8+8] || header[8+9] || header[8+10] || header[8+11] || header[8+12] || header[8+13] || header[8+14] || header[8+15] ) + d->readCapabilities |= MEDIA_BD_RE; + if( header[8+16] || header[8+17] || header[8+18] || header[8+19] || header[8+20] || header[8+21] || header[8+22] || header[8+23] ) + d->readCapabilities |= MEDIA_BD_R; + if( header[8+24] || header[8+25] || header[8+26] || header[8+27] || header[8+28] || header[8+29] || header[8+30] || header[8+31] ) + d->readCapabilities |= MEDIA_BD_ROM; + } + } + + cmd[2] = FEATURE_BD_WRITE>>8; + cmd[3] = FEATURE_BD_WRITE; + cmd[8] = 8+24; + if( !cmd.transport( TR_DIR_READ, header, 32 ) ) { + unsigned int len = from4Byte( header ); + if( len >= 28 ) { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << " feature: " << "BD Write" << endl; + if( header[8+8] || header[8+9] || header[8+10] || header[8+11] || header[8+12] || header[8+13] || header[8+14] || header[8+15] ) + d->writeCapabilities |= MEDIA_BD_RE; + if( header[8+16] || header[8+17] || header[8+18] || header[8+19] || header[8+20] || header[8+21] || header[8+22] || header[8+23] ) { + d->writeCapabilities |= MEDIA_BD_R; + m_writeModes |= WRITINGMODE_SRM; + + cmd[2] = FEATURE_BD_PSEUDO_OVERWRITE>>8; + cmd[3] = FEATURE_BD_PSEUDO_OVERWRITE; + cmd[8] = 8+8; + if( !cmd.transport( TR_DIR_READ, header, 8+8 ) ) { + unsigned int len = from4Byte( header ); + if( len >= 4+8 ) { + m_writeModes |= WRITINGMODE_SRM_POW; + } + } + + cmd[2] = FEATURE_RANDOM_WRITABLE>>8; + cmd[3] = FEATURE_RANDOM_WRITABLE; + cmd[8] = 8+16; + if( !cmd.transport( TR_DIR_READ, header, 8+16 ) ) { + unsigned int len = from4Byte( header ); + if( len >= 4+16 ) { + m_writeModes |= WRITINGMODE_RRM; + } + } + } + } + } + + + + // + // DVD-R(W) + // + cmd[2] = FEATURE_DVD_R_RW_WRITE>>8; + cmd[3] = FEATURE_DVD_R_RW_WRITE; + cmd[8] = 16; + if( !cmd.transport( TR_DIR_READ, header, 16 ) ) { + unsigned int len = from4Byte( header ); + if( len >= 12 ) { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << " feature: " << "DVD-R/-RW Write" << endl; +#ifdef WORDS_BIGENDIAN + struct dvd_r_rw_write_feature { + unsigned char reserved1 : 1; + unsigned char BUF : 1; // Burnfree + unsigned char reserved2 : 2; + unsigned char RDL : 1; + unsigned char testwrite : 1; // Simulation write support + unsigned char dvd_rw : 1; // DVD-RW Writing + unsigned char reserved3 : 1; + unsigned char reserved4[3]; + }; +#else + struct dvd_r_rw_write_feature { + unsigned char reserved3 : 1; + unsigned char dvd_rw : 1; // DVD-RW Writing + unsigned char testwrite : 1; // Simulation write support + unsigned char RDL : 1; + unsigned char reserved2 : 2; + unsigned char BUF : 1; // Burnfree + unsigned char reserved1 : 1; + unsigned char reserved4[3]; + }; +#endif + + struct dvd_r_rw_write_feature* p = (struct dvd_r_rw_write_feature*)&header[12]; + if( p->BUF ) d->burnfree = true; + d->writeCapabilities |= (MEDIA_DVD_R|MEDIA_DVD_R_SEQ); + if( p->dvd_rw ) + d->writeCapabilities |= (MEDIA_DVD_RW|MEDIA_DVD_RW_SEQ); + if( p->RDL ) + d->writeCapabilities |= (MEDIA_DVD_R_DL|MEDIA_DVD_R_DL_SEQ); + + m_dvdMinusTestwrite = p->testwrite; + } + } + + + // + // DVD-RW restricted overwrite check + // + cmd[2] = FEATURE_RIGID_RESTRICTED_OVERWRITE>>8; + cmd[3] = FEATURE_RIGID_RESTRICTED_OVERWRITE; + cmd[8] = 16; + if( !cmd.transport( TR_DIR_READ, header, 16 ) ) { + unsigned int len = from4Byte( header ); + if( len >= 12 ) { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << " feature: " << "Rigid Restricted Overwrite" << endl; + m_writeModes |= WRITINGMODE_RES_OVWR; + d->writeCapabilities |= (MEDIA_DVD_RW|MEDIA_DVD_RW_OVWR); + } + } + + + // + // DVD-R Dual Layer Layer + // + cmd[2] = FEATURE_LAYER_JUMP_RECORDING>>8; + cmd[3] = FEATURE_LAYER_JUMP_RECORDING; + cmd[8] = 12; + if( !cmd.transport( TR_DIR_READ, header, 12 ) ) { + // Now the jump feature is longer than 4 bytes but we don't need the link sizes. + unsigned int len = from4Byte( header ); + if( len >= 8 ) { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << " feature: " << "Layer Jump Recording" << endl; + d->writeCapabilities |= (MEDIA_DVD_R_DL|MEDIA_DVD_R_DL_JUMP); + m_writeModes |= WRITINGMODE_LAYER_JUMP; + } + } + + + // + // HD-DVD-ROM + // + cmd[2] = FEATURE_HD_DVD_READ>>8; + cmd[3] = FEATURE_HD_DVD_READ; + cmd[8] = 16; + if( !cmd.transport( TR_DIR_READ, header, 16 ) ) { + unsigned int len = from4Byte( header ); + if( len >= 12 ) { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << " feature: " << "HD-DVD Read" << endl; + d->readCapabilities |= MEDIA_HD_DVD_ROM; + if( header[8+4] & 0x1 ) + d->readCapabilities |= MEDIA_HD_DVD_R; + if( header[8+6] & 0x1 ) + d->readCapabilities |= MEDIA_HD_DVD_RAM; + } + } + + + // + // HD-DVD-R(AM) + // + cmd[2] = FEATURE_HD_DVD_WRITE>>8; + cmd[3] = FEATURE_HD_DVD_WRITE; + cmd[8] = 16; + if( !cmd.transport( TR_DIR_READ, header, 16 ) ) { + unsigned int len = from4Byte( header ); + if( len >= 12 ) { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << " feature: " << "HD-DVD Write" << endl; + if( header[8+4] & 0x1 ) + d->writeCapabilities |= MEDIA_HD_DVD_R; + if( header[8+6] & 0x1 ) + d->writeCapabilities |= MEDIA_HD_DVD_RAM; + } + } + + + + // + // Get the profiles + // + // the max len of the returned data is 8 (header) + 4 (feature) + 255 (additional length) + // + cmd[2] = FEATURE_PROFILE_LIST>>8; + cmd[3] = FEATURE_PROFILE_LIST; + cmd[8] = 12; // get the number of returned profiles first + if( !cmd.transport( TR_DIR_READ, header, 12 ) ) { + unsigned int len = from4Byte( header ) + 4; + if( len >= 12 ) { + cmd[7] = len>>8; + cmd[8] = len; + if( !cmd.transport( TR_DIR_READ, header, len ) ) { + int featureLen( header[11] ); + for( int j = 0; j < featureLen; j+=4 ) { + short profile = from2Byte( &header[12+j] ); + + switch (profile) { + case 0x08: + d->supportedProfiles |= MEDIA_CD_ROM; + break; + case 0x09: + d->supportedProfiles |= MEDIA_CD_R; + break; + case 0x0A: + d->supportedProfiles |= MEDIA_CD_RW; + break; + case 0x10: + d->supportedProfiles |= MEDIA_DVD_ROM; + // d->readCapabilities |= MEDIA_DVD_ROM; + break; + case 0x11: + d->supportedProfiles |= MEDIA_DVD_R_SEQ; + // d->writeCapabilities |= (MEDIA_DVD_R|MEDIA_DVD_R_SEQ); + break; + case 0x12: + d->supportedProfiles |= MEDIA_DVD_RAM; +// d->readCapabilities |= (MEDIA_DVD_RAM|MEDIA_DVD_ROM); +// d->writeCapabilities |= MEDIA_DVD_RAM; + break; + case 0x13: + d->supportedProfiles |= MEDIA_DVD_RW_OVWR; + // d->writeCapabilities |= (MEDIA_DVD_RW|MEDIA_DVD_RW_OVWR); + break; + case 0x14: + d->supportedProfiles |= MEDIA_DVD_RW_SEQ; + // d->writeCapabilities |= (MEDIA_DVD_RW|MEDIA_DVD_R|MEDIA_DVD_RW_SEQ|MEDIA_DVD_R_SEQ); + break; + case 0x15: + d->supportedProfiles |= MEDIA_DVD_R_DL_SEQ; + // d->writeCapabilities |= (MEDIA_DVD_R|MEDIA_DVD_R_DL|MEDIA_DVD_R_SEQ|MEDIA_DVD_R_DL_SEQ); + break; + case 0x16: + d->supportedProfiles |= MEDIA_DVD_R_DL_JUMP; + // d->writeCapabilities |= (MEDIA_DVD_R|MEDIA_DVD_R_DL||MEDIA_DVD_R_DL_JUMP); + break; + case 0x1A: + d->supportedProfiles |= MEDIA_DVD_PLUS_RW; + // d->writeCapabilities |= MEDIA_DVD_PLUS_RW; + break; + case 0x1B: + d->supportedProfiles |= MEDIA_DVD_PLUS_R; + // d->writeCapabilities |= MEDIA_DVD_PLUS_R; + break; + case 0x2A: + d->supportedProfiles |= MEDIA_DVD_PLUS_RW_DL; + // d->writeCapabilities |= MEDIA_DVD_PLUS_RW_DL; + break; + case 0x2B: + d->supportedProfiles |= MEDIA_DVD_PLUS_R_DL; + // d->writeCapabilities |= MEDIA_DVD_PLUS_R_DL; + break; + case 0x40: + d->supportedProfiles |= MEDIA_BD_ROM; + break; + case 0x41: + d->supportedProfiles |= MEDIA_BD_R_SRM; + break; + case 0x42: + d->supportedProfiles |= MEDIA_BD_R_RRM; + break; + case 0x43: + d->supportedProfiles |= MEDIA_BD_RE; + break; + case 0x50: + d->supportedProfiles |= MEDIA_HD_DVD_ROM; + break; + case 0x51: + d->supportedProfiles |= MEDIA_HD_DVD_R; + break; + case 0x52: + d->supportedProfiles |= MEDIA_HD_DVD_RAM; + break; + default: + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << " unknown profile: " + << profile << endl; + } + } + + // some older DVD-ROM drives claim to support DVD+R DL + if( !(d->supportedProfiles & MEDIA_DVD_PLUS_R) ) { + // remove DVD+R DL capability + // d->writeCapabilities &= ~MEDIA_DVD_PLUS_R_DL; + d->supportedProfiles &= ~MEDIA_DVD_PLUS_R_DL; + } + } + } + } +} + + +void K3bDevice::Device::checkFor2AFeatures() +{ + unsigned char* mm_cap_buffer = 0; + unsigned int mm_cap_len = 0; + + if( modeSense( &mm_cap_buffer, mm_cap_len, 0x2A ) ) { + mm_cap_page_2A* mm_p = (mm_cap_page_2A*)(mm_cap_buffer+8); + if( mm_p->BUF ) + d->burnfree = true; + + if( mm_p->cd_r_write ) + d->writeCapabilities |= MEDIA_CD_R; + else + d->writeCapabilities &= ~MEDIA_CD_R; + + if( mm_p->cd_rw_write ) + d->writeCapabilities |= MEDIA_CD_RW; + else + d->writeCapabilities &= ~MEDIA_CD_RW; + + if( mm_p->dvd_r_write ) + d->writeCapabilities |= MEDIA_DVD_R; + else + d->writeCapabilities &= ~MEDIA_DVD_R; + + if( mm_p->dvd_rom_read || mm_p->dvd_r_read ) + d->readCapabilities |= MEDIA_DVD_ROM; + + m_maxReadSpeed = from2Byte(mm_p->max_read_speed); + m_bufferSize = from2Byte( mm_p->buffer_size ); + + delete [] mm_cap_buffer; + } + else { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << ": read mode page 2A failed!" << endl; + } +} + + +void K3bDevice::Device::checkWritingModes() +{ + // if the device is already opened we do not close it + // to allow fast multiple method calls in a row + bool needToClose = !isOpen(); + + if( !open() ) + return; + + // header size is 8 + unsigned char* buffer = 0; + unsigned int dataLen = 0; + + if( !modeSense( &buffer, dataLen, 0x05 ) ) { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << ": modeSense 0x05 failed!" << endl + << "(K3bDevice::Device) " << blockDeviceName() << ": Cannot check write modes." << endl; + } + else if( dataLen < 18 ) { // 8 bytes header + 10 bytes used modepage + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << ": Missing modepage 0x05 data." << endl + << "(K3bDevice::Device) " << blockDeviceName() << ": Cannot check write modes." << endl; + } + else { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << ": dataLen: " << dataLen << endl; + + wr_param_page_05* mp = (struct wr_param_page_05*)(buffer+8); + + // reset some stuff to be on the safe side + mp->PS = 0; + mp->BUFE = 0; + mp->multi_session = 0; + mp->test_write = 0; + mp->LS_V = 0; + mp->copy = 0; + mp->fp = 0; + mp->host_appl_code= 0; + mp->session_format = 0; + mp->audio_pause_len[0] = 0; + mp->audio_pause_len[1] = 150; + + // WRITINGMODE_TAO + mp->write_type = 0x01; // Track-at-once + mp->track_mode = 4; // MMC-4 says: 5, cdrecord uses 4 ? + mp->dbtype = 8; // Mode 1 + + // k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << ": modeselect WRITINGMODE_TAO data: " << endl; + // debugBitfield( buffer, dataLen ); + + + // + // if a writer does not support WRITINGMODE_TAO it surely does not support WRITINGMODE_SAO or WRITINGMODE_RAW writing since WRITINGMODE_TAO is the minimal + // requirement + // + + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << ": checking for TAO" << endl; + if( modeSelect( buffer, dataLen, 1, 0 ) ) { + m_writeModes |= WRITINGMODE_TAO; + d->writeCapabilities |= MEDIA_CD_R; + + // WRITINGMODE_SAO + mp->write_type = 0x02; // Session-at-once + + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << ": checking for SAO" << endl; + if( modeSelect( buffer, dataLen, 1, 0 ) ) + m_writeModes |= WRITINGMODE_SAO; + +// mp->dbtype = 1; // Raw data with P and Q Sub-channel (2368 bytes) +// if( modeSelect( buffer, dataLen, 1, 0 ) ) { +// m_writeModes |= WRITINGMODE_RAW_R16; +// } + + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << ": checking for SAO_R96P" << endl; + mp->dbtype = 2; // Raw data with P-W Sub-channel (2448 bytes) + if( modeSelect( buffer, dataLen, 1, 0 ) ) { + m_writeModes |= WRITINGMODE_SAO_R96P; + } + + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << ": checking for SAO_R96R" << endl; + mp->dbtype = 3; // Raw data with P-W raw Sub-channel (2448 bytes) + if( modeSelect( buffer, dataLen, 1, 0 ) ) { + m_writeModes |= WRITINGMODE_SAO_R96R; + } + + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << ": checking for RAW_R16" << endl; + // WRITINGMODE_RAW + mp->write_type = 0x03; // WRITINGMODE_RAW + mp->dbtype = 1; // Raw data with P and Q Sub-channel (2368 bytes) + if( modeSelect( buffer, dataLen, 1, 0 ) ) { + m_writeModes |= WRITINGMODE_RAW; + m_writeModes |= WRITINGMODE_RAW_R16; + } + + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << ": checking for RAW_R96P" << endl; + mp->dbtype = 2; // Raw data with P-W Sub-channel (2448 bytes) + if( modeSelect( buffer, dataLen, 1, 0 ) ) { + m_writeModes |= WRITINGMODE_RAW; + m_writeModes |= WRITINGMODE_RAW_R96P; + } + + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << ": checking for RAW_R96R" << endl; + mp->dbtype = 3; // Raw data with P-W raw Sub-channel (2448 bytes) + if( modeSelect( buffer, dataLen, 1, 0 ) ) { + m_writeModes |= WRITINGMODE_RAW; + m_writeModes |= WRITINGMODE_RAW_R96R; + } + } + else { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << ": modeSelect with WRITINGMODE_TAO failed. No writer" << endl; + } + + + delete [] buffer; + } + + if( needToClose ) + close(); +} + + +int K3bDevice::Device::determineMaximalWriteSpeed() const +{ + int ret = 0; + unsigned char* data = 0; + unsigned int dataLen = 0; + + if( mediaType() & MEDIA_CD_ALL ) { + if( modeSense( &data, dataLen, 0x2A ) ) { + mm_cap_page_2A* mm = (mm_cap_page_2A*)&data[8]; + + // MMC1 used byte 18 and 19 for the max write speed + if( dataLen > 19 ) + ret = from2Byte( mm->max_write_speed ); + + delete [] data; + + if( ret > 0 ) + return ret; + } + } + + QValueList<int> list = determineSupportedWriteSpeeds(); + if( !list.isEmpty() ) { + for( QValueList<int>::const_iterator it = list.constBegin(); it != list.constEnd(); ++it ) + ret = QMAX( ret, *it ); + } + + if( ret > 0 ) + return ret; + else + return m_maxWriteSpeed; +} + + +QValueList<int> K3bDevice::Device::determineSupportedWriteSpeeds() const +{ + QValueList<int> ret; + + if( burner() ) { + // + // Tests with all my drives resulted in 2A for CD and GET PERFORMANCE for DVD media + // as the valid method of speed detection. + // + if( mediaType() & MEDIA_CD_ALL ) { + if( !getSupportedWriteSpeedsVia2A( ret, false ) ) + getSupportedWriteSpeedsViaGP( ret, false ); + + // restrict to max speed, although deprecated in MMC3 is still used everywhere and + // cdrecord also uses it as the max writing speed. + int max = 0; + unsigned char* data = 0; + unsigned int dataLen = 0; + if( modeSense( &data, dataLen, 0x2A ) ) { + mm_cap_page_2A* mm = (mm_cap_page_2A*)&data[8]; + + // MMC1 used byte 18 and 19 for the max write speed + if( dataLen > 19 ) + max = from2Byte( mm->max_write_speed ); + + delete [] data; + + if( max > 0 ) { + while( !ret.isEmpty() && ret.last() > max ) { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() + << " writing speed " << ret.last() << " higher than max " << max << endl; + ret.pop_back(); + } + } + } + } + else { + if( !getSupportedWriteSpeedsViaGP( ret, true ) ) + getSupportedWriteSpeedsVia2A( ret, true ); + } + } + + return ret; +} + + +bool K3bDevice::Device::getSupportedWriteSpeedsVia2A( QValueList<int>& list, bool dvd ) const +{ + unsigned char* data = 0; + unsigned int dataLen = 0; + if( modeSense( &data, dataLen, 0x2A ) ) { + mm_cap_page_2A* mm = (mm_cap_page_2A*)&data[8]; + + if( dataLen > 32 ) { + // we have descriptors + unsigned int numDesc = from2Byte( mm->num_wr_speed_des ); + + // Some CDs writer returns the number of bytes that contain + // the descriptors rather than the number of descriptors + // Ensure number of descriptors claimed actually fits in the data + // returned by the mode sense command. + if( numDesc > ((dataLen - 32 - 8) / 4) ) + numDesc = (dataLen - 32 - 8) / 4; + + cd_wr_speed_performance* wr = (cd_wr_speed_performance*)mm->wr_speed_des; + + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() + << ": Number of supported write speeds via 2A: " + << numDesc << endl; + + + for( unsigned int i = 0; i < numDesc; ++i ) { + int s = (int)from2Byte( wr[i].wr_speed_supp ); + // + // some DVD writers report CD writing speeds here + // If that is the case we cannot rely on the reported speeds + // and need to use the values gained from GET PERFORMANCE. + // + if( dvd && s < 1352 ) { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() + << " Invalid DVD speed: " << s << " KB/s" << endl; + list.clear(); + break; + } + else { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() + << " : " << s << " KB/s" << endl; + + if( dvd ) + s = fixupDvdWritingSpeed( s ); + + // sort the list + QValueList<int>::iterator it = list.begin(); + while( it != list.end() && *it < s ) + ++it; + list.insert( it, s ); + } + } + } + + delete [] data; + } + + return !list.isEmpty(); +} + + +bool K3bDevice::Device::getSupportedWriteSpeedsViaGP( QValueList<int>& list, bool dvd ) const +{ + unsigned char* data = 0; + unsigned int dataLen = 0; + if( getPerformance( &data, dataLen, 0x3, 0x0 ) ) { + int numDesc = (dataLen - 8)/16; + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() + << ": Number of supported write speeds via GET PERFORMANCE: " + << numDesc << endl; + + for( int i = 0; i < numDesc; ++i ) { + int s = from4Byte( &data[20+i*16] ); + + // Looks as if the code below does not make sense with most drives +// if( !( data[4+i*16] & 0x2 ) ) { +// k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() +// << " No write speed: " << s << " KB/s" << endl; +// continue; +// } + + if( dvd && s < 1352 ) { + // + // Does this ever happen? + // + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() + << " Invalid DVD speed: " << s << " KB/s" << endl; + } + else { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() + << " : " << s << " KB/s" << endl; + + if( dvd ) + s = fixupDvdWritingSpeed( s ); + + QValueList<int>::iterator it = list.begin(); + while( it != list.end() && *it < s ) + ++it; + // the speed might already have been found in the 2a modepage + if( it == list.end() || *it != s ) + list.insert( it, s ); + } + } + + delete [] data; + } + + return !list.isEmpty(); +} + + +int K3bDevice::Device::getIndex( unsigned long lba ) const +{ + // if the device is already opened we do not close it + // to allow fast multiple method calls in a row + bool needToClose = !isOpen(); + + if( !open() ) + return -1; + + int ret = -1; + + // + // first try readCd + // + unsigned char readData[16]; + ::memset( readData, 0, 16 ); + + // + // The index is found in the Mode-1 Q which occupies at least 9 out of 10 successive CD frames + // It can be indentified by ADR == 1 + // + // So if the current sector does not provide Mode-1 Q subchannel we try the previous. + // + + if( readCd( readData, + 16, + 1, // CD-DA + 0, // no DAP + lba, + 1, + false, + false, + false, + false, + false, + 0, + 2 // Q-Subchannel + ) ) { + // byte 0: 4 bits CONTROL (MSB) + 4 bits ADR (LSB) + if( (readData[0]&0x0f) == 0x1 ) + ret = readData[2]; + + // search previous sector for Mode1 Q Subchannel + else if( readCd( readData, + 16, + 1, // CD-DA + 0, // no DAP + lba-1, + 1, + false, + false, + false, + false, + false, + 0, + 2 // Q-Subchannel + ) ) { + if( (readData[0]&0x0f) == 0x1 ) + ret = readData[2]; + else + ret = -2; + } + } + + else { + k3bDebug() << "(K3bDevice::Device::getIndex) readCd failed. Trying seek." << endl; + + unsigned char* data = 0; + unsigned int dataLen = 0; + if( seek( lba ) && readSubChannel( &data, dataLen, 1, 0 ) ) { + // byte 5: 4 bits ADR (MSB) + 4 bits CONTROL (LSB) + if( dataLen > 7 && (data[5]>>4 & 0x0F) == 0x1 ) { + ret = data[7]; + } + else if( seek( lba-1 ) && readSubChannel( &data, dataLen, 1, 0 ) ) { + if( dataLen > 7 && (data[5]>>4 & 0x0F) == 0x1 ) + ret = data[7]; + else + ret = -2; + } + + delete [] data; + } + else + k3bDebug() << "(K3bDevice::Device::getIndex) seek or readSubChannel failed." << endl; + } + + if( needToClose ) + close(); + + return ret; +} + + +bool K3bDevice::Device::searchIndex0( unsigned long startSec, + unsigned long endSec, + long& pregapStart ) const +{ + // if the device is already opened we do not close it + // to allow fast multiple method calls in a row + bool needToClose = !isOpen(); + + if( !open() ) + return false; + + bool ret = false; + + int lastIndex = getIndex( endSec ); + if( lastIndex == 0 ) { + // there is a pregap + // let's find the position where the index turns to 0 + // we jump in 1 sec steps backwards until we find an index > 0 + unsigned long sector = endSec; + while( lastIndex == 0 && sector > startSec ) { + sector -= 75; + if( sector < startSec ) + sector = startSec; + lastIndex = getIndex(sector); + } + + if( lastIndex == 0 ) { + k3bDebug() << "(K3bDevice::Device) warning: no index != 0 found." << endl; + } + else { + // search forward to the first index = 0 + while( getIndex( sector ) != 0 && sector < endSec ) + sector++; + + pregapStart = sector; + ret = true; + } + } + else if( lastIndex > 0 ) { + // no pregap + pregapStart = -1; + ret = true; + } + + if( needToClose ) + close(); + + return ret; +} + + +bool K3bDevice::Device::indexScan( K3bDevice::Toc& toc ) const +{ + // if the device is already opened we do not close it + // to allow fast multiple method calls in a row + bool needToClose = !isOpen(); + + if( !open() ) + return false; + + bool ret = true; + + for( Toc::iterator it = toc.begin(); it != toc.end(); ++it ) { + Track& track = *it; + if( track.type() == Track::AUDIO ) { + track.m_indices.clear(); + long index0 = -1; + if( searchIndex0( track.firstSector().lba(), track.lastSector().lba(), index0 ) ) { + k3bDebug() << "(K3bDevice::Device) found index 0: " << index0 << endl; + } + if( index0 > 0 ) + track.m_index0 = K3b::Msf( index0 - track.firstSector().lba() ); + else + track.m_index0 = 0; + + if( index0 > 0 ) + searchIndexTransitions( track.firstSector().lba(), index0-1, track ); + else + searchIndexTransitions( track.firstSector().lba(), track.lastSector().lba(), track ); + } + } + + if( needToClose ) + close(); + + return ret; +} + + +void K3bDevice::Device::searchIndexTransitions( long start, long end, K3bDevice::Track& track ) const +{ + k3bDebug() << "(K3bDevice::Device) searching for index transitions between " + << start << " and " << end << endl; + int startIndex = getIndex( start ); + int endIndex = getIndex( end ); + + if( startIndex < 0 || endIndex < 0 ) { + k3bDebug() << "(K3bDevice::Device) could not retrieve index values." << endl; + } + else { + k3bDebug() << "(K3bDevice::Device) indices: " << start << " - " << startIndex + << " and " << end << " - " << endIndex << endl; + + if( startIndex != endIndex ) { + if( start+1 == end ) { + k3bDebug() << "(K3bDevice::Device) found index transition: " << endIndex << " " << end << endl; + track.m_indices.resize( endIndex ); + // we save the index relative to the first sector + track.m_indices[endIndex-1] = K3b::Msf( end ) - track.firstSector(); + } + else { + searchIndexTransitions( start, start+(end-start)/2, track ); + searchIndexTransitions( start+(end-start)/2, end, track ); + } + } + } +} + + +int K3bDevice::Device::copyrightProtectionSystemType() const +{ + unsigned char* dvdheader = 0; + unsigned int dataLen = 0; + if( readDvdStructure( &dvdheader, dataLen, 0x1 ) ) { + int ret = -1; + if( dataLen >= 6 ) + ret = dvdheader[4]; + delete [] dvdheader; + return ret; + } + else + return -1; +} + + +bool K3bDevice::Device::getNextWritableAdress( unsigned int& lastSessionStart, unsigned int& nextWritableAdress ) const +{ + bool success = false; + + // FIXME: add CD media handling + int m = mediaType(); + if( m & MEDIA_DVD_ALL ) { + // DVD+RW always returns complete + if( m & (K3bDevice::MEDIA_DVD_PLUS_RW|K3bDevice::MEDIA_DVD_RW_OVWR) ) + return false; + + unsigned char* data = 0; + unsigned int dataLen = 0; + + if( readDiscInformation( &data, dataLen ) ) { + disc_info_t* inf = (disc_info_t*)data; + + // + // The state of the last session has to be "empty" (0x0) or "incomplete" (0x1) + // The procedure here is taken from the dvd+rw-tools + // + if( !(inf->border & 0x2) ) { + // the incomplete track number is the first track in the last session (the empty session) + int nextTrack = inf->first_track_l|inf->first_track_m<<8; + + unsigned char* trackData = 0; + unsigned int trackDataLen = 0; + + // Read start address of the incomplete track + if( readTrackInformation( &trackData, trackDataLen, 0x1, nextTrack ) ) { + nextWritableAdress = from4Byte( &trackData[8] ); + delete [] trackData; + + // Read start address of the first track in the last session + if( readTocPmaAtip( &trackData, trackDataLen, 0x1, false, 0x0 ) ) { + lastSessionStart = from4Byte( &trackData[8] ); + delete [] trackData; + success = true; + } + } + } + } + + delete [] data; + } + + return success; +} + + +int K3bDevice::Device::nextWritableAddress() const +{ + unsigned char* data = 0; + unsigned int dataLen = 0; + int nwa = -1; + + if( readDiscInformation( &data, dataLen ) ) { + disc_info_t* inf = (disc_info_t*)data; + + // + // The state of the last session has to be "empty" (0x0) or "incomplete" (0x1) + // The procedure here is taken from the dvd+rw-tools and wodim + // + if( !(inf->border & 0x2) ) { + // the incomplete track number is the first track in the last session (the empty session) + int nextTrack = inf->first_track_l|inf->first_track_m<<8; + + unsigned char* trackData = 0; + unsigned int trackDataLen = 0; + + // Read start address of the incomplete track + if( readTrackInformation( &trackData, trackDataLen, 0x1, nextTrack ) ) { + nwa = from4Byte( &trackData[8] ); + delete [] trackData; + } + + // Read start address of the invisible track + else if ( readTrackInformation( &trackData, trackDataLen, 0x1, 0xff ) ) { + nwa = from4Byte( &trackData[8] ); + delete [] trackData; + } + } + + delete [] data; + } + + return nwa; +} + + +QCString K3bDevice::Device::mediaId( int mediaType ) const +{ + QCString id; + + if( mediaType & MEDIA_CD_ALL ) { + // FIXME: + } + + else if( mediaType & MEDIA_DVD_MINUS_ALL ) { + unsigned char* data = 0; + unsigned int dataLen = 0; + if( readDvdStructure( &data, dataLen, 0x0E ) ) { + if( data[4+16] == 3 && data[4+24] == 4 ) { + id.sprintf( "%6.6s%-6.6s", data+4+17, data+4+25 ); + } + delete [] data; + } + } + + else if( mediaType & MEDIA_DVD_PLUS_ALL ) { + unsigned char* data = 0; + unsigned int dataLen = 0; + if( readDvdStructure( &data, dataLen, 0x11 ) || + readDvdStructure( &data, dataLen, 0x0 ) ) { + id.sprintf( "%8.8s/%3.3s", data+23, data+31 ); + delete [] data; + } + } + + else if( mediaType & MEDIA_BD_ALL ) { + unsigned char* data = 0; + unsigned int dataLen = 0; + if( readDiscStructure( &data, dataLen, 1, 0 ) ) { + if( data[4+0] == 'D' && data[4+1] == 'I' ) + id.sprintf ("%6.6s/%-3.3s", data+4+100, data+4+106 ); + delete [] data; + } + } + + return id; +} + + +// int K3bDevice::Device::ioctl( int request, ... ) const +// { +// int r = -1; +// #if defined(Q_OS_LINUX) || defined(Q_OS_NETBSD) +// d->mutex.lock(); + +// va_list ap; +// va_start( ap, request ); +// r = ::ioctl( d->deviceFd, request, ap ); +// va_end( ap ); + +// d->mutex.unlock(); +// #endif +// return r; +// } + + +void K3bDevice::Device::usageLock() const +{ + d->mutex.lock(); +} + + +void K3bDevice::Device::usageUnlock() const +{ + d->mutex.unlock(); +} diff --git a/libk3bdevice/k3bdevice.h b/libk3bdevice/k3bdevice.h new file mode 100644 index 0000000..1dcd863 --- /dev/null +++ b/libk3bdevice/k3bdevice.h @@ -0,0 +1,836 @@ +/* + * + * $Id: k3bdevice.h 679274 2007-06-23 13:23:58Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BDEVICE_H +#define K3BDEVICE_H + +#include <qstringlist.h> +#include <qvaluelist.h> +#include <qglobal.h> + +#include <k3bdevicetypes.h> +#include <k3bdiskinfo.h> +#include <k3bcdtext.h> +#include <k3bmsf.h> +#include <k3bdevice_export.h> + +#ifdef Q_OS_FREEBSD +struct cam_device; +#endif + +namespace K3bDevice +{ + class Toc; + + /** + * \brief The main class representing a device. + * + * Devices are constructed by the DeviceManager. + * + * All methods except for open and close in Device are thread-safe which basicly means that + * no two commands are sent to the device at the same time. + */ + // FIXME: all methods are const which makes no sense at all! + class LIBK3BDEVICE_EXPORT Device + { + public: +#ifdef Q_OS_FREEBSD + typedef struct cam_device* Handle; +#else + // file descriptor + typedef int Handle; +#endif + + /** + * The available cdrdao drivers + * \deprecated This will be moved to libk3b + */ + static const char* cdrdao_drivers[]; + + // FIXME: make this protected + ~Device(); + + /** + * The interface type. + * + * \return K3bDevice::SCSI or K3bDevice::IDE. + */ + Interface interfaceType() const; + + /** + * \deprecated use readCapabilities() and writeCapabilities() + * The device type. + * + * @return A bitwise or of K3bDevice::DeviceType. + */ + int type() const; + + /** + * The mediatypes this device is able to read. + * + * \return A bitwise or of K3bDevice::MediaType + */ + int readCapabilities() const; + + /** + * The media types this device is able to write. + * + * \return A bitwise or of K3bDevice::MediaType + */ + int writeCapabilities() const; + + /** + * \return Vendor string as reported by the device's firmware. + */ + const QString& vendor() const { return m_vendor; } + + /** + * \return Description string as reported by the device's firmware. + */ + const QString& description() const { return m_description; } + + /** + * \return Version string as reported by the device's firmware. + */ + const QString& version() const { return m_version; } + + /** + * Shortcut for \code writesCd() || writesDvd() \endcode + * + * \return true if the device is able to burn media. + */ + bool burner() const; + + /** + * Shortcut for \code type() & DEVICE_CD_R \endcode + * + * \return true if the device is able to burn CD-R media. + */ + bool writesCd() const; + + /** + * Shortcut for \code type() & DEVICE_CD_RW \endcode + * + * \return true if the device is able to burn CD-RW media. + */ + bool writesCdrw() const; + + /** + * Shortcut for \code writesDvdMinus() || writesDvdPlus() \endcode + * + * \return true if the device is able to burn DVD media. + */ + bool writesDvd() const; + + + /** + * Shortcut for \code type() & (DEVICE_DVD_PLUS_R|DEVICE_DVD_PLUS_RW) \endcode + * + * \return true if the device is able to burn DVD+R or DVD+RW media. + */ + bool writesDvdPlus() const; + + /** + * Shortcut for \code type() & (DEVICE_DVD_R|DEVICE_DVD_RW) \endcode + * + * \return true if the device is able to burn DVD-R or DVD-RW media. + */ + bool writesDvdMinus() const; + + /** + * Shortcut for \code type() & DEVICE_DVD_ROM \endcode + * + * \return true if the device is able to read DVD media. + */ + bool readsDvd() const; + + /** + * @deprecated Use burnfree() + */ + bool burnproof() const; + + /** + * @return true is the device is a writer and supports buffer underrun free recording (BURNFREE) + */ + bool burnfree() const; + + /** + * Shortcut for \code writingModes() & WRITINGMODE_SAO \endcode + * + * \deprecated use supportsWritingMode() + */ + bool dao() const; + + /** + * Check if the device supports a certain writing mode. + * + * \return true if the device supports the requested writing mode or false otherwise. + */ + bool supportsWritingMode( WritingMode mode ) const { return (m_writeModes & mode); } + + /** + * Shortcut for + * \code + * writingModes() & (WRITINGMODE_RAW|WRITINGMODE_RAW_R16|WRITINGMODE_RAW_R96P|WRITINGMODE_RAW_R96R) + * \endcode + */ + bool supportsRawWriting() const; + + /** + * @return true if the device is a DVD-R(W) writer which supports test writing. + */ + bool dvdMinusTestwrite() const { return m_dvdMinusTestwrite; } + + int maxReadSpeed() const { return m_maxReadSpeed; } + int currentWriteSpeed() const { return m_currentWriteSpeed; } + + /** + * Size of the device's internal writing buffer. + * + * \return The size of the buffer in KB. + */ + int bufferSize() const { return m_bufferSize; } + + /** + * @return the corresponding device name. + */ + const QString& devicename() const; + + /** + * for SCSI devices this should be something like /dev/scd0 or /dev/sr0 + * for IDE device this should be something like /dev/hdb1 + */ + const QString& blockDeviceName() const { return m_blockDevice; } + + /** + * This is only valid for SCSI devices. Without devfs it's something + * like /dev/sg0. Otherwise something like /dev/scsi/host0/bus0/target0/lun0/generic. + * + * This is not needed in K3b at all. But cdrecord and cdrdao use the sg devices and + * we need it to fixup it's permissions in K3bSetup. + */ + const QString& genericDevice() const { return m_genericDevice; } + + /** + * \return All device nodes for this drive. + */ + const QStringList& deviceNodes() const; + + /** + * \see K3bDevice::Device::deviceNodes() + */ + void addDeviceNode( const QString& ); + + /** + * Makes only sense to use with scsi devices + * @return a string for use with the cdrtools + * @deprecated + */ + QString busTargetLun() const; + + int scsiBus() const { return m_bus; } + int scsiId() const { return m_target; } + int scsiLun() const { return m_lun; } + + int maxWriteSpeed() const { return m_maxWriteSpeed; } + + /** + * \deprecated the cdrdao driver has no place in this library. It will be removed. + */ + const QString& cdrdaoDriver() const { return m_cdrdaoDriver; } + + /** + * returns: 0 auto (no cdrdao-driver selected) + * 1 yes + * 2 no + * + * \deprecated cdrdao specific stuff has no place in this library. It will be removed. + */ + int cdTextCapable() const; + + /** + * internal K3b value. + * \deprecated This should not be handled here. + */ + void setCurrentWriteSpeed( int s ) { m_currentWriteSpeed = s; } + + /** + * Use this if the speed was not detected correctly. + */ + void setMaxReadSpeed( int s ) { m_maxReadSpeed = s; } + + /** + * Use this if the speed was not detected correctly. + */ + void setMaxWriteSpeed( int s ) { m_maxWriteSpeed = s; } + + /** + * Use this if cdrdao is not able to autodetect the nessessary driver. + * \deprecated the cdrdao driver has no place in this library. It will be removed. + */ + void setCdrdaoDriver( const QString& d ) { m_cdrdaoDriver = d; } + + /** + * Only used if the cdrdao-driver is NOT set to "auto". + * In that case it must be manually set because there + * is no way to autosense the cd-text capability. + * + * \deprecated the cdrdao driver has no place in this library. It will be removed. + */ + void setCdTextCapability( bool ); + + /** + * checks if unit is ready (medium inserted and ready for command) + * + * Refers to the MMC command: TEST UNIT READY + */ + bool testUnitReady() const; + + /** + * checks if disk is empty, returns @p K3bDevice::State + */ + int isEmpty() const; + + /** + * @return true if inserted media is rewritable. + */ + bool rewritable() const; + + /** + * Check if the inserted media is a DVD. + * + * \return true if the inserted media is a DVD. + */ + bool isDVD() const; + + /** + * @return The number of sessions on the media. + */ + int numSessions() const; + + /** + * @return The toc of the media or an empty (invalid) K3bDevice::Toc if + * no or an empty media is inserted. + */ + Toc readToc() const; + + /** + * Append ISRC and MCN to the TOC if found + * This has been moved to a separate method since it can take a very long time + * to scan for all ISRCs. + */ + void readIsrcMcn( Toc& toc ) const; + + /** + * Read the CD-TEXT of an audio or mixed-mode CD. + * + * \return A CdText object filled with the CD-TEXT values or an empty one in case of + * pure data media or if the CD does not contain CD-TEXT. + */ + CdText readCdText() const; + + /** + * @return The K3bDevice::Track::DataMode of the track. + * @see K3bDevice::Track + */ + int getTrackDataMode( const Track& track ) const; + + /** + * @return the mode of a data track. K3bDevice::Track::MODE1, K3bDevice::Track::MODE2, + * K3bDevice::Track::XA_FORM1, or K3bDevice::Track::XA_FORM2. + */ + int getDataMode( const K3b::Msf& sector ) const; + + /** + * block or unblock the drive's tray + * \return true on success and false on error. + * \see eject() + */ + bool block( bool ) const; + + /** + * Eject the media. + * \return true on success and false on error. + * \see load() + */ + bool eject() const; + + /** + * Load the media. + * @return true on success and false on error. + */ + bool load() const; + + /** + * Enable or disable auto-ejecting. For now this is a no-op on non-Linux systems. + * \param enabled if true auto-ejecting will be enabled, otherwise disabled. + * \return true if the operation was successful, false otherwise + */ + bool setAutoEjectEnabled( bool enabled ) const; + + /** + * The supported writing modes. + * + * \return A bitwise or of K3bDevice::WritingMode or 0 in case of a read-only device. + */ + int writingModes() const { return m_writeModes; } + + bool readSectorsRaw(unsigned char *buf, int start, int count) const; + + /** + * Get a list of supported profiles. See enumeration MediaType. + */ + int supportedProfiles() const; + + /** + * Tries to get the current profile from the drive. + * @returns -1 on error (command failed or unknown profile) + * MediaType otherwise (MEDIA_NONE means: no current profile) + */ + int currentProfile() const; + + /** + * Check if a certain feature is current. + * \see k3bdevicetypes.h for feature constants. + * \return 1 if the feature is current, 0 if not, -1 on error + */ + int featureCurrent( unsigned int feature ) const; + + /** + * This is the method to use! + */ + DiskInfo diskInfo() const; + + /** + * Refers to MMC command READ CAPACITY + */ + bool readCapacity( K3b::Msf& ) const; + + /** + * Refers to MMC command READ FORMAT CAPACITY + * + * @param wantedFormat The requested format type. + * @param result If true is returned this contains the requested value. + * @param currentMax If not 0 this will be filled with the Current/Maximum Descriptor value. + * @param currentMax If not 0 this will be filled with the Current/Maximum Format Type. + */ + bool readFormatCapacity( int wantedFormat, K3b::Msf& result, + K3b::Msf* currentMax = 0, int* currentMaxFormat = 0 ) const; + + /** + * Determine the type of the currently mounted medium + * + * @returns K3bDevice::MediaType + */ + int mediaType() const; + + /** + * Returnes the list of supported writing speeds as reported by + * mode page 2Ah. + * + * This only works with MMC3 compliant drives. + */ + QValueList<int> determineSupportedWriteSpeeds() const; + + /** + * @returnes the speed in kb/s or 0 on failure. + */ + int determineMaximalWriteSpeed() const; + + /** + * Open the device for access via a file descriptor. + * @return true on success or if the device is already open. + * @see close() + * + * Be aware that this method is not thread-safe. + */ + bool open( bool write = false ) const; + + /** + * Close the files descriptor. + * @see open() + * + * Be aware that this method is not thread-safe. + */ + void close() const; + + /** + * @return true if the device was successfully opened via @p open() + */ + bool isOpen() const; + + /** + * fd on linux, cam on bsd + */ + Handle handle() const; + + /** + * \return \li -1 on error (no DVD) + * \li 1 (CSS/CPPM) + * \li 2 (CPRM) if scrambled + * \li 0 otherwise + */ + int copyrightProtectionSystemType() const; + + // MMC commands + + /** + * SET SPEED command + * + * @param readingSpeed The preferred reading speed (0x0000-0xFFFE). 0xFFFF requests + * fot the logical unit to select the optimal speed. + * @param writingSpeed The preferred writing speed (0x0000-0xFFFE). 0xFFFF requests + * fot the logical unit to select the optimal speed. + * @param cav Is the speed pure CAV? + */ + bool setSpeed( unsigned int readingSpeed, + unsigned int writingSpeed, + bool cav = false ) const; + + /** + * if true is returned dataLen specifies the actual length of *data which needs to be + * deleted after using. + */ + bool readDiscInformation( unsigned char** data, unsigned int& dataLen ) const; + + /** + * @param pf If false all fields in the descriptor data is vendor specific. Default should be true. + */ + bool modeSelect( unsigned char* page, unsigned int pageLen, bool pf, bool sp ) const; + + /** + * if true is returned pageLen specifies the actual length of *pageData which needs to be + * deleted after using. + */ + bool modeSense( unsigned char** pageData, unsigned int& pageLen, int page ) const; + + /** + * if true is returned dataLen specifies the actual length of *data which needs to be + * deleted after using. + */ + bool readTocPmaAtip( unsigned char** data, unsigned int& dataLen, int format, bool msf, int track ) const; + + /** + * @param type specifies what value means: + * \li 00b - value refers to a logical block address + * \li 01b - value refers to a track number where 0 will treat the lead-in as if it + * were a logical track and ffh will read the invisible or incomplete track. + * \li 10b - value refers to a session number + * + */ + bool readTrackInformation( unsigned char** data, unsigned int& dataLen, int type, int value ) const; + + /** + * if true is returned dataLen specifies the actual length of *data which needs to be + * deleted after using. + */ + bool readDiscStructure( unsigned char** data, unsigned int& dataLen, + unsigned int mediaType = 0x0, + unsigned int format = 0x0, + unsigned int layer = 0x0, + unsigned long adress = 0, + unsigned int agid = 0x0 ) const; + + /** + * In MMC5 readDvdStructure was renamed to readDiscStructure. This method does the same + * like the above. + */ + bool readDvdStructure( unsigned char** data, unsigned int& dataLen, + unsigned int format = 0x0, + unsigned int layer = 0x0, + unsigned long adress = 0, + unsigned int agid = 0x0 ) const; + + /** + * if true is returned dataLen specifies the actual length of *data which needs to be + * deleted after using. + */ + bool mechanismStatus( unsigned char** data, unsigned int& dataLen ) const; + + /** + * Read a single feature. + * data will be filled with the feature header and the descriptor + */ + bool getFeature( unsigned char** data, unsigned int& dataLen, unsigned int feature ) const; + + + /** + * if true is returned dataLen specifies the actual length of *data which needs to be + * deleted after using. + */ + bool getPerformance( unsigned char** data, unsigned int& dataLen, + unsigned int type, + unsigned int dataType, + unsigned int lba = 0 ) const; + + /** + * @param sectorType: \li 000b - all types + * \li 001b - CD-DA + * \li 010b - Mode 1 + * \li 011b - Mode 2 formless + * \li 100b - Mode 2 form 1 + * \li 101b - Mode 2 form 2 + * + * @param startAdress Lba 0 is mapped to msf 00:00:00 so this method uses + * startAdress+150 as the starting msf. + * + * @param endAdress This is the ending address which is NOT included in the read operation. + * Lba 0 is mapped to msf 00:00:00 so this method uses + * endAdress+150 as the ending msf. + * + * @param c2: \li 00b - No error info + * \li 01b - 294 bytes, one bit for every byte of the 2352 bytes + * \li 10b - 296 bytes, xor of all c2 bits, zero pad bit, 294 c2 bits + * + * @param subChannel: \li 000b - No Sub-channel data + * \li 001b - RAW P-W Sub-channel (96 bytes) + * \li 010b - Formatted Q Sub-channel (16 bytes) + * \li 100b - Corrected and de-interleaved R-W Sub-channel (96 bytes) + */ + bool readCdMsf( unsigned char* data, + unsigned int dataLen, + int sectorType, + bool dap, + const K3b::Msf& startAdress, + const K3b::Msf& endAdress, + bool sync, + bool header, + bool subHeader, + bool userData, + bool edcEcc, + int c2, + int subChannel ) const; + + /** + * @param sectorType: \li 000b - all types + * \li 001b - CD-DA + * \li 010b - Mode 1 + * \li 011b - Mode 2 formless + * \li 100b - Mode 2 form 1 + * \li 101b - Mode 2 form 2 + * + * @param c2: \li 00b - No error info + * \li 01b - 294 bytes, one bit for every byte of the 2352 bytes + * \li 10b - 296 bytes, xor of all c2 bits, zero pad bit, 294 c2 bits + * + * @param subChannel: \li 000b - No Sub-channel data + * \li 001b - RAW P-W Sub-channel (96 bytes) + * \li 010b - Formatted Q Sub-channel (16 bytes) + * \li 100b - Corrected and de-interleaved R-W Sub-channel (96 bytes) + */ + bool readCd( unsigned char* data, + unsigned int dataLen, + int sectorType, + bool dap, + unsigned long startAdress, + unsigned long length, + bool sync, + bool header, + bool subHeader, + bool userData, + bool edcEcc, + int c2, + int subChannel ) const; + + bool read10( unsigned char* data, + unsigned int dataLen, + unsigned long startAdress, + unsigned int length, + bool fua = false ) const; + + bool read12( unsigned char* data, + unsigned int dataLen, + unsigned long startAdress, + unsigned long length, + bool streaming = false, + bool fua = false ) const; + + /** + * @param subchannelParam: 01h - CD current position + * 02h - Media Catalog number (UPC/bar code) + * 03h - ISRC + * @param trackNumber only valid if subchannelParam == 03h + */ + bool readSubChannel( unsigned char** data, + unsigned int& dataLen, + unsigned int subchannelParam, + unsigned int trackNumber ) const; + + bool readIsrc( unsigned int track, QCString& isrc ) const; + + bool readMcn( QCString& mcn ) const; + + /** + * MMC command Read Buffer Capacity + * + * \return \see K3bScsiCommand::transport() + */ + int readBufferCapacity( long long& bufferLength, long long& bufferAvail ) const; + + /** + * @returns the index number on success + * -1 on general error + * and -2 if there is no index info in that frame + */ + int getIndex( unsigned long lba ) const; + + bool searchIndex0( unsigned long startSec, unsigned long endSec, long& pregapStart ) const; + + /** + * For now this just searches index 0 for all tracks and sets + * the value in the tracks. + * In the future this should scan for all indices. + */ + bool indexScan( K3bDevice::Toc& toc ) const; + + /** + * Seek to the specified sector. + */ + bool seek( unsigned long lba ) const; + + bool getNextWritableAdress( unsigned int& lastSessionStart, unsigned int& nextWritableAdress ) const; + + /** + * Retrieve the next writable address from the currently mounted writable medium. + * \return The next writable address if the medium is empty or appendable or -1 + * if an error occured. + */ + int nextWritableAddress() const; + + /** + * Locks the device for usage. This means that no MMC command can be performed + * until usageUnlock is called. + * + * Locking a device is useful when an external application or library is called + * that opens the device itself. + * + * \sa usageUnlock + */ + void usageLock() const; + + /** + * Unlock the device after a call to usageLock. + */ + void usageUnlock() const; + + /** + * Thread-safe ioctl call for this device for Linux and Net-BSD systems. + * Be aware that so far this does not include opening the device + */ +// int ioctl( int request, ... ) const; + + protected: + bool furtherInit(); + +#ifdef Q_OS_LINUX + /** + * Fallback method that uses the evil cdrom.h stuff + */ + bool readTocLinux( Toc& ) const; +#endif + + /** + * The preferred toc reading method for all CDs. Also reads session info. + * undefined for DVDs. + */ + bool readRawToc( Toc& ) const; + bool readFormattedToc( Toc&, int mediaType ) const; + + /** + * Fixes the last block on CD-Extra disks. This is needed if the readRawToc failed since + * in that case the first sector of the last session's first track is used as the previous + * session's last track's last sector which is wrong. There is a 11400 block session lead-in + * between them. This method fixes this only for the last session and only on linux. + */ + bool fixupToc( Toc& ) const; + + private: + /** + * A Device can only be constructed the the DeviceManager. + */ + Device( const QString& devname ); + + /** + * Determines the device's capabilities. This needs to be called once before + * using the device. + * + * Should only be used by the DeviceManager. + * + * @param checkWritingModes if true the CD writing modes will be checked using + * MMC_MODE_SELECT. + */ + bool init( bool checkWritingModes = true ); + + void searchIndexTransitions( long start, long end, K3bDevice::Track& track ) const; + void checkWritingModes(); + void checkFeatures(); + void checkForJustLink(); + void checkFor2AFeatures(); + void checkForAncientWriters(); + + /** + * Internal method which checks if the raw toc data has bcd values or hex. + * @return 0 if hex, 1 if bcd, -1 if none + */ + int rawTocDataWithBcdValues( unsigned char* data, unsigned int dataLen ) const; + + bool getSupportedWriteSpeedsVia2A( QValueList<int>& list, bool dvd ) const; + bool getSupportedWriteSpeedsViaGP( QValueList<int>& list, bool dvd ) const; + + QCString mediaId( int mediaType ) const; + + QString m_vendor; + QString m_description; + QString m_version; + QString m_cdrdaoDriver; + int m_cdTextCapable; + int m_maxReadSpeed; + int m_maxWriteSpeed; + int m_currentWriteSpeed; + + bool m_dvdMinusTestwrite; + + // only needed for scsi devices + int m_bus; + int m_target; + int m_lun; + + int m_bufferSize; + + int m_writeModes; + + // only needed on FreeBSD + QString m_passDevice; + QString m_blockDevice; + QString m_genericDevice; + + class Private; + Private* d; + friend class DeviceManager; + }; + +#if defined(Q_OS_LINUX) || defined(Q_OS_NETBSD) + /** + * This should always be used to open a device since it + * uses the resmgr + * + * @internal + */ + int openDevice( const char* name, bool write = false ); +#endif +} + +#endif diff --git a/libk3bdevice/k3bdevice_export.h b/libk3bdevice/k3bdevice_export.h new file mode 100644 index 0000000..6c43716 --- /dev/null +++ b/libk3bdevice/k3bdevice_export.h @@ -0,0 +1,33 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (c) 2005 Laurent Montel <montel@kde.org> + * Copyright (C) 2005-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3BDEVICE_EXPORT_H_ +#define _K3BDEVICE_EXPORT_H_ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#ifdef __KDE_HAVE_GCC_VISIBILITY +#define LIBK3BDEVICE_NO_EXPORT __attribute__ ((visibility("hidden"))) +#define LIBK3BDEVICE_EXPORT __attribute__ ((visibility("default"))) +#else +#define LIBK3BDEVICE_NO_EXPORT +#define LIBK3BDEVICE_EXPORT +#endif + +#endif + diff --git a/libk3bdevice/k3bdevice_mmc.cpp b/libk3bdevice/k3bdevice_mmc.cpp new file mode 100644 index 0000000..77db530 --- /dev/null +++ b/libk3bdevice/k3bdevice_mmc.cpp @@ -0,0 +1,947 @@ +/* + * + * $Id: k3bdevice_mmc.cpp 690628 2007-07-21 16:05:08Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +/** +This file contains all the MMC command implementations of the K3b device class +to make the code more readable. +**/ + + +#include "k3bdevice.h" +#include "k3bscsicommand.h" +#include "k3bdeviceglobals.h" +#include "k3bdebug.h" + +#include <string.h> + + +bool K3bDevice::Device::testUnitReady() const +{ + ScsiCommand cmd( this ); + cmd.enableErrorMessages( false ); + cmd[0] = MMC_TEST_UNIT_READY; + cmd[5] = 0; // Necessary to set the proper command length + return( cmd.transport() == 0 ); +} + + +bool K3bDevice::Device::getFeature( unsigned char** data, unsigned int& dataLen, unsigned int feature ) const +{ + unsigned char header[2048]; + ::memset( header, 0, 2048 ); + + ScsiCommand cmd( this ); + cmd[0] = MMC_GET_CONFIGURATION; + cmd[1] = 2; // read only specified feature + cmd[2] = feature>>8; + cmd[3] = feature; + cmd[8] = 8; // we only read the data length first + cmd[9] = 0; // Necessary to set the proper command length + + // we only read the data length first + dataLen = 8; + if( cmd.transport( TR_DIR_READ, header, 8 ) ) + dataLen = from4Byte( header ) + 4; + else + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << ": GET CONFIGURATION length det failed." << endl; + + // + // Some buggy firmwares do not return the size of the available data + // but the returned data or something invalid altogether. + // So we simply use the maximum possible value to be on the safe side + // with these buggy drives. + // We cannot use this as default since many firmwares fail with a too high data length. + // + if( (dataLen-8) % 8 || dataLen <= 8 ) + dataLen = 0xFFFF; + + // again with real length + *data = new unsigned char[dataLen]; + ::memset( *data, 0, dataLen ); + + cmd[7] = dataLen>>8; + cmd[8] = dataLen; + if( cmd.transport( TR_DIR_READ, *data, dataLen ) == 0 ) { + dataLen = QMIN( dataLen, from4Byte( *data ) + 4 ); + return true; + } + else { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << ": GET CONFIGURATION with real length " + << dataLen << " failed." << endl; + delete [] *data; + } + + return false; +} + + +int K3bDevice::Device::featureCurrent( unsigned int feature ) const +{ + unsigned char* data = 0; + unsigned int dataLen = 0; + if( getFeature( &data, dataLen, feature ) ) { + int ret = -1; + if( dataLen >= 11 ) + ret = ( data[8+2]&1 ? 1 : 0 ); // check the current flag + + delete [] data; + + return ret; + } + else + return -1; +} + + +bool K3bDevice::Device::readIsrc( unsigned int track, QCString& isrc ) const +{ + unsigned char* data = 0; + unsigned int dataLen = 0; + + if( readSubChannel( &data, dataLen, 0x3, track ) ) { + bool isrcValid = false; + + if( dataLen >= 8+18 ) { + isrcValid = (data[8+4]>>7 & 0x1); + + if( isrcValid ) { + isrc = QCString( reinterpret_cast<char*>(data[8+5]), 13 ); + + // TODO: check the range of the chars + + } + } + + delete [] data; + + return isrcValid; + } + else + return false; +} + + +bool K3bDevice::Device::readMcn( QCString& mcn ) const +{ + unsigned char* data = 0; + unsigned int dataLen = 0; + + if( readSubChannel( &data, dataLen, 0x2, 0 ) ) { + bool mcnValid = false; + + if( dataLen >= 8+18 ) { + mcnValid = (data[8+4]>>7 & 0x1); + + if( mcnValid ) + mcn = QCString( reinterpret_cast<char*>(data[8+5]), 14 ); + } + + delete [] data; + + return mcnValid; + } + else + return false; +} + + +bool K3bDevice::Device::getPerformance( unsigned char** data, unsigned int& dataLen, + unsigned int type, + unsigned int dataType, + unsigned int lba ) const +{ + unsigned int descLen = 0; + switch( type ) { + case 0x0: + descLen = 16; + break; + case 0x1: + descLen = 8; + break; + case 0x2: + descLen = 2048; + break; + case 0x3: + descLen = 16; + break; + case 0x4: + descLen = 8; + break; + case 0x5: + descLen = 8; // FIXME: ?? + break; + } + + unsigned char header[8]; + ::memset( header, 0, 8 ); + dataLen = 8; + + ScsiCommand cmd( this ); + cmd[0] = MMC_GET_PERFORMANCE; + cmd[1] = dataType; + cmd[2] = lba >> 24; + cmd[3] = lba >> 16; + cmd[4] = lba >> 8; + cmd[5] = lba; + cmd[9] = 1; // first we read one descriptor + cmd[10] = type; + cmd[11] = 0; // Necessary to set the proper command length + if( cmd.transport( TR_DIR_READ, header, 8 ) ) { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() + << ": GET PERFORMANCE length det failed." << endl; + return false; + } + + dataLen = from4Byte( header ) + 4; + + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() + << ": GET PERFORMANCE dataLen = " << dataLen << endl; + + if( (dataLen-8) % descLen || + dataLen <= 8 || + dataLen > 2048 ) { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() + << ": GET PERFORMANCE reports bogus dataLen: " << dataLen << endl; + return false; + } + + *data = new unsigned char[dataLen]; + ::memset( *data, 0, dataLen ); + + unsigned int numDesc = (dataLen-8)/descLen; + + cmd[8] = numDesc>>8; + cmd[9] = numDesc; + if( cmd.transport( TR_DIR_READ, *data, dataLen ) == 0 ) { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() + << ": GET PERFORMANCE successful with reported length: " << from4Byte( *data ) << endl; + dataLen = QMIN( dataLen, from4Byte( *data ) + 4 ); + return true; + } + else { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() + << ": GET PERFORMANCE with real length " + << dataLen << " failed." << endl; + delete [] *data; + return false; + } +} + + +bool K3bDevice::Device::setSpeed( unsigned int readingSpeed, + unsigned int writingSpeed, + bool cav ) const +{ + ScsiCommand cmd( this ); + cmd[0] = MMC_SET_SPEED; + cmd[1] = ( cav ? 0x1 : 0x0 ); + cmd[2] = readingSpeed >> 8; + cmd[3] = readingSpeed; + cmd[4] = writingSpeed >> 8; + cmd[5] = writingSpeed; + cmd[11] = 0; // Necessary to set the proper command length + return ( cmd.transport( TR_DIR_WRITE ) == 0 ); +} + + +bool K3bDevice::Device::seek( unsigned long lba ) const +{ + ScsiCommand cmd( this ); + cmd[0] = MMC_SEEK_10; + cmd[2] = lba>>24; + cmd[3] = lba>>16; + cmd[4] = lba>>8; + cmd[5] = lba; + cmd[9] = 0; // Necessary to set the proper command length + return !cmd.transport(); +} + + +bool K3bDevice::Device::readTrackInformation( unsigned char** data, unsigned int& dataLen, int type, int value ) const +{ + unsigned char header[2048]; + ::memset( header, 0, 2048 ); + + ScsiCommand cmd( this ); + cmd[0] = MMC_READ_TRACK_INFORMATION; + cmd[9] = 0; // Necessary to set the proper command length + + switch( type ) { + case 0: + case 1: + case 2: + cmd[1] = type & 0x3; + cmd[2] = value>>24; + cmd[3] = value>>16; + cmd[4] = value>>8; + cmd[5] = value; + break; + default: + k3bDebug() << "(K3bDevice::readTrackInformation) wrong type parameter: " << type << endl; + return false; + } + + // first we read the header + dataLen = 4; + cmd[8] = 4; + if( cmd.transport( TR_DIR_READ, header, 4 ) == 0 ) + dataLen = from2Byte( header ) + 2; + else + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << ": READ TRACK INFORMATION length det failed." << endl; + + // + // Some buggy firmwares do not return the size of the available data + // but the returned data. + // So we try to determine the correct size based on the medium type + // DVD+R: 40 (MMC4) + // DVD-DL: 48 (MMC5) + // CD: 36 (MMC2) + // + if( dataLen <= 4 ) { + int m = mediaType(); + if( m & (MEDIA_DVD_R_DL|MEDIA_DVD_R_DL_SEQ|MEDIA_DVD_R_DL_JUMP) ) + dataLen = 48; + else if( m & (MEDIA_DVD_PLUS_R|MEDIA_DVD_PLUS_R_DL) ) + dataLen = 40; + else + dataLen = 36; + } + + // again with real length + *data = new unsigned char[dataLen]; + ::memset( *data, 0, dataLen ); + + cmd[7] = dataLen>>8; + cmd[8] = dataLen; + if( cmd.transport( TR_DIR_READ, *data, dataLen ) == 0 ) { + dataLen = QMIN( dataLen, from2Byte( *data ) + 2u ); + return true; + } + else { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << ": READ TRACK INFORMATION with real length " + << dataLen << " failed." << endl; + delete [] *data; + } + + return false; +} + + + +bool K3bDevice::Device::read10( unsigned char* data, + unsigned int dataLen, + unsigned long startAdress, + unsigned int length, + bool fua ) const +{ + ::memset( data, 0, dataLen ); + + ScsiCommand cmd( this ); + cmd[0] = MMC_READ_10; + cmd[1] = ( fua ? 0x8 : 0x0 ); + cmd[2] = startAdress>>24; + cmd[3] = startAdress>>16; + cmd[4] = startAdress>>8; + cmd[5] = startAdress; + cmd[7] = length>>8; + cmd[8] = length; + cmd[9] = 0; // Necessary to set the proper command length + + if( cmd.transport( TR_DIR_READ, data, dataLen ) ) { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << ": READ 10 failed!" << endl; + return false; + } + else + return true; +} + + +bool K3bDevice::Device::read12( unsigned char* data, + unsigned int dataLen, + unsigned long startAdress, + unsigned long length, + bool streaming, + bool fua ) const +{ + ::memset( data, 0, dataLen ); + + ScsiCommand cmd( this ); + cmd[0] = MMC_READ_12; + cmd[1] = ( fua ? 0x8 : 0x0 ); + cmd[2] = startAdress>>24; + cmd[3] = startAdress>>16; + cmd[4] = startAdress>>8; + cmd[5] = startAdress; + cmd[6] = length>>24; + cmd[7] = length>>16; + cmd[8] = length>>8; + cmd[9] = length; + cmd[10] = (streaming ? 0x80 : 0 ); + cmd[11] = 0; // Necessary to set the proper command length + + if( cmd.transport( TR_DIR_READ, data, dataLen ) ) { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << ": READ 12 failed!" << endl; + return false; + } + else + return true; +} + + +bool K3bDevice::Device::readCd( unsigned char* data, + unsigned int dataLen, + int sectorType, + bool dap, + unsigned long startAdress, + unsigned long length, + bool sync, + bool header, + bool subHeader, + bool userData, + bool edcEcc, + int c2, + int subChannel ) const +{ + ::memset( data, 0, dataLen ); + + ScsiCommand cmd( this ); + cmd[0] = MMC_READ_CD; + cmd[1] = (sectorType<<2 & 0x1c) | ( dap ? 0x2 : 0x0 ); + cmd[2] = startAdress>>24; + cmd[3] = startAdress>>16; + cmd[4] = startAdress>>8; + cmd[5] = startAdress; + cmd[6] = length>>16; + cmd[7] = length>>8; + cmd[8] = length; + cmd[9] = ( ( sync ? 0x80 : 0x0 ) | + ( subHeader ? 0x40 : 0x0 ) | + ( header ? 0x20 : 0x0 ) | + ( userData ? 0x10 : 0x0 ) | + ( edcEcc ? 0x8 : 0x0 ) | + ( c2<<1 & 0x6 ) ); + cmd[10] = subChannel & 0x7; + cmd[11] = 0; // Necessary to set the proper command length + + if( cmd.transport( TR_DIR_READ, data, dataLen ) ) { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << ": READ CD failed!" << endl; + return false; + } + else { + return true; + } +} + + +bool K3bDevice::Device::readCdMsf( unsigned char* data, + unsigned int dataLen, + int sectorType, + bool dap, + const K3b::Msf& startAdress, + const K3b::Msf& endAdress, + bool sync, + bool header, + bool subHeader, + bool userData, + bool edcEcc, + int c2, + int subChannel ) const +{ + ::memset( data, 0, dataLen ); + + ScsiCommand cmd( this ); + cmd[0] = MMC_READ_CD_MSF; + cmd[1] = (sectorType<<2 & 0x1c) | ( dap ? 0x2 : 0x0 ); + cmd[3] = (startAdress+150).minutes(); + cmd[4] = (startAdress+150).seconds(); + cmd[5] = (startAdress+150).frames(); + cmd[6] = (endAdress+150).minutes(); + cmd[7] = (endAdress+150).seconds(); + cmd[8] = (endAdress+150).frames(); + cmd[9] = ( ( sync ? 0x80 : 0x0 ) | + ( subHeader ? 0x40 : 0x0 ) | + ( header ? 0x20 : 0x0 ) | + ( userData ? 0x10 : 0x0 ) | + ( edcEcc ? 0x8 : 0x0 ) | + ( c2<<1 & 0x6 ) ); + cmd[10] = subChannel & 0x7; + cmd[11] = 0; // Necessary to set the proper command length + + if( cmd.transport( TR_DIR_READ, data, dataLen ) ) { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << ": READ CD MSF failed!" << endl; + return false; + } + else + return true; +} + + +bool K3bDevice::Device::readSubChannel( unsigned char** data, unsigned int& dataLen, + unsigned int subchannelParam, + unsigned int trackNumber ) const +{ + unsigned char header[2048]; + ::memset( header, 0, 2048 ); + + ScsiCommand cmd( this ); + cmd[0] = MMC_READ_SUB_CHANNEL; + cmd[2] = 0x40; // SUBQ + cmd[3] = subchannelParam; + cmd[6] = trackNumber; // only used when subchannelParam == 03h (ISRC) + cmd[8] = 4; + cmd[9] = 0; // Necessary to set the proper command length + + // first we read the header + dataLen = 4; + if( cmd.transport( TR_DIR_READ, header, 4 ) == 0 ) + dataLen = from2Byte( &header[2] ) + 4; + else + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << ": READ SUB-CHANNEL length det failed." << endl; + + // + // Some buggy firmwares do not return the size of the available data + // but the returned data. So we simply use the maximum possible value to be on the safe side + // with these buggy drives. + // We cannot use this as default since many firmwares fail with a too high data length. + // + if( dataLen <= 4 ) + dataLen = 0xFFFF; + + // again with real length + *data = new unsigned char[dataLen]; + ::memset( *data, 0, dataLen ); + + cmd[7] = dataLen>>8; + cmd[8] = dataLen; + if( cmd.transport( TR_DIR_READ, *data, dataLen ) == 0 ) { + dataLen = QMIN( dataLen, from2Byte( (*data)+2 ) + 4u ); + return true; + } + else { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << ": READ SUB-CHANNEL with real length " + << dataLen << " failed." << endl; + delete [] *data; + } + + return false; +} + + +bool K3bDevice::Device::readTocPmaAtip( unsigned char** data, unsigned int& dataLen, int format, bool time, int track ) const +{ + unsigned int descLen = 0; + + switch( format ) { + case 0x0: + descLen = 8; + break; + case 0x1: + descLen = 8; + break; + case 0x2: + descLen = 11; + break; + case 0x3: + descLen = 11; + break; + case 0x4: + descLen = 4; // MMC2: 24 and MMC4: 28, so we use the highest common factor + break; + case 0x5: + descLen = 18; + break; + } + + unsigned char header[2048]; + ::memset( header, 0, 2048 ); + + ScsiCommand cmd( this ); + cmd[0] = MMC_READ_TOC_PMA_ATIP; + cmd[1] = ( time ? 0x2 : 0x0 ); + cmd[2] = format & 0x0F; + cmd[6] = track; + cmd[8] = 4; + cmd[9] = 0; // Necessary to set the proper command length + + // we only read the header + dataLen = 4; + if( cmd.transport( TR_DIR_READ, header, 4 ) == 0 ) + dataLen = from2Byte( header ) + 2; + else + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << ": READ TOC/PMA/ATIP length det failed." << endl; + + // + // Some buggy firmwares return an invalid size here + // So we simply use the maximum possible value to be on the safe side + // with these buggy drives. + // We cannot use this as default since many firmwares fail with a too high data length. + // + if( (dataLen-4) % descLen || dataLen < 4+descLen ) { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << ": READ TOC/PMA/ATIP invalid length returned: " << dataLen << endl; + dataLen = 0xFFFF; + } + + // + // Not all drives like uneven numbers + // + if( dataLen%2 ) + ++dataLen; + + // again with real length + *data = new unsigned char[dataLen]; + ::memset( *data, 0, dataLen ); + + cmd[7] = dataLen>>8; + cmd[8] = dataLen; + if( cmd.transport( TR_DIR_READ, *data, dataLen ) == 0 ) { + dataLen = QMIN( dataLen, from2Byte( *data ) + 2u ); + if( (dataLen-4) % descLen || dataLen < 4+descLen ) { + // useless length + delete [] *data; + return false; + } + else + return true; + } + else { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << ": READ TOC/PMA/ATIP format " + << format << " with real length " + << dataLen << " failed." << endl; + delete [] *data; + } + + return false; +} + + +bool K3bDevice::Device::mechanismStatus( unsigned char** data, unsigned int& dataLen ) const +{ + unsigned char header[2048]; + ::memset( header, 0, 2048 ); + + ScsiCommand cmd( this ); + cmd[0] = MMC_MECHANISM_STATUS; + cmd[9] = 8; + cmd[11] = 0; // Necessary to set the proper command length + + // first we read the header + dataLen = 8; + if( cmd.transport( TR_DIR_READ, header, 8 ) == 0 ) + dataLen = from4Byte( &header[6] ) + 8; + else + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << ": MECHANISM STATUS length det failed." << endl; + + // + // Some buggy firmwares do not return the size of the available data + // but the returned data or something invalid altogether. + // So we simply use the maximum possible value to be on the safe side + // with these buggy drives. + // We cannot use this as default since many firmwares fail with a too high data length. + // + if( (dataLen-8) % 4 || dataLen <= 8 ) + dataLen = 0xFFFF; + + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << ": MECHANISM STATUS " + << (int)header[5] << " slots." << endl; + + // again with real length + *data = new unsigned char[dataLen]; + ::memset( *data, 0, dataLen ); + + cmd[8] = dataLen>>8; + cmd[9] = dataLen; + if( cmd.transport( TR_DIR_READ, *data, dataLen ) == 0 ) { + dataLen = QMIN( dataLen, from4Byte( (*data)+6 ) + 8 ); + return true; + } + else { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << ": MECHANISM STATUS with real length " + << dataLen << " failed." << endl; + delete [] *data; + } + + return false; +} + + + +bool K3bDevice::Device::modeSense( unsigned char** pageData, unsigned int& pageLen, int page ) const +{ + unsigned char header[2048]; + ::memset( header, 0, 2048 ); + + ScsiCommand cmd( this ); + cmd[0] = MMC_MODE_SENSE; + cmd[1] = 0x8; // Disable Block Descriptors + cmd[2] = page & 0x3F; + cmd[8] = 8; + cmd[9] = 0; // Necessary to set the proper command length + + // first we determine the data length + pageLen = 8; + if( cmd.transport( TR_DIR_READ, header, 8 ) == 0 ) + pageLen = from2Byte( header ) + 2; + else + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << ": MODE SENSE length det failed." << endl; + + // + // Some buggy firmwares do not return the size of the available data + // but the returned data. So we simply use the maximum possible value to be on the safe side + // with these buggy drives. + // We cannot use this as default since many firmwares fail with a too high data length. + // + if( pageLen == 8 ) + pageLen = 0xFFFF; + + // again with real length + *pageData = new unsigned char[pageLen]; + ::memset( *pageData, 0, pageLen ); + + cmd[7] = pageLen>>8; + cmd[8] = pageLen; + if( cmd.transport( TR_DIR_READ, *pageData, pageLen ) == 0 ) { + pageLen = QMIN( pageLen, from2Byte( *pageData ) + 2u ); + return true; + } + else { + delete [] *pageData; + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << ": MODE SENSE with real length " + << pageLen << " failed." << endl; + } + + return false; +} + + +bool K3bDevice::Device::modeSelect( unsigned char* page, unsigned int pageLen, bool pf, bool sp ) const +{ + page[0] = 0; + page[1] = 0; + page[4] = 0; + page[5] = 0; + + // we do not support Block Descriptors here + page[6] = 0; + page[7] = 0; + + // PS bit reserved + page[8] &= 0x3F; + + ScsiCommand cmd( this ); + cmd[0] = MMC_MODE_SELECT; + cmd[1] = ( sp ? 1 : 0 ) | ( pf ? 0x10 : 0 ); + cmd[7] = pageLen>>8; + cmd[8] = pageLen; + cmd[9] = 0; + return( cmd.transport( TR_DIR_WRITE, page, pageLen ) == 0 ); +} + + +// does only make sense for complete media +bool K3bDevice::Device::readCapacity( K3b::Msf& r ) const +{ + ScsiCommand cmd( this ); + cmd[0] = MMC_READ_CAPACITY; + cmd[9] = 0; // Necessary to set the proper command length + unsigned char buf[8]; + ::memset( buf, 0, 8 ); + if( cmd.transport( TR_DIR_READ, buf, 8 ) == 0 ) { + r = from4Byte( buf ); + return true; + } + else + return false; +} + + +bool K3bDevice::Device::readFormatCapacity( int wantedFormat, K3b::Msf& r, + K3b::Msf* currentMax, int* currentMaxFormat ) const +{ + bool success = false; + + // the maximal length as stated in MMC4 + static const unsigned int maxLen = 4 + (8*32); + + unsigned char buffer[maxLen]; + ::memset( buffer, 0, maxLen ); + + ScsiCommand cmd( this ); + cmd[0] = MMC_READ_FORMAT_CAPACITIES; + cmd[7] = maxLen >> 8; + cmd[8] = maxLen & 0xFF; + cmd[9] = 0; // Necessary to set the proper command length + if( cmd.transport( TR_DIR_READ, buffer, maxLen ) == 0 ) { + + unsigned int realLength = buffer[3] + 4; + + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << " READ FORMAT CAPACITY: Current/Max " + << (int)(buffer[8]&0x3) << " " << from4Byte( &buffer[4] ) << endl; + + if( currentMax ) + *currentMax = from4Byte( &buffer[4] ); + if( currentMaxFormat ) + *currentMaxFormat = (int)(buffer[8]&0x3); + + // + // Descriptor Type: + // 0 - reserved + // 1 - unformatted :) + // 2 - formatted. Here we get the used capacity (lead-in to last lead-out/border-out) + // 3 - No media present + // + for( unsigned int i = 12; i < realLength-4; i+=8 ) { + int format = (int)((buffer[i+4]>>2)&0x3f); + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << " READ FORMAT CAPACITY: " + << format << " " << from4Byte( &buffer[i] ) + << " " << (int)( buffer[i+5] << 16 & 0xFF0000 | + buffer[i+6] << 8 & 0xFF00 | + buffer[i+7] & 0xFF ) << endl; + + if( format == wantedFormat ) { + // found the descriptor + r = QMAX( (int)from4Byte( &buffer[i] ), r.lba() ); + success = true; + } + } + } + + return success; +} + + +bool K3bDevice::Device::readDiscInformation( unsigned char** data, unsigned int& dataLen ) const +{ + unsigned char header[2]; + ::memset( header, 0, 2 ); + + ScsiCommand cmd( this ); + cmd[0] = MMC_READ_DISC_INFORMATION; + cmd[8] = 2; + cmd[9] = 0; // Necessary to set the proper command length + + if( cmd.transport( TR_DIR_READ, header, 2 ) == 0 ) + dataLen = from2Byte( header ) + 2; + else + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() + << ": READ DISC INFORMATION length det failed" << endl; + + if( dataLen < 32 ) { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() + << ": Device reports bogus disc information length of " << dataLen << endl; + dataLen = 32; + } + + *data = new unsigned char[dataLen]; + ::memset( *data, 0, dataLen ); + + cmd[7] = dataLen>>8; + cmd[8] = dataLen; + if( cmd.transport( TR_DIR_READ, *data, dataLen ) == 0 ) { + dataLen = QMIN( dataLen, from2Byte( *data ) + 2u ); + return true; + } + else { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << ": READ DISC INFORMATION with real length " + << dataLen << " failed." << endl; + delete [] *data; + } + + return false; +} + + +bool K3bDevice::Device::readDvdStructure( unsigned char** data, unsigned int& dataLen, + unsigned int format, + unsigned int layer, + unsigned long adress, + unsigned int agid ) const +{ + return readDiscStructure( data, dataLen, 0x0, format, layer, adress, agid ); +} + + +bool K3bDevice::Device::readDiscStructure( unsigned char** data, unsigned int& dataLen, + unsigned int mediaType, + unsigned int format, + unsigned int layer, + unsigned long adress, + unsigned int agid ) const +{ + unsigned char header[4]; + ::memset( header, 0, 4 ); + + ScsiCommand cmd( this ); + cmd[0] = MMC_READ_DVD_STRUCTURE; + cmd[1] = mediaType & 0xF; + cmd[2] = adress>>24; + cmd[3] = adress>>16; + cmd[4] = adress>>8; + cmd[5] = adress; + cmd[6] = layer; + cmd[7] = format; + cmd[10] = (agid<<6); + cmd[11] = 0; // Necessary to set the proper command length + + cmd[9] = 4; + if( cmd.transport( TR_DIR_READ, header, 4 ) == 0 ) { + // again with real length + dataLen = from2Byte( header ) + 2; + + *data = new unsigned char[dataLen]; + ::memset( *data, 0, dataLen ); + + cmd[8] = dataLen>>8; + cmd[9] = dataLen; + if( cmd.transport( TR_DIR_READ, *data, dataLen ) == 0 ) { + dataLen = QMIN( dataLen, from2Byte( *data ) + 2u ); + return true; + } + else { + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << ": READ DVD STRUCTURE with real length failed." << endl; + delete [] *data; + } + } + else + k3bDebug() << "(K3bDevice::Device) " << blockDeviceName() << ": READ DVD STRUCTURE length det failed" << endl; + + return false; +} + + +int K3bDevice::Device::readBufferCapacity( long long& bufferLength, long long& bufferAvail ) const +{ + unsigned char data[12]; + ::memset( data, 0, 12 ); + + ScsiCommand cmd( this ); + cmd[0] = MMC_READ_BUFFER_CAPACITY; + cmd[8] = 12; + cmd[9] = 0; // Necessary to set the proper command length + int r = cmd.transport( TR_DIR_READ, data, 12 ); + if( r ) + return r; + + unsigned int dataLength = from2Byte( data ); + + if( dataLength >= 10 ) { + bufferLength = from4Byte( &data[4] ); + bufferAvail = from4Byte( &data[8] ); + } + else { + bufferAvail = bufferLength = 0; + } + + return 0; +} diff --git a/libk3bdevice/k3bdeviceglobals.cpp b/libk3bdevice/k3bdeviceglobals.cpp new file mode 100644 index 0000000..c778130 --- /dev/null +++ b/libk3bdevice/k3bdeviceglobals.cpp @@ -0,0 +1,247 @@ +/* + * + * $Id: k3bdeviceglobals.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bdeviceglobals.h" +#include "k3bdiskinfo.h" +#include "k3bdevice.h" + +#include <klocale.h> +#include <k3bdebug.h> + +#include <qstringlist.h> + + +QString K3bDevice::deviceTypeString( int t ) +{ + QStringList s; + if( t & K3bDevice::DEVICE_CD_R ) + s += i18n("CD-R"); + if( t & K3bDevice::DEVICE_CD_RW ) + s += i18n("CD-RW"); + if( t & K3bDevice::DEVICE_CD_ROM ) + s += i18n("CD-ROM"); + if( t & K3bDevice::DEVICE_DVD_ROM ) + s += i18n("DVD-ROM"); + if( t & K3bDevice::DEVICE_DVD_RAM ) + s += i18n("DVD-RAM"); + if( t & K3bDevice::DEVICE_DVD_R ) + s += i18n("DVD-R"); + if( t & K3bDevice::DEVICE_DVD_RW ) + s += i18n("DVD-RW"); + if( t & K3bDevice::DEVICE_DVD_R_DL ) + s += i18n("DVD-R DL"); + if( t & DEVICE_HD_DVD_ROM ) + s += i18n("HD DVD-ROM"); + if( t & DEVICE_HD_DVD_R ) + s += i18n("HD DVD-R"); + if( t & DEVICE_HD_DVD_RAM ) + s += i18n("HD DVD-RAM"); + if( t & DEVICE_BD_ROM ) + s += i18n("BD-ROM"); + if( t & DEVICE_BD_R ) + s += i18n("BD-R"); + if( t & DEVICE_BD_RE ) + s += i18n("BD-RE"); + if( t & K3bDevice::DEVICE_DVD_PLUS_R ) + s += i18n("DVD+R"); + if( t & K3bDevice::DEVICE_DVD_PLUS_RW ) + s += i18n("DVD+RW"); + if( t & K3bDevice::DEVICE_DVD_PLUS_R_DL ) + s += i18n("DVD+R DL"); + + if( s.isEmpty() ) + return i18n("Error"); + else + return s.join( ", " ); +} + + +QString K3bDevice::writingModeString( int m ) +{ + QStringList s; + if( m & K3bDevice::WRITINGMODE_SAO ) + s += i18n("SAO"); + if( m & K3bDevice::WRITINGMODE_TAO ) + s += i18n("TAO"); + if( m & K3bDevice::WRITINGMODE_RAW ) + s += i18n("RAW"); + if( m & K3bDevice::WRITINGMODE_SAO_R96P ) + s += i18n("SAO/R96P"); + if( m & K3bDevice::WRITINGMODE_SAO_R96R ) + s += i18n("SAO/R96R"); + if( m & K3bDevice::WRITINGMODE_RAW_R16 ) + s += i18n("RAW/R16"); + if( m & K3bDevice::WRITINGMODE_RAW_R96P ) + s += i18n("RAW/R96P"); + if( m & K3bDevice::WRITINGMODE_RAW_R96R ) + s += i18n("RAW/R96R"); + if( m & K3bDevice::WRITINGMODE_INCR_SEQ ) + s += i18n("Incremental Sequential"); + if( m & K3bDevice::WRITINGMODE_RES_OVWR ) + s += i18n("Restricted Overwrite"); + if( m & K3bDevice::WRITINGMODE_LAYER_JUMP ) + s += i18n("Layer Jump"); + + if( m & K3bDevice::WRITINGMODE_RRM ) + s += i18n("Random Recording"); + if( m & K3bDevice::WRITINGMODE_SRM ) + s += i18n("Sequential Recording"); + if( m & K3bDevice::WRITINGMODE_SRM_POW ) + s += i18n("Sequential Recording + POW"); + + if( s.isEmpty() ) + return i18n("None"); + else + return s.join( ", " ); +} + + +QString K3bDevice::mediaTypeString( int m, bool simple ) +{ + if( m == K3bDevice::MEDIA_UNKNOWN ) + return i18n("Unknown"); + + QStringList s; + if( m & MEDIA_NONE ) + s += i18n("No media"); + if( m & MEDIA_DVD_ROM ) + s += i18n("DVD-ROM"); + if( m & MEDIA_DVD_R || + (simple && (m & MEDIA_DVD_R_SEQ)) ) + s += i18n("DVD-R"); + if( m & MEDIA_DVD_R_SEQ && !simple ) + s += i18n("DVD-R Sequential"); + if( m & MEDIA_DVD_R_DL || + (simple && (m & (MEDIA_DVD_R_DL_SEQ|MEDIA_DVD_R_DL_JUMP))) ) + s += i18n("DVD-R Dual Layer"); + if( m & MEDIA_DVD_R_DL_SEQ && !simple ) + s += i18n("DVD-R Dual Layer Sequential"); + if( m & MEDIA_DVD_R_DL_JUMP && !simple ) + s += i18n("DVD-R Dual Layer Jump"); + if( m & MEDIA_DVD_RAM ) + s += i18n("DVD-RAM"); + if( m & MEDIA_DVD_RW || + (simple && (m & (MEDIA_DVD_RW_OVWR|MEDIA_DVD_RW_SEQ))) ) + s += i18n("DVD-RW"); + if( m & MEDIA_DVD_RW_OVWR && !simple ) + s += i18n("DVD-RW Restricted Overwrite"); + if( m & MEDIA_DVD_RW_SEQ && !simple ) + s += i18n("DVD-RW Sequential"); + if( m & MEDIA_DVD_PLUS_RW ) + s += i18n("DVD+RW"); + if( m & MEDIA_DVD_PLUS_R ) + s += i18n("DVD+R"); + if( m & MEDIA_DVD_PLUS_RW_DL ) + s += i18n("DVD+RW Dual Layer"); + if( m & MEDIA_DVD_PLUS_R_DL ) + s += i18n("DVD+R Dual Layer"); + if( m & MEDIA_CD_ROM ) + s += i18n("CD-ROM"); + if( m & MEDIA_CD_R ) + s += i18n("CD-R"); + if( m & MEDIA_CD_RW ) + s += i18n("CD-RW"); + if( m & MEDIA_HD_DVD_ROM ) + s += i18n("HD DVD-ROM"); + if( m & MEDIA_HD_DVD_R ) + s += i18n("HD DVD-R"); + if( m & MEDIA_HD_DVD_RAM ) + s += i18n("HD DVD-RAM"); + if( m & MEDIA_BD_ROM ) + s += i18n("BD-ROM"); + if( m & MEDIA_BD_R || + (simple && (m & (MEDIA_BD_R_SRM|MEDIA_BD_R_RRM))) ) + s += i18n("BD-R"); + if( m & MEDIA_BD_R_SRM && !simple ) + s += i18n("BD-R Sequential (SRM)"); + if( m & MEDIA_BD_R_SRM_POW && !simple ) + s += i18n("BD-R Sequential Pseudo Overwrite (SRM+POW)"); + if( m & MEDIA_BD_R_RRM && !simple ) + s += i18n("BD-R Random (RRM)"); + if( m & MEDIA_BD_RE ) + s += i18n("BD-RE"); + + if( s.isEmpty() ) + return i18n("Error"); + else + return s.join( ", " ); +} + + +void K3bDevice::debugBitfield( unsigned char* data, long len ) +{ + for( int i = 0; i < len; ++i ) { + QString index, bitString; + index.sprintf( "%4i", i ); + for( int bp = 7; bp >= 0; --bp ) + bitString[7-bp] = ( data[i] & (1<<bp) ? '1' : '0' ); + k3bDebug() << index << " - " << bitString << " - " << (int)data[i] << endl; + } +} + + +K3bDevice::uint16 K3bDevice::from2Byte( unsigned char* d ) +{ + return ( d[0] << 8 & 0xFF00 | + d[1] & 0xFF ); +} + + +K3bDevice::uint32 K3bDevice::from4Byte( unsigned char* d ) +{ + return ( d[0] << 24 & 0xFF000000 | + d[1] << 16 & 0xFF0000 | + d[2] << 8 & 0xFF00 | + d[3] & 0xFF ); +} + + +char K3bDevice::fromBcd( const char& i ) +{ + return (i & 0x0f) + 10 * ( (i >> 4) & 0x0f ); +} + + +char K3bDevice::toBcd( const char& i ) +{ + return ( i % 10 ) | ( ( (( i / 10 ) % 10) << 4 ) & 0xf0 ); +} + + +bool K3bDevice::isValidBcd( const char& i ) +{ + return ( i & 0x0f ) <= 0x09 && ( i & 0xf0 ) <= 0x90; +} + + +int K3bDevice::determineMaxReadingBufferSize( K3bDevice::Device* dev, const K3b::Msf& firstSector ) +{ + // + // As long as we do not know how to determine the max read buffer properly we simply determine it + // by trying. :) + // + + int bufferSizeSectors = 128; + unsigned char buffer[2048*128]; + while( !dev->read10( buffer, 2048*bufferSizeSectors, firstSector.lba(), bufferSizeSectors ) ) { + k3bDebug() << "(K3bDataTrackReader) determine max read sectors: " + << bufferSizeSectors << " too high." << endl; + bufferSizeSectors--; + } + k3bDebug() << "(K3bDataTrackReader) determine max read sectors: " + << bufferSizeSectors << " is max." << endl; + + return bufferSizeSectors; +} diff --git a/libk3bdevice/k3bdeviceglobals.h b/libk3bdevice/k3bdeviceglobals.h new file mode 100644 index 0000000..5e167ad --- /dev/null +++ b/libk3bdevice/k3bdeviceglobals.h @@ -0,0 +1,54 @@ +/* + * + * $Id: k3bdeviceglobals.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_DEVICE_GLOBALS_H_ +#define _K3B_DEVICE_GLOBALS_H_ + +#include <qstring.h> +#include <k3bmsf.h> +#include "k3bdevice_export.h" + +namespace K3bDevice +{ + typedef Q_UINT8 uint8; + typedef Q_UINT16 uint16; + typedef Q_UINT32 uint32; + + class Device; + + LIBK3BDEVICE_EXPORT QString deviceTypeString( int ); + LIBK3BDEVICE_EXPORT QString writingModeString( int ); + /** + * @param simplyfied if true the formatting state of DVD media is left out. + */ + LIBK3BDEVICE_EXPORT QString mediaTypeString( int, bool simplyfied = false ); + LIBK3BDEVICE_EXPORT void debugBitfield( unsigned char* data, long len ); + + LIBK3BDEVICE_EXPORT uint16 from2Byte( unsigned char* ); + LIBK3BDEVICE_EXPORT uint32 from4Byte( unsigned char* ); + + LIBK3BDEVICE_EXPORT char fromBcd( const char& ); + LIBK3BDEVICE_EXPORT char toBcd( const char& ); + LIBK3BDEVICE_EXPORT bool isValidBcd( const char& ); + + /** + * @return the maximum nuber of sectors that can be read from device @p dev starting + * at sector @p firstSector. + */ + int determineMaxReadingBufferSize( Device* dev, const K3b::Msf& firstSector ); +} + +#endif diff --git a/libk3bdevice/k3bdevicemanager.cpp b/libk3bdevice/k3bdevicemanager.cpp new file mode 100644 index 0000000..b7c04d0 --- /dev/null +++ b/libk3bdevice/k3bdevicemanager.cpp @@ -0,0 +1,903 @@ +/* + * + * $Id: k3bdevicemanager.cpp 676188 2007-06-16 08:55:00Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include <config.h> + +#include "k3bdevicemanager.h" +#include "k3bdevice.h" +#include "k3bdeviceglobals.h" +#include "k3bscsicommand.h" +#include "k3bmmc.h" +#include "k3bdebug.h" + +#include <qstring.h> +#include <qstringlist.h> +#include <qptrlist.h> +#include <qfile.h> +#include <qfileinfo.h> +#include <qregexp.h> + +#include <kprocess.h> +#include <kapplication.h> +#include <kconfig.h> +#include <ktempfile.h> + +#include <iostream> +#include <limits.h> +#include <assert.h> + +#ifdef Q_OS_FREEBSD +#include <sys/param.h> +#include <sys/ucred.h> +#include <osreldate.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/ioctl.h> + +#ifdef HAVE_RESMGR +#include <resmgr.h> +#endif + +#ifdef Q_OS_LINUX + +/* Fix definitions for 2.5 kernels */ +#include <linux/version.h> +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,70) +typedef unsigned char u8; +#endif + +#undef __STRICT_ANSI__ +#include <asm/types.h> +#define __STRICT_ANSI__ + +#include <scsi/scsi.h> +#include <linux/major.h> + + +#ifndef SCSI_DISK_MAJOR +#define SCSI_DISK_MAJOR(M) ((M) == SCSI_DISK0_MAJOR || \ + ((M) >= SCSI_DISK1_MAJOR && (M) <= SCSI_DISK7_MAJOR) || \ + ((M) >= SCSI_DISK8_MAJOR && (M) <= SCSI_DISK15_MAJOR)) +#endif + +#ifndef SCSI_BLK_MAJOR +#define SCSI_BLK_MAJOR(M) \ + (SCSI_DISK_MAJOR(M) \ + || (M) == SCSI_CDROM_MAJOR) +#endif + +#ifndef SCSI_GENERIC_MAJOR +#define SCSI_GENERIC_MAJOR 21 +#endif + +#endif // Q_OS_LINUX + + +#ifdef Q_OS_FREEBSD +#include <cam/cam.h> +#include <cam/scsi/scsi_pass.h> +#include <camlib.h> +#endif + +#ifdef Q_OS_NETBSD +#include <sys/scsiio.h> +#endif + + + +class K3bDevice::DeviceManager::Private +{ +public: + QPtrList<K3bDevice::Device> allDevices; + QPtrList<K3bDevice::Device> cdReader; + QPtrList<K3bDevice::Device> cdWriter; + QPtrList<K3bDevice::Device> dvdReader; + QPtrList<K3bDevice::Device> dvdWriter; + QPtrList<K3bDevice::Device> bdReader; + QPtrList<K3bDevice::Device> bdWriter; + + bool checkWritingModes; +}; + + + +K3bDevice::DeviceManager::DeviceManager( QObject* parent, const char* name ) + : QObject( parent, name ) +{ + d = new Private; +} + + +K3bDevice::DeviceManager::~DeviceManager() +{ + d->allDevices.setAutoDelete( true ); + delete d; +} + + +void K3bDevice::DeviceManager::setCheckWritingModes( bool b ) +{ + d->checkWritingModes = b; +} + + +K3bDevice::Device* K3bDevice::DeviceManager::deviceByName( const QString& name ) +{ + return findDevice( name ); +} + + +K3bDevice::Device* K3bDevice::DeviceManager::findDevice( int bus, int id, int lun ) +{ + QPtrListIterator<K3bDevice::Device> it( d->allDevices ); + while( it.current() ) + { + if( it.current()->scsiBus() == bus && + it.current()->scsiId() == id && + it.current()->scsiLun() == lun ) + return it.current(); + + ++it; + } + + return 0; +} + + +K3bDevice::Device* K3bDevice::DeviceManager::findDevice( const QString& devicename ) +{ + if( devicename.isEmpty() ) { + k3bDebug() << "(K3bDevice::DeviceManager) request for empty device!" << endl; + return 0; + } + QPtrListIterator<K3bDevice::Device> it( d->allDevices ); + while( it.current() ) { + if( it.current()->deviceNodes().contains(devicename) ) + return it.current(); + + ++it; + } + + return 0; +} + + +const QPtrList<K3bDevice::Device>& K3bDevice::DeviceManager::cdWriter() const +{ + return d->cdWriter; +} + +const QPtrList<K3bDevice::Device>& K3bDevice::DeviceManager::cdReader() const +{ + return d->cdReader; +} + +const QPtrList<K3bDevice::Device>& K3bDevice::DeviceManager::dvdWriter() const +{ + return d->dvdWriter; +} + +const QPtrList<K3bDevice::Device>& K3bDevice::DeviceManager::dvdReader() const +{ + return d->dvdReader; +} + +const QPtrList<K3bDevice::Device>& K3bDevice::DeviceManager::blueRayReader() const +{ + return d->bdReader; +} + +const QPtrList<K3bDevice::Device>& K3bDevice::DeviceManager::blueRayWriters() const +{ + return d->bdWriter; +} + +const QPtrList<K3bDevice::Device>& K3bDevice::DeviceManager::burningDevices() const +{ + return cdWriter(); +} + + +const QPtrList<K3bDevice::Device>& K3bDevice::DeviceManager::readingDevices() const +{ + return cdReader(); +} + + +const QPtrList<K3bDevice::Device>& K3bDevice::DeviceManager::allDevices() const +{ + return d->allDevices; +} + + +int K3bDevice::DeviceManager::scanBus() +{ + unsigned int numDevs = d->allDevices.count(); + +#ifdef Q_OS_LINUX + LinuxDeviceScan(); +#endif +#ifdef Q_OS_FREEBSD + BSDDeviceScan(); +#endif +#ifdef Q_OS_NETBSD + NetBSDDeviceScan(); +#endif + + return d->allDevices.count() - numDevs; +} + + +void K3bDevice::DeviceManager::LinuxDeviceScan() +{ +#ifdef HAVE_RESMGR + // + // Resmgr device scan + // + char** resmgrDevices = rsm_list_devices( 0 ); + if( resmgrDevices ) { + for( int i = 0; resmgrDevices[i]; ++i ) { + addDevice( resmgrDevices[i] ); + free( resmgrDevices[i] ); + } + + free( resmgrDevices ); + } +#endif + + QFile info("/proc/sys/dev/cdrom/info"); + QString line,devstring; + if( info.open(IO_ReadOnly) ) { + info.readLine(line,80); // CD-ROM information, Id: cdrom.c 3.12 2000/10/18 + info.readLine(line,80); // + + QRegExp re("[\t\n:]+"); + while( info.readLine( line, 80 ) > 0 ) { + if( line.contains("drive name") > 0 ) { + int i = 1; + QString dev; + while( !(dev = line.section(re, i, i)).isEmpty() ) { + if( addDevice( QString("/dev/%1").arg(dev) ) ) { + devstring += dev + "|"; + } + // according to the LINUX ALLOCATED DEVICES document (http://www.lanana.org/docs/device-list/), + // the official device names for SCSI-CDROM's (block major 11) are /dev/sr*, the + // prefix /dev/scd instead of /dev/sr has been used as well, and might make more sense. + // Since there should be one and only one device node (and maybe several symbolic links) for + // each physical device the next line should be better + // else if ( dev.startsWith("sr") ) + if ( dev.startsWith("sr") ) { + if( addDevice(QString("/dev/%1").arg(dev.replace(QRegExp("r"),"cd"))) ) + devstring += dev + "|"; + } + ++i; + } + } + break; + } + info.close(); + } + else { + kdError() << "(K3bDevice::DeviceManager) could not open /proc/sys/dev/cdrom/info" << endl; + } + + // + // Scan the generic devices if we have scsi devices + // + k3bDebug() << "(K3bDevice::DeviceManager) SCANNING FOR GENERIC DEVICES." << endl; + for( int i = 0; i < 16; i++ ) { + QString sgDev = resolveSymLink( QString("/dev/sg%1").arg(i) ); + int bus = -1, id = -1, lun = -1; + if( determineBusIdLun( sgDev, bus, id, lun ) ) { + if( Device* dev = findDevice( bus, id, lun ) ) { + dev->m_genericDevice = sgDev; + } + } + } + // FIXME: also scan /dev/scsi/hostX.... for devfs without symlinks +} + + +void K3bDevice::DeviceManager::NetBSDDeviceScan() +{ + // Generate entries for /dev/cd* devices + // Note: As there are only 10 possible /dev/(r)cd devices, + // only these will be found. + + int i; + + // Whole disk mask (According to cd(4), the AMD64, i386 and BeBox ports use + // 'd' as whole-disk partition, the rest uses 'c'.) + +#if defined(__i386__) || defined (__amd64__) || defined (__bebox__) + static const char slicename = 'd'; +#else + static const char slicename = 'c'; +#endif + + char devicename[11]; // /dev/rcdXd + trailing zero + + for (i = 0; i < 10; i++ ) // cd(4) claims there are max. 10 CD devices. + { + snprintf(devicename,11,"/dev/rcd%d%c",i, slicename); + addDevice(QString(devicename)); + } +} + + +void K3bDevice::DeviceManager::BSDDeviceScan() +{ + // Unfortunately uses lots of FBSD-specific data structures +#ifndef Q_OS_FREEBSD + // bool bsdspecificcode = false; + // assert(bsdspecificcode); +#endif + +#ifdef Q_OS_FREEBSD + union ccb ccb; + int fd; + int need_close = 0; + int skip_device = 0; + int bus, target, lun; + QString dev1, dev2; + + if ((fd = open(XPT_DEVICE, O_RDWR)) == -1) + { + k3bDebug() << "couldn't open %s " << XPT_DEVICE << endl; + return; + } + + memset(&ccb, 0, sizeof(ccb)); + + ccb.ccb_h.func_code = XPT_DEV_MATCH; + char buffer[100*sizeof(struct dev_match_result)]; + ccb.cdm.match_buf_len = 100*sizeof(struct dev_match_result); + ccb.cdm.matches = (struct dev_match_result *)buffer; + ccb.cdm.num_matches = 0; + ccb.cdm.num_patterns = 0; + ccb.cdm.pattern_buf_len = 0; + do { + if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) { + k3bDebug() << "(BSDDeviceScan) error sending CAMIOCOMMAND ioctl: " << errno << endl; + break; + } + + if ((ccb.ccb_h.status != CAM_REQ_CMP) + || ((ccb.cdm.status != CAM_DEV_MATCH_LAST) && (ccb.cdm.status != CAM_DEV_MATCH_MORE))) { + k3bDebug() << "(BSDDeviceScan) got CAM error " << ccb.ccb_h.status << ", CDM error %d" << ccb.cdm.status << endl; + break; + } + k3bDebug() << "(BSDDeviceScan) number of matches " << (int)ccb.cdm.num_matches << endl; + for (int i = 0; i < (int)ccb.cdm.num_matches; i++) { + switch (ccb.cdm.matches[i].type) { + case DEV_MATCH_DEVICE: { + struct device_match_result *dev_result = &ccb.cdm.matches[i].result.device_result; + + if (dev_result->flags & DEV_RESULT_UNCONFIGURED) + { + skip_device = 1; + break; + } + else + skip_device = 0; + if (need_close) + { + QString pass = dev1; + QString dev = "/dev/" + dev2; + if (dev2.startsWith("pass")) + { + pass = dev2; + dev = "/dev/" + dev1; + } +#if __FreeBSD_version < 500100 + dev += "c"; +#endif + if (!dev1.isEmpty() && !dev2.isEmpty() && dev.startsWith("/dev/cd")) + { + Device* device = new Device(dev.latin1()); + device->m_bus = bus; + device->m_target = target; + device->m_lun = lun; + device->m_passDevice = "/dev/" + pass; + k3bDebug() << "(BSDDeviceScan) add device " << dev << ":" << bus << ":" << target << ":" << lun << endl; + addDevice(device); + } + need_close = 0; + dev1=""; + dev2=""; + } + bus = dev_result->path_id; + target = dev_result->target_id; + lun = dev_result->target_lun; + + need_close = 1; + + break; + } + case DEV_MATCH_PERIPH: { + struct periph_match_result *periph_result = &ccb.cdm.matches[i].result.periph_result; + + if (skip_device != 0) + break; + + if (need_close > 1) + dev1 = periph_result->periph_name + QString::number(periph_result->unit_number); + else + dev2 = periph_result->periph_name + QString::number(periph_result->unit_number); + + need_close++; + break; + } + case DEV_MATCH_BUS : { + // bool cannotmatchbus = false; + // assert(cannotmatchbus); + break; + } + } + } + + } while ((ccb.ccb_h.status == CAM_REQ_CMP) + && (ccb.cdm.status == CAM_DEV_MATCH_MORE)); + + if (need_close) + { + QString pass = dev1; + QString dev = "/dev/" + dev2; + if (dev2.startsWith("pass")) + { + pass = dev2; + dev = "/dev/" + dev1; + } +#if __FreeBSD_version < 500100 + dev += "c"; +#endif + if (!dev1.isEmpty() && !dev2.isEmpty() && dev.startsWith("/dev/cd")) + { + Device* device = new Device(dev.latin1()); + device->m_bus = bus; + device->m_target = target; + device->m_lun = lun; + device->m_passDevice = "/dev/" + pass; + k3bDebug() << "(BSDDeviceScan) add device " << dev << ":" << bus << ":" << target << ":" << lun << endl; + addDevice(device); + } + } + close(fd); +#endif +} + + +void K3bDevice::DeviceManager::printDevices() +{ + k3bDebug() << "Devices:" << endl + << "------------------------------" << endl; + QPtrListIterator<Device> it( allDevices() ); + for( ; *it; ++it ) { + Device* dev = *it; + k3bDebug() << "Blockdevice: " << dev->blockDeviceName() << endl + << "Generic device: " << dev->genericDevice() << endl + << "Vendor: " << dev->vendor() << endl + << "Description: " << dev->description() << endl + << "Version: " << dev->version() << endl + << "Write speed: " << dev->maxWriteSpeed() << endl + << "Profiles: " << mediaTypeString( dev->supportedProfiles() ) << endl + << "Read Cap: " << mediaTypeString( dev->readCapabilities() ) << endl + << "Write Cap: " << mediaTypeString( dev->writeCapabilities() ) << endl + << "Writing modes: " << writingModeString( dev->writingModes() ) << endl + << "Reader aliases: " << dev->deviceNodes().join(", ") << endl + << "------------------------------" << endl; + } +} + + +void K3bDevice::DeviceManager::clear() +{ + // clear current devices + d->cdReader.clear(); + d->cdWriter.clear(); + d->dvdReader.clear(); + d->dvdWriter.clear(); + d->bdReader.clear(); + d->bdWriter.clear(); + + // to make sure no one crashes lets keep the devices around until the changed + // signals return + QPtrList<K3bDevice::Device> tmp = d->allDevices; + tmp.setAutoDelete( true ); + + d->allDevices.clear(); + + emit changed( this ); + emit changed(); +} + + +bool K3bDevice::DeviceManager::readConfig( KConfig* c ) +{ + // + // New configuration format since K3b 0.11.94 + // for details see saveConfig() + // + + if( !c->hasGroup( "Devices" ) ) + return false; + + c->setGroup( "Devices" ); + + QStringList deviceSearchPath = c->readListEntry( "device_search_path" ); + for( QStringList::const_iterator it = deviceSearchPath.constBegin(); + it != deviceSearchPath.constEnd(); ++it ) + addDevice( *it ); + + // + // Iterate over all devices and check if we have a config entry + // + for( QPtrListIterator<K3bDevice::Device> it( d->allDevices ); *it; ++it ) { + K3bDevice::Device* dev = *it; + + QString configEntryName = dev->vendor() + " " + dev->description(); + QStringList list = c->readListEntry( configEntryName ); + if( !list.isEmpty() ) { + k3bDebug() << "(K3bDevice::DeviceManager) found config entry for devicetype: " << configEntryName << endl; + + dev->setMaxReadSpeed( list[0].toInt() ); + if( list.count() > 1 ) + dev->setMaxWriteSpeed( list[1].toInt() ); + if( list.count() > 2 ) + dev->setCdrdaoDriver( list[2] ); + if( list.count() > 3 ) + dev->setCdTextCapability( list[3] == "yes" ); + } + } + + return true; +} + + +bool K3bDevice::DeviceManager::saveConfig( KConfig* c ) +{ + // + // New configuration format since K3b 0.11.94 + // + // We save a device search path which contains all device nodes + // where devices could be found including the old search path. + // This way also for example a manually added USB device will be + // found between sessions. + // Then we do not save the device settings (writing speed, cdrdao driver) + // for every single device but for every device type. + // This also makes sure device settings are kept between sessions + // + + c->setGroup( "Devices" ); + QStringList deviceSearchPath = c->readListEntry( "device_search_path" ); + // remove duplicate entries (caused by buggy old implementations) + QStringList saveDeviceSearchPath; + for( QStringList::const_iterator it = deviceSearchPath.constBegin(); it != deviceSearchPath.constEnd(); ++it ) + if( !saveDeviceSearchPath.contains( *it ) ) + saveDeviceSearchPath.append( *it ); + + for( QPtrListIterator<K3bDevice::Device> it( d->allDevices ); *it; ++it ) { + K3bDevice::Device* dev = *it; + + // update device search path + if( !saveDeviceSearchPath.contains( dev->blockDeviceName() ) ) + saveDeviceSearchPath.append( dev->blockDeviceName() ); + + // save the device type settings + QString configEntryName = dev->vendor() + " " + dev->description(); + QStringList list; + list << QString::number(dev->maxReadSpeed()) + << QString::number(dev->maxWriteSpeed()) + << dev->cdrdaoDriver(); + + if( dev->cdrdaoDriver() != "auto" ) + list << ( dev->cdTextCapable() == 1 ? "yes" : "no" ); + else + list << "auto"; + + c->writeEntry( configEntryName, list ); + } + + c->writeEntry( "device_search_path", saveDeviceSearchPath ); + + c->sync(); + + return true; +} + + +bool K3bDevice::DeviceManager::testForCdrom( const QString& devicename ) +{ +#ifdef Q_OS_FREEBSD + Q_UNUSED(devicename); + return true; +#endif +#if defined(Q_OS_LINUX) || defined(Q_OS_NETBSD) + bool ret = false; + int cdromfd = K3bDevice::openDevice( devicename.ascii() ); + if (cdromfd < 0) { + k3bDebug() << "could not open device " << devicename << " (" << strerror(errno) << ")" << endl; + return ret; + } + + // stat the device + struct stat cdromStat; + if( ::fstat( cdromfd, &cdromStat ) ) + return false; + + if( !S_ISBLK( cdromStat.st_mode) ) { + k3bDebug() << devicename << " is no block device" << endl; + } + else { + k3bDebug() << devicename << " is block device (" << (int)(cdromStat.st_rdev & 0xFF) << ")" << endl; +#if defined(Q_OS_NETBSD) + } + { +#endif + // inquiry + // use a 36 bytes buffer since not all devices return the full inquiry struct + unsigned char buf[36]; + struct inquiry* inq = (struct inquiry*)buf; + ::memset( buf, 0, sizeof(buf) ); + + ScsiCommand cmd( cdromfd ); + cmd[0] = MMC_INQUIRY; + cmd[4] = sizeof(buf); + cmd[5] = 0; + + if( cmd.transport( TR_DIR_READ, buf, sizeof(buf) ) ) { + k3bDebug() << "(K3bDevice::Device) Unable to do inquiry. " << devicename << " is not a cdrom device" << endl; + } + else if( (inq->p_device_type&0x1f) != 0x5 ) { + k3bDebug() << devicename << " seems not to be a cdrom device: " << strerror(errno) << endl; + } + else { + ret = true; + k3bDebug() << devicename << " seems to be cdrom" << endl; + } + } + + ::close( cdromfd ); + return ret; +#endif +} + +K3bDevice::Device* K3bDevice::DeviceManager::addDevice( const QString& devicename ) +{ +#ifdef Q_OS_FREEBSD + return 0; +#endif + + K3bDevice::Device* device = 0; + + // resolve all symlinks + QString resolved = resolveSymLink( devicename ); + k3bDebug() << devicename << " resolved to " << resolved << endl; + + if ( K3bDevice::Device* oldDev = findDevice(resolved) ) { + k3bDebug() << "(K3bDevice::DeviceManager) dev " << resolved << " already found" << endl; + oldDev->addDeviceNode( devicename ); + return 0; + } + + if( !testForCdrom(resolved) ) { +#ifdef HAVE_RESMGR + // With resmgr we might only be able to open the symlink name. + if( testForCdrom(devicename) ) { + resolved = devicename; + } + else { + return 0; + } +#else + return 0; +#endif + } + + int bus = -1, target = -1, lun = -1; + bool scsi = determineBusIdLun( resolved, bus, target, lun ); + if(scsi) { + if ( K3bDevice::Device* oldDev = findDevice(bus, target, lun) ) { + k3bDebug() << "(K3bDevice::DeviceManager) dev " << resolved << " already found" << endl; + oldDev->addDeviceNode( devicename ); + return 0; + } + } + + device = new K3bDevice::Device(resolved); + if( scsi ) { + device->m_bus = bus; + device->m_target = target; + device->m_lun = lun; + } + + return addDevice(device); +} + + +K3bDevice::Device* K3bDevice::DeviceManager::addDevice( K3bDevice::Device* device ) +{ + const QString devicename = device->devicename(); + + if( !device->init() ) { + k3bDebug() << "Could not initialize device " << devicename << endl; + delete device; + return 0; + } + + if( device ) { + d->allDevices.append( device ); + + // not every drive is able to read CDs + // there are some 1st generation DVD writer that cannot + if( device->type() & K3bDevice::DEVICE_CD_ROM ) + d->cdReader.append( device ); + if( device->readsDvd() ) + d->dvdReader.append( device ); + if( device->writesCd() ) + d->cdWriter.append( device ); + if( device->writesDvd() ) + d->dvdWriter.append( device ); + if( device->readCapabilities() & MEDIA_BD_ALL ) + d->bdReader.append( device ); + if( device->writeCapabilities() & MEDIA_BD_ALL ) + d->bdWriter.append( device ); + + if( device->writesCd() ) { + // default to max write speed + k3bDebug() << "(K3bDevice::DeviceManager) setting current write speed of device " + << device->blockDeviceName() + << " to " << device->maxWriteSpeed() << endl; + device->setCurrentWriteSpeed( device->maxWriteSpeed() ); + } + + emit changed( this ); + emit changed(); + } + + return device; +} + + +void K3bDevice::DeviceManager::removeDevice( const QString& dev ) +{ + if( Device* device = findDevice( dev ) ) { + d->cdReader.removeRef( device ); + d->dvdReader.removeRef( device ); + d->bdReader.removeRef( device ); + d->cdWriter.removeRef( device ); + d->dvdWriter.removeRef( device ); + d->bdWriter.removeRef( device ); + d->allDevices.removeRef( device ); + + emit changed( this ); + emit changed(); + + delete device; + } +} + + +bool K3bDevice::DeviceManager::determineBusIdLun( const QString& dev, int& bus, int& id, int& lun ) +{ +#ifdef Q_OS_FREEBSD + Q_UNUSED(dev); + Q_UNUSED(bus); + Q_UNUSED(id); + Q_UNUSED(lun); + return false; + /* NOTREACHED */ +#endif + +#ifdef Q_OS_NETBSD + int cdromfd = K3bDevice::openDevice ( dev.ascii() ); + if (cdromfd < 0) { + int local_errno = errno; // For all we know, k3bDebug() destroys errno + k3bDebug() << "could not open device " << dev << " (" << strerror(local_errno) << ")" << endl; + return false; + } + + struct scsi_addr my_addr; + + if (::ioctl(cdromfd, SCIOCIDENTIFY, &my_addr)) + { + int local_errno = errno; // For all we know, k3bDebug() destroys errno + k3bDebug() << "ioctl(SCIOCIDENTIFY) failed on device " << dev << " (" << strerror(local_errno) << ")" << endl; + + ::close(cdromfd); + return false; + } + + if (my_addr.type == TYPE_ATAPI) + { + // XXX Re-map atapibus, so it doesn't conflict with "real" scsi + // busses + + bus = 15; + id = my_addr.addr.atapi.drive + 2 * my_addr.addr.atapi.atbus; + lun = 0; + } + else + { + bus = my_addr.addr.scsi.scbus; + id = my_addr.addr.scsi.target; + lun = my_addr.addr.scsi.lun; + } + + ::close(cdromfd); + + return true; +#endif + +#ifdef Q_OS_LINUX + int ret = false; + int cdromfd = K3bDevice::openDevice( dev.ascii() ); + if (cdromfd < 0) { + return false; + } + + struct stat cdromStat; + if ( ::fstat( cdromfd, &cdromStat ) ) + return false; + + if( SCSI_BLK_MAJOR( cdromStat.st_rdev>>8 ) || + SCSI_GENERIC_MAJOR == (cdromStat.st_rdev>>8) ) { + struct ScsiIdLun + { + int id; + int lun; + }; + ScsiIdLun idLun; + + // in kernel 2.2 SCSI_IOCTL_GET_IDLUN does not contain the bus id + if ( (::ioctl( cdromfd, SCSI_IOCTL_GET_IDLUN, &idLun ) < 0) || + (::ioctl( cdromfd, SCSI_IOCTL_GET_BUS_NUMBER, &bus ) < 0) ) { + k3bDebug() << "Need a filename that resolves to a SCSI device" << endl; + ret = false; + } + else { + id = idLun.id & 0xff; + lun = (idLun.id >> 8) & 0xff; + k3bDebug() << "bus: " << bus << ", id: " << id << ", lun: " << lun << endl; + ret = true; + } + } + + ::close(cdromfd); + return ret; +#endif +} + + +QString K3bDevice::DeviceManager::resolveSymLink( const QString& path ) +{ + char resolved[PATH_MAX]; + if( !realpath( QFile::encodeName(path), resolved ) ) + { + k3bDebug() << "Could not resolve " << path << endl; + return path; + } + + return QString::fromLatin1( resolved ); +} + + +#include "k3bdevicemanager.moc" diff --git a/libk3bdevice/k3bdevicemanager.h b/libk3bdevice/k3bdevicemanager.h new file mode 100644 index 0000000..4656538 --- /dev/null +++ b/libk3bdevice/k3bdevicemanager.h @@ -0,0 +1,247 @@ +/* + * + * $Id: k3bdevicemanager.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BDEVICEMANAGER_H +#define K3BDEVICEMANAGER_H + +#include <qobject.h> +#include <qstring.h> +#include <qstringlist.h> +#include <qmemarray.h> +#include <qptrlist.h> + +#include "k3bdevice_export.h" +#include <kdebug.h> + +class KProcess; +class KConfig; +class K3bExternalBin; + + +namespace K3bDevice { + + class Device; + + /** + * \brief Manages all devices. + * + * Searches the system for devices and maintains lists of them. + * + * <b>Basic usage:</b> + * \code + * K3bDevice::DeviceManager* manager = new K3bDevice::DeviceManager( this ); + * manager->scanBus(); + * K3bDevice::Device* dev = manager->findDevice( "/dev/cdrom" ); + * \endcode + */ + class LIBK3BDEVICE_EXPORT DeviceManager : public QObject + { + Q_OBJECT + + public: + /** + * Creates a new DeviceManager + */ + DeviceManager( QObject* parent = 0, const char* name = 0 ); + virtual ~DeviceManager(); + + /** + * By default the DeviceManager makes the Devices check their writing modes. + * This includes commands to be sent which require writing permissions on the + * devices and might take some time. + * + * So if you don't need the information about the writing modes use this method + * to speed up the device detection procedure. + * + * Be aware that this only refers to CD writing modes. If you only want to handle + * DVD devices it's always save to set this to false. + */ + void setCheckWritingModes( bool b ); + + /** + * \deprecated use findDevice( const QString& ) + */ + Device* deviceByName( const QString& ); + + /** + * Search an SCSI device by SCSI bus, id, and lun. + * + * \note This method does not initialize new devices. + * Devices cannot be found until they have been added via addDevice(const QString&) + * or scanBus(). + * + * \return The corresponding device or 0 if there is no such device. + */ + Device* findDevice( int bus, int id, int lun ); + + /** + * Search a device by blockdevice name. + * + * \note This method does not initialize new devices. + * Devices cannot be found until they have been added via addDevice(const QString&) + * or scanBus(). + * + * \return The corresponding device or 0 if there is no such device. + */ + Device* findDevice( const QString& devicename ); + + /** + * Before getting the devices do a @ref scanBus(). + * \return List of all cd writer devices. + * \deprecated use cdWriter() + */ + const QPtrList<Device>& burningDevices() const; + + /** + * \return List of all reader devices without writer devices. + * \deprecated use cdReader() + **/ + const QPtrList<Device>& readingDevices() const; + + /** + * Before getting the devices do a @ref scanBus() or add + * devices via addDevice( const QString& ). + * + * \return List of all devices. + */ + const QPtrList<Device>& allDevices() const; + + /** + * Before getting the devices do a @ref scanBus() or add + * devices via addDevice( const QString& ). + * + * \return List of all cd writer devices. + */ + const QPtrList<Device>& cdWriter() const; + + /** + * Before getting the devices do a @ref scanBus() or add + * devices via addDevice( const QString& ). + * + * \return List of all cd reader devices. + */ + const QPtrList<Device>& cdReader() const; + + /** + * Before getting the devices do a @ref scanBus() or add + * devices via addDevice( const QString& ). + * + * \return List of all DVD writer devices. + */ + const QPtrList<Device>& dvdWriter() const; + + /** + * Before getting the devices do a @ref scanBus() or add + * devices via addDevice( const QString& ). + * + * \return List of all DVD reader devices. + */ + const QPtrList<Device>& dvdReader() const; + + /** + * Before getting the devices do a @ref scanBus() or add + * devices via addDevice( const QString& ). + * + * \return List of all Blue Ray reader devices. + */ + const QPtrList<Device>& blueRayReader() const; + + /** + * Before getting the devices do a @ref scanBus() or add + * devices via addDevice( const QString& ). + * + * \return List of all Blue Ray writer devices. + */ + const QPtrList<Device>& blueRayWriters() const; + + /** + * Reads the device information from the config file. + */ + virtual bool readConfig( KConfig* ); + + virtual bool saveConfig( KConfig* ); + + + public slots: + /** + * Writes a list of all devices to stderr. + */ + void printDevices(); + + /** + * Scan the system for devices. Call this to initialize all devices. + * + * If the system uses the HAL device deamon it is possible to use + * HalConnection instead of calling this method. + * + * \return Number of found devices. + **/ + virtual int scanBus(); + + /** + * Clears the writers and readers list of devices. + */ + virtual void clear(); + + /** + * Add a new device. + * + * \param dev Name of a block device or link to a block device. If the + * corresponding device has already been detected it will simply + * be returned. Otherwise if a device is found it will be initialized + * and added to the internal lists (meaning it can be accessed through + * emthods like cdReader()). + * + * Called by scanBus() + * + * \return The device if it could be found or 0 otherwise. + */ + virtual Device* addDevice( const QString& dev ); + + /** + * Remove a device from the device manager. Basicly this method + * only makes sense in combination with the HalConnection. Connect + * it to the deviceRemoved signal. + */ + virtual void removeDevice( const QString& dev ); + + signals: + /** + * Emitted if the device configuration changed, i.e. a device was added or removed. + */ + void changed( K3bDevice::DeviceManager* ); + void changed(); + + private: + bool testForCdrom( const QString& ); + bool determineBusIdLun( const QString &dev, int& bus, int& id, int& lun ); + QString resolveSymLink( const QString& path ); + + class Private; + Private* d; + + /** + * Add a device to the managers device lists and initialize the device. + */ + Device *addDevice( Device* ); + + void BSDDeviceScan(); + void NetBSDDeviceScan(); + void LinuxDeviceScan(); + }; +} + +#endif diff --git a/libk3bdevice/k3bdevicetypes.h b/libk3bdevice/k3bdevicetypes.h new file mode 100644 index 0000000..feb9a4e --- /dev/null +++ b/libk3bdevice/k3bdevicetypes.h @@ -0,0 +1,266 @@ +/* + * + * $Id: k3bdevicetypes.h 654649 2007-04-16 17:55:50Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_DEVICE_TYPES_H_ +#define _K3B_DEVICE_TYPES_H_ + +namespace K3bDevice { + const unsigned short FEATURE_PROFILE_LIST = 0x000; + const unsigned short FEATURE_CORE = 0x001; + const unsigned short FEATURE_MORPHING = 0x002; + const unsigned short FEATURE_REMOVABLE_MEDIA = 0x003; + const unsigned short FEATURE_WRITE_PROTECT = 0x004; + const unsigned short FEATURE_RANDOM_READABLE = 0x010; + const unsigned short FEATURE_MULTI_READ = 0x01D; + const unsigned short FEATURE_CD_READ = 0x01E; + const unsigned short FEATURE_DVD_READ = 0x01F; + const unsigned short FEATURE_RANDOM_WRITABLE = 0x020; + const unsigned short FEATURE_INCREMENTAL_STREAMING_WRITABLE = 0x021; + const unsigned short FEATURE_SECTOR_ERASABLE = 0x022; + const unsigned short FEATURE_FORMATTABLE = 0x023; + const unsigned short FEATURE_DEFECT_MANAGEMENT = 0x024; + const unsigned short FEATURE_WRITE_ONCE = 0x025; + const unsigned short FEATURE_RESTRICTED_OVERWRITE = 0x026; + const unsigned short FEATURE_CD_RW_CAV_WRITE = 0x027; + const unsigned short FEATURE_MRW = 0x028; + const unsigned short FEATURE_ENHANCED_DEFECT_REPORTING = 0x029; + const unsigned short FEATURE_DVD_PLUS_RW = 0x02A; + const unsigned short FEATURE_DVD_PLUS_R = 0x02B; + const unsigned short FEATURE_RIGID_RESTRICTED_OVERWRITE = 0x02C; + const unsigned short FEATURE_CD_TRACK_AT_ONCE = 0x02D; + const unsigned short FEATURE_CD_MASTERING = 0x02E; + const unsigned short FEATURE_DVD_R_RW_WRITE = 0x02F; + const unsigned short FEATURE_DDCD_READ = 0x030; + const unsigned short FEATURE_DDCD_R_WRITE = 0x031; + const unsigned short FEATURE_DDCD_RW_WRITE = 0x032; + const unsigned short FEATURE_LAYER_JUMP_RECORDING = 0x033; + const unsigned short FEATURE_CD_RW_MEDIA_WRITE_SUPPORT = 0x037; + const unsigned short FEATURE_BD_PSEUDO_OVERWRITE = 0x038; + const unsigned short FEATURE_DVD_PLUS_RW_DUAL_LAYER = 0x03A; /**< since MMC5 revision 3 */ + const unsigned short FEATURE_DVD_PLUS_R_DUAL_LAYER = 0x03B; + const unsigned short FEATURE_BD_READ = 0x040; + const unsigned short FEATURE_BD_WRITE = 0x041; + const unsigned short FEATURE_HD_DVD_READ = 0x050; + const unsigned short FEATURE_HD_DVD_WRITE = 0x051; + const unsigned short FEATURE_POWER_MANAGEMENT = 0x100; + const unsigned short FEATURE_EMBEDDED_CHANGER = 0x102; + const unsigned short FEATURE_CD_AUDIO_ANALOG_PLAY = 0x103; + const unsigned short FEATURE_MICROCODE_UPGRADE = 0x104; + const unsigned short FEATURE_TIMEOUT = 0x105; + const unsigned short FEATURE_DVD_CSS = 0x106; + const unsigned short FEATURE_REAL_TIME_STREAMING = 0x107; + const unsigned short FEATURE_LOGICAL_UNIT_SERIAL_NUMBER = 0x108; + const unsigned short FEATURE_DISC_CONTROL_BLOCKS = 0x10A; + const unsigned short FEATURE_DVD_CPRM = 0x10B; + const unsigned short FEATURE_FIRMWARE_DATE = 0x10C; + + enum Interface { + SCSI, /**< The device is accessed through the SCSI subsystem. */ + IDE, /**< The device is accessed through the IDE (ATAPI) interface. */ + OTHER /**< Unknown interface (this is not used as the DeviceManager does only handle SCSI and IDE anyway). */ + }; + + /** + * Specifies the device type. Device::type() returns a bitwise or + * of device types. + */ + enum DeviceType { + DEVICE_CD_ROM = 0x1, /**< Device reads CD-ROM media (every device in K3b supports this.) */ + DEVICE_CD_R = 0x2, /**< Device writes CD-R media */ + DEVICE_CD_RW = 0x4, /**< Device writes CD-RW media */ + DEVICE_DVD_ROM = 0x8, /**< Device reads DVD-ROM media */ + DEVICE_DVD_RAM = 0x10, /**< Device writes DVD-RAM media */ + DEVICE_DVD_R = 0x20, /**< Device writes DVD-R media */ + DEVICE_DVD_RW = 0x40, /**< Device writes DVD-RW media */ + DEVICE_DVD_R_DL = 0x80, /**< Device writes DVD-R Dual Layer media */ + DEVICE_DVD_PLUS_R = 0x100, /**< Device writes DVD+R media */ + DEVICE_DVD_PLUS_RW = 0x200, /**< Device writes DVD+RW media */ + DEVICE_DVD_PLUS_R_DL = 0x400, /**< Device writes DVD+R Double Layer media */ + DEVICE_HD_DVD_ROM = 0x800, /**< Device reads HD DVD-ROM media */ + DEVICE_HD_DVD_R = 0x1000, /**< Device writes HD DVD-R media */ + DEVICE_HD_DVD_RAM = 0x2000, /**< Device writes HD DVD-RAM media */ + DEVICE_BD_ROM = 0x4000, /**< Device reads BD-ROM media */ + DEVICE_BD_R = 0x8000, /**< Device writes BD-R media */ + DEVICE_BD_RE = 0x10000, /**< Device writes BD-RE media */ + CDR = DEVICE_CD_R, /**< \deprecated {use DEVICE_CD_R instead) */ + CDRW = DEVICE_CD_RW, /**< \deprecated {use DEVICE_CD_RW instead) */ + CDROM = DEVICE_CD_ROM, /**< \deprecated {use DEVICE_CD_ROM instead) */ + DVD = DEVICE_DVD_ROM, /**< \deprecated {use DEVICE_DVD_ROM instead) */ + DVDRAM = DEVICE_DVD_RAM, /**< \deprecated {use DEVICE_DVD_RAM instead) */ + DVDR = DEVICE_DVD_R, /**< \deprecated {use DEVICE_DVD_R instead) */ + DVDRW = DEVICE_DVD_RW, /**< \deprecated {use DEVICE_DVD_RW instead) */ + DVDPR = DEVICE_DVD_PLUS_R, /**< \deprecated {use DEVICE_DVD_PLUS_R instead) */ + DVDPRW = DEVICE_DVD_PLUS_RW /**< \deprecated {use DEVICE_DVD_PLUS_RW instead) */ + }; + + + /** + * The different writing modes. Device::writingModes() returns a bitwise or of writing modes. + */ + enum WritingMode { + WRITINGMODE_SAO = 0x1, /**< Device writes CD or DVD-R media in Session at once (also known as DAO) writing mode */ + WRITINGMODE_SAO_R96P = 0x2, /**< Device writes CD media with packed R-W subchannels Session at once writing mode */ + WRITINGMODE_SAO_R96R = 0x4, /**< Device writes CD media with raw R-W subchannels Session at once writing mode */ + WRITINGMODE_TAO = 0x8, /**< Device writes CD media in Track at once writing mode */ + WRITINGMODE_RAW = 0x10, /**< Device writes CD media in Raw writing mode */ + WRITINGMODE_RAW_R16 = 0x20, /**< Device writes CD media with P/Q subchannels in Raw writing mode */ + WRITINGMODE_RAW_R96P = 0x40, /**< Device writes CD media with packed R-W subchannels Raw writing mode */ + WRITINGMODE_RAW_R96R = 0x80, /**< Device writes CD media with raw R-W subchannels Raw writing mode */ + WRITINGMODE_INCR_SEQ = 0x100, /**< Device writes DVD-R(W) media in incremental sequential writing mode */ + WRITINGMODE_RES_OVWR = 0x200, /**< Device writes DVD-RW media in restricted overwrite mode */ + WRITINGMODE_LAYER_JUMP = 0x400, /**< Device writes DVD-R Dual layer media in Layer Jump writing mode */ + WRITINGMODE_RRM = 0x800, /**< Device writes BD-R media in Random Recording Mode */ + WRITINGMODE_SRM = 0x1000, /**< Device writes BD-R media in Sequential recording mode */ + WRITINGMODE_SRM_POW = 0x2000, /**< Device writes BD-R media in Pseudo overwrite Sequential recording mode */ + SAO = WRITINGMODE_SAO, /**< \deprecated {use WRITINGMODE_SAO instead) */ + TAO = WRITINGMODE_TAO, /**< \deprecated {use WRITINGMODE_TAO instead) */ + RAW = WRITINGMODE_RAW, /**< \deprecated {use WRITINGMODE_RAW instead) */ + SAO_R96P = WRITINGMODE_SAO_R96P, /**< \deprecated {use WRITINGMODE_SAO_R96P instead) */ + SAO_R96R = WRITINGMODE_SAO_R96R, /**< \deprecated {use WRITINGMODE_SAO_R96R instead) */ + RAW_R16 = WRITINGMODE_RAW_R16, /**< \deprecated {use WRITINGMODE_RAW_R16 instead) */ + RAW_R96P = WRITINGMODE_RAW_R96P, /**< \deprecated {use WRITINGMODE_RAW_R96P instead) */ + RAW_R96R = WRITINGMODE_RAW_R96R /**< \deprecated {use WRITINGMODE_RAW_R96R instead) */ + }; + + + enum MediaState { + STATE_UNKNOWN = 0x1, /**< Media state is unknown (when an error occurred or the device is unable to determine the media state). */ + STATE_NO_MEDIA = 0x2, /**< No media inserted. */ + STATE_COMPLETE = 0x4, /**< The inserted media is complete. */ + STATE_INCOMPLETE = 0x8, /**< The inserted media is incomplete/appendable. */ + STATE_EMPTY = 0x10 /**< The inserted media is empty. */ + }; + + enum BackGroundFormattingState { + BG_FORMAT_NONE = 0x1, + BG_FORMAT_INCOMPLETE = 0x2, + BG_FORMAT_IN_PROGRESS = 0x4, + BG_FORMAT_COMPLETE = 0x8 + }; + + /** + * Defines the different media types as retured by + * Device::cdMediaType() and Device::dvdMediaType() + */ + enum MediaType { + MEDIA_UNKNOWN = 0x1, /**< Represents an unknown media type (when an error occurred) */ + MEDIA_NONE = 0x2, /**< No medium is inserted */ + MEDIA_DVD_ROM = 0x4, /**< */ + MEDIA_DVD_R = 0x8, /**< */ + MEDIA_DVD_R_SEQ = 0x10, /**< */ + MEDIA_DVD_R_DL = 0x20, /**< Dual Layer DVD-R media. */ + MEDIA_DVD_R_DL_SEQ = 0x40, /**< */ + MEDIA_DVD_R_DL_JUMP = 0x80, /**< */ + MEDIA_DVD_RAM = 0x100, /**< */ + MEDIA_DVD_RW = 0x200, /**< */ + MEDIA_DVD_RW_OVWR = 0x400, /**< DVD-RW media formatted in Restricted Overwrite mode. */ + MEDIA_DVD_RW_SEQ = 0x800, /**< DVD-RW media formatted in Incremental Sequential mode. */ + MEDIA_DVD_PLUS_RW = 0x1000, /**< */ + MEDIA_DVD_PLUS_R = 0x2000, /**< */ + MEDIA_DVD_PLUS_R_DL = 0x4000, /**< Double Layer DVD+R media. */ + MEDIA_DVD_PLUS_RW_DL = 0x8000, /**< Double Layer DVD+RW media. */ + MEDIA_CD_ROM = 0x10000, /**< */ + MEDIA_CD_R = 0x20000, /**< */ + MEDIA_CD_RW = 0x40000, /**< */ + MEDIA_HD_DVD_ROM = 0x80000, /**< */ + MEDIA_HD_DVD_R = 0x100000, /**< */ + MEDIA_HD_DVD_RAM = 0x200000, /**< */ + MEDIA_BD_ROM = 0x400000, /**< Read-only Blu-ray Disc (BD) */ + MEDIA_BD_R = 0x800000, /**< Writable Blu-ray Disc (BD-R) */ + MEDIA_BD_R_SRM = 0x1000000, /**< Writable Blu-ray Disc (BD-R) */ + MEDIA_BD_R_SRM_POW = 0x2000000, /**< Writable Blu-ray Disc (BD-R) */ + MEDIA_BD_R_RRM = 0x4000000, /**< Writable Blu-ray Disc (BD-R) */ + MEDIA_BD_RE = 0x8000000, /**< Rewritable Blu-ray Disc (BD-RE) */ + MEDIA_WRITABLE_CD = MEDIA_CD_R | /**< This is a bitwise or of media types representing all writable CD media.*/ + MEDIA_CD_RW, + MEDIA_CD_ALL = MEDIA_WRITABLE_CD | + MEDIA_CD_ROM, + MEDIA_WRITABLE_DVD_SL = MEDIA_DVD_R | /**< This is a bitwise or of media types representing all writable single layer DVD media.*/ + MEDIA_DVD_R_SEQ | + MEDIA_DVD_RW | + MEDIA_DVD_RW_OVWR | + MEDIA_DVD_RW_SEQ | + MEDIA_DVD_PLUS_RW | + MEDIA_DVD_PLUS_R, + MEDIA_WRITABLE_DVD_DL = MEDIA_DVD_R_DL | /**< This is a bitwise or of media types representing all writable double layer DVD media.*/ + MEDIA_DVD_R_DL_SEQ | + MEDIA_DVD_R_DL_JUMP | + MEDIA_DVD_PLUS_R_DL | + MEDIA_DVD_PLUS_RW_DL, + MEDIA_WRITABLE_DVD = MEDIA_WRITABLE_DVD_SL | /**< This is a bitwise or of media types representing all writable DVD media.*/ + MEDIA_WRITABLE_DVD_DL, + MEDIA_REWRITABLE_DVD = MEDIA_DVD_RW | + MEDIA_DVD_RW_OVWR | + MEDIA_DVD_RW_SEQ | + MEDIA_DVD_PLUS_RW_DL | + MEDIA_DVD_PLUS_RW, + MEDIA_WRITABLE_BD = MEDIA_BD_R | /**< This is a bitwise or of media types representing all writable BD media.*/ + MEDIA_BD_R_SRM | + MEDIA_BD_R_SRM_POW | + MEDIA_BD_R_RRM | + MEDIA_BD_RE, + MEDIA_WRITABLE = MEDIA_WRITABLE_CD | /**< This is a bitwise or of media types representing all writable media.*/ + MEDIA_WRITABLE_DVD | + MEDIA_WRITABLE_BD, + MEDIA_REWRITABLE = MEDIA_CD_RW | + MEDIA_REWRITABLE_DVD | + MEDIA_BD_RE, + MEDIA_DVD_MINUS_ALL = MEDIA_DVD_R | /**< This is a bitwise or of media types representing all DVD-R/W media.*/ + MEDIA_DVD_R_SEQ | + MEDIA_DVD_RW | + MEDIA_DVD_RW_OVWR | + MEDIA_DVD_RW_SEQ | + MEDIA_DVD_R_DL | + MEDIA_DVD_R_DL_SEQ | + MEDIA_DVD_R_DL_JUMP, + MEDIA_DVD_PLUS_ALL = MEDIA_DVD_PLUS_RW | /**< This is a bitwise or of media types representing all DVD+R/W media.*/ + MEDIA_DVD_PLUS_R | + MEDIA_DVD_PLUS_R_DL | + MEDIA_DVD_PLUS_RW_DL, + MEDIA_DVD_ALL = MEDIA_WRITABLE_DVD | + MEDIA_DVD_ROM, + MEDIA_BD_ALL = MEDIA_WRITABLE_BD | + MEDIA_BD_ROM, + MEDIA_ALL = MEDIA_CD_ALL | + MEDIA_DVD_ALL | + MEDIA_BD_ALL + }; + + inline bool isDvdMedia( int mediaType ) { + return ( mediaType == MEDIA_DVD_ROM || + mediaType == MEDIA_DVD_R || + mediaType == MEDIA_DVD_R_SEQ || + mediaType == MEDIA_DVD_R_DL || + mediaType == MEDIA_DVD_R_DL_SEQ || + mediaType == MEDIA_DVD_R_DL_JUMP || + mediaType == MEDIA_DVD_RW || + mediaType == MEDIA_DVD_RW_OVWR || + mediaType == MEDIA_DVD_RW_SEQ || + mediaType == MEDIA_DVD_PLUS_RW || + mediaType == MEDIA_DVD_PLUS_R || + mediaType == MEDIA_DVD_PLUS_R_DL ); + } + + inline bool isRewritableMedia( int mediaType ) { + return ( mediaType == MEDIA_DVD_RW || + mediaType == MEDIA_DVD_RW_OVWR || + mediaType == MEDIA_DVD_RW_SEQ || + mediaType == MEDIA_DVD_PLUS_RW || + mediaType == MEDIA_CD_RW ); + } +} + +#endif diff --git a/libk3bdevice/k3bdiskinfo.cpp b/libk3bdevice/k3bdiskinfo.cpp new file mode 100644 index 0000000..6c91d19 --- /dev/null +++ b/libk3bdevice/k3bdiskinfo.cpp @@ -0,0 +1,266 @@ +/* + * + * $Id: k3bdiskinfo.cpp 654649 2007-04-16 17:55:50Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bdiskinfo.h" +#include "k3bdeviceglobals.h" + +#include <k3bmsf.h> + +#include <klocale.h> +#include <k3bdebug.h> +#include <kio/global.h> + +#include <qstringlist.h> + + +K3bDevice::DiskInfo::DiskInfo() + : m_mediaType(MEDIA_UNKNOWN), + m_currentProfile(MEDIA_UNKNOWN), + m_diskState(STATE_UNKNOWN), + m_lastSessionState(STATE_UNKNOWN), + m_bgFormatState(0), + m_numSessions(0), + m_numTracks(0), + m_rewritable(false) +{ +} + + +K3bDevice::DiskInfo::~DiskInfo() +{ +} + + +int K3bDevice::DiskInfo::diskState() const +{ + return m_diskState; +} + + +int K3bDevice::DiskInfo::lastSessionState() const +{ + return m_lastSessionState; +} + + +int K3bDevice::DiskInfo::bgFormatState() const +{ + return m_bgFormatState; +} + + +bool K3bDevice::DiskInfo::empty() const +{ + return diskState() == STATE_EMPTY; +} + + +bool K3bDevice::DiskInfo::rewritable() const +{ + return m_rewritable; +} + + +bool K3bDevice::DiskInfo::appendable() const +{ + return diskState() == STATE_INCOMPLETE; +} + + +int K3bDevice::DiskInfo::mediaType() const +{ + return m_mediaType; +} + + +bool K3bDevice::DiskInfo::isDvdMedia() const +{ + return K3bDevice::isDvdMedia( mediaType() ); +} + + +int K3bDevice::DiskInfo::numSessions() const +{ + if( empty() ) + return 0; + else + return m_numSessions; +} + + +int K3bDevice::DiskInfo::numTracks() const +{ + if( empty() ) + return 0; + else + return m_numTracks; +} + + +int K3bDevice::DiskInfo::numLayers() const +{ + if( isDvdMedia() ) + return m_numLayers; + else + return 1; +} + + +K3b::Msf K3bDevice::DiskInfo::remainingSize() const +{ + if( empty() ) + return capacity(); + + // + // There is no way to properly determine the used size on an overwrite media + // without having a look at the filesystem (or is there?) + // + else if( appendable() || + mediaType() & (MEDIA_DVD_PLUS_RW|MEDIA_DVD_RW_OVWR) ) + return capacity() - m_usedCapacity; + + else + return 0; +} + + +K3b::Msf K3bDevice::DiskInfo::capacity() const +{ + return (m_capacity == 0 ? size() : m_capacity); +} + + +K3b::Msf K3bDevice::DiskInfo::size() const +{ + if( empty() ) + return 0; + else + return m_usedCapacity; +} + + +K3b::Msf K3bDevice::DiskInfo::firstLayerSize() const +{ + if( numLayers() > 1 ) + return m_firstLayerSize; + else + return size(); +} + + +void K3bDevice::DiskInfo::debug() const +{ + k3bDebug() << "DiskInfo:" << endl + << "Mediatype: " << K3bDevice::mediaTypeString( mediaType() ) << endl + << "Current Profile: " << K3bDevice::mediaTypeString( currentProfile() ) << endl + << "Disk state: " << ( diskState() == K3bDevice::STATE_EMPTY ? + "empty" : + ( diskState() == K3bDevice::STATE_INCOMPLETE ? + "incomplete" : + ( diskState() == K3bDevice::STATE_COMPLETE ? + "complete" : + ( diskState() == K3bDevice::STATE_NO_MEDIA ? + "no media" : + "unknown" ) ) ) ) << endl + << "Empty: " << empty() << endl + << "Rewritable: " << rewritable() << endl + << "Appendable: " << appendable() << endl + << "Sessions: " << numSessions() << endl + << "Tracks: " << numTracks() << endl + << "Layers: " << numLayers() << endl + << "Capacity: " << capacity() + << " (LBA " << capacity().lba() + << ") (" << capacity().mode1Bytes() << " Bytes)" << endl + + << "Remaining size: " << remainingSize() + << " (LBA " << remainingSize().lba() + << ") (" << remainingSize().mode1Bytes() << " Bytes)" << endl + + << "Used Size: " << size() + << " (LBA " << size().lba() + << ") (" << size().mode1Bytes() << " Bytes)" << endl; + + if( mediaType() == K3bDevice::MEDIA_DVD_PLUS_RW ) + k3bDebug() << "Bg Format: " << ( bgFormatState() == BG_FORMAT_NONE ? + "none" : + ( bgFormatState() == BG_FORMAT_INCOMPLETE ? + "incomplete" : + ( bgFormatState() == BG_FORMAT_IN_PROGRESS ? + "in progress" : + ( bgFormatState() == BG_FORMAT_COMPLETE ? + "complete" : "unknown" ) ) ) ) << endl; +} + + +bool K3bDevice::DiskInfo::operator==( const K3bDevice::DiskInfo& other ) const +{ + return( m_mediaType == other.m_mediaType && + m_currentProfile == other.m_currentProfile && + m_diskState == other.m_diskState && + m_lastSessionState == other.m_lastSessionState && + m_bgFormatState == other.m_bgFormatState && + m_numSessions == other.m_numSessions && + m_numTracks == other.m_numTracks && + m_numLayers == other.m_numLayers && + m_rewritable == other.m_rewritable && + m_capacity == other.m_capacity && + m_usedCapacity == other.m_usedCapacity && + m_firstLayerSize == other.m_firstLayerSize && + m_mediaId == other.m_mediaId ); +} + + +bool K3bDevice::DiskInfo::operator!=( const K3bDevice::DiskInfo& other ) const +{ + return( m_mediaType != other.m_mediaType || + m_currentProfile != other.m_currentProfile || + m_diskState != other.m_diskState || + m_lastSessionState != other.m_lastSessionState || + m_bgFormatState != other.m_bgFormatState || + m_numSessions != other.m_numSessions || + m_numTracks != other.m_numTracks || + m_numLayers != other.m_numLayers || + m_rewritable != other.m_rewritable || + m_capacity != other.m_capacity || + m_usedCapacity != other.m_usedCapacity || + m_firstLayerSize != other.m_firstLayerSize || + m_mediaId != other.m_mediaId ); +} + + +// kdbgstream& K3bDevice::operator<<( kdbgstream& s, const K3bDevice::DiskInfo& ngInf ) +// { +// s << "DiskInfo:" << endl +// << "Mediatype: " << K3bDevice::mediaTypeString( ngInf.mediaType() ) << endl +// << "Current Profile: " << K3bDevice::mediaTypeString( ngInf.currentProfile() ) << endl +// << "Disk state: " << ( ngInf.diskState() == K3bDevice::STATE_EMPTY ? +// "empty" : +// ( ngInf.diskState() == K3bDevice::STATE_INCOMPLETE ? +// "incomplete" : +// ( ngInf.diskState() == K3bDevice::STATE_COMPLETE ? +// "complete" : +// ( ngInf.diskState() == K3bDevice::STATE_NO_MEDIA ? +// "no media" : +// "unknown" ) ) ) ) << endl +// << "Empty: " << ngInf.empty() << endl +// << "Rewritable: " << ngInf.rewritable() << endl +// << "Appendable: " << ngInf.appendable() << endl +// << "Sessions: " << ngInf.numSessions() << endl +// << "Tracks: " << ngInf.numTracks() << endl +// << "Size: " << ngInf.capacity().toString() << endl +// << "Remaining size: " << ngInf.remainingSize().toString() << endl; + +// return s; +// } diff --git a/libk3bdevice/k3bdiskinfo.h b/libk3bdevice/k3bdiskinfo.h new file mode 100644 index 0000000..ed7c382 --- /dev/null +++ b/libk3bdevice/k3bdiskinfo.h @@ -0,0 +1,182 @@ +/* + * + * $Id: k3bdiskinfo.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_DISKINFO_H_ +#define _K3B_DISKINFO_H_ + +#include <k3bdevicetypes.h> + +#include <k3btoc.h> +#include <k3bmsf.h> +#include "k3bdevice_export.h" + +#include <qcstring.h> + + +class kdbgstream; + + +namespace K3bDevice +{ + /** + * This class is directly accociated to a strcuture from + * the MMC draft READ_DISK_INFO. + * It also holds some additional data. + * This class' data will be retrieved by K3bDevice::Device. + * + * Before using any values one should check diskState != STATE_UNKNOWN or + * diskState == STATE_NO_MEDIA. + * That may mean that no disk is in the drive or an error occurred. + * Writers should never give the STATE_UNKNOWN state. CD-ROM or DVD-ROM + * drives on the other hand may have trouble determining the state of the disk. + */ + class LIBK3BDEVICE_EXPORT DiskInfo + { + public: + DiskInfo(); + ~DiskInfo(); + + /** + * Returnes the state of the disk. + * See enum State. + */ + int diskState() const; + + /** + * Returnes the state of the last session. + * See enum State. + */ + int lastSessionState() const; + + /** + * Returnes the state of the background formatting. This does + * only make sense for DVD+RW (and MRW which is not yet supported) + */ + int bgFormatState() const; + + /** + * returnes true if diskState() == STATE_EMPTY + */ + bool empty() const; + + /** + * Is this a rewritable media (e.g. a CD-RW, DVD-RW, or DVD+RW) + */ + bool rewritable() const; + + /** + * Is this disk appendable + * returnes true if diskState() == STATE_INCOMPLETE + */ + bool appendable() const; + + /** + * The type of the disk: + * CD-ROM, CD-R, CD-RW, DVD-ROM, DVD-R(W), DVD+R(W) + */ + int mediaType() const; + + /** + * This is the current profile of the drive. That means it may differ + * from drive to drive. + * -1 means no info. + * Mainly interesting for the distiction of DVD-R(W) modes: + * Sequential and Restricted Overwrite. + */ + int currentProfile() const { return m_currentProfile; } + + /** + * Just for easy implementation since there are so many + * different DVD formats. + */ + bool isDvdMedia() const; + + /** + * The number of sessions on the disk. + * This does not include any leadout or the last empty session + * on a DVD+-R(W) + */ + int numSessions() const; + + /** + * The number of finished tracks. + * This does not include the empty track. + */ + int numTracks() const; + + /** + * Number of layers on a DVD media. For CD media this is always 1. + */ + int numLayers() const; + + /** + * Does only make sense for appendable disks. + */ + K3b::Msf remainingSize() const; + + /** + * The capacity of the disk. + * For complete disks this may be the same as size() + */ + K3b::Msf capacity() const; + + /** + * Returns the size of the used part. + * For appendable media this equals capacity() - remainingSize() + */ + K3b::Msf size() const; + + /** + * Returns the size of Data area in the first layer for DL DVD media. + * Otherwise size() is returned. + * + * This does not specify the layer change sector as the data area on DVD media does + * not start at sector 0 but at sector 30000h or 31000h depending on the type. + */ + K3b::Msf firstLayerSize() const; + + const QCString& mediaId() const { return m_mediaId; } + + void debug() const; + + bool operator==( const DiskInfo& ) const; + bool operator!=( const DiskInfo& ) const; + + private: + int m_mediaType; + int m_currentProfile; + + int m_diskState; + int m_lastSessionState; + int m_bgFormatState; + int m_numSessions; + int m_numTracks; + int m_numLayers; // only for DVD media + int m_rewritable; + + K3b::Msf m_capacity; + K3b::Msf m_usedCapacity; + K3b::Msf m_firstLayerSize; + + QCString m_mediaId; + + friend class Device; + }; + + // kdbgstream& operator<<( kdbgstream& s, const DiskInfo& ngInf ); +} + +#endif diff --git a/libk3bdevice/k3bhalconnection.cpp b/libk3bdevice/k3bhalconnection.cpp new file mode 100644 index 0000000..2b0877b --- /dev/null +++ b/libk3bdevice/k3bhalconnection.cpp @@ -0,0 +1,610 @@ +/* + * + * $Id: sourceheader,v 1.3 2005/01/19 13:03:46 trueg Exp $ + * Copyright (C) 2005-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bhalconnection.h" +#include "k3bdevice.h" + +#include <k3bdebug.h> +#include <klocale.h> + +#include <qtimer.h> + +// We acknowledge the the dbus API is unstable +#define DBUS_API_SUBJECT_TO_CHANGE +#include <dbus/connection.h> +#include <dbus/dbus.h> +#include <hal/libhal.h> + + +static char** qstringListToArray( const QStringList& s ) +{ + char** a = new char*[s.count()]; + for( unsigned int i = 0; i < s.count(); ++i ) { + a[i] = new char[s[i].length()+1]; + ::strncpy( a[i], s[i].local8Bit().data(), s[i].length() ); + a[s[i].length()] = '\0'; + } + return a; +} + +static void freeArray( char** a, unsigned int length ) +{ + for( unsigned int i = 0; i < length; ++i ) + delete [] a[i]; + delete a; +} + + +// CALLBACKS +void halDeviceAdded( LibHalContext* ctx, const char* udi ) +{ + Q_UNUSED( ctx ); + k3bDebug() << "adding udi " << udi << endl; + K3bDevice::HalConnection::instance()->addDevice( udi ); +} + + +void halDeviceRemoved( LibHalContext* ctx, const char* udi ) +{ + Q_UNUSED( ctx ); + k3bDebug() << "removing udi " << udi << endl; + K3bDevice::HalConnection::instance()->removeDevice( udi ); +} + + +K3bDevice::HalConnection* K3bDevice::HalConnection::s_instance = 0; + + +class K3bDevice::HalConnection::Private +{ +public: + Private() + : halContext(0), + dBusQtConnection(0), + bOpen(false) { + } + + LibHalContext* halContext; + DBusConnection* connection; + DBusQt::Connection* dBusQtConnection; + + bool bOpen; + + QMap<QCString, QString> udiDeviceMap; + QMap<QString, QCString> deviceUdiMap; + + QMap<QCString, QCString> deviceMediumUdiMap; +}; + + +K3bDevice::HalConnection* K3bDevice::HalConnection::instance() +{ + if( s_instance == 0 ) + s_instance = new HalConnection( 0 ); + + if( !s_instance->isConnected() && !s_instance->open() ) + k3bDebug() << "(K3bDevice::HalConnection) failed to open connection to HAL." << endl; + + return s_instance; +} + + +K3bDevice::HalConnection::HalConnection( QObject* parent, const char* name ) + : QObject( parent, name ) +{ + d = new Private(); +} + + +K3bDevice::HalConnection::~HalConnection() +{ + s_instance = 0; + close(); + delete d; +} + + +bool K3bDevice::HalConnection::isConnected() const +{ + return d->bOpen; +} + + +bool K3bDevice::HalConnection::open() +{ + close(); + + k3bDebug() << "(K3bDevice::HalConnection) initializing HAL >= 0.5" << endl; + + d->halContext = libhal_ctx_new(); + if( !d->halContext ) { + k3bDebug() << "(K3bDevice::HalConnection) unable to create HAL context." << endl; + return false; + } + + DBusError error; + dbus_error_init( &error ); + d->connection = dbus_bus_get( DBUS_BUS_SYSTEM, &error ); + if( dbus_error_is_set(&error) ) { + k3bDebug() << "(K3bDevice::HalConnection) unable to connect to DBUS: " << error.message << endl; + return false; + } + + setupDBusQtConnection( d->connection ); + + libhal_ctx_set_dbus_connection( d->halContext, d->connection ); + + libhal_ctx_set_device_added( d->halContext, halDeviceAdded ); + libhal_ctx_set_device_removed( d->halContext, halDeviceRemoved ); + libhal_ctx_set_device_new_capability( d->halContext, 0 ); + libhal_ctx_set_device_lost_capability( d->halContext, 0 ); + libhal_ctx_set_device_property_modified( d->halContext, 0 ); + libhal_ctx_set_device_condition( d->halContext, 0 ); + + if( !libhal_ctx_init( d->halContext, 0 ) ) { + k3bDebug() << "(K3bDevice::HalConnection) Failed to init HAL context!" << endl; + return false; + } + + d->bOpen = true; + + // + // report all devices + // + int numDevices; + char** halDeviceList = libhal_get_all_devices( d->halContext, &numDevices, 0 ); + for( int i = 0; i < numDevices; ++i ) + addDevice( halDeviceList[i] ); + + return true; +} + + +void K3bDevice::HalConnection::close() +{ + if( d->halContext ) { + // clear the context + if( isConnected() ) + libhal_ctx_shutdown( d->halContext, 0 ); + libhal_ctx_free( d->halContext ); + + // delete the connection (may be 0 if open() failed) + delete d->dBusQtConnection; + + d->halContext = 0; + d->dBusQtConnection = 0; + d->bOpen = false; + } +} + + +QStringList K3bDevice::HalConnection::devices() const +{ + return QStringList( d->udiDeviceMap.values() ); +} + + +void K3bDevice::HalConnection::addDevice( const char* udi ) +{ + // ignore devices that have no property "info.capabilities" to suppress error messages + if( !libhal_device_property_exists( d->halContext, udi, "info.capabilities", 0 ) ) + return; + + if( libhal_device_query_capability( d->halContext, udi, "storage.cdrom", 0 ) ) { + char* dev = libhal_device_get_property_string( d->halContext, udi, "block.device", 0 ); + if( dev ) { + QString s( dev ); + libhal_free_string( dev ); + + if( !s.isEmpty() ) { + k3bDebug() << "Mapping udi " << udi << " to device " << s << endl; + d->udiDeviceMap[udi] = s; + d->deviceUdiMap[s] = udi; + emit deviceAdded( s ); + } + } + } + else { + if( libhal_device_property_exists( d->halContext, udi, "block.storage_device", 0 ) ) { + char* deviceUdi = libhal_device_get_property_string( d->halContext, udi, "block.storage_device", 0 ); + if( deviceUdi ) { + QCString du( deviceUdi ); + libhal_free_string( deviceUdi ); + + if( d->udiDeviceMap.contains( du ) ) { + // + // A new medium has been inserted. Save this medium's udi so we can reuse it later + // on for the mount/unmount/eject methods + // + d->deviceMediumUdiMap[du] = QCString( udi ); + emit mediumChanged( d->udiDeviceMap[du] ); + } + } + } + } +} + + +void K3bDevice::HalConnection::removeDevice( const char* udi ) +{ + QMapIterator<QCString, QString> it = d->udiDeviceMap.find( udi ); + if( it != d->udiDeviceMap.end() ) { + k3bDebug() << "Unmapping udi " << udi << " from device " << it.data() << endl; + emit deviceRemoved( it.data() ); + d->udiDeviceMap.erase( it ); + d->deviceUdiMap.erase( it.data() ); + } + else { + if( libhal_device_property_exists( d->halContext, udi, "block.storage_device", 0 ) ) { + char* deviceUdi = libhal_device_get_property_string( d->halContext, udi, "block.storage_device", 0 ); + if( deviceUdi ) { + QCString du( deviceUdi ); + libhal_free_string( deviceUdi ); + + if( d->udiDeviceMap.contains( du ) ) { + // + // A medium has been removed/ejected. + // + d->deviceMediumUdiMap[du] = 0; + emit mediumChanged( d->udiDeviceMap[du] ); + } + } + } + } +} + + +int K3bDevice::HalConnection::lock( Device* dev ) +{ + // + // The code below is based on the code from kioslave/media/mediamanager/halbackend.cpp in the kdebase package + // Copyright (c) 2004-2005 Jérôme Lodewyck <jerome dot lodewyck at normalesup dot org> + // + DBusMessage* dmesg = 0; + DBusMessage* reply = 0; + DBusError error; + + if( !d->deviceUdiMap.contains( dev->blockDeviceName() ) ) { + return org_freedesktop_Hal_Device_Volume_NoSuchDevice; + } + + QCString udi = d->deviceUdiMap[dev->blockDeviceName()]; + + if( !( dmesg = dbus_message_new_method_call( "org.freedesktop.Hal", udi.data(), + "org.freedesktop.Hal.Device", + "Lock" ) ) ) { + k3bDebug() << "(K3bDevice::HalConnection) lock failed for " << udi << ": could not create dbus message\n"; + return org_freedesktop_Hal_CommunicationError; + } + + const char* lockComment = "Locked by the K3b libraries"; + + if( !dbus_message_append_args( dmesg, + DBUS_TYPE_STRING, &lockComment, + DBUS_TYPE_INVALID ) ) { + k3bDebug() << "(K3bDevice::HalConnection) lock failed for " << udi << ": could not append args to dbus message\n"; + dbus_message_unref( dmesg ); + return org_freedesktop_Hal_CommunicationError; + } + + int ret = org_freedesktop_Hal_Success; + + dbus_error_init( &error ); + reply = dbus_connection_send_with_reply_and_block( d->connection, dmesg, -1, &error ); + if( dbus_error_is_set( &error ) ) { + kdError() << "(K3bDevice::HalConnection) lock failed for " << udi << ": " << error.name << " - " << error.message << endl; + if( !strcmp(error.name, "org.freedesktop.Hal.NoSuchDevice" ) ) + ret = org_freedesktop_Hal_NoSuchDevice; + else if( !strcmp(error.name, "org.freedesktop.Hal.DeviceAlreadyLocked" ) ) + ret = org_freedesktop_Hal_DeviceAlreadyLocked; + else if( !strcmp(error.name, "org.freedesktop.Hal.PermissionDenied" ) ) + ret = org_freedesktop_Hal_PermissionDenied; + + dbus_error_free( &error ); + } + else + k3bDebug() << "(K3bDevice::HalConnection) lock queued for " << udi << endl; + + dbus_message_unref( dmesg ); + if( reply ) + dbus_message_unref( reply ); + + return ret; +} + + +int K3bDevice::HalConnection::unlock( Device* dev ) +{ + // + // The code below is based on the code from kioslave/media/mediamanager/halbackend.cpp in the kdebase package + // Copyright (c) 2004-2005 Jérôme Lodewyck <jerome dot lodewyck at normalesup dot org> + // + DBusMessage* dmesg = 0; + DBusMessage* reply = 0; + DBusError error; + + if( !d->deviceUdiMap.contains( dev->blockDeviceName() ) ) { + return org_freedesktop_Hal_Device_Volume_NoSuchDevice; + } + + QCString udi = d->deviceUdiMap[dev->blockDeviceName()]; + + if( !( dmesg = dbus_message_new_method_call( "org.freedesktop.Hal", udi.data(), + "org.freedesktop.Hal.Device", + "Unlock" ) ) ) { + k3bDebug() << "(K3bDevice::HalConnection) unlock failed for " << udi << ": could not create dbus message\n"; + return org_freedesktop_Hal_CommunicationError; + } + + if( !dbus_message_append_args( dmesg, + DBUS_TYPE_INVALID ) ) { + k3bDebug() << "(K3bDevice::HalConnection) unlock failed for " << udi << ": could not append args to dbus message\n"; + dbus_message_unref( dmesg ); + return org_freedesktop_Hal_CommunicationError; + } + + int ret = org_freedesktop_Hal_Success; + + dbus_error_init( &error ); + reply = dbus_connection_send_with_reply_and_block( d->connection, dmesg, -1, &error ); + if( dbus_error_is_set( &error ) ) { + kdError() << "(K3bDevice::HalConnection) unlock failed for " << udi << ": " << error.name << " - " << error.message << endl; + if( !strcmp(error.name, "org.freedesktop.Hal.NoSuchDevice" ) ) + ret = org_freedesktop_Hal_NoSuchDevice; + else if( !strcmp(error.name, "org.freedesktop.Hal.DeviceAlreadyLocked" ) ) + ret = org_freedesktop_Hal_DeviceAlreadyLocked; + else if( !strcmp(error.name, "org.freedesktop.Hal.PermissionDenied" ) ) + ret = org_freedesktop_Hal_PermissionDenied; + + dbus_error_free( &error ); + } + else + k3bDebug() << "(K3bDevice::HalConnection) unlock queued for " << udi << endl; + + dbus_message_unref( dmesg ); + if( reply ) + dbus_message_unref( reply ); + + return ret; +} + + +int K3bDevice::HalConnection::mount( K3bDevice::Device* dev, + const QString& mountPoint, + const QString& fstype, + const QStringList& options ) +{ + // + // The code below is based on the code from kioslave/media/mediamanager/halbackend.cpp in the kdebase package + // Copyright (c) 2004-2005 Jérôme Lodewyck <jerome dot lodewyck at normalesup dot org> + // + DBusMessage* dmesg = 0; + DBusMessage* reply = 0; + DBusError error; + + if( !d->deviceUdiMap.contains( dev->blockDeviceName() ) ) + return org_freedesktop_Hal_NoSuchDevice; + + if( !d->deviceMediumUdiMap.contains( d->deviceUdiMap[dev->blockDeviceName()] ) ) + return org_freedesktop_Hal_Device_Volume_NoSuchDevice; + + QCString mediumUdi = d->deviceMediumUdiMap[d->deviceUdiMap[dev->blockDeviceName()]]; + + if( !( dmesg = dbus_message_new_method_call( "org.freedesktop.Hal", mediumUdi.data(), + "org.freedesktop.Hal.Device.Volume", + "Mount" ) ) ) { + k3bDebug() << "(K3bDevice::HalConnection) mount failed for " << mediumUdi << ": could not create dbus message\n"; + return org_freedesktop_Hal_CommunicationError; + } + + char** poptions = qstringListToArray( options ); + + QByteArray strMountPoint = mountPoint.local8Bit(); + QByteArray strFstype = fstype.local8Bit(); + + if( !dbus_message_append_args( dmesg, + DBUS_TYPE_STRING, strMountPoint.data(), + DBUS_TYPE_STRING, strFstype.data(), + DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &poptions, options.count(), + DBUS_TYPE_INVALID ) ) { + k3bDebug() << "(K3bDevice::HalConnection) mount failed for " << mediumUdi << ": could not append args to dbus message\n"; + dbus_message_unref( dmesg ); + freeArray( poptions, options.count() ); + return org_freedesktop_Hal_CommunicationError; + } + + freeArray( poptions, options.count() ); + + int ret = org_freedesktop_Hal_Success; + + dbus_error_init( &error ); + reply = dbus_connection_send_with_reply_and_block( d->connection, dmesg, -1, &error ); + if( dbus_error_is_set( &error ) ) { + kdError() << "(K3bDevice::HalConnection) mount failed for " << mediumUdi << ": " << error.name << " - " << error.message << endl; + if( !strcmp(error.name, "org.freedesktop.Hal.Device.Volume.NoSuchDevice" ) ) + ret = org_freedesktop_Hal_Device_Volume_NoSuchDevice; + else if( !strcmp(error.name, "org.freedesktop.Hal.Device.Volume.PermissionDenied" ) ) + ret = org_freedesktop_Hal_Device_Volume_PermissionDenied; + else if( !strcmp(error.name, "org.freedesktop.Hal.Device.Volume.UnknownFilesystemType" ) ) + ret = org_freedesktop_Hal_Device_Volume_UnknownFilesystemType; + else if( !strcmp(error.name, "org.freedesktop.Hal.Device.Volume.MountPointNotAvailable" ) ) + ret = org_freedesktop_Hal_Device_Volume_MountPointNotAvailable; + else if( !strcmp(error.name, "org.freedesktop.Hal.Device.Volume.AlreadyMounted" ) ) + ret = org_freedesktop_Hal_Device_Volume_AlreadyMounted; + else if( !strcmp(error.name, "org.freedesktop.Hal.Device.Volume.InvalidMountpoint" ) ) + ret = org_freedesktop_Hal_Device_Volume_InvalidMountpoint; + else if( !strcmp(error.name, "org.freedesktop.Hal.Device.Volume.InvalidMountOption" ) ) + ret = org_freedesktop_Hal_Device_Volume_InvalidMountOption; + else if( !strcmp(error.name, "org.freedesktop.Hal.Device.Volume.PermissionDeniedByPolicy" ) ) + ret = org_freedesktop_Hal_Device_Volume_PermissionDeniedByPolicy; + + dbus_error_free( &error ); + } + else + k3bDebug() << "(K3bDevice::HalConnection) mount queued for " << mediumUdi << endl; + + dbus_message_unref( dmesg ); + if( reply ) + dbus_message_unref( reply ); + + return ret; +} + + +int K3bDevice::HalConnection::unmount( K3bDevice::Device* dev, + const QStringList& options ) +{ + // + // The code below is based on the code from kioslave/media/mediamanager/halbackend.cpp in the kdebase package + // Copyright (c) 2004-2005 Jérôme Lodewyck <jerome dot lodewyck at normalesup dot org> + // + DBusMessage* dmesg = 0; + DBusMessage* reply = 0; + DBusError error; + + if( !d->deviceUdiMap.contains( dev->blockDeviceName() ) ) + return org_freedesktop_Hal_NoSuchDevice; + + if( !d->deviceMediumUdiMap.contains( d->deviceUdiMap[dev->blockDeviceName()] ) ) + return org_freedesktop_Hal_Device_Volume_NoSuchDevice; + + QCString mediumUdi = d->deviceMediumUdiMap[d->deviceUdiMap[dev->blockDeviceName()]]; + + if( !( dmesg = dbus_message_new_method_call( "org.freedesktop.Hal", mediumUdi.data(), + "org.freedesktop.Hal.Device.Volume", + "Unmount" ) ) ) { + k3bDebug() << "(K3bDevice::HalConnection) unmount failed for " << mediumUdi << ": could not create dbus message\n"; + return org_freedesktop_Hal_CommunicationError; + } + + char** poptions = qstringListToArray( options ); + + if( !dbus_message_append_args( dmesg, + DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &poptions, options.count(), + DBUS_TYPE_INVALID ) ) { + k3bDebug() << "(K3bDevice::HalConnection) unmount failed for " << mediumUdi << ": could not append args to dbus message\n"; + dbus_message_unref( dmesg ); + freeArray( poptions, options.count() ); + return org_freedesktop_Hal_CommunicationError; + } + + freeArray( poptions, options.count() ); + + int ret = org_freedesktop_Hal_Success; + + dbus_error_init( &error ); + reply = dbus_connection_send_with_reply_and_block( d->connection, dmesg, -1, &error ); + if( dbus_error_is_set( &error ) ) { + kdError() << "(K3bDevice::HalConnection) unmount failed for " << mediumUdi << ": " << error.name << " - " << error.message << endl; + if( !strcmp(error.name, "org.freedesktop.Hal.Device.Volume.NoSuchDevice" ) ) + ret = org_freedesktop_Hal_Device_Volume_NoSuchDevice; + else if( !strcmp(error.name, "org.freedesktop.Hal.Device.Volume.PermissionDenied" ) ) + ret = org_freedesktop_Hal_Device_Volume_PermissionDenied; + else if( !strcmp(error.name, "org.freedesktop.Hal.Device.Volume.MountPointNotAvailable" ) ) + ret = org_freedesktop_Hal_Device_Volume_MountPointNotAvailable; + else if( !strcmp(error.name, "org.freedesktop.Hal.Device.Volume.InvalidUnmountOption" ) ) + ret = org_freedesktop_Hal_Device_Volume_InvalidUnmountOption; + else if( !strcmp(error.name, "org.freedesktop.Hal.Device.Volume.InvalidMountpoint" ) ) + ret = org_freedesktop_Hal_Device_Volume_InvalidMountpoint; + else if( !strcmp(error.name, "org.freedesktop.Hal.Device.Volume.PermissionDeniedByPolicy" ) ) + ret = org_freedesktop_Hal_Device_Volume_PermissionDeniedByPolicy; + + dbus_error_free( &error ); + } + else + k3bDebug() << "(K3bDevice::HalConnection) unmount queued for " << mediumUdi << endl; + + dbus_message_unref( dmesg ); + if( reply ) + dbus_message_unref( reply ); + + return ret; +} + + +int K3bDevice::HalConnection::eject( K3bDevice::Device* dev, + const QStringList& options ) +{ + // + // The code below is based on the code from kioslave/media/mediamanager/halbackend.cpp in the kdebase package + // Copyright (c) 2004-2005 Jérôme Lodewyck <jerome dot lodewyck at normalesup dot org> + // + DBusMessage* dmesg = 0; + DBusMessage* reply = 0; + DBusError error; + + if( !d->deviceUdiMap.contains( dev->blockDeviceName() ) ) + return org_freedesktop_Hal_NoSuchDevice; + + if( !d->deviceMediumUdiMap.contains( d->deviceUdiMap[dev->blockDeviceName()] ) ) + return org_freedesktop_Hal_Device_Volume_NoSuchDevice; + + QCString mediumUdi = d->deviceMediumUdiMap[d->deviceUdiMap[dev->blockDeviceName()]]; + + if( !( dmesg = dbus_message_new_method_call( "org.freedesktop.Hal", mediumUdi.data(), + "org.freedesktop.Hal.Device.Volume", + "Eject" ) ) ) { + k3bDebug() << "(K3bDevice::HalConnection) eject failed for " << mediumUdi << ": could not create dbus message\n"; + return org_freedesktop_Hal_CommunicationError; + } + + char** poptions = qstringListToArray( options ); + + if( !dbus_message_append_args( dmesg, + DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &poptions, options.count(), + DBUS_TYPE_INVALID ) ) { + k3bDebug() << "(K3bDevice::HalConnection) eject failed for " << mediumUdi << ": could not append args to dbus message\n"; + dbus_message_unref( dmesg ); + freeArray( poptions, options.count() ); + return org_freedesktop_Hal_CommunicationError; + } + + freeArray( poptions, options.count() ); + + int ret = org_freedesktop_Hal_Success; + + dbus_error_init( &error ); + reply = dbus_connection_send_with_reply_and_block( d->connection, dmesg, -1, &error ); + if( dbus_error_is_set( &error ) ) { + kdError() << "(K3bDevice::HalConnection) eject failed for " << mediumUdi << ": " << error.name << " - " << error.message << endl; + if( !strcmp(error.name, "org.freedesktop.Hal.Device.Volume.NoSuchDevice" ) ) + ret = org_freedesktop_Hal_Device_Volume_NoSuchDevice; + else if( !strcmp(error.name, "org.freedesktop.Hal.Device.Volume.PermissionDenied" ) ) + ret = org_freedesktop_Hal_Device_Volume_PermissionDenied; + else if( !strcmp(error.name, "org.freedesktop.Hal.Device.Volume.InvalidEjectOption" ) ) + ret = org_freedesktop_Hal_Device_Volume_InvalidEjectOption; + else if( !strcmp(error.name, "org.freedesktop.Hal.Device.Volume.PermissionDeniedByPolicy" ) ) + ret = org_freedesktop_Hal_Device_Volume_PermissionDeniedByPolicy; + + dbus_error_free( &error ); + } + else + k3bDebug() << "(K3bDevice::HalConnection) eject queued for " << mediumUdi << endl; + + dbus_message_unref( dmesg ); + if( reply ) + dbus_message_unref( reply ); + + return ret; +} + + +void K3bDevice::HalConnection::setupDBusQtConnection( DBusConnection* dbusConnection ) +{ + d->dBusQtConnection = new DBusQt::Connection( this ); + d->dBusQtConnection->dbus_connection_setup_with_qt_main( dbusConnection ); +} + +#include "k3bhalconnection.moc" diff --git a/libk3bdevice/k3bhalconnection.h b/libk3bdevice/k3bhalconnection.h new file mode 100644 index 0000000..583bbf2 --- /dev/null +++ b/libk3bdevice/k3bhalconnection.h @@ -0,0 +1,223 @@ +/* + * + * $Id: sourceheader,v 1.3 2005/01/19 13:03:46 trueg Exp $ + * Copyright (C) 2005-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_HAL_CONNECTION_H_ +#define _K3B_HAL_CONNECTION_H_ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "k3bdevice_export.h" + +#include <qobject.h> +#include <qmap.h> +#include <qstringlist.h> + +class DBusConnection; + + +namespace K3bDevice { + + class Device; + + /** + * This is a simple HAL/DBUS wrapper which creates QT signals whenever a new optical + * drive is plugged into the system or one is unplugged. + * + * The HalConnection class also handles media changes. Whenever a new medium is inserted + * into a drive or a medium is removed (i.e. ejected) a signal is emitted. This way it + * is easy to keep track of the inserted media. + * + * This class does not deal with K3b devices but with system device names + * such as /dev/cdrom. These device names can be used in DeviceManager::findDevice(). + */ + class LIBK3BDEVICE_EXPORT HalConnection : public QObject + { + Q_OBJECT + + public: + ~HalConnection(); + + /** + * Creates a new singleton HalConnection object or returns the already existing one. + * A newly created HalConnection will emit newDevice signals for all devices in the HAL + * manager. However, since one cannot be sure if this is the first time the HalConnection + * is created it is recommended to connect to the signals and query the list of current + * devices. + * + * \return An instance of the singleton HalConnection object. + */ + static HalConnection* instance(); + + /** + * \return true if a connection to the HAL deamon could be established and + * communication has been set up. + */ + bool isConnected() const; + + /** + * \return a list of optical devices as reported by HAL. + */ + QStringList devices() const; + + /** + * \internal + */ + void addDevice( const char* udi ); + + /** + * \internal + */ + void removeDevice( const char* udi ); + + /** + * Error codes named as the HAL deamon raises them + */ + enum ErrorCodes { + org_freedesktop_Hal_Success = 0, //*< The operation was successful. This code does not match any in HAL + org_freedesktop_Hal_CommunicationError, //*< DBus communication error. This code does not match any in HAL + org_freedesktop_Hal_NoSuchDevice, + org_freedesktop_Hal_DeviceAlreadyLocked, + org_freedesktop_Hal_PermissionDenied, + org_freedesktop_Hal_Device_Volume_NoSuchDevice, + org_freedesktop_Hal_Device_Volume_PermissionDenied, + org_freedesktop_Hal_Device_Volume_AlreadyMounted, + org_freedesktop_Hal_Device_Volume_InvalidMountOption, + org_freedesktop_Hal_Device_Volume_UnknownFilesystemType, + org_freedesktop_Hal_Device_Volume_InvalidMountpoint, + org_freedesktop_Hal_Device_Volume_MountPointNotAvailable, + org_freedesktop_Hal_Device_Volume_PermissionDeniedByPolicy, + org_freedesktop_Hal_Device_Volume_InvalidUnmountOption, + org_freedesktop_Hal_Device_Volume_InvalidEjectOption + }; + + public slots: + /** + * Lock the device in HAL + * + * Be aware that once the method returns the HAL deamon has not necessarily + * finished the procedure yet. + * + * \param dev The device to lock + * \return An error code + * + * \see ErrorCode + */ + int lock( Device* ); + + /** + * Unlock a previously locked device in HAL + * + * Be aware that once the method returns the HAL deamon has not necessarily + * finished the procedure yet. + * + * \param dev The device to lock + * \return An error code + * + * \see ErrorCode + */ + int unlock( Device* ); + + /** + * Mounts a device via HAL + * + * Be aware that once the method returns the HAL deamon has not necessarily + * finished the procedure yet. + * + * \param dev The device to lock + * \return An error code + * + * \see ErrorCode + */ + int mount( Device*, + const QString& mountPoint = QString::null, + const QString& fstype = QString::null, + const QStringList& options = QStringList() ); + + /** + * Unmounts a device via HAL + * + * Be aware that once the method returns the HAL deamon has not necessarily + * finished the procedure yet. + * + * \param dev The device to lock + * \return An error code + * + * \see ErrorCode + */ + int unmount( Device*, + const QStringList& options = QStringList() ); + + /** + * Unmounts a device via HAL + * + * Be aware that once the method returns the HAL deamon has not necessarily + * finished the procedure yet. + * + * \param dev The device to lock + * \return An error code + * + * \see ErrorCode + */ + int eject( Device*, + const QStringList& options = QStringList() ); + + signals: + /** + * This signal gets emitted whenever HAL finds a new optical drive. + * + * \param dev The block device name of the new drive. + */ + void deviceAdded( const QString& dev ); + + /** + * This signal gets emitted whenever HAL detects that an optical drive + * has been unplugged. + * + * \param dev The block device name of the drive. + */ + void deviceRemoved( const QString& dev ); + + /** + * This signal gets emitted whenever a new medium is inserted into a + * device or an inserted is removed (i.e. ejected) + * + * \param dev The block device name of the drive the medium is or was inserted into. + */ + void mediumChanged( const QString& dev ); + + private: + /** + * HalConnection is a signelton class. Use the instance() method to create it. + */ + HalConnection( QObject* parent = 0, const char* name = 0 ); + + /** + * Tries to open a connection to HAL. + */ + bool open(); + void close(); + + static HalConnection* s_instance; + + class Private; + Private* d; + + void setupDBusQtConnection( DBusConnection* dbusConnection ); + }; +} + +#endif diff --git a/libk3bdevice/k3bmmc.h b/libk3bdevice/k3bmmc.h new file mode 100644 index 0000000..ebe2171 --- /dev/null +++ b/libk3bdevice/k3bmmc.h @@ -0,0 +1,697 @@ +/* + * + * $Id: k3bmmc.h 630384 2007-02-05 09:33:17Z mlaurent $ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_MMC_H_ +#define _K3B_MMC_H_ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + + +namespace K3bDevice +{ + /* + * struct disc_info taken from cdrwtool.h + * + * + * disc status (status): + * 00b - empty disc + * 01b - incomplete disc (appendable) + * 10b - Complete disc + * 11b - Others + * + * State of last session (border) + * 00b - Empty session + * 01b - Incomplete session + * 10b - Reseverd + * 11b - Complete session (only possible when disc status is complete) + */ + + typedef struct disc_info { + Q_UINT16 length; +#ifdef WORDS_BIGENDIAN // __BYTE_ORDER == __BIG_ENDIAN + unsigned char reserved1 : 3; + unsigned char erasable : 1; + unsigned char border : 2; + unsigned char status : 2; +#else + unsigned char status : 2; + unsigned char border : 2; + unsigned char erasable : 1; + unsigned char reserved1 : 3; +#endif + unsigned char n_first_track; + unsigned char n_sessions_l; + unsigned char first_track_l; + unsigned char last_track_l; +#ifdef WORDS_BIGENDIAN // __BYTE_ORDER == __BIG_ENDIAN + unsigned char did_v : 1; + unsigned char dbc_v : 1; + unsigned char uru : 1; + unsigned char reserved2 : 2; + unsigned char dbit : 1; + unsigned char bg_f_status : 1; +#else + unsigned char bg_f_status : 1; + unsigned char dbit : 1; + unsigned char reserved2 : 2; + unsigned char uru : 1; + unsigned char dbc_v : 1; + unsigned char did_v : 1; +#endif + + /* + * disc type + * 00h - CD-DA of CDROM + * 10h - CD-I + * 20h - CD-ROM XA + * FFh - Undefined + * All other values are reserved + */ + unsigned char disc_type; + unsigned char n_sessions_m; + unsigned char first_track_m; + unsigned char last_track_m; + Q_UINT32 disc_id; + + /* + * Last session lead-in start time + * if the disc is complete this shall be FF/FF/FF + */ + unsigned char lead_in_r; + unsigned char lead_in_m; + unsigned char lead_in_s; + unsigned char lead_in_f; + + /* + * Last possible start time for start of lead-in + * if the disc is complete this shall be FF/FF/FF + */ + unsigned char lead_out_r; + unsigned char lead_out_m; + unsigned char lead_out_s; + unsigned char lead_out_f; + + unsigned char disc_bar_code[8]; + + // + // We need to make sure the structure has a proper size + // I think it needs to be a power of 2. + // With ide-scsi there is no problem. But without the + // GPCMD_READ_DISC_INFO command failes if the size is 34 + // + +/* unsigned char reserved3; */ +/* unsigned char opc_entries; */ + } disc_info_t; + + + + /* + * struct track_info taken from cdrwtool.h + */ + typedef struct track_info { + unsigned char data_length[2]; + unsigned char track_number_l; + unsigned char session_number_l; + unsigned char reserved1; +#ifdef WORDS_BIGENDIAN // __BYTE_ORDER == __BIG_ENDIAN + unsigned char reserved2 : 2; + unsigned char damage : 1; + unsigned char copy : 1; + unsigned char track_mode : 4; + unsigned char rt : 1; + unsigned char blank : 1; + unsigned char packet : 1; + unsigned char fp : 1; + unsigned char data_mode : 4; + unsigned char reserved3 : 6; + unsigned char lra_v : 1; + unsigned char nwa_v : 1; +#else + unsigned char track_mode : 4; + unsigned char copy : 1; + unsigned char damage : 1; + unsigned char reserved2 : 2; + unsigned char data_mode : 4; + unsigned char fp : 1; + unsigned char packet : 1; + unsigned char blank : 1; + unsigned char rt : 1; + unsigned char nwa_v : 1; + unsigned char lra_v : 1; + unsigned char reserved3 : 6; +#endif + unsigned char track_start[4]; + unsigned char next_writable[4]; + unsigned char free_blocks[4]; + unsigned char packet_size[4]; + unsigned char track_size[4]; + unsigned char last_recorded[4]; + unsigned char track_number_m; + unsigned char session_number_m; + unsigned char reserved4; + unsigned char reserved5; + unsigned char read_compatibility[4]; + } track_info_t; + + + /* + * Use this with the GPCMD_READ_TOC_PMA_ATIP command + * where format is set to 2 (Full TOC) + */ + struct toc_raw_track_descriptor { + unsigned char session_number; +#ifdef WORDS_BIGENDIAN // __BYTE_ORDER == __BIG_ENDIAN + unsigned char adr : 4; + unsigned char control : 4; +#else + unsigned char control : 4; + unsigned char adr : 4; +#endif + unsigned char tno; + unsigned char point; + unsigned char min; + unsigned char sec; + unsigned char frame; + unsigned char zero; + unsigned char p_min; + unsigned char p_sec; + unsigned char p_frame; + }; + + +#ifdef WORDS_BIGENDIAN // __BYTE_ORDER == __BIG_ENDIAN + struct cd_wr_speed_performance { + unsigned char res0; /* Reserved */ + unsigned char res_1_27 : 6; /* Reserved */ + unsigned char rot_ctl_sel : 2; /* Rotational control selected */ + unsigned char wr_speed_supp[2]; /* Supported write speed */ + }; +#else + struct cd_wr_speed_performance { + unsigned char res0; /* Reserved */ + unsigned char rot_ctl_sel : 2; /* Rotational control selected */ + unsigned char res_1_27 : 6; /* Reserved */ + unsigned char wr_speed_supp[2]; /* Supported write speed */ + }; +#endif + + + /** + * Based on the cdrecord struct cd_mode_page_2A + * MM Capabilities and Mechanical Status Page + */ +#ifdef WORDS_BIGENDIAN // __BYTE_ORDER == __BIG_ENDIAN + + struct mm_cap_page_2A { + unsigned char PS : 1; + unsigned char res_1 : 1; + unsigned char page_code : 6; + unsigned char page_len; /* 0x14 = 20 Bytes (MMC) */ + /* 0x18 = 24 Bytes (MMC-2) */ + /* 0x1C >= 28 Bytes (MMC-3) */ + unsigned char res_2_67 : 2; /* Reserved */ + unsigned char dvd_ram_read : 1; /* Reads DVD-RAM media */ + unsigned char dvd_r_read : 1; /* Reads DVD-R media */ + unsigned char dvd_rom_read : 1; /* Reads DVD ROM media */ + unsigned char method2 : 1; /* Reads fixed packet method2 media */ + unsigned char cd_rw_read : 1; /* Reads CD-RW media */ + unsigned char cd_r_read : 1; /* Reads CD-R media */ + unsigned char res_3_67 : 2; /* Reserved */ + unsigned char dvd_ram_write : 1; /* Supports writing DVD-RAM media */ + unsigned char dvd_r_write : 1; /* Supports writing DVD-R media */ + unsigned char res_3_3 : 1; /* Reserved */ + unsigned char test_write : 1; /* Supports emulation write */ + unsigned char cd_rw_write : 1; /* Supports writing CD-RW media */ + unsigned char cd_r_write : 1; /* Supports writing CD-R media */ + unsigned char BUF : 1; /* Supports Buffer under. free rec. */ + unsigned char multi_session : 1; /* Reads multi-session media */ + unsigned char mode_2_form_2 : 1; /* Reads Mode-2 form 2 media */ + unsigned char mode_2_form_1 : 1; /* Reads Mode-2 form 1 media (XA) */ + unsigned char digital_port_1 : 1; /* Supports digital output on port 1 */ + unsigned char digital_port_2 : 1; /* Supports digital output on port 2 */ + unsigned char composite : 1; /* Deliveres composite A/V stream */ + unsigned char audio_play : 1; /* Supports Audio play operation */ + unsigned char read_bar_code : 1; /* Supports reading bar codes */ + unsigned char UPC : 1; /* Reads media catalog number (UPC) */ + unsigned char ISRC : 1; /* Reads ISRC information */ + unsigned char c2_pointers : 1; /* Supports C2 error pointers */ + unsigned char rw_deint_corr : 1; /* Reads de-interleved R-W sub chan */ + unsigned char rw_supported : 1; /* Reads R-W sub channel information */ + unsigned char cd_da_accurate : 1; /* READ CD data stream is accurate */ + unsigned char cd_da_supported : 1; /* Reads audio data with READ CD cmd */ + unsigned char loading_type : 3; /* Loading mechanism type */ + unsigned char res_6_4 : 1; /* Reserved */ + unsigned char eject : 1; /* Ejects disc/cartr with STOP LoEj */ + unsigned char prevent_jumper : 1; /* State of prev/allow jumper 0=pres */ + unsigned char lock_state : 1; /* Lock state 0=unlocked 1=locked */ + unsigned char lock : 1; /* PREVENT/ALLOW may lock media */ + unsigned char res_7 : 2; /* Reserved */ + unsigned char rw_in_lead_in : 1; /* Reads raw R-W subcode from lead in */ + unsigned char side_change : 1; /* Side change capable */ + unsigned char sw_slot_sel : 1; /* Load empty slot in changer */ + unsigned char disk_present_rep : 1; /* Changer supports disk present rep */ + unsigned char sep_chan_mute : 1; /* Mute controls each channel separat*/ + unsigned char sep_chan_vol : 1; /* Vol controls each channel separat */ + unsigned char max_read_speed[2]; /* Max. read speed in KB/s */ + /* obsolete in MMC-4 */ + unsigned char num_vol_levels[2]; /* # of supported volume levels */ + unsigned char buffer_size[2]; /* Buffer size for the data in KB */ + unsigned char cur_read_speed[2]; /* Current read speed in KB/s */ + /* obsolete in MMC-4 */ + unsigned char res_16; /* Reserved */ + unsigned char res_17 : 2; /* Reserved */ + unsigned char length : 2; /* 0=32BCKs 1=16BCKs 2=24BCKs 3=24I2c*/ + unsigned char LSBF : 1; /* Set: LSB first Clear: MSB first */ + unsigned char RCK : 1; /* Set: HIGH high LRCK=left channel */ + unsigned char BCK : 1; /* Data valid on falling edge of BCK */ + unsigned char res_17_0 : 1; /* Reserved */ + unsigned char max_write_speed[2]; /* Max. write speed supported in KB/s*/ + /* obsolete in MMC-4 */ + unsigned char cur_write_speed[2]; /* Current write speed in KB/s */ + /* obsolete in MMC-4 */ + + /* Byte 22 ... Only in MMC-2 */ + unsigned char copy_man_rev[2]; /* Copy management revision supported*/ + unsigned char res_24; /* Reserved */ + unsigned char res_25; /* Reserved */ + + /* Byte 26 ... Only in MMC-3 */ + unsigned char res_26; /* Reserved */ + unsigned char res_27_27 : 6; /* Reserved */ + unsigned char rot_ctl_sel : 2; /* Rotational control selected */ + unsigned char v3_cur_write_speed[2]; /* Current write speed in KB/s */ + unsigned char num_wr_speed_des[2]; /* # of wr speed perf descr. tables */ + struct cd_wr_speed_performance + wr_speed_des[1]; /* wr speed performance descriptor */ + /* Actually more (num_wr_speed_des) */ + }; + +#else // LITTLE_ENDIAN + + struct mm_cap_page_2A { + unsigned char page_code : 6; + unsigned char res_1 : 1; + unsigned char PS : 1; + unsigned char page_len; /* 0x14 = 20 Bytes (MMC) */ + /* 0x18 = 24 Bytes (MMC-2) */ + /* 0x1C >= 28 Bytes (MMC-3) */ + unsigned char cd_r_read : 1; /* Reads CD-R media */ + unsigned char cd_rw_read : 1; /* Reads CD-RW media */ + unsigned char method2 : 1; /* Reads fixed packet method2 media */ + unsigned char dvd_rom_read : 1; /* Reads DVD ROM media */ + unsigned char dvd_r_read : 1; /* Reads DVD-R media */ + unsigned char dvd_ram_read : 1; /* Reads DVD-RAM media */ + unsigned char res_2_67 : 2; /* Reserved */ + unsigned char cd_r_write : 1; /* Supports writing CD-R media */ + unsigned char cd_rw_write : 1; /* Supports writing CD-RW media */ + unsigned char test_write : 1; /* Supports emulation write */ + unsigned char res_3_3 : 1; /* Reserved */ + unsigned char dvd_r_write : 1; /* Supports writing DVD-R media */ + unsigned char dvd_ram_write : 1; /* Supports writing DVD-RAM media */ + unsigned char res_3_67 : 2; /* Reserved */ + unsigned char audio_play : 1; /* Supports Audio play operation */ + unsigned char composite : 1; /* Deliveres composite A/V stream */ + unsigned char digital_port_2 : 1; /* Supports digital output on port 2 */ + unsigned char digital_port_1 : 1; /* Supports digital output on port 1 */ + unsigned char mode_2_form_1 : 1; /* Reads Mode-2 form 1 media (XA) */ + unsigned char mode_2_form_2 : 1; /* Reads Mode-2 form 2 media */ + unsigned char multi_session : 1; /* Reads multi-session media */ + unsigned char BUF : 1; /* Supports Buffer under. free rec. */ + unsigned char cd_da_supported : 1; /* Reads audio data with READ CD cmd */ + unsigned char cd_da_accurate : 1; /* READ CD data stream is accurate */ + unsigned char rw_supported : 1; /* Reads R-W sub channel information */ + unsigned char rw_deint_corr : 1; /* Reads de-interleved R-W sub chan */ + unsigned char c2_pointers : 1; /* Supports C2 error pointers */ + unsigned char ISRC : 1; /* Reads ISRC information */ + unsigned char UPC : 1; /* Reads media catalog number (UPC) */ + unsigned char read_bar_code : 1; /* Supports reading bar codes */ + unsigned char lock : 1; /* PREVENT/ALLOW may lock media */ + unsigned char lock_state : 1; /* Lock state 0=unlocked 1=locked */ + unsigned char prevent_jumper : 1; /* State of prev/allow jumper 0=pres */ + unsigned char eject : 1; /* Ejects disc/cartr with STOP LoEj */ + unsigned char res_6_4 : 1; /* Reserved */ + unsigned char loading_type : 3; /* Loading mechanism type */ + unsigned char sep_chan_vol : 1; /* Vol controls each channel separat */ + unsigned char sep_chan_mute : 1; /* Mute controls each channel separat*/ + unsigned char disk_present_rep : 1; /* Changer supports disk present rep */ + unsigned char sw_slot_sel : 1; /* Load empty slot in changer */ + unsigned char side_change : 1; /* Side change capable */ + unsigned char rw_in_lead_in : 1; /* Reads raw R-W subcode from lead in */ + unsigned char res_7 : 2; /* Reserved */ + unsigned char max_read_speed[2]; /* Max. read speed in KB/s */ + /* obsolete in MMC-4 */ + unsigned char num_vol_levels[2]; /* # of supported volume levels */ + unsigned char buffer_size[2]; /* Buffer size for the data in KB */ + unsigned char cur_read_speed[2]; /* Current read speed in KB/s */ + /* obsolete in MMC-4 */ + unsigned char res_16; /* Reserved */ + unsigned char res_17_0 : 1; /* Reserved */ + unsigned char BCK : 1; /* Data valid on falling edge of BCK */ + unsigned char RCK : 1; /* Set: HIGH high LRCK=left channel */ + unsigned char LSBF : 1; /* Set: LSB first Clear: MSB first */ + unsigned char length : 2; /* 0=32BCKs 1=16BCKs 2=24BCKs 3=24I2c*/ + unsigned char res_17 : 2; /* Reserved */ + unsigned char max_write_speed[2]; /* Max. write speed supported in KB/s*/ + /* obsolete in MMC-4 */ + unsigned char cur_write_speed[2]; /* Current write speed in KB/s */ + /* obsolete in MMC-4 */ + + /* Byte 22 ... Only in MMC-2 */ + unsigned char copy_man_rev[2]; /* Copy management revision supported*/ + unsigned char res_24; /* Reserved */ + unsigned char res_25; /* Reserved */ + + /* Byte 26 ... Only in MMC-3 */ + unsigned char res_26; /* Reserved */ + unsigned char rot_ctl_sel : 2; /* Rotational control selected */ + unsigned char res_27_27 : 6; /* Reserved */ + unsigned char v3_cur_write_speed[2]; /* Current write speed in KB/s */ + unsigned char num_wr_speed_des[2]; /* # of wr speed perf descr. tables */ + struct cd_wr_speed_performance + wr_speed_des[1]; /* wr speed performance descriptor */ + /* Actually more (num_wr_speed_des) */ + }; +#endif + + /** + * Based on the cdrecord struct cd_mode_page_05 + * Write Parameters Mode Page + */ +#ifdef WORDS_BIGENDIAN // __BYTE_ORDER == __BIG_ENDIAN + struct wr_param_page_05 { /* write parameters */ + unsigned char PS : 1; + unsigned char res_1 : 1; + unsigned char page_code : 6; + unsigned char page_len; /* 0x32 = 50 Bytes */ + unsigned char res_2_7 : 1; + unsigned char BUFE : 1; /* Enable Bufunderrun free rec. */ + unsigned char LS_V : 1; /* Link size valid */ + unsigned char test_write : 1; /* Do not actually write data */ + unsigned char write_type : 4; /* Session write type (PACKET/TAO...)*/ + unsigned char multi_session : 2; /* Multi session write type */ + unsigned char fp : 1; /* Fixed packed (if in packet mode) */ + unsigned char copy : 1; /* 1st higher gen of copy prot track */ + unsigned char track_mode : 4; /* Track mode (Q-sub control nibble) */ + unsigned char res_4 : 4; /* Reserved */ + unsigned char dbtype : 4; /* Data block type */ + unsigned char link_size; /* Link Size (default is 7) */ + unsigned char res_6; /* Reserved */ + unsigned char res_7 : 2; /* Reserved */ + unsigned char host_appl_code : 6; /* Host application code of disk */ + unsigned char session_format; /* Session format (DA/CDI/XA) */ + unsigned char res_9; /* Reserved */ + unsigned char packet_size[4]; /* # of user datablocks/fixed packet */ + unsigned char audio_pause_len[2]; /* # of blocks where index is zero */ + unsigned char media_cat_number[16]; /* Media catalog Number (MCN) */ + unsigned char ISRC[14]; /* ISRC for this track */ + unsigned char sub_header[4]; + unsigned char vendor_uniq[4]; + }; + +#else // __LITTLE_ENDIAN + struct wr_param_page_05 { /* write parameters */ + unsigned char page_code : 6; + unsigned char res_1 : 1; + unsigned char PS : 1; + unsigned char p_len; /* 0x32 = 50 Bytes */ + unsigned char write_type : 4; /* Session write type (PACKET/TAO...)*/ + unsigned char test_write : 1; /* Do not actually write data */ + unsigned char LS_V : 1; /* Link size valid */ + unsigned char BUFE : 1; /* Enable Bufunderrun free rec. */ + unsigned char res_2_7 : 1; + unsigned char track_mode : 4; /* Track mode (Q-sub control nibble) */ + unsigned char copy : 1; /* 1st higher gen of copy prot track ~*/ + unsigned char fp : 1; /* Fixed packed (if in packet mode) */ + unsigned char multi_session : 2; /* Multi session write type */ + unsigned char dbtype : 4; /* Data block type */ + unsigned char res_4 : 4; /* Reserved */ + unsigned char link_size; /* Link Size (default is 7) */ + unsigned char res_6; /* Reserved */ + unsigned char host_appl_code : 6; /* Host application code of disk */ + unsigned char res_7 : 2; /* Reserved */ + unsigned char session_format; /* Session format (DA/CDI/XA) */ + unsigned char res_9; /* Reserved */ + unsigned char packet_size[4]; /* # of user datablocks/fixed packet */ + unsigned char audio_pause_len[2]; /* # of blocks where index is zero */ + unsigned char media_cat_number[16]; /* Media catalog Number (MCN) */ + unsigned char ISRC[14]; /* ISRC for this track */ + unsigned char sub_header[4]; + unsigned char vendor_uniq[4]; + }; +#endif + + + struct toc_track_descriptor { + unsigned char res1; +#ifdef WORDS_BIGENDIAN // __BYTE_ORDER == __BIG_ENDIAN + unsigned char adr : 4; + unsigned char control : 4; +#else + unsigned char control : 4; + unsigned char adr : 4; +#endif + unsigned char track_no; + unsigned char res2; + unsigned char start_adr[4]; + }; + + + struct atip_descriptor { + unsigned char dataLength[2]; + unsigned char res1; + unsigned char res2; +#ifdef WORDS_BIGENDIAN // __BYTE_ORDER == __BIG_ENDIAN + unsigned char ind_wr_power : 4; // indicated writing power + unsigned char ddcd : 1; // DDCD + unsigned char ref_speed : 3; // reference Speed + unsigned char zero : 1; // 0 + unsigned char uru : 1; // Uru + unsigned char res3 : 6; + unsigned char one : 1; // 1 + unsigned char disc_type : 1; // Disc Type + unsigned char disc_subtype : 3; // Disc Sub-Type + unsigned char a1_valid : 1; + unsigned char a2_valid : 1; + unsigned char a3_valid : 1; +#else + unsigned char ref_speed : 3; // reference Speed + unsigned char ddcd : 1; // DDCD + unsigned char ind_wr_power : 4; // indicated writing power + unsigned char res3 : 6; + unsigned char uru : 1; // Uru + unsigned char zero : 1; // 0 + unsigned char a3_valid : 1; + unsigned char a2_valid : 1; + unsigned char a1_valid : 1; + unsigned char disc_subtype : 3; // Disc Sub-Type + unsigned char disc_type : 1; // Disc Type + unsigned char one : 1; // 1 +#endif + unsigned char res4; + unsigned char lead_in_m; + unsigned char lead_in_s; + unsigned char lead_in_f; + unsigned char res5; + unsigned char lead_out_m; + unsigned char lead_out_s; + unsigned char lead_out_f; + unsigned char res6; + unsigned char a1[3]; + unsigned char res7; + unsigned char a2[3]; + unsigned char res8; + unsigned char a3[3]; + unsigned char res9; + unsigned char s4[3]; + unsigned char res10; + }; + + + struct mechanism_status_header { +#ifdef WORDS_BIGENDIAN // __BYTE_ORDER == __BIG_ENDIAN + unsigned char fault : 1; + unsigned char changer_state : 2; + unsigned char slot_low : 5; +#else + unsigned char slot_low : 5; + unsigned char changer_state : 2; + unsigned char fault : 1; +#endif +#ifdef WORDS_BIGENDIAN // __BYTE_ORDER == __BIG_ENDIAN + unsigned char mech_state : 3; + unsigned char door_open : 1; + unsigned char res1 : 1; + unsigned char slot_high : 3; +#else + unsigned char slot_high : 3; + unsigned char res1 : 1; + unsigned char door_open : 1; + unsigned char mech_state : 3; +#endif + unsigned char current_lba[3]; + unsigned char num_slots; + unsigned char slot_len[2]; + }; + + struct mechanism_status_slot { +#ifdef WORDS_BIGENDIAN // __BYTE_ORDER == __BIG_ENDIAN + unsigned char disc_present : 1; + unsigned char res1 : 6; + unsigned char change : 1; +#else + unsigned char change : 1; + unsigned char res1 : 6; + unsigned char disc_present : 1; +#endif +#ifdef WORDS_BIGENDIAN // __BYTE_ORDER == __BIG_ENDIAN + unsigned char res2 : 6; + unsigned char cwp_v : 1; + unsigned char cwp : 1; +#else + unsigned char cwp : 1; + unsigned char cwp_v : 1; + unsigned char res2 : 6; +#endif + unsigned char res3; + unsigned char res4; + }; + + + struct inquiry { +#ifdef WORDS_BIGENDIAN // __BYTE_ORDER == __BIG_ENDIAN + unsigned char p_qualifier : 3; + unsigned char p_device_type : 5; + unsigned char rmb : 1; + unsigned char reserved1 : 7; +#else + unsigned char p_device_type : 5; + unsigned char p_qualifier : 3; + unsigned char reserved1 : 7; + unsigned char rmb : 1; +#endif + unsigned char version; +#ifdef WORDS_BIGENDIAN // __BYTE_ORDER == __BIG_ENDIAN + unsigned char interface_dep : 4; + unsigned char data_format : 4; +#else + unsigned char data_format : 4; + unsigned char interface_dep : 4; +#endif + unsigned char add_length; + unsigned char reserved2; +#ifdef WORDS_BIGENDIAN // __BYTE_ORDER == __BIG_ENDIAN + unsigned char bque : 1; + unsigned char enc_serv : 1; + unsigned char vs1 : 1; + unsigned char multi_p : 1; + unsigned char m_chngr : 1; + unsigned char reserved3 : 1; + unsigned char reserved4 : 1; + unsigned char addr_16 : 1; + unsigned char rel_adr : 1; + unsigned char reserved5 : 1; + unsigned char w_bus_16 : 1; + unsigned char sync : 1; + unsigned char linked : 1; + unsigned char reserved6 : 1; + unsigned char cmd_que : 1; + unsigned char vs2 : 1; +#else + unsigned char addr_16 : 1; + unsigned char reserved4 : 1; + unsigned char reserved3 : 1; + unsigned char m_chngr : 1; + unsigned char multi_p : 1; + unsigned char vs1 : 1; + unsigned char enc_serv : 1; + unsigned char bque : 1; + unsigned char vs2 : 1; + unsigned char cmd_que : 1; + unsigned char reserved6 : 1; + unsigned char linked : 1; + unsigned char sync : 1; + unsigned char w_bus_16 : 1; + unsigned char reserved5 : 1; + unsigned char rel_adr : 1; +#endif + unsigned char vendor[8]; + unsigned char product[16]; + unsigned char revision[4]; + unsigned char vendor_specific[20]; + unsigned char reserved7[2]; + unsigned char version1[2]; + unsigned char version2[2]; + unsigned char version3[2]; + unsigned char version4[2]; + unsigned char version5[2]; + unsigned char version6[2]; + unsigned char version7[2]; + unsigned char version8[2]; + + // bytes 74-95: reserved + // bytes 96-n: vendor specific + }; + + + struct ricoh_mode_page_30 { +#ifdef WORDS_BIGENDIAN // __BYTE_ORDER == __BIG_ENDIAN + unsigned char PS : 1; + unsigned char res_1 : 1; + unsigned char page_code : 6; +#else + unsigned char page_code : 6; + unsigned char res_1 : 1; + unsigned char PS : 1; +#endif + unsigned char page_len; /* 0xE = 14 Bytes */ +#ifdef WORDS_BIGENDIAN // __BYTE_ORDER == __BIG_ENDIAN + unsigned char res_2_67 :2; + unsigned char AWSCS :1; /* Auto write speed control supp. */ + unsigned char ARSCS :1; /* Auto read speed control supp. */ + unsigned char res_2_23 :2; + unsigned char TWBFS :1; /* Test Burn-Free sup. */ + unsigned char BUEFS :1; /* Burn-Free supported */ +#else + unsigned char BUEFS :1; /* Burn-Free supported */ + unsigned char TWBFS :1; /* Test Burn-Free sup. */ + unsigned char res_2_23 :2; + unsigned char ARSCS :1; /* Auto read speed control supp. */ + unsigned char AWSCS :1; /* Auto write speed control supp. */ + unsigned char res_2_67 :2; +#endif +#ifdef WORDS_BIGENDIAN // __BYTE_ORDER == __BIG_ENDIAN + unsigned char res_3_67 :2; + unsigned char AWSCD :1; /* Auto write speed control disabled */ + unsigned char ARSCE :1; /* Auto read speed control enabled */ + unsigned char res_2_13 :3; + unsigned char BUEFE :1; /* Burn-Free enabled */ +#else + unsigned char BUEFE :1; /* Burn-Free enabled */ + unsigned char res_2_13 :3; + unsigned char ARSCE :1; /* Auto read speed control enabled */ + unsigned char AWSCD :1; /* Auto write speed control disabled */ + unsigned char res_3_67 :2; +#endif + unsigned char link_counter[2]; /* Burn-Free link counter */ + unsigned char res[10]; /* Padding up to 16 bytes */ + }; +} + + +#endif diff --git a/libk3bdevice/k3bmsf.cpp b/libk3bdevice/k3bmsf.cpp new file mode 100644 index 0000000..c7257a1 --- /dev/null +++ b/libk3bdevice/k3bmsf.cpp @@ -0,0 +1,335 @@ +/* + * + * $Id: k3bmsf.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bmsf.h" +#include <qregexp.h> + +#include <math.h> + + +K3b::Msf::Msf() + : m_minutes(0), + m_seconds(0), + m_frames(0) +{ +} + +K3b::Msf::Msf( const K3b::Msf& m ) + : m_minutes(m.minutes()), + m_seconds(m.seconds()), + m_frames(m.frames()) +{ +} + +K3b::Msf::Msf( int m, int s, int f ) + : m_minutes(m), + m_seconds(s), + m_frames(f) +{ + makeValid(); +} + +K3b::Msf::Msf( int i ) + : m_minutes(0), + m_seconds(0), + m_frames(i) +{ + makeValid(); +} + + +void K3b::Msf::setValue( int m, int s, int f ) +{ + m_minutes = m; + m_seconds = s; + m_frames = f; + makeValid(); +} + + +void K3b::Msf::addMinutes( int m ) +{ + m_minutes += m; + makeValid(); +} + +void K3b::Msf::addSeconds( int s ) +{ + m_seconds += s; + makeValid(); +} + +void K3b::Msf::addFrames( int f ) +{ + m_frames += f; + makeValid(); +} + +K3b::Msf& K3b::Msf::operator=( const K3b::Msf& m ) +{ + m_frames = m.frames(); + m_seconds = m.seconds(); + m_minutes = m.minutes(); + return *this; +} + +K3b::Msf& K3b::Msf::operator=( int i ) +{ + m_frames = i; + m_seconds = 0; + m_minutes = 0; + makeValid(); + return *this; +} + +K3b::Msf& K3b::Msf::operator+=( const K3b::Msf& m ) +{ + m_frames += m.frames(); + m_seconds += m.seconds(); + m_minutes += m.minutes(); + makeValid(); + return *this; +} + +K3b::Msf& K3b::Msf::operator+=( int i ) +{ + addFrames(i); + return *this; +} + +K3b::Msf& K3b::Msf::operator-=( const K3b::Msf& m ) +{ + m_frames -= m.frames(); + m_seconds -= m.seconds(); + m_minutes -= m.minutes(); + makeValid(); + return *this; +} + +K3b::Msf& K3b::Msf::operator-=( int i ) +{ + m_frames -= i; + makeValid(); + return *this; +} + + +const K3b::Msf K3b::Msf::operator++( int ) +{ + Msf old = *this; + ++(*this); + return old; +} + + +K3b::Msf& K3b::Msf::operator++() +{ + (*this) += 1; + return *this; +} + + +const K3b::Msf K3b::Msf::operator--( int ) +{ + Msf old = *this; + --(*this); + return old; +} + + +K3b::Msf& K3b::Msf::operator--() +{ + (*this) -= 1; + return *this; +} + + +QString K3b::Msf::toString( bool showFrames ) const +{ + QString str; + + if( showFrames ) + str.sprintf( "%.2i:%.2i:%.2i", m_minutes, m_seconds, m_frames ); + else + str.sprintf( "%.2i:%.2i", m_minutes, m_seconds ); + + return str; +} + + +KIO::filesize_t K3b::Msf::mode1Bytes() const +{ + return (KIO::filesize_t)2048 * ( (KIO::filesize_t)lba() ); +} + +KIO::filesize_t K3b::Msf::mode2Form1Bytes() const +{ + return (KIO::filesize_t)2048 * ( (KIO::filesize_t)lba() ); +} + +KIO::filesize_t K3b::Msf::mode2Form2Bytes() const +{ + return (KIO::filesize_t)2324 * ( (KIO::filesize_t)lba() ); +} + +KIO::filesize_t K3b::Msf::audioBytes() const +{ + return (KIO::filesize_t)2352 * ( (KIO::filesize_t)lba() ); +} + +KIO::filesize_t K3b::Msf::rawBytes() const +{ + return (KIO::filesize_t)2448 * ( (KIO::filesize_t)lba() ); +} + +void K3b::Msf::makeValid() +{ + if( m_frames < 0 ) { + int newFrames = m_frames/-75 + 1; + m_seconds -= newFrames; + m_frames += 75*newFrames; + } + m_seconds += m_frames/75; + m_frames = m_frames % 75; + if( m_seconds < 0 ) { + int newSecs = m_seconds/-60 + 1; + m_minutes -= newSecs; + m_seconds += 60*newSecs; + } + m_minutes += m_seconds/60; + m_seconds = m_seconds % 60; + if( m_minutes < 0 ) { + m_minutes = 0; + m_seconds = 0; + m_frames = 0; + } +} + + + +QRegExp K3b::Msf::regExp() +{ + // + // An MSF can have the following formats: + // 100 (treated as frames) + // 100:23 (minutes:seconds) + // 100:23:72 (minutes:seconds:frames) + // 100:23.72 (minutes:seconds.frames) + // + static QRegExp rx( "(\\d+)(?::([0-5]?\\d)(?:[:\\.]((?:[0-6]?\\d)|(?:7[0-4])))?)?" ); + return rx; +} + + +K3b::Msf K3b::Msf::fromSeconds( double ms ) +{ + return K3b::Msf( static_cast<int>( ::ceil(ms*75.0) ) ); +} + + +K3b::Msf K3b::Msf::fromString( const QString& s, bool* ok ) +{ + QRegExp rx = regExp(); + + K3b::Msf msf; + + if( rx.exactMatch( s ) ) { + // + // first number - cap(1) + // second number - cap(2) + // third number - cap(3) + // + if( rx.cap(2).isEmpty() ) { + msf.m_frames = rx.cap(1).toInt(); + } + else { + msf.m_minutes = rx.cap(1).toInt(); + msf.m_seconds = rx.cap(2).toInt(); + msf.m_frames = rx.cap(3).toInt(); + } + + if( ok ) + *ok = true; + } + else if( ok ) + *ok = false; + + msf.makeValid(); + + return msf; +} + + + +K3b::Msf K3b::operator+( const K3b::Msf& m1, const K3b::Msf& m2 ) +{ + K3b::Msf msf(m1); + return msf += m2; +} + +K3b::Msf K3b::operator+( const K3b::Msf& m, int i ) +{ + K3b::Msf msf(m); + return msf += i; +} + +K3b::Msf K3b::operator-( const K3b::Msf& m1, const K3b::Msf& m2 ) +{ + K3b::Msf msf(m1); + return msf -= m2; +} + +K3b::Msf K3b::operator-( const K3b::Msf& m, int i ) +{ + K3b::Msf msf(m); + return msf -= i; +} + +bool K3b::operator==( const K3b::Msf& m1, const K3b::Msf& m2 ) +{ + return ( m1.minutes() == m2.minutes() && + m1.seconds() == m2.seconds() && + m1.frames() == m2.frames() ); +} + +bool K3b::operator!=( const K3b::Msf& m1, const K3b::Msf& m2 ) +{ + return !operator==( m1, m2 ); +} + +bool K3b::operator<( const K3b::Msf& m1, const K3b::Msf& m2 ) +{ + return ( m1.lba() < m2.lba() ); +} + +bool K3b::operator>( const K3b::Msf& m1, const K3b::Msf& m2 ) +{ + return ( m1.lba() > m2.lba() ); +} + +bool K3b::operator<=( const K3b::Msf& m1, const K3b::Msf& m2 ) +{ + return ( m1.lba() <= m2.lba() ); +} + +bool K3b::operator>=( const K3b::Msf& m1, const K3b::Msf& m2 ) +{ + return ( m1.lba() >= m2.lba() ); +} + +kdbgstream& K3b::operator<<( kdbgstream& s, const Msf& m ) +{ + return s << m.toString(); +} diff --git a/libk3bdevice/k3bmsf.h b/libk3bdevice/k3bmsf.h new file mode 100644 index 0000000..d2209c3 --- /dev/null +++ b/libk3bdevice/k3bmsf.h @@ -0,0 +1,118 @@ +/* + * + * $Id: k3bmsf.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_MSF_H_ +#define _K3B_MSF_H_ + +#include <qstring.h> +#include <qregexp.h> + +#include <kdebug.h> +#include <kio/global.h> +#include "k3bdevice_export.h" + +namespace K3b +{ + /** + * int values are always treated as frames + * except in the set methods + * A MSF is never < 0. + */ + class LIBK3BDEVICE_EXPORT Msf + { + public: + Msf(); + Msf( const Msf& ); + Msf( int, int, int ); + Msf( int ); + + Msf& operator=( const Msf& ); + Msf& operator=( int ); + Msf& operator+=( const Msf& ); + Msf& operator+=( int ); + Msf& operator-=( const Msf& ); + Msf& operator-=( int ); + const Msf operator++( int ); + Msf& operator++(); + const Msf operator--( int ); + Msf& operator--(); + + int minutes() const { return m_minutes; } + int seconds() const { return m_seconds; } + int frames() const { return m_frames; } + + int totalFrames() const { return ( m_minutes*60 + m_seconds )*75 + m_frames; } + int lba() const { return totalFrames(); } + + // operator int () const { return lba(); } + + void setValue( int m, int s, int f ); + + void addMinutes( int m ); + void addSeconds( int s ); + void addFrames( int f ); + + QString toString( bool showFrames = true ) const; + + KIO::filesize_t mode1Bytes() const; + KIO::filesize_t mode2Form1Bytes() const; + KIO::filesize_t mode2Form2Bytes() const; + KIO::filesize_t audioBytes() const; + KIO::filesize_t rawBytes() const; + unsigned long long pcmSamples() const { return lba()*588; } + + /** + * Convert a string representation into an Msf object. + * + * Valid strings include: + * \li 100 - treated as 100 frames + * \li 100:23 - treated as 100 minutes and 23 seconds + * \li 100:23:57 - treated as 100 minutes, 23 seconds, and 57 frames + * \li 100:23.57 - treated as 100 minutes, 23 seconds, and 57 frames + */ + static Msf fromString( const QString&, bool* ok = 0 ); + + /** + * @param ms seconds + * frames will be rounded up + */ + static Msf fromSeconds( double ms ); + + static QRegExp regExp(); + + private: + void makeValid(); + int m_minutes; + int m_seconds; + int m_frames; + }; + + LIBK3BDEVICE_EXPORT Msf operator+( const Msf&, const Msf& ); + LIBK3BDEVICE_EXPORT Msf operator+( const Msf&, int ); + LIBK3BDEVICE_EXPORT Msf operator-( const Msf&, const Msf& ); + LIBK3BDEVICE_EXPORT Msf operator-( const Msf&, int ); + LIBK3BDEVICE_EXPORT bool operator==( const Msf&, const Msf& ); + LIBK3BDEVICE_EXPORT bool operator!=( const Msf&, const Msf& ); + LIBK3BDEVICE_EXPORT bool operator<( const Msf&, const Msf& ); + LIBK3BDEVICE_EXPORT bool operator>( const Msf&, const Msf& ); + LIBK3BDEVICE_EXPORT bool operator<=( const Msf&, const Msf& ); + LIBK3BDEVICE_EXPORT bool operator>=( const Msf&, const Msf& ); + + LIBK3BDEVICE_EXPORT kdbgstream& operator<<( kdbgstream&, const Msf& ); + LIBK3BDEVICE_EXPORT inline kndbgstream& operator<<( kndbgstream &stream, const Msf& ) { return stream; } +} + +#endif diff --git a/libk3bdevice/k3bscsicommand.cpp b/libk3bdevice/k3bscsicommand.cpp new file mode 100644 index 0000000..2b34217 --- /dev/null +++ b/libk3bdevice/k3bscsicommand.cpp @@ -0,0 +1,218 @@ +/* + * + * $Id: k3bscsicommand.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bscsicommand.h" +#include "k3bdevice.h" + +#include <k3bdebug.h> + + +QString K3bDevice::commandString( const unsigned char& command ) +{ + if( command == MMC_BLANK ) + return "BLANK"; + if( command == MMC_CLOSE_TRACK_SESSION ) + return "CLOSE TRACK/SESSION"; + if( command == MMC_ERASE ) + return "ERASE"; + if( command == MMC_FORMAT_UNIT ) + return "FORMAT UNIT"; + if( command == MMC_GET_CONFIGURATION ) + return "GET CONFIGURATION"; + if( command == MMC_GET_EVENT_STATUS_NOTIFICATION ) + return "GET EVENT STATUS NOTIFICATION"; + if( command == MMC_GET_PERFORMANCE ) + return "GET PERFORMANCE"; + if( command == MMC_INQUIRY ) + return "INQUIRY"; + if( command == MMC_LOAD_UNLOAD_MEDIUM ) + return "LOAD/UNLOAD MEDIUM"; + if( command == MMC_MECHANISM_STATUS ) + return "MECHANISM STATUS"; + if( command == MMC_MODE_SELECT ) + return "MODE SELECT"; + if( command == MMC_MODE_SENSE ) + return "MODE SENSE"; + if( command == MMC_PAUSE_RESUME ) + return "PAUSE/RESUME"; + if( command == MMC_PLAY_AUDIO_10 ) + return "PLAY AUDIO (10)"; + if( command == MMC_PLAY_AUDIO_12 ) + return "PLAY AUDIO (12)"; + if( command == MMC_PLAY_AUDIO_MSF ) + return "PLAY AUDIO (MSF)"; + if( command == MMC_PREVENT_ALLOW_MEDIUM_REMOVAL ) + return "PREVENT ALLOW MEDIUM REMOVAL"; + if( command == MMC_READ_10 ) + return "READ (10)"; + if( command == MMC_READ_12 ) + return "READ (12)"; + if( command == MMC_READ_BUFFER ) + return "READ BUFFER"; + if( command == MMC_READ_BUFFER_CAPACITY ) + return "READ BUFFER CAPACITY"; + if( command == MMC_READ_CAPACITY ) + return "READ CAPACITY"; + if( command == MMC_READ_CD ) + return "READ CD"; + if( command == MMC_READ_CD_MSF ) + return "READ CD MSF"; + if( command == MMC_READ_DISC_INFORMATION ) + return "READ DISC INFORMATION"; + if( command == MMC_READ_DVD_STRUCTURE ) + return "READ DVD STRUCTURE"; + if( command == MMC_READ_FORMAT_CAPACITIES ) + return "READ FORMAT CAPACITIES"; + if( command == MMC_READ_SUB_CHANNEL ) + return "READ SUB-CHANNEL"; + if( command == MMC_READ_TOC_PMA_ATIP ) + return "READ TOC/PMA/ATIP"; + if( command == MMC_READ_TRACK_INFORMATION ) + return "READ TRACK INFORMATION"; + if( command == MMC_REPAIR_TRACK ) + return "REPAIR TRACK"; + if( command == MMC_REPORT_KEY ) + return "REPORT KEY"; + if( command == MMC_REQUEST_SENSE ) + return "REQUEST SENSE"; + if( command == MMC_RESERVE_TRACK ) + return "RESERVE TRACK"; + if( command == MMC_SCAN ) + return "SCAN"; + if( command == MMC_SEEK_10 ) + return "SEEK (10)"; + if( command == MMC_SEND_CUE_SHEET ) + return "SEND CUE SHEET"; + if( command == MMC_SEND_DVD_STRUCTURE ) + return "SEND DVD STRUCTURE"; + if( command == MMC_SEND_KEY ) + return "SEND KEY"; + if( command == MMC_SEND_OPC_INFORMATION ) + return "SEND OPC INFORMATION"; + if( command == MMC_SET_SPEED ) + return "SET SPEED"; + if( command == MMC_SET_READ_AHEAD ) + return "SET READ AHEAD"; + if( command == MMC_SET_STREAMING ) + return "SET STREAMING"; + if( command == MMC_START_STOP_UNIT ) + return "START STOP UNIT"; + if( command == MMC_STOP_PLAY_SCAN ) + return "STOP PLAY/SCAN"; + if( command == MMC_SYNCHRONIZE_CACHE ) + return "SYNCHRONIZE CACHE"; + if( command == MMC_TEST_UNIT_READY ) + return "TEST UNIT READY"; + if( command == MMC_VERIFY_10 ) + return "VERIFY (10)"; + if( command == MMC_WRITE_10 ) + return "WRITE (10)"; + if( command == MMC_WRITE_12 ) + return "WRITE (12)"; + if( command == MMC_WRITE_AND_VERIFY_10 ) + return "WRITE AND VERIFY (10)"; + if( command == MMC_WRITE_BUFFER ) + return "WRITE BUFFER"; + + return "unknown"; +} + + +QString K3bDevice::ScsiCommand::senseKeyToString( int key ) +{ + switch( key ) { + case 0x0: + return "NO SENSE (2)"; + case 0x1: + return "RECOVERED ERROR (1)"; + case 0x2: + return "NOT READY (2)"; + case 0x3: + return "MEDIUM ERROR (3)"; + case 0x4: + return "HARDWARE ERROR (4)"; + case 0x5: + return "ILLEGAL REQUEST (5)"; + case 0x6: + return "UNIT ATTENTION (6)"; + case 0x7: + return "DATA PROTECT (7)"; + case 0x8: + return "BLANK CHECK (8)"; + case 0x9: + return "VENDOR SPECIFIC (9)"; + case 0xA: + return "COPY ABORTED (A)"; + case 0xB: + return "ABORTED COMMAND (B)"; + case 0xC: + return "0xC is obsolete... ??"; + } + + return "unknown"; +} + + +void K3bDevice::ScsiCommand::debugError( int command, int errorCode, int senseKey, int asc, int ascq ) { + if( m_printErrors ) { + k3bDebug() << "(K3bDevice::ScsiCommand) failed: " << endl + << " command: " << QString("%1 (%2)") + .arg( K3bDevice::commandString( command ) ) + .arg( QString::number(command, 16) ) << endl + << " errorcode: " << QString::number(errorCode, 16) << endl + << " sense key: " << senseKeyToString(senseKey) << endl + << " asc: " << QString::number(asc, 16) << endl + << " ascq: " << QString::number(ascq, 16) << endl; + } +} + + + +#ifdef Q_OS_LINUX +#include "k3bscsicommand_linux.cpp" +#endif +#ifdef Q_OS_FREEBSD +#include "k3bscsicommand_bsd.cpp" +#endif +#ifdef Q_OS_NETBSD +#include "k3bscsicommand_netbsd.cpp" +#endif + + + +K3bDevice::ScsiCommand::ScsiCommand( K3bDevice::Device::Handle handle ) + : d(new Private), + m_device(0), + m_printErrors(true) +{ + m_deviceHandle = handle; + clear(); +} + + +K3bDevice::ScsiCommand::ScsiCommand( const K3bDevice::Device* dev ) + : d(new Private), + m_device(dev), + m_printErrors(true) +{ + clear(); +} + + +K3bDevice::ScsiCommand::~ScsiCommand() +{ + delete d; +} + diff --git a/libk3bdevice/k3bscsicommand.h b/libk3bdevice/k3bscsicommand.h new file mode 100644 index 0000000..11a9860 --- /dev/null +++ b/libk3bdevice/k3bscsicommand.h @@ -0,0 +1,142 @@ +/* + * + * $Id: k3bscsicommand.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_SCSI_COMMAND_H_ +#define _K3B_SCSI_COMMAND_H_ + +#include <qglobal.h> +#include <qstring.h> + +#include "k3bdevice.h" + + +namespace K3bDevice +{ + const unsigned char MMC_BLANK = 0xA1; + const unsigned char MMC_CLOSE_TRACK_SESSION = 0x5B; + const unsigned char MMC_ERASE = 0x2C; + const unsigned char MMC_FORMAT_UNIT = 0x04; + const unsigned char MMC_GET_CONFIGURATION = 0x46; + const unsigned char MMC_GET_EVENT_STATUS_NOTIFICATION = 0x4A; + const unsigned char MMC_GET_PERFORMANCE = 0xAC; + const unsigned char MMC_INQUIRY = 0x12; + const unsigned char MMC_LOAD_UNLOAD_MEDIUM = 0xA6; + const unsigned char MMC_MECHANISM_STATUS = 0xBD; + const unsigned char MMC_MODE_SELECT = 0x55; + const unsigned char MMC_MODE_SENSE = 0x5A; + const unsigned char MMC_PAUSE_RESUME = 0x4B; + const unsigned char MMC_PLAY_AUDIO_10 = 0x45; + const unsigned char MMC_PLAY_AUDIO_12 = 0xA5; + const unsigned char MMC_PLAY_AUDIO_MSF = 0x47; + const unsigned char MMC_PREVENT_ALLOW_MEDIUM_REMOVAL = 0x1E; + const unsigned char MMC_READ_10 = 0x28; + const unsigned char MMC_READ_12 = 0xA8; + const unsigned char MMC_READ_BUFFER = 0x3C; + const unsigned char MMC_READ_BUFFER_CAPACITY = 0x5C; + const unsigned char MMC_READ_CAPACITY = 0x25; + const unsigned char MMC_READ_CD = 0xBE; + const unsigned char MMC_READ_CD_MSF = 0xB9; + const unsigned char MMC_READ_DISC_INFORMATION = 0x51; + const unsigned char MMC_READ_DVD_STRUCTURE = 0xAD; + const unsigned char MMC_READ_DISC_STRUCTURE = 0xAD; /**< READ DVD STRUCTURE has been renamed to READ DISC STRUCTURE in MMC5 */ + const unsigned char MMC_READ_FORMAT_CAPACITIES = 0x23; + const unsigned char MMC_READ_SUB_CHANNEL = 0x42; + const unsigned char MMC_READ_TOC_PMA_ATIP = 0x43; + const unsigned char MMC_READ_TRACK_INFORMATION = 0x52; + const unsigned char MMC_REPAIR_TRACK = 0x58; + const unsigned char MMC_REPORT_KEY = 0xA4; + const unsigned char MMC_REQUEST_SENSE = 0x03; + const unsigned char MMC_RESERVE_TRACK = 0x53; + const unsigned char MMC_SCAN = 0xBA; + const unsigned char MMC_SEEK_10 = 0x2B; + const unsigned char MMC_SEND_CUE_SHEET = 0x5D; + const unsigned char MMC_SEND_DVD_STRUCTURE = 0xBF; + const unsigned char MMC_SEND_KEY = 0xA3; + const unsigned char MMC_SEND_OPC_INFORMATION = 0x54; + const unsigned char MMC_SET_SPEED = 0xBB; + const unsigned char MMC_SET_READ_AHEAD = 0xA7; + const unsigned char MMC_SET_STREAMING = 0xB6; + const unsigned char MMC_START_STOP_UNIT = 0x1B; + const unsigned char MMC_STOP_PLAY_SCAN = 0x4E; + const unsigned char MMC_SYNCHRONIZE_CACHE = 0x35; + const unsigned char MMC_TEST_UNIT_READY = 0x00; + const unsigned char MMC_VERIFY_10 = 0x2F; + const unsigned char MMC_WRITE_10 = 0x2A; + const unsigned char MMC_WRITE_12 = 0xAA; + const unsigned char MMC_WRITE_AND_VERIFY_10 = 0x2E; + const unsigned char MMC_WRITE_BUFFER = 0x3B; + + QString commandString( const unsigned char& command ); + + enum TransportDirection { + TR_DIR_NONE, + TR_DIR_READ, + TR_DIR_WRITE + }; + + class ScsiCommand + { + public: + ScsiCommand( K3bDevice::Device::Handle handle ); + ScsiCommand( const Device* ); + ~ScsiCommand(); + + /** + * Enales or disables printing of debugging messages for failed + * commands. + * + * Default is enabled. + */ + void enableErrorMessages( bool b ) { m_printErrors = b; } + + void clear(); + + unsigned char& operator[]( size_t ); + + // TODO: use this +/* union ErrorCode { */ +/* K3bDevice::uint32 code; */ +/* struct { */ +/* K3bDevice::uint8 errorCode; */ +/* K3bDevice::uint8 senseKey; */ +/* K3bDevice::uint8 asc; */ +/* K3bDevice::uint8 ascq; */ +/* } details; */ +/* }; */ + + /** + * \return 0 on success, -1 if the device could not be opened, and + * an error code otherwise. The error code is constructed from + * the scsi error code, the sense key, asc, and ascq. These four values are + * combined into the lower 32 bit of an integer in the order used above. + */ + int transport( TransportDirection dir = TR_DIR_NONE, + void* = 0, + size_t len = 0 ); + + private: + static QString senseKeyToString( int key ); + void debugError( int command, int errorCode, int senseKey, int asc, int ascq ); + + class Private; + Private *d; + Device::Handle m_deviceHandle; + const Device* m_device; + + bool m_printErrors; + }; +} + +#endif diff --git a/libk3bdevice/k3bscsicommand_bsd.cpp b/libk3bdevice/k3bscsicommand_bsd.cpp new file mode 100644 index 0000000..84e12f9 --- /dev/null +++ b/libk3bdevice/k3bscsicommand_bsd.cpp @@ -0,0 +1,208 @@ +/* + * + * $Id: k3bscsicommand_bsd.cpp 679320 2007-06-23 15:57:22Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bscsicommand.h" +#include "k3bdevice.h" + +#include <k3bdebug.h> + +#include <stdio.h> +#include <errno.h> +#include <camlib.h> +#include <cam/scsi/scsi_message.h> +#include <cam/scsi/scsi_pass.h> + +#define ERRCODE(s) ((((s)[2]&0x0F)<<16)|((s)[12]<<8)|((s)[13])) +#define EMEDIUMTYPE EINVAL +#define ENOMEDIUM ENODEV +#define CREAM_ON_ERRNO(s) do { \ + switch ((s)[12]) \ + { case 0x04: errno=EAGAIN; break; \ + case 0x20: errno=ENODEV; break; \ + case 0x21: if ((s)[13]==0) errno=ENOSPC; \ + else errno=EINVAL; \ + break; \ + case 0x30: errno=EMEDIUMTYPE; break; \ + case 0x3A: errno=ENOMEDIUM; break; \ + } \ +} while(0) + + + +class K3bDevice::ScsiCommand::Private +{ +public: + union ccb ccb; +}; + + +void K3bDevice::ScsiCommand::clear() +{ + memset (&d->ccb,0,sizeof(ccb)); +} + + +unsigned char& K3bDevice::ScsiCommand::operator[]( size_t i ) +{ + if( d->ccb.csio.cdb_len < i+1 ) + d->ccb.csio.cdb_len = i+1; + return d->ccb.csio.cdb_io.cdb_bytes[i]; +} + +int K3bDevice::ScsiCommand::transport( TransportDirection dir, + void* data, + size_t len ) +{ + if( !m_device ) + return -1; + + m_device->usageLock(); + + bool needToClose = false; + if( !m_device->isOpen() ) { + needToClose = true; + } + + if( !m_device->open( true ) ) { + m_device->usageUnlock(); + return -1; + } + d->ccb.ccb_h.path_id = m_device->handle()->path_id; + d->ccb.ccb_h.target_id = m_device->handle()->target_id; + d->ccb.ccb_h.target_lun = m_device->handle()->target_lun; + + k3bDebug() << "(K3bDevice::ScsiCommand) transport command " << QString::number((int)d->ccb.csio.cdb_io.cdb_bytes[0], 16) << ", length: " << (int)d->ccb.csio.cdb_len << endl; + int ret=0; + int direction = CAM_DEV_QFRZDIS; + if (!len) + direction |= CAM_DIR_NONE; + else + direction |= (dir & TR_DIR_READ)?CAM_DIR_IN : CAM_DIR_OUT; + cam_fill_csio (&(d->ccb.csio), 1, 0 /* NULL */, direction, MSG_SIMPLE_Q_TAG, (u_int8_t *)data, len, sizeof(d->ccb.csio.sense_data), d->ccb.csio.cdb_len, 30*1000); + unsigned char * sense = (unsigned char *)&d->ccb.csio.sense_data; + + ret = cam_send_ccb(m_device->handle(), &d->ccb); + + if (ret < 0) { + k3bDebug() << "(K3bDevice::ScsiCommand) transport failed: " << ret << endl; + + if( needToClose ) + m_device->close(); + + m_device->usageUnlock(); + + struct scsi_sense_data* senset = (struct scsi_sense_data*)sense; + debugError( d->ccb.csio.cdb_io.cdb_bytes[0], + senset->error_code & SSD_ERRCODE, + senset->flags & SSD_KEY, + senset->add_sense_code, + senset->add_sense_code_qual ); + + int result = (((senset->error_code & SSD_ERRCODE)<<24) & 0xF000 | + ((senset->flags & SSD_KEY)<<16) & 0x0F00 | + (senset->add_sense_code<<8) & 0x00F0 | + (senset->add_sense_code_qual) & 0x000F ); + + return result ? result : ret; + } + + else if ((d->ccb.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { + if( needToClose ) + m_device->close(); + m_device->usageUnlock(); + return 0; + } + + errno = EIO; + // FreeBSD 5-CURRENT since 2003-08-24, including 5.2 fails to + // pull sense data automatically, at least for ATAPI transport, + // so I reach for it myself... + if ((d->ccb.csio.scsi_status==SCSI_STATUS_CHECK_COND) && + !(d->ccb.ccb_h.status&CAM_AUTOSNS_VALID)) + { + u_int8_t _sense[18]; + u_int32_t resid=d->ccb.csio.resid; + + memset(_sense,0,sizeof(_sense)); + + operator[](0) = 0x03; // REQUEST SENSE + d->ccb.csio.cdb_io.cdb_bytes[4] = sizeof(_sense); + d->ccb.csio.cdb_len = 6; + d->ccb.csio.ccb_h.flags |= CAM_DIR_IN|CAM_DIS_AUTOSENSE; + d->ccb.csio.data_ptr = _sense; + d->ccb.csio.dxfer_len = sizeof(_sense); + d->ccb.csio.sense_len = 0; + + ret = cam_send_ccb(m_device->handle(), &d->ccb); + + d->ccb.csio.resid = resid; + if (ret<0) + { + k3bDebug() << "(K3bDevice::ScsiCommand) transport failed (2): " << ret << endl; + ret = -1; + struct scsi_sense_data* senset = (struct scsi_sense_data*)sense; + debugError( d->ccb.csio.cdb_io.cdb_bytes[0], + senset->error_code & SSD_ERRCODE, + senset->flags & SSD_KEY, + senset->add_sense_code, + senset->add_sense_code_qual ); + + if( needToClose ) + m_device->close(); + m_device->usageUnlock(); + + return -1; + } + if ((d->ccb.ccb_h.status&CAM_STATUS_MASK) != CAM_REQ_CMP) + { + k3bDebug() << "(K3bDevice::ScsiCommand) transport failed (3): " << ret << endl; + errno=EIO,-1; + ret = -1; + struct scsi_sense_data* senset = (struct scsi_sense_data*)sense; + debugError( d->ccb.csio.cdb_io.cdb_bytes[0], + senset->error_code & SSD_ERRCODE, + senset->flags & SSD_KEY, + senset->add_sense_code, + senset->add_sense_code_qual ); + + if( needToClose ) + m_device->close(); + m_device->usageUnlock(); + + return -1; + } + + memcpy(sense,_sense,sizeof(_sense)); + } + + ret = ERRCODE(sense); + k3bDebug() << "(K3bDevice::ScsiCommand) transport failed (4): " << ret << endl; + if (ret == 0) + ret = -1; + else + CREAM_ON_ERRNO(((unsigned char *)&d->ccb.csio.sense_data)); + struct scsi_sense_data* senset = (struct scsi_sense_data*)sense; + debugError( d->ccb.csio.cdb_io.cdb_bytes[0], + senset->error_code & SSD_ERRCODE, + senset->flags & SSD_KEY, + senset->add_sense_code, + senset->add_sense_code_qual ); + + if( needToClose ) + m_device->close(); + m_device->usageUnlock(); + + return ret; +} diff --git a/libk3bdevice/k3bscsicommand_linux.cpp b/libk3bdevice/k3bscsicommand_linux.cpp new file mode 100644 index 0000000..774da06 --- /dev/null +++ b/libk3bdevice/k3bscsicommand_linux.cpp @@ -0,0 +1,177 @@ +/* + * + * $Id: k3bscsicommand_linux.cpp 679274 2007-06-23 13:23:58Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * Parts of this file are inspired (and copied) from transport.hxx + * from the dvd+rw-tools (C) Andy Polyakov <appro@fy.chalmers.se> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bscsicommand.h" +#include "k3bdevice.h" + +#include <k3bdebug.h> + +#include <sys/ioctl.h> +#undef __STRICT_ANSI__ +#include <linux/cdrom.h> +#define __STRICT_ANSI__ +#include <scsi/sg.h> + +#include <unistd.h> +#include <sys/types.h> +#include <sys/utsname.h> + + +#if !defined(SG_FLAG_LUN_INHIBIT) +# if defined(SG_FLAG_UNUSED_LUN_INHIBIT) +# define SG_FLAG_LUN_INHIBIT SG_FLAG_UNUSED_LUN_INHIBIT +# else +# define SG_FLAG_LUN_INHIBIT 0 +# endif +#endif + +#ifdef SG_IO +static bool useSgIo() +{ + struct utsname buf; + uname( &buf ); + // was CDROM_SEND_PACKET declared dead in 2.5? + return ( strcmp( buf.release, "2.5.43" ) >=0 ); +} +#endif + + +class K3bDevice::ScsiCommand::Private +{ +public: + struct cdrom_generic_command cmd; + struct request_sense sense; + +#ifdef SG_IO + bool useSgIo; + struct sg_io_hdr sgIo; +#endif +}; + + +void K3bDevice::ScsiCommand::clear() +{ + ::memset( &d->cmd, 0, sizeof(struct cdrom_generic_command) ); + ::memset( &d->sense, 0, sizeof(struct request_sense) ); + + d->cmd.quiet = 1; + d->cmd.sense = &d->sense; + +#ifdef SG_IO + d->useSgIo = useSgIo(); + ::memset( &d->sgIo, 0, sizeof(struct sg_io_hdr) ); +#endif +} + + +unsigned char& K3bDevice::ScsiCommand::operator[]( size_t i ) +{ +#ifdef SG_IO + if( d->sgIo.cmd_len < i+1 ) + d->sgIo.cmd_len = i+1; +#endif + return d->cmd.cmd[i]; +} + + +int K3bDevice::ScsiCommand::transport( TransportDirection dir, + void* data, + size_t len ) +{ + bool needToClose = false; + if( m_device ) { + m_device->usageLock(); + if( !m_device->isOpen() ) { + needToClose = true; + } + if ( !m_device->open( dir == TR_DIR_WRITE ) ) { + m_device->usageUnlock(); + return -1; + } + m_deviceHandle = m_device->handle(); + } + + if( m_deviceHandle == -1 ) { + return -1; + } + + int i = -1; + +#ifdef SG_IO + if( d->useSgIo ) { + d->sgIo.interface_id= 'S'; + d->sgIo.mx_sb_len = sizeof( struct request_sense ); + d->sgIo.cmdp = d->cmd.cmd; + d->sgIo.sbp = (unsigned char*)&d->sense; + d->sgIo.flags = SG_FLAG_LUN_INHIBIT|SG_FLAG_DIRECT_IO; + d->sgIo.dxferp = data; + d->sgIo.dxfer_len = len; + d->sgIo.timeout = 5000; + if( dir == TR_DIR_READ ) + d->sgIo.dxfer_direction = SG_DXFER_FROM_DEV; + else if( dir == TR_DIR_WRITE ) + d->sgIo.dxfer_direction = SG_DXFER_TO_DEV; + else + d->sgIo.dxfer_direction = SG_DXFER_NONE; + + i = ::ioctl( m_deviceHandle, SG_IO, &d->sgIo ); + + if( ( d->sgIo.info&SG_INFO_OK_MASK ) != SG_INFO_OK ) + i = -1; + } + else { +#endif + d->cmd.buffer = (unsigned char*)data; + d->cmd.buflen = len; + if( dir == TR_DIR_READ ) + d->cmd.data_direction = CGC_DATA_READ; + else if( dir == TR_DIR_WRITE ) + d->cmd.data_direction = CGC_DATA_WRITE; + else + d->cmd.data_direction = CGC_DATA_NONE; + + i = ::ioctl( m_deviceHandle, CDROM_SEND_PACKET, &d->cmd ); +#ifdef SG_IO + } +#endif + + if( needToClose ) + m_device->close(); + + if ( m_device ) { + m_device->usageUnlock(); + } + + if( i ) { + debugError( d->cmd.cmd[0], + d->sense.error_code, + d->sense.sense_key, + d->sense.asc, + d->sense.ascq ); + + int errCode = + (d->sense.error_code<<24) & 0xF000 | + (d->sense.sense_key<<16) & 0x0F00 | + (d->sense.asc<<8) & 0x00F0 | + (d->sense.ascq) & 0x000F; + + return( errCode != 0 ? errCode : 1 ); + } + else + return 0; +} diff --git a/libk3bdevice/k3bscsicommand_netbsd.cpp b/libk3bdevice/k3bscsicommand_netbsd.cpp new file mode 100644 index 0000000..bd09e7a --- /dev/null +++ b/libk3bdevice/k3bscsicommand_netbsd.cpp @@ -0,0 +1,111 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Mark Davies <mark@mcs.vuw.ac.nz> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bscsicommand.h" +#include "k3bdevice.h" + +#include <k3bdebug.h> + +#include <sys/ioctl.h> +#include <sys/scsiio.h> +// #include <sys/cdio.h> +// #include <sys/dkio.h> + +#include <unistd.h> +#include <sys/types.h> + + +class K3bDevice::ScsiCommand::Private +{ +public: + struct scsireq cmd; +}; + + +void K3bDevice::ScsiCommand::clear() +{ + ::memset( &d->cmd, 0, sizeof(struct scsireq ) ); +} + + +unsigned char& K3bDevice::ScsiCommand::operator[]( size_t i ) +{ + if( d->cmd.cmdlen < i+1 ) + d->cmd.cmdlen = i+1; + return d->cmd.cmd[i]; +} + + +int K3bDevice::ScsiCommand::transport( TransportDirection dir, + void* data, + size_t len ) +{ + bool needToClose = false; + if( m_device ) { + m_device->usageLock(); + if( !m_device->isOpen() ) { + needToClose = true; + } + m_device->open( dir == TR_DIR_WRITE ); + m_deviceHandle = m_device->handle(); + } + + if( m_deviceHandle == -1 ) { + if ( m_device ) { + m_device->usageUnlock(); + } + + return -1; + } + + d->cmd.timeout = 10000; + d->cmd.databuf = (caddr_t) data; + d->cmd.datalen = len; + // d->cmd.datalen_used = len; + d->cmd.senselen = SENSEBUFLEN; + switch (dir) + { + case TR_DIR_READ: + d->cmd.flags = SCCMD_READ; + break; + case TR_DIR_WRITE: + d->cmd.flags = SCCMD_WRITE; + break; + default: + d->cmd.flags = SCCMD_READ; + break; + } + + int i = ::ioctl( m_deviceHandle, SCIOCCOMMAND, &d->cmd ); + + if ( m_device ) { + if( needToClose ) + m_device->close(); + m_device->usageUnlock(); + } + + if( i || (d->cmd.retsts != SCCMD_OK)) { + debugError( d->cmd.cmd[0], + d->cmd.retsts, + d->cmd.sense[2], + d->cmd.sense[12], + d->cmd.sense[13] ); + + return 1; + } + else + return 0; +} diff --git a/libk3bdevice/k3btoc.cpp b/libk3bdevice/k3btoc.cpp new file mode 100644 index 0000000..570bc9e --- /dev/null +++ b/libk3bdevice/k3btoc.cpp @@ -0,0 +1,163 @@ +/* + * + * $Id: k3btoc.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3btoc.h" +#include "k3bdebug.h" + +#include <qstring.h> + + +K3bDevice::Toc::Toc() + : QValueList<K3bDevice::Track>() +{ +} + + +K3bDevice::Toc::Toc( const Toc& toc ) + : QValueList<K3bDevice::Track>( toc ) +{ + m_firstSector = toc.firstSector(); +} + + +K3bDevice::Toc::~Toc() +{ +} + + +K3bDevice::Toc& K3bDevice::Toc::operator=( const Toc& toc ) +{ + if( &toc == this ) return *this; + + m_firstSector = toc.firstSector(); + + QValueList<K3bDevice::Track>::operator=( toc ); + + return *this; +} + + +const K3b::Msf& K3bDevice::Toc::firstSector() const +{ + return m_firstSector; +} + + +K3b::Msf K3bDevice::Toc::lastSector() const +{ + if( isEmpty() ) + return 0; + // the last track's last sector should be the last sector of the entire cd + return last().lastSector(); +} + + +K3b::Msf K3bDevice::Toc::length() const +{ + // +1 since the last sector is included + return lastSector() - firstSector() + 1; +} + + +unsigned int K3bDevice::Toc::discId() const +{ + // calculate cddb-id + unsigned int id = 0; + for( Toc::const_iterator it = constBegin(); it != constEnd(); ++it ) { + unsigned int n = (*it).firstSector().lba() + 150; + n /= 75; + while( n > 0 ) { + id += n % 10; + n /= 10; + } + } + unsigned int l = length().lba(); + l /= 75; + id = ( ( id % 0xff ) << 24 ) | ( l << 8 ) | count(); + + return id; +} + + +int K3bDevice::Toc::contentType() const +{ + int audioCnt = 0, dataCnt = 0; + for( Toc::const_iterator it = constBegin(); it != constEnd(); ++it ) { + if( (*it).type() == K3bDevice::Track::AUDIO ) + audioCnt++; + else + dataCnt++; + } + + if( audioCnt + dataCnt == 0 ) + return K3bDevice::NONE; + if( audioCnt == 0 ) + return K3bDevice::DATA; + if( dataCnt == 0 ) + return K3bDevice::AUDIO; + return K3bDevice::MIXED; +} + + +int K3bDevice::Toc::sessions() const +{ + if( isEmpty() ) + return 0; + else if( last().session() == 0 ) + return 1; // default if unknown + else + return last().session(); +} + + +void K3bDevice::Toc::clear() +{ + QValueList<Track>::clear(); + m_mcn.resize( 0 ); + m_firstSector = 0; +} + + +void K3bDevice::Toc::debug() const +{ + k3bDebug() << count() << " in " << sessions() << " sessions" << endl; + int sessionN = 0; + int trackN = 0; + for( Toc::const_iterator it = begin(); it != end(); ++it ) { + ++trackN; + if( sessionN != (*it).session() ) { + sessionN = (*it).session(); + k3bDebug() << "Session Number " << sessionN << endl; + } + k3bDebug() << " Track " << trackN << ( (*it).type() == Track::AUDIO ? " AUDIO" : " DATA" ) + << " " << (*it).firstSector().lba() << " - " << (*it).lastSector().lba() + << " (" << (*it).length().lba() << ")" << endl; + } +} + + +bool K3bDevice::Toc::operator==( const Toc& other ) const +{ + return( m_firstSector == other.m_firstSector && + QValueList<Track>::operator==( other ) ); +} + + +bool K3bDevice::Toc::operator!=( const Toc& other ) const +{ + return( m_firstSector != other.m_firstSector || + QValueList<Track>::operator!=( other ) ); +} diff --git a/libk3bdevice/k3btoc.h b/libk3bdevice/k3btoc.h new file mode 100644 index 0000000..adfba74 --- /dev/null +++ b/libk3bdevice/k3btoc.h @@ -0,0 +1,101 @@ +/* + * + * $Id: k3btoc.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BTOC_H +#define K3BTOC_H + +#include <qvaluelist.h> +#include <qcstring.h> + +#include <k3bmsf.h> + +#include "k3btrack.h" +#include "k3bdevice_export.h" +class QString; + +namespace K3bDevice +{ + + enum ContentsType { + DATA, + AUDIO, + MIXED, + NONE // no tracks + }; + + /** + * A list of K3bTracks that represents the contents + * of a cd. + * The Toc deletes all its tracks when it is deleted and + * deletes removed tracks. + */ + class LIBK3BDEVICE_EXPORT Toc : public QValueList<K3bTrack> + { + public: + Toc(); + /** deep copy */ + Toc( const Toc& ); + /** deletes all tracks */ + ~Toc(); + /** deep copy */ + Toc& operator=( const Toc& ); + + /** + * CDDB disc Id + */ + unsigned int discId() const; + + const QCString& mcn() const { return m_mcn; } + + /** + * determine the contents type based on the tracks' types. + * Audio, Data, or Mixed + */ + int contentType() const; + + /** + * \return the number of sessions in this TOC. + */ + int sessions() const; + + /** + * The first track's first sector could differ from the disc's + * first sector if there is a pregap before index 1 + */ + const K3b::Msf& firstSector() const; + K3b::Msf lastSector() const; + K3b::Msf length() const; + + void setFirstSector( int i ) { m_firstSector = i; } + + void setMcn( const QCString& mcn ) { m_mcn = mcn; } + + void clear(); + + void debug() const; + + bool operator==( const Toc& ) const; + bool operator!=( const Toc& ) const; + + private: + unsigned int m_discId; + K3b::Msf m_firstSector; + + QCString m_mcn; + }; +} + +#endif diff --git a/libk3bdevice/k3btrack.cpp b/libk3bdevice/k3btrack.cpp new file mode 100644 index 0000000..6efcdcb --- /dev/null +++ b/libk3bdevice/k3btrack.cpp @@ -0,0 +1,123 @@ +/* + * + * $Id: k3btrack.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3btrack.h" + + +K3bDevice::Track::Track() + : m_type(-1), + m_mode(-1), + m_copyPermitted(true), + m_preEmphasis(false), + m_session(0) +{ +} + + +K3bDevice::Track::Track( const Track& track ) + : m_firstSector( track.firstSector() ), + m_lastSector( track.lastSector() ), + m_index0( track.index0() ), + m_type( track.type() ), + m_mode( track.mode() ), + m_copyPermitted( track.copyPermitted() ), + m_preEmphasis( track.preEmphasis() ), + m_session( track.session() ), + m_indices( track.indices() ) +{ +} + + +K3bDevice::Track::Track( const K3b::Msf& firstSector, + const K3b::Msf& lastSector, + int type, + int mode ) + : m_firstSector( firstSector ), + m_lastSector( lastSector ), + m_type( type ), + m_mode( mode ), + m_copyPermitted(true), + m_preEmphasis(false), + m_session(0) +{ +} + + +K3bDevice::Track& K3bDevice::Track::operator=( const K3bTrack& track ) +{ + if( this != &track ) { + m_firstSector = track.firstSector(); + m_lastSector = track.lastSector(); + m_index0 = track.index0(); + m_type = track.type(); + m_mode = track.mode(); + m_indices = track.indices(); + } + + return *this; +} + + +K3b::Msf K3bDevice::Track::length() const +{ + // +1 since the last sector is included + return m_lastSector - m_firstSector + 1; +} + + +K3b::Msf K3bDevice::Track::realAudioLength() const +{ + if( index0() > 0 ) + return index0(); + else + return length(); +} + + +void K3bDevice::Track::setIndex0( const K3b::Msf& msf ) +{ + if( msf <= m_lastSector-m_firstSector ) + m_index0 = msf; +} + + +int K3bDevice::Track::indexCount() const +{ + return m_indices.count()-1; +} + + +bool K3bDevice::Track::operator==( const Track& other ) const +{ + return( m_firstSector == other.m_firstSector && + m_lastSector == other.m_lastSector && + m_index0 == other.m_index0 && + m_nextWritableAddress == other.m_nextWritableAddress && + m_freeBlocks == other.m_freeBlocks && + m_type == other.m_type && + m_mode == other.m_mode && + m_copyPermitted == other.m_copyPermitted && + m_preEmphasis == other.m_preEmphasis && + m_session == other.m_session && + m_indices == other.m_indices && + m_isrc == other.m_isrc ); +} + + +bool K3bDevice::Track::operator!=( const Track& other ) const +{ + return !operator==( other ); +} diff --git a/libk3bdevice/k3btrack.h b/libk3bdevice/k3btrack.h new file mode 100644 index 0000000..f68cc86 --- /dev/null +++ b/libk3bdevice/k3btrack.h @@ -0,0 +1,151 @@ +/* + * + * $Id: k3btrack.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + + +#ifndef K3BTRACK_H +#define K3BTRACK_H + +#include <qcstring.h> +#include <qvaluevector.h> + +#include <k3bmsf.h> +#include "k3bdevice_export.h" + +namespace K3bDevice +{ + class LIBK3BDEVICE_EXPORT Track + { + friend class Device; + + public: + enum TrackType { + AUDIO, + DATA + }; + + enum DataMode { + MODE1, + MODE2, + XA_FORM1, + XA_FORM2, + DVD, + UNKNOWN + }; + + Track(); + Track( const Track& ); + Track( const K3b::Msf& firstSector, + const K3b::Msf& lastSector, + int type, + int mode = UNKNOWN ); + Track& operator=( const Track& ); + + int type() const { return m_type; } + + /** + * Invalid for DVDs and Audio CDs + */ + int mode() const { return m_mode; } + + /** + * Invalid for DVDs + */ + bool copyPermitted() const { return m_copyPermitted; } + void setCopyPermitted( bool b ) { m_copyPermitted = b; } + + /** + * Only valid for audio tracks + */ + bool preEmphasis() const { return m_preEmphasis; } + void setPreEmphasis( bool b ) { m_preEmphasis = b; } + + bool recordedIncremental() const { return m_preEmphasis; } + bool recordedUninterrupted() const { return !recordedIncremental(); } + + const QCString& isrc() const { return m_isrc; } + void setIsrc( const QCString& s ) { m_isrc = s; } + + const K3b::Msf& firstSector() const { return m_firstSector; } + const K3b::Msf& lastSector() const { return m_lastSector; } + void setFirstSector( const K3b::Msf& msf ) { m_firstSector = msf; } + void setLastSector( const K3b::Msf& msf ) { m_lastSector = msf; } + + const K3b::Msf& nextWritableAddress() const { return m_nextWritableAddress; } + const K3b::Msf& freeBlocks() const { return m_freeBlocks; } + + K3b::Msf length() const; + + /** + * This takes index0 into account + */ + K3b::Msf realAudioLength() const; + + /** + * 0 if unknown + */ + int session() const { return m_session; } + void setSession( int s ) { m_session = s; } + + /** + * @return number of indices. This does not include index 0. + */ + int indexCount() const; + + /** + * Returns the index relative to the track's start. + * If it is zero there is no index0. + */ + const K3b::Msf& index0() const { return m_index0; } + + /** + * Set the track's index0 value. + * @param msf offset relative to track start. + */ + void setIndex0( const K3b::Msf& msf ); + + /** + * All indices. Normally this list is empty as indices are rarely used. + * Starts with index 2 (since index 1 are all other sectors FIXME) + */ + const QValueVector<K3b::Msf>& indices() const { return m_indices; } + + bool operator==( const Track& ) const; + bool operator!=( const Track& ) const; + + private: + K3b::Msf m_firstSector; + K3b::Msf m_lastSector; + K3b::Msf m_index0; + + K3b::Msf m_nextWritableAddress; + K3b::Msf m_freeBlocks; + + int m_type; + int m_mode; + bool m_copyPermitted; + bool m_preEmphasis; + + int m_session; + + QValueVector<K3b::Msf> m_indices; + + QCString m_isrc; + }; +} + +typedef K3bDevice::Track K3bTrack; + +#endif diff --git a/libk3bdevice/libk3bdevice.doxy b/libk3bdevice/libk3bdevice.doxy new file mode 100644 index 0000000..cb7325a --- /dev/null +++ b/libk3bdevice/libk3bdevice.doxy @@ -0,0 +1,214 @@ +# Doxyfile 1.3.9.1 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = libk3bdevice +PROJECT_NUMBER = 1.0 +OUTPUT_DIRECTORY = docs/ +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +USE_WINDOWS_ENCODING = NO +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +DETAILS_AT_TOP = NO +INHERIT_DOCS = YES +DISTRIBUTE_GROUP_DOC = NO +TAB_SIZE = 8 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +SUBGROUPING = YES +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = YES +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_DIRECTORIES = YES +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = +FILE_PATTERNS = *.h +RECURSIVE = NO +EXCLUDE = k3bmmc.h +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = NO +REFERENCES_RELATION = NO +VERBATIM_HEADERS = NO +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = NO +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = NO +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = NO +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +UML_LOOK = YES +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +MAX_DOT_GRAPH_WIDTH = 1024 +MAX_DOT_GRAPH_HEIGHT = 1024 +MAX_DOT_GRAPH_DEPTH = 0 +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff --git a/plugins/Makefile.am b/plugins/Makefile.am new file mode 100644 index 0000000..9523e70 --- /dev/null +++ b/plugins/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = decoder encoder audiooutput project diff --git a/plugins/audiooutput/Makefile.am b/plugins/audiooutput/Makefile.am new file mode 100644 index 0000000..d8335ad --- /dev/null +++ b/plugins/audiooutput/Makefile.am @@ -0,0 +1,9 @@ +if include_arts +ARTSDIR=arts +endif + +if include_ALSA +ALSADIR=alsa +endif + +SUBDIRS = $(ARTSDIR) $(ALSADIR) diff --git a/plugins/audiooutput/alsa/Makefile.am b/plugins/audiooutput/alsa/Makefile.am new file mode 100644 index 0000000..5cc7f06 --- /dev/null +++ b/plugins/audiooutput/alsa/Makefile.am @@ -0,0 +1,14 @@ +AM_CPPFLAGS = -I$(srcdir)/../../../libk3b/core -I$(srcdir)/../../../libk3b/plugin $(all_includes) + +kde_module_LTLIBRARIES = libk3balsaoutputplugin.la + +libk3balsaoutputplugin_la_SOURCES = k3balsaoutputplugin.cpp + +libk3balsaoutputplugin_la_CFLAGS = $(ALSA_CFLAGS) +libk3balsaoutputplugin_la_LIBADD = ../../../libk3b/libk3b.la $(ALSA_LIBS) +libk3balsaoutputplugin_la_LDFLAGS = -avoid-version -module -no-undefined $(all_libraries) + +pluginsdir = $(kde_datadir)/k3b/plugins +plugins_DATA = k3balsaoutputplugin.plugin + +METASOURCES = AUTO diff --git a/plugins/audiooutput/alsa/configure.in.bot b/plugins/audiooutput/alsa/configure.in.bot new file mode 100644 index 0000000..d5c8d17 --- /dev/null +++ b/plugins/audiooutput/alsa/configure.in.bot @@ -0,0 +1,7 @@ +echo "" + +if test "x$have_alsa" = xyes; then + echo "K3b - Audioplayer available (alsa) yes" +else + echo "K3b - Audioplayer available (alsa) no" +fi diff --git a/plugins/audiooutput/alsa/configure.in.in b/plugins/audiooutput/alsa/configure.in.in new file mode 100644 index 0000000..244dce4 --- /dev/null +++ b/plugins/audiooutput/alsa/configure.in.in @@ -0,0 +1,26 @@ +dnl --------- ALSA CHECK BEGIN ------------- + +AC_DEFUN([KDE_CHECK_ALSA], +[ + PKG_CHECK_MODULES([ALSA], [alsa >= 0.9], [have_alsa=yes], [have_alsa=no]) + AC_SUBST([ALSA_CFLAGS]) + AC_SUBST([ALSA_LIBS]) +]) + +AC_ARG_WITH(alsa, + [AS_HELP_STRING(--with-alsa, + [enable support for ALSA output @<:@default=check@:>@])], + [], with_alsa=check) + +have_alsa=no +if test "x$with_alsa" != xno; then + KDE_CHECK_ALSA + + if test "x$with_alsa" != xcheck && test "x$have_alsa" != xyes; then + AC_MSG_FAILURE([--with-alsa was given, but test for ALSA failed]) + fi +fi + +AM_CONDITIONAL(include_ALSA, [test "x$have_alsa" = "xyes"]) + +dnl --------- ALSA CHECK END --------------- diff --git a/plugins/audiooutput/alsa/k3balsaoutputplugin.cpp b/plugins/audiooutput/alsa/k3balsaoutputplugin.cpp new file mode 100644 index 0000000..7351ffc --- /dev/null +++ b/plugins/audiooutput/alsa/k3balsaoutputplugin.cpp @@ -0,0 +1,293 @@ +/* + * + * $Id: k3bartsoutputplugin.cpp 369057 2004-12-07 14:05:11Z trueg $ + * Copyright (C) 2004 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include <config.h> + +#include "k3balsaoutputplugin.h" +#include <k3bpluginfactory.h> +#include <k3bcore.h> + +#include <kdebug.h> +#include <kcombobox.h> +#include <klocale.h> +#include <kconfig.h> +#include <kdialog.h> + +#include <qlayout.h> +#include <qlabel.h> + +#include <alsa/asoundlib.h> +#include <alsa/pcm.h> + + +K_EXPORT_COMPONENT_FACTORY( libk3balsaoutputplugin, K3bPluginFactory<K3bAlsaOutputPlugin>( "k3balsaoutputplugin" ) ) + + +class K3bAlsaOutputPlugin::Private +{ +public: + Private() + : pcm_playback(0), + error(false) { + } + + snd_pcm_t *pcm_playback; + + bool error; + QString lastErrorMessage; + + bool swap; + + unsigned int sampleRate; +}; + + +K3bAlsaOutputPlugin::K3bAlsaOutputPlugin( QObject* parent, const char* name ) + : K3bAudioOutputPlugin( parent, name ) +{ + d = new Private; +} + + +K3bAlsaOutputPlugin::~K3bAlsaOutputPlugin() +{ + cleanup(); + + delete d; +} + + +int K3bAlsaOutputPlugin::write( char* data, int len ) +{ + if( d->error ) + return -1; + + char* buffer = data; + if( d->swap ) { + buffer = new char[len]; + for( int i = 0; i < len-1; i+=2 ) { + buffer[i] = data[i+1]; + buffer[i+1] = data[i]; + } + } + + int written = 0; + while( written < len ) { + snd_pcm_sframes_t frames = snd_pcm_writei( d->pcm_playback, + buffer+written, + snd_pcm_bytes_to_frames( d->pcm_playback, len-written ) ); + + if( frames < 0 ) { + if( !recoverFromError( frames ) ) { + d->error = true; + return -1; + } + } + else { + written += snd_pcm_frames_to_bytes( d->pcm_playback, frames ); + } + } + + return written; +} + + +bool K3bAlsaOutputPlugin::recoverFromError( int err ) +{ + if( err == -EPIPE ) { + err = snd_pcm_prepare( d->pcm_playback ); + if( err < 0 ) { + d->lastErrorMessage = i18n("Internal Alsa problem: %1").arg(snd_strerror(err)); + return false; + } + } + else if( err == -ESTRPIPE ) { + while( ( err = snd_pcm_resume( d->pcm_playback ) ) == -EAGAIN ) + sleep( 1 ); + + if (err < 0) { + // unable to wake up pcm device, restart it + err = snd_pcm_prepare( d->pcm_playback ); + if( err < 0 ) { + d->lastErrorMessage = i18n("Internal Alsa problem: %1").arg(snd_strerror(err)); + return false; + } + } + + return true; + } + + return false; +} + + +void K3bAlsaOutputPlugin::cleanup() +{ + if( d->pcm_playback ) { + snd_pcm_drain( d->pcm_playback ); + snd_pcm_close( d->pcm_playback ); + } + d->pcm_playback = 0; + d->error = false; +} + + +bool K3bAlsaOutputPlugin::init() +{ + cleanup(); + + KConfigGroup c( k3bcore->config(), "Alsa Output Plugin" ); + QString alsaDevice = c.readEntry( "output device", "default" ); + + int err = snd_pcm_open( &d->pcm_playback, alsaDevice.local8Bit(), SND_PCM_STREAM_PLAYBACK, 0 ); + if( err < 0 ) { + d->lastErrorMessage = i18n("Could not open alsa audio device '%1' (%2).").arg(alsaDevice).arg(snd_strerror(err)); + d->error = true; + return false; + } + + if( !setupHwParams() ) { + d->error = true; + return false; + } + + d->error = false; + return true; +} + + +bool K3bAlsaOutputPlugin::setupHwParams() +{ + snd_pcm_hw_params_t* hw_params; + int err = 0; + + if( ( err = snd_pcm_hw_params_malloc( &hw_params ) ) < 0 ) { + d->lastErrorMessage = i18n("Could not allocate hardware parameter structure (%1)").arg(snd_strerror(err)); + d->error = true; + return false; + } + + if( (err = snd_pcm_hw_params_any( d->pcm_playback, hw_params )) < 0) { + d->lastErrorMessage = i18n("Could not initialize hardware parameter structure (%1).").arg(snd_strerror(err)); + snd_pcm_hw_params_free( hw_params ); + d->error = true; + return false; + } + + if( (err = snd_pcm_hw_params_set_access( d->pcm_playback, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { + d->lastErrorMessage = i18n("Could not set access type (%1).").arg(snd_strerror(err)); + snd_pcm_hw_params_free( hw_params ); + d->error = true; + return false; + } + + if( (err = snd_pcm_hw_params_set_format( d->pcm_playback, hw_params, SND_PCM_FORMAT_S16_BE)) < 0) { + if( (err = snd_pcm_hw_params_set_format( d->pcm_playback, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) { + d->lastErrorMessage = i18n("Could not set sample format (%1).").arg(snd_strerror(err)); + snd_pcm_hw_params_free( hw_params ); + d->error = true; + return false; + } + else + d->swap = true; + } + else + d->swap = false; + + d->sampleRate = 44100; + if( (err = snd_pcm_hw_params_set_rate_near( d->pcm_playback, hw_params, &d->sampleRate, 0)) < 0) { + d->lastErrorMessage = i18n("Could not set sample rate (%1).").arg(snd_strerror(err)); + snd_pcm_hw_params_free( hw_params ); + d->error = true; + return false; + } + + kdDebug() << "(K3bAlsaOutputPlugin) samplerate set to " << d->sampleRate << endl; + + if( (err = snd_pcm_hw_params_set_channels( d->pcm_playback, hw_params, 2)) < 0) { + d->lastErrorMessage = i18n("Could not set channel count (%1).").arg(snd_strerror(err)); + snd_pcm_hw_params_free( hw_params ); + d->error = true; + return false; + } + + if( (err = snd_pcm_hw_params( d->pcm_playback, hw_params )) < 0) { + d->lastErrorMessage = i18n("Could not set parameters (%1).").arg(snd_strerror(err)); + snd_pcm_hw_params_free( hw_params ); + d->error = true; + return false; + } + + snd_pcm_hw_params_free(hw_params); + + return true; +} + + +QString K3bAlsaOutputPlugin::lastErrorMessage() const +{ + return d->lastErrorMessage; +} + + +K3bPluginConfigWidget* K3bAlsaOutputPlugin::createConfigWidget( QWidget* parent, + const char* name ) const +{ + return new K3bAlsaOutputPluginConfigWidget( parent, name ); +} + + + +K3bAlsaOutputPluginConfigWidget::K3bAlsaOutputPluginConfigWidget( QWidget* parent, const char* name ) + : K3bPluginConfigWidget( parent, name ) +{ + QHBoxLayout* l = new QHBoxLayout( this ); + l->setSpacing( KDialog::spacingHint() ); + l->setAutoAdd( true ); + + (void)new QLabel( i18n("Alsa device:"), this ); + + m_comboDevice = new KComboBox( this ); + m_comboDevice->setEditable( true ); + // enable completion + m_comboDevice->completionObject(); + + // FIXME: initialize the list of devices + m_comboDevice->insertItem( "default" ); +} + + +K3bAlsaOutputPluginConfigWidget::~K3bAlsaOutputPluginConfigWidget() +{ +} + + +void K3bAlsaOutputPluginConfigWidget::loadConfig() +{ + KConfigGroup c( k3bcore->config(), "Alsa Output Plugin" ); + + m_comboDevice->setCurrentText( c.readEntry( "output device", "default" ) ); +} + + +void K3bAlsaOutputPluginConfigWidget::saveConfig() +{ + KConfigGroup c( k3bcore->config(), "Alsa Output Plugin" ); + + c.writeEntry( "output device", m_comboDevice->currentText() ); +} + + +#include "k3balsaoutputplugin.moc" diff --git a/plugins/audiooutput/alsa/k3balsaoutputplugin.h b/plugins/audiooutput/alsa/k3balsaoutputplugin.h new file mode 100644 index 0000000..7e59b1e --- /dev/null +++ b/plugins/audiooutput/alsa/k3balsaoutputplugin.h @@ -0,0 +1,69 @@ +/* + * + * $Id: k3bartsoutputplugin.h 369057 2004-12-07 14:05:11Z trueg $ + * Copyright (C) 2004 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_ALSA_AUDIO_OUTPUT_H_ +#define _K3B_ALSA_AUDIO_OUTPUT_H_ + +#include <k3baudiooutputplugin.h> +#include <k3bpluginconfigwidget.h> + +class KComboBox; + + +class K3bAlsaOutputPlugin : public K3bAudioOutputPlugin +{ + public: + K3bAlsaOutputPlugin( QObject* parent = 0, const char* name = 0 ); + ~K3bAlsaOutputPlugin(); + + int pluginSystemVersion() const { return 3; } + QCString soundSystem() const { return "alsa"; } + + bool init(); + void cleanup(); + + QString lastErrorMessage() const; + + int write( char* data, int len ); + + K3bPluginConfigWidget* createConfigWidget( QWidget* parent = 0, + const char* name = 0 ) const; + + private: + bool setupHwParams(); + bool recoverFromError( int err ); + + class Private; + Private* d; +}; + + +class K3bAlsaOutputPluginConfigWidget : public K3bPluginConfigWidget +{ + Q_OBJECT + + public: + K3bAlsaOutputPluginConfigWidget( QWidget* parent = 0, const char* name = 0 ); + ~K3bAlsaOutputPluginConfigWidget(); + + public slots: + void loadConfig(); + void saveConfig(); + + private: + KComboBox* m_comboDevice; +}; + +#endif diff --git a/plugins/audiooutput/alsa/k3balsaoutputplugin.plugin b/plugins/audiooutput/alsa/k3balsaoutputplugin.plugin new file mode 100644 index 0000000..b5957d7 --- /dev/null +++ b/plugins/audiooutput/alsa/k3balsaoutputplugin.plugin @@ -0,0 +1,9 @@ +[K3b Plugin] +Lib=libk3balsaoutputplugin +Group=AudioOutput +Name=K3b Alsa Audio Output Plugin +Author=Sebastian Trueg +Email=trueg@k3b.org +Version=1.0 +Comment=Audio Output plugin which plays through alsa +License=GPL diff --git a/plugins/audiooutput/arts/Makefile.am b/plugins/audiooutput/arts/Makefile.am new file mode 100644 index 0000000..6d5adf5 --- /dev/null +++ b/plugins/audiooutput/arts/Makefile.am @@ -0,0 +1,13 @@ +AM_CPPFLAGS = -I$(srcdir)/../../../libk3b/core -I$(srcdir)/../../../libk3b/plugin $(all_includes) + +kde_module_LTLIBRARIES = libk3bartsoutputplugin.la + +libk3bartsoutputplugin_la_SOURCES = k3bartsoutputplugin.cpp + +libk3bartsoutputplugin_la_LIBADD = ../../../libk3b/libk3b.la -lartsc +libk3bartsoutputplugin_la_LDFLAGS = -avoid-version -module -no-undefined $(all_libraries) + +pluginsdir = $(kde_datadir)/k3b/plugins +plugins_DATA = k3bartsoutputplugin.plugin + +METASOURCES = AUTO diff --git a/plugins/audiooutput/arts/k3bartsoutputplugin.cpp b/plugins/audiooutput/arts/k3bartsoutputplugin.cpp new file mode 100644 index 0000000..893571a --- /dev/null +++ b/plugins/audiooutput/arts/k3bartsoutputplugin.cpp @@ -0,0 +1,90 @@ +/* + * + * $Id: k3bartsoutputplugin.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include <config.h> + +#include "k3bartsoutputplugin.h" +#include <k3bpluginfactory.h> + +#include <kdebug.h> + + +K_EXPORT_COMPONENT_FACTORY( libk3bartsoutputplugin, K3bPluginFactory<K3bArtsOutputPlugin>( "k3bartsoutputplugin" ) ) + + +K3bArtsOutputPlugin::K3bArtsOutputPlugin( QObject* parent, const char* name ) + : K3bAudioOutputPlugin( parent, name ), + m_initialized(false), + m_lastErrorCode(0) +{ +} + + +K3bArtsOutputPlugin::~K3bArtsOutputPlugin() +{ + cleanup(); +} + + +int K3bArtsOutputPlugin::write( char* data, int len ) +{ + for( int i = 0; i < len-1; i+=2 ) { + char b = data[i]; + data[i] = data[i+1]; + data[i+1] = b; + } + + m_lastErrorCode = arts_write( m_stream, data, len ); + + if( m_lastErrorCode < 0 ) + return -1; + else + return len; +} + + +void K3bArtsOutputPlugin::cleanup() +{ + if( m_initialized ) { + arts_close_stream( m_stream ); + kdDebug() << "(K3bArtsOutputPlugin::cleanup) arts_free()" << endl; + arts_free(); + kdDebug() << "(K3bArtsOutputPlugin::cleanup) arts_free() done" << endl; + m_initialized = false; + } +} + + +bool K3bArtsOutputPlugin::init() +{ + kdDebug() << "(K3bArtsOutputPlugin::init)" << endl; + if( !m_initialized ) { + kdDebug() << "(K3bArtsOutputPlugin::init) arts_init()" << endl; + m_lastErrorCode = arts_init(); + m_initialized = ( m_lastErrorCode == 0 ); + kdDebug() << "(K3bArtsOutputPlugin::init) arts_init() done: " << m_lastErrorCode << endl; + if( m_initialized ) + m_stream = arts_play_stream( 44100, 16, 2, "K3bArtsOutputPlugin" ); + } + + return m_initialized; +} + + +QString K3bArtsOutputPlugin::lastErrorMessage() const +{ + return QString::fromLocal8Bit( arts_error_text(m_lastErrorCode) ); +} + diff --git a/plugins/audiooutput/arts/k3bartsoutputplugin.h b/plugins/audiooutput/arts/k3bartsoutputplugin.h new file mode 100644 index 0000000..57a2b22 --- /dev/null +++ b/plugins/audiooutput/arts/k3bartsoutputplugin.h @@ -0,0 +1,47 @@ +/* + * + * $Id: k3bartsoutputplugin.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_ARTS_AUDIO_OUTPUT_H_ +#define _K3B_ARTS_AUDIO_OUTPUT_H_ + +#include <k3baudiooutputplugin.h> + +#include <artsc/artsc.h> + + +class K3bArtsOutputPlugin : public K3bAudioOutputPlugin +{ + public: + K3bArtsOutputPlugin( QObject* parent = 0, const char* name = 0 ); + ~K3bArtsOutputPlugin(); + + int pluginSystemVersion() const { return 3; } + QCString soundSystem() const { return "arts"; } + + bool init(); + void cleanup(); + + QString lastErrorMessage() const; + + int write( char* data, int len ); + + private: + bool m_initialized; + int m_lastErrorCode; + + arts_stream_t m_stream; +}; + +#endif diff --git a/plugins/audiooutput/arts/k3bartsoutputplugin.plugin b/plugins/audiooutput/arts/k3bartsoutputplugin.plugin new file mode 100644 index 0000000..599869f --- /dev/null +++ b/plugins/audiooutput/arts/k3bartsoutputplugin.plugin @@ -0,0 +1,9 @@ +[K3b Plugin] +Lib=libk3bartsoutputplugin +Group=AudioOutput +Name=K3b Arts Audio Output Plugin +Author=Sebastian Trueg +Email=trueg@k3b.org +Version=1.0 +Comment=Audio Output plugin which plays through arts +License=GPL diff --git a/plugins/decoder/Makefile.am b/plugins/decoder/Makefile.am new file mode 100644 index 0000000..1b4eafa --- /dev/null +++ b/plugins/decoder/Makefile.am @@ -0,0 +1,26 @@ + +if include_OGG +DECOGGDIR = ogg +endif + +if include_MP3 +DECMP3DIR = mp3 +endif + +if include_FLAC +DECFLACDIR = flac +endif + +if include_AIFF +DECAIFFDIR = libsndfile +endif + +if include_FFMPEG +FFMPEGDIR = ffmpeg +endif + +if include_MPC +MPCDIR = musepack +endif + +SUBDIRS = wave $(DECOGGDIR) $(DECMP3DIR) $(DECFLACDIR) $(DECAIFFDIR) $(FFMPEGDIR) $(MPCDIR) diff --git a/plugins/decoder/ffmpeg/Makefile.am b/plugins/decoder/ffmpeg/Makefile.am new file mode 100644 index 0000000..b4c46e2 --- /dev/null +++ b/plugins/decoder/ffmpeg/Makefile.am @@ -0,0 +1,15 @@ +AM_CPPFLAGS = -I$(srcdir)/../../../libk3b/core -I$(srcdir)/../../../libk3b/plugin -I$(srcdir)/../../../libk3bdevice $(all_includes) +KDE_CXXFLAGS = -D__STDC_CONSTANT_MACROS + +kde_module_LTLIBRARIES = libk3bffmpegdecoder.la + +libk3bffmpegdecoder_la_SOURCES = k3bffmpegdecoder.cpp k3bffmpegwrapper.cpp + +libk3bffmpegdecoder_la_LIBADD = ../../../libk3b/libk3b.la $(LIB_KDEUI) -lavcodec -lavformat +libk3bffmpegdecoder_la_LDFLAGS = -avoid-version -module -no-undefined $(all_libraries) + +pluginsdir = $(kde_datadir)/k3b/plugins +plugins_DATA = k3bffmpegdecoder.plugin + +METASOURCES = AUTO + diff --git a/plugins/decoder/ffmpeg/configure.in.bot b/plugins/decoder/ffmpeg/configure.in.bot new file mode 100644 index 0000000..3d24645 --- /dev/null +++ b/plugins/decoder/ffmpeg/configure.in.bot @@ -0,0 +1,25 @@ +echo "" + +echo "K3b - FFMpeg decoder plugin (decodes wma and others):" +if test x$have_ffmpeg = xyes; then + echo "K3b - yes" + if test x$enable_ffmpeg_all_codecs = xyes; then + echo "K3b - WARNING: You enabled all codecs in the ffmpeg decoder plugin." + echo "K3b - Be aware that most are not tested and track lengths" + echo "K3b - will be wrong in many cases." + fi +else + echo "K3b - no" +if test "$ac_cv_use_ffmpeg" = "yes"; then + if test "$ffmpeg_compiles" = "yes"; then + echo "K3b - You are missing the ffmpeg libraries." + echo "K3b - Make sure ffmpeg has been configured as a" + echo "K3b - shared library (which is not the default)." + else + echo "K3b - You are missing the ffmpeg headers and libraries" + echo "K3b - version 0.4.9 or higher." + fi + echo "K3b - The ffmpeg audio decoding plugin (decodes wma and" + echo "K3b - others) won't be compiled." +fi +fi diff --git a/plugins/decoder/ffmpeg/configure.in.in b/plugins/decoder/ffmpeg/configure.in.in new file mode 100644 index 0000000..84b345a --- /dev/null +++ b/plugins/decoder/ffmpeg/configure.in.in @@ -0,0 +1,68 @@ +dnl --------------- FFMPEG CHECK --------------------------------- + +AC_ARG_WITH( + ffmpeg, + AS_HELP_STRING( + [--without-ffmpeg], + [build K3b without ffmpeg audio decoder support (default=no)]), + [ac_cv_use_ffmpeg=$withval], + [ac_cv_use_ffmpeg=yes] +) + +# +# The ffmpeg decoder plugin needs ffmpeg 0.4.9 or higher +# +have_ffmpeg=no +if test "$ac_cv_use_ffmpeg" = "yes"; then + k3b_cxxflags_save="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -D__STDC_CONSTANT_MACROS" + AC_MSG_CHECKING(for ffmpeg >= 0.4.9) + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + AC_COMPILE_IFELSE( + extern "C" { + #include <libavformat/avformat.h> + #include <libavcodec/avcodec.h> + } + + int main() { + AVFormatContext* fc = 0; + AVPacket* p = 0; + av_register_all(); + return av_read_frame( fc, p ); + }, + [ffmpeg_compiles=yes], [ffmpeg_compiles=no] ) + OLD_LIBS=$LIBS + LIBS="-lavformat -lavcodec $LIBS" + AC_LINK_IFELSE( + extern "C" { + #include <libavformat/avformat.h> + #include <libavcodec/avcodec.h> + } + + int main() { + AVFormatContext* fc = 0; + AVPacket* p = 0; + av_register_all(); + return av_read_frame( fc, p ); + }, + [ffmpeg_links=yes], [ffmpeg_links=no] ) + AC_LANG_RESTORE + LIBS=$OLD_LIBS + have_ffmpeg=$ffmpeg_links + AC_MSG_RESULT($have_ffmpeg) + CXXFLAGS=$k3b_cxxflags_save +fi +AM_CONDITIONAL(include_FFMPEG, [test x$have_ffmpeg = xyes]) + +dnl --------------- FFMPEG CHECK END ------------------------------ + +AC_ARG_ENABLE( + ffmpeg-all-codecs, + AS_HELP_STRING( + [--enable-ffmpeg-all-codecs], + [Build K3b's ffmeg decoder plugin with all audio codecs enabled (default=disabled)]), + [AC_DEFINE(K3B_FFMPEG_ALL_CODECS, 1, [Defined if all ffmpeg codecs should be allowed]) + enable_ffmpeg_all_codecs=yes], + [enable_ffmpeg_all_codecs=no] +) diff --git a/plugins/decoder/ffmpeg/k3bffmpegdecoder.cpp b/plugins/decoder/ffmpeg/k3bffmpegdecoder.cpp new file mode 100644 index 0000000..fd47c52 --- /dev/null +++ b/plugins/decoder/ffmpeg/k3bffmpegdecoder.cpp @@ -0,0 +1,155 @@ +/* + * + * $Id: k3bffmpegdecoder.cpp 641798 2007-03-12 16:07:10Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include <config.h> + +#include "k3bffmpegdecoder.h" +#include "k3bffmpegwrapper.h" + +#include <kdebug.h> +#include <k3bpluginfactory.h> + +extern "C" { +#include <libavcodec/avcodec.h> +} + +#include <math.h> + + +K_EXPORT_COMPONENT_FACTORY( libk3bffmpegdecoder, K3bPluginFactory<K3bFFMpegDecoderFactory>( "k3bffmpegdecoder" ) ) + + +K3bFFMpegDecoderFactory::K3bFFMpegDecoderFactory( QObject* parent, const char* name ) + : K3bAudioDecoderFactory( parent, name ) +{ +} + + +K3bFFMpegDecoderFactory::~K3bFFMpegDecoderFactory() +{ +} + + +K3bAudioDecoder* K3bFFMpegDecoderFactory::createDecoder( QObject* parent, + const char* name ) const +{ + return new K3bFFMpegDecoder( parent, name ); +} + + +bool K3bFFMpegDecoderFactory::canDecode( const KURL& url ) +{ + K3bFFMpegFile* file = K3bFFMpegWrapper::instance()->open( url.path() ); + if( file ) { + delete file; + return true; + } + else { + return false; + } +} + + + + + + +K3bFFMpegDecoder::K3bFFMpegDecoder( QObject* parent, const char* name ) + : K3bAudioDecoder( parent, name ), + m_file(0) +{ +} + + +K3bFFMpegDecoder::~K3bFFMpegDecoder() +{ +} + + +QString K3bFFMpegDecoder::fileType() const +{ + return m_type; +} + + +bool K3bFFMpegDecoder::analyseFileInternal( K3b::Msf& frames, int& samplerate, int& ch ) +{ + m_file = K3bFFMpegWrapper::instance()->open( filename() ); + if( m_file ) { + + // TODO: call addTechnicalInfo + + addMetaInfo( META_TITLE, m_file->title() ); + addMetaInfo( META_ARTIST, m_file->author() ); + addMetaInfo( META_COMMENT, m_file->comment() ); + + samplerate = m_file->sampleRate(); + ch = m_file->channels(); + m_type = m_file->typeComment(); + frames = m_file->length(); + + // ffmpeg's length information is not reliable at all + // so we have to decode the whole file in order to get the correct length +// char buffer[10*2048]; +// int len = 0; +// unsigned long long bytes = 0; +// while( ( len = m_file->read( buffer, 10*2048 ) ) > 0 ) +// bytes += len; + +// frames = (unsigned long)ceil((double)bytes/2048.0); + + // cleanup; + delete m_file; + m_file = 0; + + return true; + } + else + return false; +} + + +bool K3bFFMpegDecoder::initDecoderInternal() +{ + if( !m_file ) + m_file = K3bFFMpegWrapper::instance()->open( filename() ); + + return (m_file != 0); +} + + +void K3bFFMpegDecoder::cleanup() +{ + delete m_file; + m_file = 0; +} + + +bool K3bFFMpegDecoder::seekInternal( const K3b::Msf& msf ) +{ + if( msf == 0 ) + return initDecoderInternal(); + else + return m_file->seek( msf ); +} + + +int K3bFFMpegDecoder::decodeInternal( char* _data, int maxLen ) +{ + return m_file->read( _data, maxLen ); +} + + +#include "k3bffmpegdecoder.moc" diff --git a/plugins/decoder/ffmpeg/k3bffmpegdecoder.h b/plugins/decoder/ffmpeg/k3bffmpegdecoder.h new file mode 100644 index 0000000..1c21827 --- /dev/null +++ b/plugins/decoder/ffmpeg/k3bffmpegdecoder.h @@ -0,0 +1,67 @@ +/* + * + * $Id: k3bffmpegdecoder.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_FFMPEG_DECODER_H_ +#define _K3B_FFMPEG_DECODER_H_ + +#include <k3baudiodecoder.h> + +class K3bFFMpegFile; + + +class K3bFFMpegDecoderFactory : public K3bAudioDecoderFactory +{ + Q_OBJECT + + public: + K3bFFMpegDecoderFactory( QObject* parent = 0, const char* name = 0 ); + ~K3bFFMpegDecoderFactory(); + + bool canDecode( const KURL& filename ); + + int pluginSystemVersion() const { return 3; } + + bool multiFormatDecoder() const { return true; } + + K3bAudioDecoder* createDecoder( QObject* parent = 0, + const char* name = 0 ) const; +}; + + +class K3bFFMpegDecoder : public K3bAudioDecoder +{ + Q_OBJECT + + public: + K3bFFMpegDecoder( QObject* parent = 0, const char* name = 0 ); + ~K3bFFMpegDecoder(); + + QString fileType() const; + + void cleanup(); + + protected: + bool analyseFileInternal( K3b::Msf& frames, int& samplerate, int& ch ); + bool initDecoderInternal(); + bool seekInternal( const K3b::Msf& ); + + int decodeInternal( char* _data, int maxLen ); + + private: + K3bFFMpegFile* m_file; + QString m_type; +}; + +#endif diff --git a/plugins/decoder/ffmpeg/k3bffmpegdecoder.plugin b/plugins/decoder/ffmpeg/k3bffmpegdecoder.plugin new file mode 100644 index 0000000..3592388 --- /dev/null +++ b/plugins/decoder/ffmpeg/k3bffmpegdecoder.plugin @@ -0,0 +1,9 @@ +[K3b Plugin] +Lib=libk3bffmpegdecoder +Group=AudioDecoder +Name=K3b FFMpeg Decoder +Author=Sebastian Trueg +Email=trueg@k3b.org +Version=0.9.1 +Comment=Decoding module to decode wma files +License=GPL diff --git a/plugins/decoder/ffmpeg/k3bffmpegwrapper.cpp b/plugins/decoder/ffmpeg/k3bffmpegwrapper.cpp new file mode 100644 index 0000000..514fd67 --- /dev/null +++ b/plugins/decoder/ffmpeg/k3bffmpegwrapper.cpp @@ -0,0 +1,375 @@ +/* + * + * $Id: k3bffmpegwrapper.cpp 641819 2007-03-12 17:29:23Z trueg $ + * Copyright (C) 2004-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include <config.h> + +#include "k3bffmpegwrapper.h" + +extern "C" { +#include <libavcodec/avcodec.h> +#include <libavformat/avformat.h> +} + +#include <string.h> + +#include <klocale.h> + + +#if LIBAVFORMAT_BUILD < 4629 +#define FFMPEG_BUILD_PRE_4629 +#endif + + +K3bFFMpegWrapper* K3bFFMpegWrapper::s_instance = 0; + + +class K3bFFMpegFile::Private +{ +public: + AVFormatContext* formatContext; + AVCodec* codec; + + K3b::Msf length; + + // for decoding + char outputBuffer[AVCODEC_MAX_AUDIO_FRAME_SIZE]; + char* outputBufferPos; + int outputBufferSize; + AVPacket packet; + Q_UINT8* packetData; + int packetSize; +}; + + +K3bFFMpegFile::K3bFFMpegFile( const QString& filename ) + : m_filename(filename) +{ + d = new Private; + d->formatContext = 0; + d->codec = 0; +} + + +K3bFFMpegFile::~K3bFFMpegFile() +{ + close(); + delete d; +} + + +bool K3bFFMpegFile::open() +{ + close(); + + // open the file + int err = av_open_input_file( &d->formatContext, m_filename.local8Bit(), 0, 0, 0 ); + if( err < 0 ) { + kdDebug() << "(K3bFFMpegFile) unable to open " << m_filename << " with error " << err << endl; + return false; + } + + // analyze the streams + av_find_stream_info( d->formatContext ); + + // we only handle files containing one audio stream + if( d->formatContext->nb_streams != 1 ) { + kdDebug() << "(K3bFFMpegFile) more than one stream in " << m_filename << endl; + return false; + } + + // urgh... ugly +#ifdef FFMPEG_BUILD_PRE_4629 + AVCodecContext* codecContext = &d->formatContext->streams[0]->codec; +#else + AVCodecContext* codecContext = d->formatContext->streams[0]->codec; +#endif + if( codecContext->codec_type != CODEC_TYPE_AUDIO ) { + kdDebug() << "(K3bFFMpegFile) not a simple audio stream: " << m_filename << endl; + return false; + } + + // get the codec + d->codec = avcodec_find_decoder(codecContext->codec_id); + if( !d->codec ) { + kdDebug() << "(K3bFFMpegFile) no codec found for " << m_filename << endl; + return false; + } + + // open the codec on our context + kdDebug() << "(K3bFFMpegFile) found codec for " << m_filename << endl; + if( avcodec_open( codecContext, d->codec ) < 0 ) { + kdDebug() << "(K3bFFMpegDecoderFactory) could not open codec." << endl; + return false; + } + + // determine the length of the stream + d->length = K3b::Msf::fromSeconds( (double)d->formatContext->duration / (double)AV_TIME_BASE ); + + if( d->length == 0 ) { + kdDebug() << "(K3bFFMpegDecoderFactory) invalid length." << endl; + return false; + } + + // dump some debugging info + dump_format( d->formatContext, 0, m_filename.local8Bit(), 0 ); + + return true; +} + + +void K3bFFMpegFile::close() +{ + d->outputBufferSize = 0; + d->packetSize = 0; + d->packetData = 0; + + if( d->codec ) { +#ifdef FFMPEG_BUILD_PRE_4629 + avcodec_close( &d->formatContext->streams[0]->codec ); +#else + avcodec_close( d->formatContext->streams[0]->codec ); +#endif + d->codec = 0; + } + + if( d->formatContext ) { + av_close_input_file( d->formatContext ); + d->formatContext = 0; + } +} + + +K3b::Msf K3bFFMpegFile::length() const +{ + return d->length; +} + + +int K3bFFMpegFile::sampleRate() const +{ +#ifdef FFMPEG_BUILD_PRE_4629 + return d->formatContext->streams[0]->codec.sample_rate; +#else + return d->formatContext->streams[0]->codec->sample_rate; +#endif +} + + +int K3bFFMpegFile::channels() const +{ +#ifdef FFMPEG_BUILD_PRE_4629 + return d->formatContext->streams[0]->codec.channels; +#else + return d->formatContext->streams[0]->codec->channels; +#endif +} + + +int K3bFFMpegFile::type() const +{ +#ifdef FFMPEG_BUILD_PRE_4629 + return d->formatContext->streams[0]->codec.codec_id; +#else + return d->formatContext->streams[0]->codec->codec_id; +#endif +} + + +QString K3bFFMpegFile::typeComment() const +{ + switch( type() ) { + case CODEC_ID_WMAV1: + return i18n("Windows Media v1"); + case CODEC_ID_WMAV2: + return i18n("Windows Media v2"); + case CODEC_ID_MP3: + return i18n("MPEG 1 Layer III"); + case CODEC_ID_AAC: + return i18n("Advanced Audio Coding (AAC)"); + default: + return QString::fromLocal8Bit( d->codec->name ); + } +} + + +QString K3bFFMpegFile::title() const +{ + // FIXME: is this UTF8 or something?? + if( d->formatContext->title[0] != '\0' ) + return QString::fromLocal8Bit( d->formatContext->title ); + else + return QString::null; +} + + +QString K3bFFMpegFile::author() const +{ + // FIXME: is this UTF8 or something?? + if( d->formatContext->author[0] != '\0' ) + return QString::fromLocal8Bit( d->formatContext->author ); + else + return QString::null; +} + + +QString K3bFFMpegFile::comment() const +{ + // FIXME: is this UTF8 or something?? + if( d->formatContext->comment[0] != '\0' ) + return QString::fromLocal8Bit( d->formatContext->comment ); + else + return QString::null; +} + + +int K3bFFMpegFile::read( char* buf, int bufLen ) +{ + if( fillOutputBuffer() > 0 ) { + int len = QMIN(bufLen, d->outputBufferSize); + ::memcpy( buf, d->outputBufferPos, len ); + + // TODO: only swap if needed + for( int i = 0; i < len-1; i+=2 ) { + char a = buf[i]; + buf[i] = buf[i+1]; + buf[i+1] = a; + } + + d->outputBufferPos += len; + d->outputBufferSize -= len; + return len; + } + else + return 0; +} + + +// fill d->packetData with data to decode +int K3bFFMpegFile::readPacket() +{ + if( d->packetSize <= 0 ) { + av_init_packet( &d->packet ); + + if( av_read_frame( d->formatContext, &d->packet ) < 0 ) { + return 0; + } + + d->packetSize = d->packet.size; + d->packetData = d->packet.data; + } + + return d->packetSize; +} + + +// decode data in d->packetData and fill d->outputBuffer +int K3bFFMpegFile::fillOutputBuffer() +{ + // decode if the output buffer is empty + if( d->outputBufferSize <= 0 ) { + + // make sure we have data to decode + if( readPacket() == 0 ) { + return 0; + } + + d->outputBufferPos = d->outputBuffer; + +#ifdef FFMPEG_BUILD_PRE_4629 + int len = avcodec_decode_audio2( &d->formatContext->streams[0]->codec, +#else + int len = avcodec_decode_audio2( d->formatContext->streams[0]->codec, +#endif + (short*)d->outputBuffer, &d->outputBufferSize, + d->packetData, d->packetSize ); + + d->packetSize -= len; + d->packetData += len; + + if( d->packetSize <= 0 ) + av_free_packet( &d->packet ); + } + + // if it is still empty try again + if( d->outputBufferSize <= 0 ) + return fillOutputBuffer(); + else + return d->outputBufferSize; +} + + +bool K3bFFMpegFile::seek( const K3b::Msf& msf ) +{ + d->outputBufferSize = 0; + d->packetSize = 0; + + double seconds = (double)msf.totalFrames()/75.0; + Q_UINT64 timestamp = (Q_UINT64)(seconds * (double)AV_TIME_BASE); + + // FIXME: do we really need the start_time and why? +#if LIBAVFORMAT_BUILD >= 4619 + return ( av_seek_frame( d->formatContext, -1, timestamp + d->formatContext->start_time, 0 ) >= 0 ); +#else + return ( av_seek_frame( d->formatContext, -1, timestamp + d->formatContext->start_time ) >= 0 ); +#endif +} + + + + + + +K3bFFMpegWrapper::K3bFFMpegWrapper() +{ + av_register_all(); +} + + +K3bFFMpegWrapper::~K3bFFMpegWrapper() +{ + s_instance = 0; +} + + +K3bFFMpegWrapper* K3bFFMpegWrapper::instance() +{ + if( !s_instance ) { + s_instance = new K3bFFMpegWrapper(); + } + + return s_instance; +} + + +K3bFFMpegFile* K3bFFMpegWrapper::open( const QString& filename ) const +{ + K3bFFMpegFile* file = new K3bFFMpegFile( filename ); + if( file->open() ) { +#ifndef K3B_FFMPEG_ALL_CODECS + // + // only allow tested formats. ffmpeg seems not to be too reliable with every format. + // mp3 being one of them sadly. Most importantly: allow the libsndfile decoder to do + // its thing. + // + if( file->type() == CODEC_ID_WMAV1 || + file->type() == CODEC_ID_WMAV2 || + file->type() == CODEC_ID_AAC ) +#endif + return file; + } + + delete file; + return 0; +} diff --git a/plugins/decoder/ffmpeg/k3bffmpegwrapper.h b/plugins/decoder/ffmpeg/k3bffmpegwrapper.h new file mode 100644 index 0000000..63b5f58 --- /dev/null +++ b/plugins/decoder/ffmpeg/k3bffmpegwrapper.h @@ -0,0 +1,85 @@ +/* + * + * $Id: k3bffmpegwrapper.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_FFMPEG_WRAPPER_H_ +#define _K3B_FFMPEG_WRAPPER_H_ + +#include <k3bmsf.h> + + + +/** + * Create with K3bFFMpegWrapper::open + */ +class K3bFFMpegFile +{ + friend class K3bFFMpegWrapper; + + public: + ~K3bFFMpegFile(); + + const QString& filename() const { return m_filename; } + + bool open(); + void close(); + + K3b::Msf length() const; + int sampleRate() const; + int channels() const; + + /** + * ffmpeg internal enumeration + */ + int type() const; + QString typeComment() const; + + QString title() const; + QString author() const; + QString comment() const; + + int read( char* buf, int bufLen ); + bool seek( const K3b::Msf& ); + + private: + K3bFFMpegFile( const QString& filename ); + int readPacket(); + int fillOutputBuffer(); + + QString m_filename; + + class Private; + Private* d; +}; + + +class K3bFFMpegWrapper +{ + public: + ~K3bFFMpegWrapper(); + + /** + * returns 0 on failure. + */ + K3bFFMpegFile* open( const QString& filename ) const; + + static K3bFFMpegWrapper* instance(); + + private: + K3bFFMpegWrapper(); + + static K3bFFMpegWrapper* s_instance; +}; + +#endif diff --git a/plugins/decoder/flac/Makefile.am b/plugins/decoder/flac/Makefile.am new file mode 100644 index 0000000..bdcc4a3 --- /dev/null +++ b/plugins/decoder/flac/Makefile.am @@ -0,0 +1,13 @@ +AM_CPPFLAGS = -I$(srcdir)/../../../libk3b/plugin -I$(srcdir)/../../../libk3bdevice -I$(srcdir)/../../../libk3b/core $(taglib_includes) $(all_includes) + +kde_module_LTLIBRARIES = libk3bflacdecoder.la + +libk3bflacdecoder_la_SOURCES = k3bflacdecoder.cpp + +libk3bflacdecoder_la_LIBADD = ../../../libk3b/libk3b.la $(LIB_KDEUI) -lFLAC++ -lFLAC $(taglib_libs) +libk3bflacdecoder_la_LDFLAGS = -avoid-version -module -no-undefined $(all_libraries) + +pluginsdir = $(kde_datadir)/k3b/plugins +plugins_DATA = k3bflacdecoder.plugin + +METASOURCES = AUTO diff --git a/plugins/decoder/flac/configure.in.bot b/plugins/decoder/flac/configure.in.bot new file mode 100644 index 0000000..f2d95a4 --- /dev/null +++ b/plugins/decoder/flac/configure.in.bot @@ -0,0 +1,13 @@ +echo "" + +if test x$have_flac = xyes; then + echo "K3b - FLAC support: yes" +else + echo "K3b - FLAC support: no" +if test "$ac_cv_use_flac" = "yes"; then + if test "$have_flac" = "no"; then + echo "K3b - You are missing the FLAC++ headers and libraries." + echo "K3b - The FLAC decoding plugin won't be compiled." + fi +fi +fi diff --git a/plugins/decoder/flac/configure.in.in b/plugins/decoder/flac/configure.in.in new file mode 100644 index 0000000..e6a3700 --- /dev/null +++ b/plugins/decoder/flac/configure.in.in @@ -0,0 +1,41 @@ +dnl === test for FLAC++ and FLAC - begin ==== +AC_ARG_WITH( + flac, + AS_HELP_STRING([--without-flac], [build K3b without FLAC support (default=no)]), + [ac_cv_use_flac=$withval], + [ac_cv_use_flac=yes] +) + +have_flac=no +if test "$ac_cv_use_flac" = "yes"; then + KDE_CHECK_HEADERS(FLAC++/decoder.h, [ + AC_CHECK_LIB(FLAC,FLAC__stream_decoder_process_single, + have_flac=yes,[],$all_libraries)]) + + AC_MSG_CHECKING(for libFLAC newer than 1.1.1) + AC_CACHE_VAL(k3b_flac_new, + [ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + AC_TRY_COMPILE( + [ + #include <FLAC++/metadata.h> + ], [ + FLAC::Metadata::VorbisComment* vc; + vc->get_vendor_string().get_field(); + ], k3b_flac_new=no, k3b_flac_new=yes ) + AC_LANG_RESTORE + ]) + AC_MSG_RESULT($k3b_flac_new) + if test $k3b_flac_new = yes; then + AC_DEFINE(FLAC_NEWER_THAN_1_1_1, + 1, + [Define to 1 if your flac library's version is newer than or equal to 1.1.2] + ) + fi +else + have_flac=no +fi + +AM_CONDITIONAL(include_FLAC, [test x$have_flac = xyes]) +dnl === test for FLAC++ and FLAC - end ==== diff --git a/plugins/decoder/flac/k3bflacdecoder.cpp b/plugins/decoder/flac/k3bflacdecoder.cpp new file mode 100644 index 0000000..762403f --- /dev/null +++ b/plugins/decoder/flac/k3bflacdecoder.cpp @@ -0,0 +1,494 @@ +/* + * FLAC decoder module for K3b. + * Based on the Ogg Vorbis module for same. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * Copyright (C) 2003-2004 John Steele Scott <toojays@toojays.net> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include <config.h> + +#include "k3bflacdecoder.h" + +#include <k3bpluginfactory.h> + +#include <qbuffer.h> +#include <qfile.h> +#include <qstringlist.h> + +#include <kurl.h> +#include <kdebug.h> +#include <klocale.h> + +#include <string.h> +#include <math.h> +#include <FLAC++/metadata.h> +#include <FLAC++/decoder.h> + +#ifdef HAVE_TAGLIB +#include <taglib/tag.h> +#include <taglib/flacfile.h> +#endif + +#if !defined FLACPP_API_VERSION_CURRENT || FLACPP_API_VERSION_CURRENT < 6 +#define LEGACY_FLAC +#else +#undef LEGACY_FLAC +#endif + +K_EXPORT_COMPONENT_FACTORY( libk3bflacdecoder, K3bPluginFactory<K3bFLACDecoderFactory>( "libk3bflacdecoder" ) ) + + +class K3bFLACDecoder::Private +#ifdef LEGACY_FLAC + : public FLAC::Decoder::SeekableStream +#else + : public FLAC::Decoder::Stream +#endif +{ +public: + void open(QFile* f) { + file = f; + file->open(IO_ReadOnly); + + internalBuffer->flush(); + + set_metadata_respond(FLAC__METADATA_TYPE_STREAMINFO); + set_metadata_respond(FLAC__METADATA_TYPE_VORBIS_COMMENT); + + init(); + process_until_end_of_metadata(); + } + + void cleanup() { + file->close(); + finish(); + delete comments; + comments = 0; + } + + Private(QFile* f) +#ifdef LEGACY_FLAC + : FLAC::Decoder::SeekableStream(), +#else + : FLAC::Decoder::Stream(), +#endif + comments(0) { + internalBuffer = new QBuffer(); + internalBuffer->open(IO_ReadWrite); + + open(f); + } + + + ~Private() { + cleanup(); + delete internalBuffer; + } + + bool seekToFrame(int frame); + + QFile* file; + QBuffer* internalBuffer; + FLAC::Metadata::VorbisComment* comments; + unsigned rate; + unsigned channels; + unsigned bitsPerSample; + unsigned maxFramesize; + unsigned maxBlocksize; + unsigned minFramesize; + unsigned minBlocksize; + FLAC__uint64 samples; + +protected: +#ifdef LEGACY_FLAC + virtual FLAC__SeekableStreamDecoderReadStatus read_callback(FLAC__byte buffer[], unsigned *bytes); + virtual FLAC__SeekableStreamDecoderSeekStatus seek_callback(FLAC__uint64 absolute_byte_offset); + virtual FLAC__SeekableStreamDecoderTellStatus tell_callback(FLAC__uint64 *absolute_byte_offset); + virtual FLAC__SeekableStreamDecoderLengthStatus length_callback(FLAC__uint64 *stream_length); +#else + virtual FLAC__StreamDecoderReadStatus read_callback(FLAC__byte buffer[], size_t *bytes); + virtual FLAC__StreamDecoderSeekStatus seek_callback(FLAC__uint64 absolute_byte_offset); + virtual FLAC__StreamDecoderTellStatus tell_callback(FLAC__uint64 *absolute_byte_offset); + virtual FLAC__StreamDecoderLengthStatus length_callback(FLAC__uint64 *stream_length); +#endif + virtual bool eof_callback(); + virtual void error_callback(FLAC__StreamDecoderErrorStatus){}; + virtual void metadata_callback(const ::FLAC__StreamMetadata *metadata); + virtual ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]); +}; + +bool K3bFLACDecoder::Private::seekToFrame(int frame) { + FLAC__uint64 sample = frame * rate / 75; + return seek_absolute(sample); +} + +bool K3bFLACDecoder::Private::eof_callback() { + return file->atEnd(); +} + +#ifdef LEGACY_FLAC +FLAC__SeekableStreamDecoderReadStatus K3bFLACDecoder::Private::read_callback(FLAC__byte buffer[], unsigned *bytes) { + long retval = file->readBlock((char *)buffer, (*bytes)); + if(-1 == retval) { + return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR; + } else { + (*bytes) = retval; + return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK; + } +} +#else +FLAC__StreamDecoderReadStatus K3bFLACDecoder::Private::read_callback(FLAC__byte buffer[], size_t *bytes) { + long retval = file->readBlock((char *)buffer, (*bytes)); + if(-1 == retval) { + return FLAC__STREAM_DECODER_READ_STATUS_ABORT; + } else { + (*bytes) = retval; + return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; + } +} +#endif + +#ifdef LEGACY_FLAC +FLAC__SeekableStreamDecoderSeekStatus +K3bFLACDecoder::Private::seek_callback(FLAC__uint64 absolute_byte_offset) { + if(!file->at(absolute_byte_offset)) + return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR; + else + return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK; +} +#else +FLAC__StreamDecoderSeekStatus +K3bFLACDecoder::Private::seek_callback(FLAC__uint64 absolute_byte_offset) { + if(file->at(absolute_byte_offset) == FALSE) + return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR; + else + return FLAC__STREAM_DECODER_SEEK_STATUS_OK; +} +#endif + +#ifdef LEGACY_FLAC +FLAC__SeekableStreamDecoderTellStatus +K3bFLACDecoder::Private::tell_callback(FLAC__uint64 *absolute_byte_offset) { + (*absolute_byte_offset) = file->at(); + return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK; +} +#else +FLAC__StreamDecoderTellStatus +K3bFLACDecoder::Private::tell_callback(FLAC__uint64 *absolute_byte_offset) { + (*absolute_byte_offset) = file->at(); + return FLAC__STREAM_DECODER_TELL_STATUS_OK; +} +#endif + +#ifdef LEGACY_FLAC +FLAC__SeekableStreamDecoderLengthStatus +K3bFLACDecoder::Private::length_callback(FLAC__uint64 *stream_length) { + (*stream_length) = file->size(); + return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK; +} +#else +FLAC__StreamDecoderLengthStatus +K3bFLACDecoder::Private::length_callback(FLAC__uint64 *stream_length) { + (*stream_length) = file->size(); + return FLAC__STREAM_DECODER_LENGTH_STATUS_OK; +} +#endif + + +void K3bFLACDecoder::Private::metadata_callback(const FLAC__StreamMetadata *metadata) { + switch (metadata->type) { + case FLAC__METADATA_TYPE_STREAMINFO: + channels = metadata->data.stream_info.channels; + rate = metadata->data.stream_info.sample_rate; + bitsPerSample = metadata->data.stream_info.bits_per_sample; + samples = metadata->data.stream_info.total_samples; + maxFramesize = metadata->data.stream_info.max_framesize; + minFramesize = metadata->data.stream_info.min_framesize; + maxBlocksize = metadata->data.stream_info.max_blocksize; + minBlocksize = metadata->data.stream_info.min_blocksize; + break; + case FLAC__METADATA_TYPE_VORBIS_COMMENT: + comments = new FLAC::Metadata::VorbisComment((FLAC__StreamMetadata *)metadata, true); + break; + default: + break; + } +} + +FLAC__StreamDecoderWriteStatus K3bFLACDecoder::Private::write_callback(const FLAC__Frame *frame, const FLAC__int32 * const buffer[]) { + unsigned i, j; + // Note that in canDecode we made sure that the input is 1-16 bit stereo or mono. + unsigned samples = frame->header.blocksize; + + for(i=0; i < samples; i++) { + // in FLAC channel 0 is left, 1 is right + for(j=0; j < this->channels; j++) { + FLAC__int32 value = (buffer[j][i])<<(16 - frame->header.bits_per_sample); + internalBuffer->putch(value >> 8); // msb + internalBuffer->putch(value & 0xFF); // lsb + } + } + + // Rewind the buffer so the decode method will take data from the beginning. + internalBuffer->at(0); + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; +} + +K3bFLACDecoder::K3bFLACDecoder( QObject* parent, const char* name ) + : K3bAudioDecoder( parent, name ) +{ + d = 0; +} + + +K3bFLACDecoder::~K3bFLACDecoder() +{ + delete d; +} + +void K3bFLACDecoder::cleanup() +{ + if (d) { + d->cleanup(); + d->open(new QFile(filename())); + } + else + d = new Private(new QFile(filename())); +} + +bool K3bFLACDecoder::analyseFileInternal( K3b::Msf& frames, int& samplerate, int& ch ) +{ + cleanup(); + + frames = (unsigned long)ceil((d->samples * 75.0)/d->rate); + samplerate = d->rate; + ch = d->channels; + + // add meta info + if( d->comments != 0 ) { + kdDebug() << "(K3bFLACDecoder) unpacking Vorbis tags" << endl; + for( unsigned int i = 0; i < d->comments->get_num_comments(); ++i ) { + QString key = QString::fromUtf8( d->comments->get_comment(i).get_field_name(), + d->comments->get_comment(i).get_field_name_length() ); + QString value = QString::fromUtf8( d->comments->get_comment(i).get_field_value(), + d->comments->get_comment(i).get_field_value_length() ); + + if( key.upper() == "TITLE" ) + addMetaInfo( META_TITLE, value ); + else if( key.upper() == "ARTIST" ) + addMetaInfo( META_ARTIST, value ); + else if( key.upper() == "DESCRIPTION" ) + addMetaInfo( META_COMMENT, value ); + } + } +#ifdef HAVE_TAGLIB + if ((d->comments == 0) || (d->comments->get_num_comments() == 0)) { + // no Vorbis comments, check for ID3 tags + kdDebug() << "(K3bFLACDecoder) using taglib to read tag" << endl; + TagLib::FLAC::File f( QFile::encodeName(filename()) ); + if( f.isOpen() ) { + addMetaInfo( META_TITLE, TStringToQString( f.tag()->title() ) ); + addMetaInfo( META_ARTIST, TStringToQString( f.tag()->artist() ) ); + addMetaInfo( META_COMMENT, TStringToQString( f.tag()->comment() ) ); + } + } +#endif + + return true; +} + + +bool K3bFLACDecoder::initDecoderInternal() +{ + cleanup(); + + return true; +} + + +int K3bFLACDecoder::decodeInternal( char* _data, int maxLen ) +{ + int bytesToCopy; + int bytesCopied; + int bytesAvailable; + +#ifdef LEGACY_FLAC + if(d->internalBuffer->size() == 0) { + // want more data + switch(d->get_state()) { + case FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM: + d->finish(); + break; + case FLAC__SEEKABLE_STREAM_DECODER_OK: + if(! d->process_single()) + return -1; + break; + default: + return -1; + } + } +#else + if(d->internalBuffer->size() == 0) { + // want more data + if(d->get_state() == FLAC__STREAM_DECODER_END_OF_STREAM) + d->finish(); + else if(d->get_state() < FLAC__STREAM_DECODER_END_OF_STREAM) { + if(! d->process_single()) + return -1; + } + else + return -1; + } +#endif + + bytesAvailable = d->internalBuffer->size() - d->internalBuffer->at(); + bytesToCopy = QMIN(maxLen, bytesAvailable); + bytesCopied = (int)d->internalBuffer->readBlock(_data, bytesToCopy); + + if(bytesCopied == bytesAvailable) { + // reset the buffer + d->internalBuffer->close(); + d->internalBuffer->open(IO_ReadWrite|IO_Truncate); + } + + return bytesCopied; +} + + +bool K3bFLACDecoder::seekInternal( const K3b::Msf& pos ) +{ + return d->seekToFrame(pos.totalFrames()); +} + + +QString K3bFLACDecoder::fileType() const +{ + return i18n("FLAC"); +} + + +QStringList K3bFLACDecoder::supportedTechnicalInfos() const +{ + return QStringList::split( ";", + i18n("Channels") + ";" + + i18n("Sampling Rate") + ";" + + i18n("Sample Size") ); +} + + +QString K3bFLACDecoder::technicalInfo( const QString& info ) const +{ + if( d->comments != 0 ) { + if( info == i18n("Vendor") ) +#ifdef FLAC_NEWER_THAN_1_1_1 + return QString::fromUtf8((char*)d->comments->get_vendor_string()); +#else + return QString::fromUtf8(d->comments->get_vendor_string().get_field()); +#endif + else if( info == i18n("Channels") ) + return QString::number(d->channels); + else if( info == i18n("Sampling Rate") ) + return i18n("%1 Hz").arg(d->rate); + else if( info == i18n("Sample Size") ) + return i18n("%1 bits").arg(d->bitsPerSample); + } + + return QString::null; +} + + + +K3bFLACDecoderFactory::K3bFLACDecoderFactory( QObject* parent, const char* name ) + : K3bAudioDecoderFactory( parent, name ) +{ +} + + +K3bFLACDecoderFactory::~K3bFLACDecoderFactory() +{ +} + + +K3bAudioDecoder* K3bFLACDecoderFactory::createDecoder( QObject* parent, + const char* name ) const +{ + return new K3bFLACDecoder( parent, name ); +} + + +bool K3bFLACDecoderFactory::canDecode( const KURL& url ) +{ + // buffer large enough to read an ID3 tag header + char buf[10]; + + // Note: since file is created on the stack it will be closed automatically + // by its destructor when this method (i.e. canDecode) returns. + QFile file(url.path()); + + if(!file.open(IO_ReadOnly)) { + kdDebug() << "(K3bFLACDecoder) Could not open file " << url.path() << endl; + return false; + } + + // look for a fLaC magic number or ID3 tag header + if(10 != file.readBlock(buf, 10)) { + kdDebug() << "(K3bFLACDecorder) File " << url.path() + << " is too small to be a FLAC file" << endl; + return false; + } + + if(0 == memcmp(buf, "ID3", 3)) { + // Found ID3 tag, try and seek past it. + kdDebug() << "(K3bFLACDecorder) File " << url.path() << ": found ID3 tag" << endl; + + // See www.id3.org for details of the header, note that the size field + // unpacks to 7-bit bytes, then the +10 is for the header itself. + int pos; + pos = ((buf[6]<<21)|(buf[7]<<14)|(buf[8]<<7)|buf[9]) + 10; + + kdDebug() << "(K3bFLACDecoder) " << url.path() << ": seeking to " + << pos << endl; + if(!file.at(pos)) { + kdDebug() << "(K3bFLACDecoder) " << url.path() << ": couldn't seek to " + << pos << endl; + return false; + }else{ + // seek was okay, try and read magic number into buf + if(4 != file.readBlock(buf, 4)) { + kdDebug() << "(K3bFLACDecorder) File " << url.path() + << " has ID3 tag but naught else!" << endl; + return false; + } + } + } + + if(memcmp(buf, "fLaC", 4) != 0) { + kdDebug() << "(K3bFLACDecoder) " << url.path() << ": not a FLAC file" << endl; + return false; + } + + FLAC::Metadata::StreamInfo info = FLAC::Metadata::StreamInfo(); + FLAC::Metadata::get_streaminfo(url.path().ascii(), info); + + if((info.get_channels() <= 2) && + (info.get_bits_per_sample() <= 16)) { + return true; + } else { + kdDebug() << "(K3bFLACDecoder) " << url.path() << ": wrong format:" << endl + << " channels: " + << QString::number(info.get_channels()) << endl + << " samplerate: " + << QString::number(info.get_sample_rate()) << endl + << " bits/sample: " + << QString::number(info.get_bits_per_sample()) << endl; + return false; + } +} + +#include "k3bflacdecoder.moc" diff --git a/plugins/decoder/flac/k3bflacdecoder.h b/plugins/decoder/flac/k3bflacdecoder.h new file mode 100644 index 0000000..aace651 --- /dev/null +++ b/plugins/decoder/flac/k3bflacdecoder.h @@ -0,0 +1,68 @@ +/* + * FLAC decoder module for K3b. + * Based on the Ogg Vorbis module for same. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * Copyright (C) 2003 John Steele Scott <toojays@toojays.net> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_FLAC_DECODER_H_ +#define _K3B_FLAC_DECODER_H_ + + +#include <k3baudiodecoder.h> + +class KURL; + + +class K3bFLACDecoderFactory : public K3bAudioDecoderFactory +{ + Q_OBJECT + + public: + K3bFLACDecoderFactory( QObject* parent = 0, const char* name = 0 ); + ~K3bFLACDecoderFactory(); + + bool canDecode( const KURL& filename ); + + int pluginSystemVersion() const { return 3; } + + K3bAudioDecoder* createDecoder( QObject* parent = 0, + const char* name = 0 ) const; +}; + + +class K3bFLACDecoder : public K3bAudioDecoder +{ + Q_OBJECT + + public: + K3bFLACDecoder( QObject* parent = 0, const char* name = 0 ); + ~K3bFLACDecoder(); + + void cleanup(); + + bool seekInternal( const K3b::Msf& ); + + QString fileType() const; + QStringList supportedTechnicalInfos() const; + QString technicalInfo( const QString& ) const; + + protected: + bool analyseFileInternal( K3b::Msf& frames, int& samplerate, int& ch ); + bool initDecoderInternal(); + + int decodeInternal( char* _data, int maxLen ); + + private: + class Private; + Private* d; +}; + +#endif diff --git a/plugins/decoder/flac/k3bflacdecoder.plugin b/plugins/decoder/flac/k3bflacdecoder.plugin new file mode 100644 index 0000000..1e1bcbb --- /dev/null +++ b/plugins/decoder/flac/k3bflacdecoder.plugin @@ -0,0 +1,9 @@ +[K3b Plugin] +Lib=libk3bflacdecoder +Group=AudioDecoder +Name=K3b FLAC Decoder +Author=John Steele Scott +Email=toojays@toojays.net +Version=2.1 +Comment=Decoding module to decode FLAC files +License=GPL diff --git a/plugins/decoder/libsndfile/Makefile.am b/plugins/decoder/libsndfile/Makefile.am new file mode 100644 index 0000000..2af9911 --- /dev/null +++ b/plugins/decoder/libsndfile/Makefile.am @@ -0,0 +1,14 @@ +AM_CPPFLAGS = -I$(srcdir)/../../../libk3b/core -I$(srcdir)/../../../libk3b/plugin -I$(srcdir)/../../../libk3bdevice $(all_includes) + +kde_module_LTLIBRARIES = libk3blibsndfiledecoder.la + +libk3blibsndfiledecoder_la_SOURCES = k3blibsndfiledecoder.cpp + +libk3blibsndfiledecoder_la_LIBADD = ../../../libk3b/libk3b.la $(LIB_KDEUI) -lsndfile +libk3blibsndfiledecoder_la_LDFLAGS = -avoid-version -module -no-undefined $(all_libraries) + +pluginsdir = $(kde_datadir)/k3b/plugins +plugins_DATA = k3blibsndfiledecoder.plugin + +METASOURCES = AUTO + diff --git a/plugins/decoder/libsndfile/configure.in.bot b/plugins/decoder/libsndfile/configure.in.bot new file mode 100644 index 0000000..cf1e4e9 --- /dev/null +++ b/plugins/decoder/libsndfile/configure.in.bot @@ -0,0 +1,11 @@ +echo "" + +if $av_cv_sndfile; then + echo "K3b - libsndfile audio decoding support: yes" +else + echo "K3b - libsndfile audio decoding support: no" +if test "$ac_cv_use_sndfile" = "yes"; then + echo "K3b - You are missing the libsndfile headers and libraries." + echo "K3b - The libsndfile audio decoding plugin won't be compiled." +fi +fi diff --git a/plugins/decoder/libsndfile/configure.in.in b/plugins/decoder/libsndfile/configure.in.in new file mode 100644 index 0000000..e0efcc5 --- /dev/null +++ b/plugins/decoder/libsndfile/configure.in.in @@ -0,0 +1,52 @@ +dnl === test for libsndfile - begin === +dnl +dnl Don't use PKG_CHECK, since if there is no pkg-config installed, +dnl then there is no auto* magic for it either. +dnl +dnl Tests copied from kdebase/kioslave/thumbnail/ +dnl +if test -z "$PKG_CONFIG"; then + AC_PATH_PROG(PKG_CONFIG, pkg-config, no) +fi + +AC_ARG_WITH( + sndfile, + AS_HELP_STRING([--without-sndfile], + [build K3b without libsndfile support (default=no)]), + [ac_cv_use_sndfile=$withval], + [ac_cv_use_sndfile=yes] +) + +if test "$ac_cv_use_sndfile" = "yes"; then + SNDFILE_CFLAGS="" + SNDFILE_LIBS="" + if test "$PKG_CONFIG" = "no" ; then + ac_cv_sndfile=0 + echo "*** The pkg-config script could not be found. Make sure it is" + echo "*** in your path, or set the PKG_CONFIG environment variable" + echo "*** to the full path to pkg-config." + echo "*** Or see http://www.freedesktop.org/software/pkgconfig to get pkg-config." + else + if !(`$PKG_CONFIG --exists sndfile`) ; then + echo "*** sndfile is not installed." + ac_cv_sndfile=0 + else + if !(`$PKG_CONFIG --atleast-version="1.0.2" sndfile`) ; then + echo "*** You need at least version 1.0.2 of sndfile." + ac_cv_sndfile=0 + else + ac_cv_sndfile=1 + SNDFILE_CFLAGS=`$PKG_CONFIG --cflags sndfile` + SNDFILE_LIBS=`$PKG_CONFIG --libs sndfile` + fi + fi + fi + + AC_DEFINE_UNQUOTED([HAVE_SNDFILE],${ac_cv_sndfile}, + [Set to 1 if you have libsndfile.]) + AC_SUBST(SNDFILE_CFLAGS) + AC_SUBST(SNDFILE_LIBS) +fi + +AM_CONDITIONAL(include_AIFF, [test x$ac_cv_sndfile = x1]) +dnl === test for libsndfile - end === diff --git a/plugins/decoder/libsndfile/k3blibsndfiledecoder.cpp b/plugins/decoder/libsndfile/k3blibsndfiledecoder.cpp new file mode 100644 index 0000000..ea3d014 --- /dev/null +++ b/plugins/decoder/libsndfile/k3blibsndfiledecoder.cpp @@ -0,0 +1,254 @@ +/* + * + * $Id: k3blibsndfiledecoder.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Matthieu Bedouet <mbedouet@no-log.org> + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include <config.h> + +#include "k3blibsndfiledecoder.h" + +#include <k3bpluginfactory.h> + +#include <qfile.h> +#include <qstringlist.h> + +#include <kurl.h> +#include <kdebug.h> +#include <klocale.h> +#include <kinstance.h> + + +#include <math.h> +#include <stdio.h> +#include <sndfile.h> + + +K_EXPORT_COMPONENT_FACTORY( libk3blibsndfiledecoder, K3bPluginFactory<K3bLibsndfileDecoderFactory>( "libk3blibsndfiledecoder" ) ) + + +class K3bLibsndfileDecoder::Private +{ +public: + Private(): + isOpen(false), + buffer(0), + bufferSize(0) { + format_info.name = 0; + } + + SNDFILE *sndfile; + SF_INFO sndinfo; + SF_FORMAT_INFO format_info; + bool isOpen; + float* buffer; + int bufferSize; +}; + + + +K3bLibsndfileDecoder::K3bLibsndfileDecoder( QObject* parent, const char* name ) + : K3bAudioDecoder( parent, name ) +{ + d = new Private(); +} + + +K3bLibsndfileDecoder::~K3bLibsndfileDecoder() +{ + delete d; +} + + +QString K3bLibsndfileDecoder::fileType() const +{ + if( d->format_info.name ) + return QString::fromLocal8Bit(d->format_info.name); + else + return "-"; +} + + + +bool K3bLibsndfileDecoder::openFile() +{ + if( !d->isOpen ) { + + cleanup(); + + d->sndinfo.format = 0; + d->sndfile = sf_open (QFile::encodeName(filename()), SFM_READ, &d->sndinfo); + if ( !d->sndfile ) { + kdDebug() << "(K3bLibsndfileDecoder::openLibsndfileFile) : " << sf_strerror(d->sndfile) << endl; + return false; + } + else { + //retrieve infos (name, extension) about the format: + d->format_info.format = d->sndinfo.format & SF_FORMAT_TYPEMASK ; + sf_command (d->sndfile, SFC_GET_FORMAT_INFO, &d->format_info, sizeof (SF_FORMAT_INFO)) ; + + d->isOpen = true; + kdDebug() << "(K3bLibsndfileDecoder::openLibsndfileFile) " << d->format_info.name << " file opened " << endl; + return true; + } + } + + return d->isOpen; +} + + +bool K3bLibsndfileDecoder::analyseFileInternal( K3b::Msf& frames, int& samplerate, int& ch ) +{ + cleanup(); + + if( openFile() ) { + // check length of track + if ( d->sndinfo.frames <= 0 ) { + kdDebug() << "(K3bLibsndfileDecoder::analyseFileInternal) Could not determine length of file " + << filename() << endl; + cleanup(); + return false; + } + else { + addMetaInfo( META_TITLE, sf_get_string(d->sndfile, SF_STR_TITLE) ); + addMetaInfo( META_ARTIST, sf_get_string(d->sndfile, SF_STR_ARTIST) ); + addMetaInfo( META_COMMENT, sf_get_string(d->sndfile, SF_STR_COMMENT) ); + + addTechnicalInfo( i18n("Channels"), QString::number(d->sndinfo.channels) ); + addTechnicalInfo( i18n("Sampling Rate"), i18n("%1 Hz").arg(d->sndinfo.samplerate) ); + + frames = (unsigned long)ceil(d->sndinfo.frames / d->sndinfo.samplerate * 75.0); + samplerate = d->sndinfo.samplerate; + ch = d->sndinfo.channels; + + kdDebug() << "(K3bLibsndfileDecoder) successfully analysed file: " << frames << " frames." << endl; + + cleanup(); + return true; + } + } + else + return false; +} + + + +bool K3bLibsndfileDecoder::initDecoderInternal() +{ + cleanup(); + return openFile(); +} + + + +int K3bLibsndfileDecoder::decodeInternal( char* data, int maxLen ) +{ + if( !d->buffer ) { + d->buffer = new float[maxLen]; + d->bufferSize = maxLen/2; + } + + int read = (int) sf_read_float(d->sndfile, d->buffer,d->bufferSize) ; + fromFloatTo16BitBeSigned( d->buffer, data, read ); + read = read * 2; + + if( read < 0 ) { + kdDebug() << "(K3bLibsndfileDecoder::decodeInternal) Error: " << read << endl; + return -1; + } + else if( read == 0 ) { + kdDebug() << "(K3bLibsndfileDecoder::decodeInternal) successfully finished decoding." << endl; + return 0; + } + else if( read != maxLen ) { + kdDebug() << "(K3bLibsndfileDecoder::decodeInternal) read:" << read << " expected:" << maxLen << endl; + return -1; + } + else + return read; + } + + + +bool K3bLibsndfileDecoder::seekInternal( const K3b::Msf& pos) +{ + return ( sf_seek( d->sndfile, pos.pcmSamples(), SEEK_SET ) == 0 ); +} + + + + +void K3bLibsndfileDecoder::cleanup() +{ + if( d->isOpen ) { + kdDebug() << "(K3bLibsndfileDecoder) cleaning up." << endl; + sf_close( d->sndfile ); + d->isOpen = false; + } +} + + + +/********************************************************/ + + +K3bLibsndfileDecoderFactory::K3bLibsndfileDecoderFactory( QObject* parent, const char* name ) + : K3bAudioDecoderFactory( parent, name ) +{ +} + + +K3bLibsndfileDecoderFactory::~K3bLibsndfileDecoderFactory() +{ +} + + +K3bAudioDecoder* K3bLibsndfileDecoderFactory::createDecoder( QObject* parent, + const char* name ) const +{ + return new K3bLibsndfileDecoder( parent, name ); +} + + +bool K3bLibsndfileDecoderFactory::canDecode( const KURL& url ) +{ + SF_INFO infos; + infos.format = 0; + SNDFILE* sndfile = sf_open (QFile::encodeName(url.path()), SFM_READ, &infos); + + //is it supported by libsndfile? + if ( !sndfile ) { + kdDebug() << "(K3bLibsndfileDecoder) " << sf_strerror(sndfile) << endl; + return false; + } + //we exclude only WAVE as there is another plugin for this + else if ( infos.format && ((infos.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_WAV) ) { + + //retrieve infos (name) about the format: + SF_FORMAT_INFO format_info; + format_info.format = infos.format & SF_FORMAT_TYPEMASK ; + sf_command (sndfile, SFC_GET_FORMAT_INFO, &format_info, sizeof (format_info)) ; + + kdDebug() << "(K3bLibsndfileDecoder) " << format_info.name << " file === OK === " << endl; + sf_close( sndfile ); + return true; + } + else { + kdDebug() << "(K3bLibsndfileDecoder) " << url.path() << "not supported" << endl; + sf_close( sndfile ); + return false; + } + return false; +} + +#include "k3blibsndfiledecoder.moc" diff --git a/plugins/decoder/libsndfile/k3blibsndfiledecoder.h b/plugins/decoder/libsndfile/k3blibsndfiledecoder.h new file mode 100644 index 0000000..7ffbe2d --- /dev/null +++ b/plugins/decoder/libsndfile/k3blibsndfiledecoder.h @@ -0,0 +1,69 @@ +/* + * + * $Id: k3blibsndfiledecoder.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Matthieu Bedouet <mbedouet@no-log.org> + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_AIFF_DECODER_H_ +#define _K3B_AIFF_DECODER_H_ + +#include <k3baudiodecoder.h> + +class KURL; + + +class K3bLibsndfileDecoderFactory : public K3bAudioDecoderFactory +{ + Q_OBJECT + + public: + K3bLibsndfileDecoderFactory( QObject* parent = 0, const char* name = 0 ); + ~K3bLibsndfileDecoderFactory(); + + bool canDecode( const KURL& filename ); + + int pluginSystemVersion() const { return 3; } + + bool multiFormatDecoder() const { return true; } + + K3bAudioDecoder* createDecoder( QObject* parent = 0, + const char* name = 0 ) const; +}; + + +class K3bLibsndfileDecoder : public K3bAudioDecoder +{ + Q_OBJECT + + public: + K3bLibsndfileDecoder( QObject* parent = 0, const char* name = 0 ); + ~K3bLibsndfileDecoder(); + void cleanup(); + QString fileType() const; + + protected: + bool analyseFileInternal( K3b::Msf& frames, int& samplerate, int& ch ); + bool initDecoderInternal(); + bool seekInternal( const K3b::Msf& ); + + int decodeInternal( char* _data, int maxLen ); + + private: + bool openFile(); + + class Private; + Private* d; + +}; + +#endif diff --git a/plugins/decoder/libsndfile/k3blibsndfiledecoder.plugin b/plugins/decoder/libsndfile/k3blibsndfiledecoder.plugin new file mode 100644 index 0000000..7ae05f1 --- /dev/null +++ b/plugins/decoder/libsndfile/k3blibsndfiledecoder.plugin @@ -0,0 +1,9 @@ +[K3b Plugin] +Lib=libk3blibsndfiledecoder +Group=AudioDecoder +Name=K3b Libsndfile Decoder +Author=Matthieu Bedouet +Email=mbedouet@no-log.org +Version=1.0 +Comment=Decoding module to decode audio files supported by libsndfile +License=GPL diff --git a/plugins/decoder/mp3/Makefile.am b/plugins/decoder/mp3/Makefile.am new file mode 100644 index 0000000..7f74d21 --- /dev/null +++ b/plugins/decoder/mp3/Makefile.am @@ -0,0 +1,13 @@ +AM_CPPFLAGS = -I$(srcdir)/../../../libk3b/core -I$(srcdir)/../../../libk3b/plugin -I$(srcdir)/../../../libk3bdevice $(taglib_includes) $(all_includes) + +kde_module_LTLIBRARIES = libk3bmaddecoder.la + +libk3bmaddecoder_la_SOURCES = k3bmad.cpp k3bmaddecoder.cpp + +libk3bmaddecoder_la_LIBADD = $(LIB_KDECORE) $(MAD_LIB) $(taglib_libs) ../../../libk3b/libk3b.la +libk3bmaddecoder_la_LDFLAGS = -avoid-version -module -no-undefined $(all_libraries) + +pluginsdir = $(kde_datadir)/k3b/plugins +plugins_DATA = k3bmaddecoder.plugin + +METASOURCES = AUTO diff --git a/plugins/decoder/mp3/configure.in.bot b/plugins/decoder/mp3/configure.in.bot new file mode 100644 index 0000000..0ee4872 --- /dev/null +++ b/plugins/decoder/mp3/configure.in.bot @@ -0,0 +1,11 @@ +echo "" + +if test -n "$MAD_LIB"; then + echo "K3b - Mp3 decoding support (libmad): yes" +else + echo "K3b - Mp3 decoding support (libmad): no" +if test "$ac_cv_use_libmad" = "yes"; then + echo "K3b - You are missing the libmad headers and libraries." + echo "K3b - The Mp3 decoding plugin won't be compiled." +fi +fi diff --git a/plugins/decoder/mp3/configure.in.in b/plugins/decoder/mp3/configure.in.in new file mode 100644 index 0000000..fb92936 --- /dev/null +++ b/plugins/decoder/mp3/configure.in.in @@ -0,0 +1,24 @@ +dnl === libmad MPEG decoder check - begin === +AC_ARG_WITH( + libmad, + AS_HELP_STRING([--without-libmad], [build K3b without libmad support (default=no)]), + [ac_cv_use_libmad=$withval], + [ac_cv_use_libmad=yes] +) + +if test "$ac_cv_use_libmad" = "yes"; then + MAD_LIB="" + KDE_CHECK_HEADER(mad.h, [ + AC_CHECK_LIB(mad, mad_synth_frame, [ + MAD_LIB="-lmad" + AC_DEFINE(HAVE_LIBMAD,1,[defined if you have libmad headers and libraries])], + [], + $all_libraries + ) + ]) + AC_SUBST(MAD_LIB) + +fi + +AM_CONDITIONAL(include_MP3, [test -n "$MAD_LIB"]) +dnl === libmad MPeg decoder check - end === diff --git a/plugins/decoder/mp3/k3bmad.cpp b/plugins/decoder/mp3/k3bmad.cpp new file mode 100644 index 0000000..cb4cf6c --- /dev/null +++ b/plugins/decoder/mp3/k3bmad.cpp @@ -0,0 +1,359 @@ +/* + * + * $Id: k3bmad.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bmad.h" + +#include <qfile.h> +#include <kdebug.h> + + +static const int INPUT_BUFFER_SIZE = 5*8192; + + +K3bMad::K3bMad() + : m_madStructuresInitialized(false), + m_bInputError(false) +{ + madStream = new mad_stream; + madFrame = new mad_frame; + madSynth = new mad_synth; + madTimer = new mad_timer_t; + + // + // we allocate additional MAD_BUFFER_GUARD bytes to always be able to append the + // zero bytes needed for decoding the last frame. + // + m_inputBuffer = new unsigned char[INPUT_BUFFER_SIZE+MAD_BUFFER_GUARD]; +} + + +K3bMad::~K3bMad() +{ + cleanup(); + + delete madStream; + delete madFrame; + delete madSynth; + delete madTimer; + + delete [] m_inputBuffer; +} + + +bool K3bMad::open( const QString& filename ) +{ + cleanup(); + + m_bInputError = false; + m_channels = m_sampleRate = 0; + + m_inputFile.setName( filename ); + + if( !m_inputFile.open( IO_ReadOnly ) ) { + kdError() << "(K3bMad) could not open file " << m_inputFile.name() << endl; + return false; + } + + initMad(); + + memset( m_inputBuffer, 0, INPUT_BUFFER_SIZE+MAD_BUFFER_GUARD ); + + return true; +} + + +bool K3bMad::inputError() const +{ + return m_bInputError; +} + + +bool K3bMad::fillStreamBuffer() +{ + /* The input bucket must be filled if it becomes empty or if + * it's the first execution of the loop. + */ + if( madStream->buffer == 0 || madStream->error == MAD_ERROR_BUFLEN ) { + if( eof() ) + return false; + + long readSize, remaining; + unsigned char* readStart; + + if( madStream->next_frame != 0 ) { + remaining = madStream->bufend - madStream->next_frame; + memmove( m_inputBuffer, madStream->next_frame, remaining ); + readStart = m_inputBuffer + remaining; + readSize = INPUT_BUFFER_SIZE - remaining; + } + else { + readSize = INPUT_BUFFER_SIZE; + readStart = m_inputBuffer; + remaining = 0; + } + + // Fill-in the buffer. + Q_LONG result = m_inputFile.readBlock( (char*)readStart, readSize ); + if( result < 0 ) { + kdDebug() << "(K3bMad) read error on bitstream)" << endl; + m_bInputError = true; + return false; + } + else if( result == 0 ) { + kdDebug() << "(K3bMad) end of input stream" << endl; + return false; + } + else { + readStart += result; + + if( eof() ) { + kdDebug() << "(K3bMad::fillStreamBuffer) MAD_BUFFER_GUARD" << endl; + memset( readStart, 0, MAD_BUFFER_GUARD ); + result += MAD_BUFFER_GUARD; + } + + // Pipe the new buffer content to libmad's stream decoder facility. + mad_stream_buffer( madStream, m_inputBuffer, result + remaining ); + madStream->error = MAD_ERROR_NONE; + } + } + + return true; +} + + +bool K3bMad::skipTag() +{ + // skip the tag at the beginning of the file + m_inputFile.at( 0 ); + + // + // now check if the file starts with an id3 tag and skip it if so + // + char buf[4096]; + int bufLen = 4096; + if( m_inputFile.readBlock( buf, bufLen ) < bufLen ) { + kdDebug() << "(K3bMad) unable to read " << bufLen << " bytes from " + << m_inputFile.name() << endl; + return false; + } + + if( ( buf[0] == 'I' && buf[1] == 'D' && buf[2] == '3' ) && + ( (unsigned short)buf[3] < 0xff && (unsigned short)buf[4] < 0xff ) ) { + // do we have a footer? + bool footer = (buf[5] & 0x10); + + // the size is saved as a synched int meaning bit 7 is always cleared to 0 + unsigned int size = + ( (buf[6] & 0x7f) << 21 ) | + ( (buf[7] & 0x7f) << 14 ) | + ( (buf[8] & 0x7f) << 7) | + (buf[9] & 0x7f); + unsigned int offset = size + 10; + if( footer ) + offset += 10; + + kdDebug() << "(K3bMad) skipping past ID3 tag to " << offset << endl; + + // skip the id3 tag + if( !m_inputFile.at(offset) ) { + kdDebug() << "(K3bMad) " << m_inputFile.name() + << ": couldn't seek to " << offset << endl; + return false; + } + } + else { + // reset file + return m_inputFile.at( 0 ); + } + + return true; +} + + +bool K3bMad::seekFirstHeader() +{ + // + // A lot of mp3 files start with a lot of junk which confuses mad. + // We "allow" an mp3 file to start with at most 1 KB of junk. This is just + // some random value since we do not want to search the hole file. That would + // take way to long for non-mp3 files. + // + bool headerFound = findNextHeader(); + QIODevice::Offset inputPos = streamPos(); + while( !headerFound && + !m_inputFile.atEnd() && + streamPos() <= inputPos+1024 ) { + headerFound = findNextHeader(); + } + + // seek back to the begin of the frame + if( headerFound ) { + int streamSize = madStream->bufend - madStream->buffer; + int bytesToFrame = madStream->this_frame - madStream->buffer; + m_inputFile.at( m_inputFile.at() - streamSize + bytesToFrame ); + + kdDebug() << "(K3bMad) found first header at " << m_inputFile.at() << endl; + } + + // reset the stream to make sure mad really starts decoding at out seek position + mad_stream_finish( madStream ); + mad_stream_init( madStream ); + + return headerFound; +} + + +bool K3bMad::eof() const +{ + return m_inputFile.atEnd(); +} + + +QIODevice::Offset K3bMad::inputPos() const +{ + return m_inputFile.at(); +} + + +QIODevice::Offset K3bMad::streamPos() const +{ + return inputPos() - (madStream->bufend - madStream->this_frame + 1); +} + + +bool K3bMad::inputSeek( QIODevice::Offset pos ) +{ + return m_inputFile.at( pos ); +} + + +void K3bMad::initMad() +{ + if( !m_madStructuresInitialized ) { + mad_stream_init( madStream ); + mad_timer_reset( madTimer ); + mad_frame_init( madFrame ); + mad_synth_init( madSynth ); + + m_madStructuresInitialized = true; + } +} + + +void K3bMad::cleanup() +{ + if( m_inputFile.isOpen() ) { + kdDebug() << "(K3bMad) cleanup at offset: " + << "Input file at: " << m_inputFile.at() << " " + << "Input file size: " << m_inputFile.size() << " " + << "stream pos: " + << ( m_inputFile.at() - (madStream->bufend - madStream->this_frame + 1) ) + << endl; + m_inputFile.close(); + } + + if( m_madStructuresInitialized ) { + mad_frame_finish( madFrame ); + mad_synth_finish( madSynth ); + mad_stream_finish( madStream ); + } + + m_madStructuresInitialized = false; +} + + +// +// LOSTSYNC could happen when mad encounters the id3 tag... +// +bool K3bMad::findNextHeader() +{ + if( !fillStreamBuffer() ) + return false; + + // + // MAD_RECOVERABLE == true: frame was read, decoding failed (about to skip frame) + // MAD_RECOVERABLE == false: frame was not read, need data + // + + if( mad_header_decode( &madFrame->header, madStream ) < 0 ) { + if( MAD_RECOVERABLE( madStream->error ) || + madStream->error == MAD_ERROR_BUFLEN ) { + return findNextHeader(); + } + else + kdDebug() << "(K3bMad::findNextHeader) error: " << mad_stream_errorstr( madStream ) << endl; + + // FIXME probably we should not do this here since we don't do it + // in the frame decoding +// if( !checkFrameHeader( &madFrame->header ) ) +// return findNextHeader(); + + return false; + } + + if( !m_channels ) { + m_channels = MAD_NCHANNELS(&madFrame->header); + m_sampleRate = madFrame->header.samplerate; + } + + mad_timer_add( madTimer, madFrame->header.duration ); + + return true; +} + + +bool K3bMad::decodeNextFrame() +{ + if( !fillStreamBuffer() ) + return false; + + if( mad_frame_decode( madFrame, madStream ) < 0 ) { + if( MAD_RECOVERABLE( madStream->error ) || + madStream->error == MAD_ERROR_BUFLEN ) { + return decodeNextFrame(); + } + + return false; + } + + if( !m_channels ) { + m_channels = MAD_NCHANNELS(&madFrame->header); + m_sampleRate = madFrame->header.samplerate; + } + + mad_timer_add( madTimer, madFrame->header.duration ); + + return true; +} + + +// +// This is from the arts mad decoder +// +bool K3bMad::checkFrameHeader( mad_header* header ) const +{ + int frameSize = MAD_NSBSAMPLES( header ) * 32; + + if( frameSize <= 0 ) + return false; + + if( m_channels && m_channels != MAD_NCHANNELS(header) ) + return false; + + return true; +} + + diff --git a/plugins/decoder/mp3/k3bmad.h b/plugins/decoder/mp3/k3bmad.h new file mode 100644 index 0000000..a4d9aae --- /dev/null +++ b/plugins/decoder/mp3/k3bmad.h @@ -0,0 +1,92 @@ +/* + * + * $Id: k3bmad.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_MAD_H_ +#define _K3B_MAD_H_ + +extern "C" { +#include <mad.h> +} + +#include <qfile.h> + + +class K3bMad +{ +public: + K3bMad(); + ~K3bMad(); + + bool open( const QString& filename ); + + /** + * @return true if the mad stream contains data + * false if there is no data left or an error occurred. + * In the latter case inputError() returns true. + */ + bool fillStreamBuffer(); + + /** + * Skip id3 tags. + * + * This will reset the input file. + */ + bool skipTag(); + + /** + * Find first frame and seek to the beginning of that frame. + * This is used to skip the junk that many mp3 files start with. + */ + bool seekFirstHeader(); + + bool eof() const; + bool inputError() const; + + /** + * Current position in theinput file. This does NOT + * care about the status of the mad stream. Use streamPos() + * in that case. + */ + QIODevice::Offset inputPos() const; + + /** + * Current absolut position of the decoder stream. + */ + QIODevice::Offset streamPos() const; + bool inputSeek( QIODevice::Offset pos ); + + void initMad(); + void cleanup(); + + bool decodeNextFrame(); + bool findNextHeader(); + bool checkFrameHeader( mad_header* header ) const; + + mad_stream* madStream; + mad_frame* madFrame; + mad_synth* madSynth; + mad_timer_t* madTimer; + +private: + QFile m_inputFile; + bool m_madStructuresInitialized; + unsigned char* m_inputBuffer; + bool m_bInputError; + + int m_channels; + int m_sampleRate; +}; + +#endif diff --git a/plugins/decoder/mp3/k3bmaddecoder.cpp b/plugins/decoder/mp3/k3bmaddecoder.cpp new file mode 100644 index 0000000..e3aef56 --- /dev/null +++ b/plugins/decoder/mp3/k3bmaddecoder.cpp @@ -0,0 +1,542 @@ +/* + * + * $Id$ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +// +// Some notes on mp3: +// A mp3 Frame is always samples/samplerate seconds in length +// +// +// +// What we need are raw 16 bit stereo samples at 44100 Hz which results in 588 samples +// per block (2352 bytes: 32*588 bit). 1 second are 75 blocks. +// + +#include <config.h> + +#include "k3bmaddecoder.h" +#include "k3bmad.h" + +#include <k3bpluginfactory.h> + +#include <kurl.h> +#include <kdebug.h> +#include <klocale.h> + +#include <qstring.h> +#include <qfile.h> +#include <qvaluevector.h> + +#include <stdlib.h> +#include <cmath> +#include <cstdlib> + +#include <config.h> + +#ifdef HAVE_TAGLIB +#include <taglib/tag.h> +#include <taglib/mpegfile.h> +#endif + + +K_EXPORT_COMPONENT_FACTORY( libk3bmaddecoder, K3bPluginFactory<K3bMadDecoderFactory>( "k3bmaddecoder" ) ) + + +int K3bMadDecoder::MaxAllowedRecoverableErrors = 10; + + + +class K3bMadDecoder::MadDecoderPrivate +{ +public: + MadDecoderPrivate() + : outputBuffer(0), + outputPointer(0), + outputBufferEnd(0) { + mad_header_init( &firstHeader ); + } + + K3bMad* handle; + + QValueVector<unsigned long long> seekPositions; + + bool bOutputFinished; + + char* outputBuffer; + char* outputPointer; + char* outputBufferEnd; + + // the first frame header for technical info + mad_header firstHeader; + bool vbr; +}; + + + + +K3bMadDecoder::K3bMadDecoder( QObject* parent, const char* name ) + : K3bAudioDecoder( parent, name ) +{ + d = new MadDecoderPrivate(); + d->handle = new K3bMad(); +} + + +K3bMadDecoder::~K3bMadDecoder() +{ + cleanup(); + delete d->handle; + delete d; +} + + +QString K3bMadDecoder::metaInfo( MetaDataField f ) +{ +#ifdef HAVE_TAGLIB + TagLib::MPEG::File file( QFile::encodeName( filename() ).data() ); + + if ( file.tag() ) { + switch( f ) { + case META_TITLE: + return TStringToQString( file.tag()->title() ); + case META_ARTIST: + return TStringToQString( file.tag()->artist() ); + case META_COMMENT: + return TStringToQString( file.tag()->comment() ); + default: + return QString::null; + } + } + else { + return QString::null; + } + +#else + return K3bAudioDecoder::metaInfo( f ); +#endif +} + + +bool K3bMadDecoder::analyseFileInternal( K3b::Msf& frames, int& samplerate, int& ch ) +{ + initDecoderInternal(); + frames = countFrames(); + if( frames > 0 ) { + // we convert mono to stereo all by ourselves. :) + ch = 2; + samplerate = d->firstHeader.samplerate; + return true; + } + else + return false; +} + + +bool K3bMadDecoder::initDecoderInternal() +{ + cleanup(); + + d->bOutputFinished = false; + + if( !d->handle->open( filename() ) ) + return false; + + if( !d->handle->skipTag() ) + return false; + + if( !d->handle->seekFirstHeader() ) + return false; + + return true; +} + + +unsigned long K3bMadDecoder::countFrames() +{ + kdDebug() << "(K3bMadDecoder::countFrames)" << endl; + + unsigned long frames = 0; + bool error = false; + d->vbr = false; + bool bFirstHeaderSaved = false; + + d->seekPositions.clear(); + + while( !error && d->handle->findNextHeader() ) { + + if( !bFirstHeaderSaved ) { + bFirstHeaderSaved = true; + d->firstHeader = d->handle->madFrame->header; + } + else if( d->handle->madFrame->header.bitrate != d->firstHeader.bitrate ) + d->vbr = true; + + // + // position in stream: postion in file minus the not yet used buffer + // + unsigned long long seekPos = d->handle->inputPos() - + (d->handle->madStream->bufend - d->handle->madStream->this_frame + 1); + + // save the number of bytes to be read to decode i-1 frames at position i + // in other words: when seeking to seekPos the next decoded frame will be i + d->seekPositions.append( seekPos ); + } + + if( !d->handle->inputError() && !error ) { + // we need the length of the track to be multiple of frames (1/75 second) + float seconds = (float)d->handle->madTimer->seconds + + (float)d->handle->madTimer->fraction/(float)MAD_TIMER_RESOLUTION; + frames = (unsigned long)ceil(seconds * 75.0); + kdDebug() << "(K3bMadDecoder) length of track " << seconds << endl; + } + + cleanup(); + + kdDebug() << "(K3bMadDecoder::countFrames) end" << endl; + + return frames; +} + + +int K3bMadDecoder::decodeInternal( char* _data, int maxLen ) +{ + d->outputBuffer = _data; + d->outputBufferEnd = d->outputBuffer + maxLen; + d->outputPointer = d->outputBuffer; + + bool bOutputBufferFull = false; + + while( !bOutputBufferFull && d->handle->fillStreamBuffer() ) { + + // a mad_synth contains of the data of one mad_frame + // one mad_frame represents a mp3-frame which is always 1152 samples + // for us that means we need 4*1152 bytes of output buffer for every frame + // since one sample has 16 bit + if( d->outputBufferEnd - d->outputPointer < 4*1152 ) { + bOutputBufferFull = true; + } + else if( d->handle->decodeNextFrame() ) { + // + // Once decoded the frame is synthesized to PCM samples. No errors + // are reported by mad_synth_frame(); + // + mad_synth_frame( d->handle->madSynth, d->handle->madFrame ); + + // this fills the output buffer + if( !createPcmSamples( d->handle->madSynth ) ) { + return -1; + } + } + else if( d->handle->inputError() ) { + return -1; + } + } + + // flush the output buffer + size_t buffersize = d->outputPointer - d->outputBuffer; + + return buffersize; +} + + +unsigned short K3bMadDecoder::linearRound( mad_fixed_t fixed ) +{ + // round + fixed += (1L << ( MAD_F_FRACBITS - 16 )); + + // clip + if( fixed >= MAD_F_ONE - 1 ) + fixed = MAD_F_ONE - 1; + else if( fixed < -MAD_F_ONE ) + fixed = -MAD_F_ONE; + + // quatisize + return fixed >> (MAD_F_FRACBITS + 1 - 16 ); +} + + +bool K3bMadDecoder::createPcmSamples( mad_synth* synth ) +{ + unsigned short nsamples = synth->pcm.length; + + // this should not happen since we only decode if the + // output buffer has enough free space + if( d->outputBufferEnd - d->outputPointer < nsamples*4 ) { + kdDebug() << "(K3bMadDecoder) buffer overflow!" << endl; + return false; + } + + // now create the output + for( int i = 0; i < nsamples; i++ ) { + + /* Left channel */ + unsigned short sample = linearRound( synth->pcm.samples[0][i] ); + *(d->outputPointer++) = (sample >> 8) & 0xff; + *(d->outputPointer++) = sample & 0xff; + + /* Right channel. If the decoded stream is monophonic then + * the right output channel is the same as the left one. + */ + if( synth->pcm.channels == 2 ) + sample = linearRound( synth->pcm.samples[1][i] ); + + *(d->outputPointer++) = (sample >> 8) & 0xff; + *(d->outputPointer++) = sample & 0xff; + } // pcm conversion + + return true; +} + + +void K3bMadDecoder::cleanup() +{ + d->handle->cleanup(); +} + + +bool K3bMadDecoder::seekInternal( const K3b::Msf& pos ) +{ + // + // we need to reset the complete mad stuff + // + if( !initDecoderInternal() ) + return false; + + // + // search a position + // This is all hacking, I don't really know what I am doing here... ;) + // + double mp3FrameSecs = static_cast<double>(d->firstHeader.duration.seconds) + + static_cast<double>(d->firstHeader.duration.fraction) / static_cast<double>(MAD_TIMER_RESOLUTION); + + double posSecs = static_cast<double>(pos.totalFrames()) / 75.0; + + // seekPosition to seek after frame i + unsigned int frame = static_cast<unsigned int>( posSecs / mp3FrameSecs ); + + // Rob said: 29 frames is the theoretically max frame reservoir limit (whatever that means...) + // it seems that mad needs at most 29 frames to get ready + unsigned int frameReservoirProtect = ( frame > 29 ? 29 : frame ); + + frame -= frameReservoirProtect; + + // seek in the input file behind the already decoded data + d->handle->inputSeek( d->seekPositions[frame] ); + + kdDebug() << "(K3bMadDecoder) Seeking to frame " << frame << " with " + << frameReservoirProtect << " reservoir frames." << endl; + + // decode some frames ignoring MAD_ERROR_BADDATAPTR errors + unsigned int i = 1; + while( i <= frameReservoirProtect ) { + d->handle->fillStreamBuffer(); + if( mad_frame_decode( d->handle->madFrame, d->handle->madStream ) ) { + if( MAD_RECOVERABLE( d->handle->madStream->error ) ) { + if( d->handle->madStream->error == MAD_ERROR_BUFLEN ) + continue; + else if( d->handle->madStream->error != MAD_ERROR_BADDATAPTR ) { + kdDebug() << "(K3bMadDecoder) Seeking: recoverable mad error (" + << mad_stream_errorstr(d->handle->madStream) << ")" << endl; + continue; + } + else { + kdDebug() << "(K3bMadDecoder) Seeking: ignoring (" + << mad_stream_errorstr(d->handle->madStream) << ")" << endl; + } + } + else + return false; + } + + if( i == frameReservoirProtect ) // synth only the last frame (Rob said so ;) + mad_synth_frame( d->handle->madSynth, d->handle->madFrame ); + + ++i; + } + + return true; +} + + +QString K3bMadDecoder::fileType() const +{ + switch( d->firstHeader.layer ) { + case MAD_LAYER_I: + return "MPEG1 Layer I"; + case MAD_LAYER_II: + return "MPEG1 Layer II"; + case MAD_LAYER_III: + return "MPEG1 Layer III"; + default: + return "Mp3"; + } +} + +QStringList K3bMadDecoder::supportedTechnicalInfos() const +{ + return QStringList::split( ";", + i18n("Channels") + ";" + + i18n("Sampling Rate") + ";" + + i18n("Bitrate") + ";" + + i18n("Layer") + ";" + + i18n("Emphasis") + ";" + + i18n("Copyright") + ";" + + i18n("Original") + ";" + + i18n("CRC") ); +} + + +QString K3bMadDecoder::technicalInfo( const QString& name ) const +{ + if( name == i18n("Channels") ) { + switch( d->firstHeader.mode ) { + case MAD_MODE_SINGLE_CHANNEL: + return i18n("Mono"); + case MAD_MODE_DUAL_CHANNEL: + return i18n("Dual"); + case MAD_MODE_JOINT_STEREO: + return i18n("Joint Stereo"); + case MAD_MODE_STEREO: + return i18n("Stereo"); + default: + return "?"; + } + } + else if( name == i18n("Sampling Rate") ) + return i18n("%1 Hz").arg(d->firstHeader.samplerate); + else if( name == i18n("Bitrate") ) { + if( d->vbr ) + return i18n("VBR"); + else + return i18n("%1 bps").arg(d->firstHeader.bitrate); + } + else if( name == i18n("Layer") ){ + switch( d->firstHeader.layer ) { + case MAD_LAYER_I: + return "I"; + case MAD_LAYER_II: + return "II"; + case MAD_LAYER_III: + return "III"; + default: + return "?"; + } + } + else if( name == i18n("Emphasis") ) { + switch( d->firstHeader.emphasis ) { + case MAD_EMPHASIS_NONE: + return i18n("None"); + case MAD_EMPHASIS_50_15_US: + return i18n("50/15 ms"); + case MAD_EMPHASIS_CCITT_J_17: + return i18n("CCITT J.17"); + default: + return i18n("Unknown"); + } + } + else if( name == i18n("Copyright") ) + return ( d->firstHeader.flags & MAD_FLAG_COPYRIGHT ? i18n("Yes") : i18n("No") ); + else if( name == i18n("Original") ) + return ( d->firstHeader.flags & MAD_FLAG_ORIGINAL ? i18n("Yes") : i18n("No") ); + else if( name == i18n("CRC") ) + return ( d->firstHeader.flags & MAD_FLAG_PROTECTION ? i18n("Yes") : i18n("No") ); + else + return QString::null; +} + + +K3bMadDecoderFactory::K3bMadDecoderFactory( QObject* parent, const char* name ) + : K3bAudioDecoderFactory( parent, name ) +{ +} + + +K3bMadDecoderFactory::~K3bMadDecoderFactory() +{ +} + + +K3bAudioDecoder* K3bMadDecoderFactory::createDecoder( QObject* parent, + const char* name ) const +{ + return new K3bMadDecoder( parent, name ); +} + + +bool K3bMadDecoderFactory::canDecode( const KURL& url ) +{ + // + // HACK: + // + // I am simply no good at this and this detection code is no good as well + // It always takes waves for mp3 files so we introduce this hack to + // filter out wave files. :( + // + QFile f( url.path() ); + if( !f.open( IO_ReadOnly ) ) + return false; + char buffer[12]; + if( f.readBlock( buffer, 12 ) != 12 ) + return false; + if( !qstrncmp( buffer, "RIFF", 4 ) && + !qstrncmp( buffer + 8, "WAVE", 4 ) ) + return false; + f.close(); + + + K3bMad handle; + if( !handle.open( url.path() ) ) + return false; + + handle.skipTag(); + if( !handle.seekFirstHeader() ) + return false; + + if( handle.findNextHeader() ) { + int c = MAD_NCHANNELS( &handle.madFrame->header ); + int layer = handle.madFrame->header.layer; + unsigned int s = handle.madFrame->header.samplerate; + + // + // find 4 more mp3 headers (random value since 2 was not enough) + // This way we get most of the mp3 files while sorting out + // for example wave files. + // + int cnt = 1; + while( handle.findNextHeader() ) { + // compare the found headers + if( MAD_NCHANNELS( &handle.madFrame->header ) == c && + handle.madFrame->header.layer == layer && + handle.madFrame->header.samplerate == s ) { + // only support layer III for now since otherwise some wave files + // are taken for layer I + if( ++cnt >= 5 ) { + kdDebug() << "(K3bMadDecoder) valid mpeg 1 layer " << layer + << " file with " << c << " channels and a samplerate of " + << s << endl; + return ( layer == MAD_LAYER_III ); + } + } + else + break; + } + } + + kdDebug() << "(K3bMadDecoder) unsupported format: " << url.path() << endl; + + return false; +} + +#include "k3bmaddecoder.moc" diff --git a/plugins/decoder/mp3/k3bmaddecoder.h b/plugins/decoder/mp3/k3bmaddecoder.h new file mode 100644 index 0000000..91e0f6c --- /dev/null +++ b/plugins/decoder/mp3/k3bmaddecoder.h @@ -0,0 +1,79 @@ +/* + * + * $Id$ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef K3BMP3MODULE_H +#define K3BMP3MODULE_H + + +#include <k3baudiodecoder.h> + +extern "C" { +#include <mad.h> +} + + +class K3bMadDecoderFactory : public K3bAudioDecoderFactory +{ + Q_OBJECT + + public: + K3bMadDecoderFactory( QObject* parent = 0, const char* name = 0 ); + ~K3bMadDecoderFactory(); + + bool canDecode( const KURL& filename ); + + int pluginSystemVersion() const { return 3; } + + K3bAudioDecoder* createDecoder( QObject* parent = 0, + const char* name = 0 ) const; +}; + + +class K3bMadDecoder : public K3bAudioDecoder +{ + Q_OBJECT + + public: + K3bMadDecoder( QObject* parent = 0, const char* name = 0 ); + ~K3bMadDecoder(); + + QString metaInfo( MetaDataField ); + + void cleanup(); + + bool seekInternal( const K3b::Msf& ); + + QString fileType() const; + QStringList supportedTechnicalInfos() const; + QString technicalInfo( const QString& ) const; + + protected: + bool analyseFileInternal( K3b::Msf& frames, int& samplerate, int& ch ); + bool initDecoderInternal(); + + int decodeInternal( char* _data, int maxLen ); + + private: + unsigned long countFrames(); + inline unsigned short linearRound( mad_fixed_t fixed ); + bool createPcmSamples( mad_synth* ); + + static int MaxAllowedRecoverableErrors; + + class MadDecoderPrivate; + MadDecoderPrivate* d; +}; + +#endif diff --git a/plugins/decoder/mp3/k3bmaddecoder.plugin b/plugins/decoder/mp3/k3bmaddecoder.plugin new file mode 100644 index 0000000..69fbbb8 --- /dev/null +++ b/plugins/decoder/mp3/k3bmaddecoder.plugin @@ -0,0 +1,9 @@ +[K3b Plugin] +Lib=libk3bmaddecoder +Group=AudioDecoder +Name=K3b MAD Decoder +Author=Sebastian Trueg +Email=trueg@k3b.org +Version=3.1 +Comment=Decoding module to decode MPEG 1 Layer III files +License=GPL diff --git a/plugins/decoder/musepack/Makefile.am b/plugins/decoder/musepack/Makefile.am new file mode 100644 index 0000000..beb7d63 --- /dev/null +++ b/plugins/decoder/musepack/Makefile.am @@ -0,0 +1,16 @@ +AM_CPPFLAGS = -I$(srcdir)/../../../libk3b/plugin \ + -I$(srcdir)/../../../libk3b/core \ + -I$(srcdir)/../../../libk3bdevice \ + $(all_includes) + +kde_module_LTLIBRARIES = libk3bmpcdecoder.la + +libk3bmpcdecoder_la_SOURCES = k3bmpcdecoder.cpp k3bmpcwrapper.cpp + +libk3bmpcdecoder_la_LIBADD = ../../../libk3b/libk3b.la $(MPC_LIBS) +libk3bmpcdecoder_la_LDFLAGS = -avoid-version -module -no-undefined $(all_libraries) + +pluginsdir = $(kde_datadir)/k3b/plugins +plugins_DATA = k3bmpcdecoder.plugin + +METASOURCES = AUTO diff --git a/plugins/decoder/musepack/configure.in.bot b/plugins/decoder/musepack/configure.in.bot new file mode 100644 index 0000000..8fb871b --- /dev/null +++ b/plugins/decoder/musepack/configure.in.bot @@ -0,0 +1,12 @@ +echo "" + +if test x$have_mpc = xyes; then + echo "K3b - Musepack support: yes" +else + echo "K3b - Musepack support: no" +if test "$ac_cv_use_mpc" = "yes"; then + echo "K3b - You are missing the Musepack headers and libraries >= 1.1." + echo "K3b - The Musepack audio decoding plugin won't be compiled." +fi +fi + diff --git a/plugins/decoder/musepack/configure.in.in b/plugins/decoder/musepack/configure.in.in new file mode 100644 index 0000000..42d24c0 --- /dev/null +++ b/plugins/decoder/musepack/configure.in.in @@ -0,0 +1,52 @@ +dnl --------- MUSEPACK CHECK --------------- + +AC_ARG_WITH( + musepack, + AS_HELP_STRING( + [--without-musepack], + [build K3b without Musepack audio support (default=no)]), + [ac_cv_use_mpc=$withval], + [ac_cv_use_mpc=yes] +) + +have_mpc=no +if test "$ac_cv_use_mpc" = "yes"; then + + dnl - search for both the new and the old naming - + + KDE_CHECK_HEADERS(mpcdec/mpcdec.h, [ + AC_CHECK_LIB(mpcdec, mpc_decoder_setup, [ + have_mpc=yes + MPC_LIBS="-lmpcdec" + AC_DEFINE( + MPC_HEADER_FILE, + <mpcdec/mpcdec.h>, + [The header to include for MPC decoding.]) + ], + [], [], []) + ]) + + if test "$have_mpc" = "no"; then + KDE_CHECK_HEADERS(musepack/musepack.h, [ + AC_CHECK_LIB(musepack, mpc_decoder_setup, [ + have_mpc=yes + MPC_LIBS="-lmusepack" + AC_DEFINE( + MPC_HEADER_FILE, + <musepack/musepack.h>, + [The header to include for MPC decoding.] + ) + AC_DEFINE( + mpc_bool_t, + BOOL, + [backwards compatibility stuff] + ) + ], [], []) + ]) + fi +fi +AC_SUBST(MPC_LIBS) + +AM_CONDITIONAL(include_MPC, [test x$have_mpc = xyes]) + +dnl --------- MUSEPACK CHECK END ----------- diff --git a/plugins/decoder/musepack/k3bmpcdecoder.cpp b/plugins/decoder/musepack/k3bmpcdecoder.cpp new file mode 100644 index 0000000..0cdf644 --- /dev/null +++ b/plugins/decoder/musepack/k3bmpcdecoder.cpp @@ -0,0 +1,111 @@ +/* + * + * $Id: k3bmpcdecoder.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include <config.h> + +#include "k3bmpcdecoder.h" +#include "k3bmpcwrapper.h" + +#include <k3bpluginfactory.h> + +#include <klocale.h> + + +K_EXPORT_COMPONENT_FACTORY( libk3bmpcdecoder, K3bPluginFactory<K3bMpcDecoderFactory>( "libk3bmpcdecoder" ) ) + + +K3bMpcDecoderFactory::K3bMpcDecoderFactory( QObject* parent, const char* name ) + : K3bAudioDecoderFactory( parent, name ) +{ +} + + +K3bMpcDecoderFactory::~K3bMpcDecoderFactory() +{ +} + + +K3bAudioDecoder* K3bMpcDecoderFactory::createDecoder( QObject* parent, + const char* name ) const +{ + return new K3bMpcDecoder( parent, name ); +} + + +bool K3bMpcDecoderFactory::canDecode( const KURL& url ) +{ + K3bMpcWrapper w; + return w.open( url.path() ); +} + + + + + + +K3bMpcDecoder::K3bMpcDecoder( QObject* parent, const char* name ) + : K3bAudioDecoder( parent, name ) +{ + m_mpc = new K3bMpcWrapper(); +} + + +K3bMpcDecoder::~K3bMpcDecoder() +{ + delete m_mpc; +} + + +QString K3bMpcDecoder::fileType() const +{ + return i18n("Musepack"); +} + + +bool K3bMpcDecoder::analyseFileInternal( K3b::Msf& frames, int& samplerate, int& ch ) +{ + if( m_mpc->open( filename() ) ) { + frames = m_mpc->length(); + samplerate = m_mpc->samplerate(); + ch = m_mpc->channels(); + + // call addTechnicalInfo and addMetaInfo here + + return true; + } + else + return false; +} + + +bool K3bMpcDecoder::initDecoderInternal() +{ + return m_mpc->open( filename() ); +} + + +bool K3bMpcDecoder::seekInternal( const K3b::Msf& msf ) +{ + return m_mpc->seek( msf ); +} + + +int K3bMpcDecoder::decodeInternal( char* _data, int maxLen ) +{ + return m_mpc->decode( _data, maxLen ); +} + + +#include "k3bmpcdecoder.moc" diff --git a/plugins/decoder/musepack/k3bmpcdecoder.h b/plugins/decoder/musepack/k3bmpcdecoder.h new file mode 100644 index 0000000..74dc509 --- /dev/null +++ b/plugins/decoder/musepack/k3bmpcdecoder.h @@ -0,0 +1,62 @@ +/* + * + * $Id: k3bmpcdecoder.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_MPC_DECODER_H_ +#define _K3B_MPC_DECODER_H_ + +#include <k3baudiodecoder.h> + +class K3bMpcWrapper; + + +class K3bMpcDecoderFactory : public K3bAudioDecoderFactory +{ + Q_OBJECT + + public: + K3bMpcDecoderFactory( QObject* parent = 0, const char* name = 0 ); + ~K3bMpcDecoderFactory(); + + bool canDecode( const KURL& filename ); + + int pluginSystemVersion() const { return 3; } + + K3bAudioDecoder* createDecoder( QObject* parent = 0, + const char* name = 0 ) const; +}; + + +class K3bMpcDecoder : public K3bAudioDecoder +{ + Q_OBJECT + + public: + K3bMpcDecoder( QObject* parent = 0, const char* name = 0 ); + ~K3bMpcDecoder(); + + QString fileType() const; + + protected: + bool analyseFileInternal( K3b::Msf& frames, int& samplerate, int& ch ); + bool initDecoderInternal(); + bool seekInternal( const K3b::Msf& ); + + int decodeInternal( char* _data, int maxLen ); + + private: + K3bMpcWrapper* m_mpc; +}; + +#endif diff --git a/plugins/decoder/musepack/k3bmpcdecoder.plugin b/plugins/decoder/musepack/k3bmpcdecoder.plugin new file mode 100644 index 0000000..6e350dc --- /dev/null +++ b/plugins/decoder/musepack/k3bmpcdecoder.plugin @@ -0,0 +1,9 @@ +[K3b Plugin] +Lib=libk3bmpcdecoder +Group=AudioDecoder +Name=K3b Musepack Decoder +Author=Sebastian Trueg +Email=trueg@k3b.org +Version=1.0 +Comment=Decoding module to decode Musepack audio files +License=GPL diff --git a/plugins/decoder/musepack/k3bmpcwrapper.cpp b/plugins/decoder/musepack/k3bmpcwrapper.cpp new file mode 100644 index 0000000..9f54b28 --- /dev/null +++ b/plugins/decoder/musepack/k3bmpcwrapper.cpp @@ -0,0 +1,193 @@ +/* + * + * $Id: k3bmpcwrapper.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bmpcwrapper.h" + +#include <kdebug.h> +#include <qfile.h> + + +mpc_int32_t read_impl( void* data, void* ptr, mpc_int32_t size ) +{ + QFile* input = static_cast<QFile*>( data ); + return input->readBlock( (char*)ptr, size ); +} + + +mpc_bool_t seek_impl( void* data, mpc_int32_t offset ) +{ + QFile* input = static_cast<QFile*>( data ); + return input->at( offset ); +} + +mpc_int32_t tell_impl( void* data ) +{ + QFile* input = static_cast<QFile*>( data ); + return input->at(); +} + +mpc_int32_t get_size_impl( void* data ) +{ + QFile* input = static_cast<QFile*>( data ); + return input->size(); +} + +mpc_bool_t canseek_impl( void* ) +{ + return true; +} + + +#ifdef MPC_FIXED_POINT +static int shift_signed( MPC_SAMPLE_FORMAT val, int shift ) +{ + if(shift > 0) + val <<= shift; + else if(shift < 0) + val >>= -shift; + return (int) val; +} +#endif + + +K3bMpcWrapper::K3bMpcWrapper() +{ + m_input = new QFile(); + + m_reader = new mpc_reader; + m_reader->read = read_impl; + m_reader->seek = seek_impl; + m_reader->tell = tell_impl; + m_reader->get_size = get_size_impl; + m_reader->canseek = canseek_impl; + m_reader->data = m_input; + + m_decoder = new mpc_decoder; + + m_info = new mpc_streaminfo; +} + + +K3bMpcWrapper::~K3bMpcWrapper() +{ + close(); + + delete m_reader; + delete m_decoder; + delete m_info; + delete m_input; +} + + +bool K3bMpcWrapper::open( const QString& filename ) +{ + close(); + + m_input->setName( filename ); + + if( m_input->open( IO_ReadOnly ) ) { + mpc_streaminfo_init( m_info ); + if( mpc_streaminfo_read( m_info, m_reader ) != ERROR_CODE_OK ) { + kdDebug() << "(K3bMpcWrapper) Not a valid musepack file: \"" << filename << "\"" << endl; + return false; + } + else { + mpc_decoder_setup( m_decoder, m_reader ); + if( !mpc_decoder_initialize( m_decoder, m_info ) ) { + kdDebug() << "(K3bMpcWrapper) failed to initialize the Musepack decoder." << endl; + close(); + return false; + } + else { + kdDebug() << "(K3bMpcWrapper) valid musepack file. " + << channels() << " Channels and Samplerate: " << samplerate() << endl; + return true; + } + } + } + else + return false; +} + + +void K3bMpcWrapper::close() +{ + m_input->close(); +} + + +int K3bMpcWrapper::decode( char* data, int max ) +{ + // FIXME: make this a member variable + MPC_SAMPLE_FORMAT sample_buffer[MPC_DECODER_BUFFER_LENGTH]; + + unsigned int samples = mpc_decoder_decode( m_decoder, sample_buffer, 0, 0 ); + + if( samples*channels()*2 > (unsigned int)max ) { + kdDebug() << "(K3bMpcWrapper) buffer not big enough." << endl; + return -1; + } + + static const unsigned int bps = 16; + static const int clip_min = -1 << (bps - 1); + static const int clip_max = (1 << (bps - 1)) - 1; + static const int float_scale = 1 << (bps - 1); + + for( unsigned int n = 0; n < samples*channels(); ++n ) { + int val = 0; + +#ifdef MPC_FIXED_POINT + val = shift_signed( sample_buffer[n], + bps - MPC_FIXED_POINT_SCALE_SHIFT); +#else + val = (int)(sample_buffer[n] * float_scale); +#endif + + if( val < clip_min ) + val = clip_min; + else if( val > clip_max ) + val = clip_max; + + data[2*n] = (val>>8) & 0xff; + data[2*n+1] = val & 0xff; + } + + return samples*channels()*2; +} + + +bool K3bMpcWrapper::seek( const K3b::Msf& msf ) +{ + return mpc_decoder_seek_seconds( m_decoder, (double)msf.totalFrames()/75.0 ); +} + + +K3b::Msf K3bMpcWrapper::length() const +{ + return K3b::Msf::fromSeconds( mpc_streaminfo_get_length( m_info ) ); +} + + +int K3bMpcWrapper::samplerate() const +{ + return m_info->sample_freq; +} + + +unsigned int K3bMpcWrapper::channels() const +{ + return m_info->channels; +} + diff --git a/plugins/decoder/musepack/k3bmpcwrapper.h b/plugins/decoder/musepack/k3bmpcwrapper.h new file mode 100644 index 0000000..743e25f --- /dev/null +++ b/plugins/decoder/musepack/k3bmpcwrapper.h @@ -0,0 +1,58 @@ +/* + * + * $Id: k3bmpcwrapper.h 630384 2007-02-05 09:33:17Z mlaurent $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_MPC_WRAPPER_H_ +#define _K3B_MPC_WRAPPER_H_ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <qstring.h> + +#include <k3bmsf.h> + +#include MPC_HEADER_FILE + +class QFile; + + +class K3bMpcWrapper +{ + public: + K3bMpcWrapper(); + ~K3bMpcWrapper(); + + bool open( const QString& filename ); + void close(); + + int decode( char*, int max ); + + bool seek( const K3b::Msf& ); + + K3b::Msf length() const; + int samplerate() const; + unsigned int channels() const; + + QFile* input() const { return m_input; } + + private: + QFile* m_input; + mpc_reader* m_reader; + mpc_decoder* m_decoder; + mpc_streaminfo* m_info; +}; + +#endif diff --git a/plugins/decoder/ogg/Makefile.am b/plugins/decoder/ogg/Makefile.am new file mode 100644 index 0000000..6705be2 --- /dev/null +++ b/plugins/decoder/ogg/Makefile.am @@ -0,0 +1,13 @@ +AM_CPPFLAGS = -I$(srcdir)/../../../libk3b/plugin -I$(srcdir)/../../../libk3b/core -I$(srcdir)/../../../libk3bdevice $(all_includes) + +kde_module_LTLIBRARIES = libk3boggvorbisdecoder.la + +libk3boggvorbisdecoder_la_SOURCES = k3boggvorbisdecoder.cpp + +libk3boggvorbisdecoder_la_LIBADD = ../../../libk3b/libk3b.la -logg -lvorbis -lvorbisfile +libk3boggvorbisdecoder_la_LDFLAGS = -avoid-version -module -no-undefined $(all_libraries) + +pluginsdir = $(kde_datadir)/k3b/plugins +plugins_DATA = k3boggvorbisdecoder.plugin + +METASOURCES = AUTO diff --git a/plugins/decoder/ogg/configure.in.bot b/plugins/decoder/ogg/configure.in.bot new file mode 100644 index 0000000..b27ab18 --- /dev/null +++ b/plugins/decoder/ogg/configure.in.bot @@ -0,0 +1,11 @@ +echo "" + +if test x$ogg_vorbis = xyes; then + echo "K3b - Ogg Vorbis support: yes" +else + echo "K3b - Ogg Vorbis support: no" +if test "$ac_cv_use_oggvorbis" = "yes"; then + echo "K3b - You are missing the Ogg-Vorbis headers and libraries." + echo "K3b - The Ogg Vorbis decoding and encoding plugins won't be compiled." +fi +fi diff --git a/plugins/decoder/ogg/configure.in.in b/plugins/decoder/ogg/configure.in.in new file mode 100644 index 0000000..69b1b9c --- /dev/null +++ b/plugins/decoder/ogg/configure.in.in @@ -0,0 +1,32 @@ +dnl === Ogg Vorbis Test - Begin === +AC_ARG_WITH( + oggvorbis, + AS_HELP_STRING([--without-oggvorbis], [build K3b without OggVorbis support (default=no)]), + [ac_cv_use_oggvorbis=$withval], + [ac_cv_use_oggvorbis=yes] +) + +if test "$ac_cv_use_oggvorbis" = "yes"; then + + AC_MSG_CHECKING(for ogg/vorbis headers) + ogg_vorbis=no + AC_TRY_COMPILE([ + #include <vorbis/codec.h> + #include <vorbis/vorbisfile.h> + ],[ + ],[ + ogg_vorbis=yes + ]) + AC_MSG_RESULT($ogg_vorbis) + if test x$ogg_vorbis = xyes; then + dnl we need the ogg_vorbis_lib because otherwise we override LIBS ! + AC_CHECK_LIB(vorbisfile,ov_open,ogg_vorbis_lib=yes, + ogg_vorbis=no,[$all_libraries -lvorbisfile -lvorbis -logg]) + fi + if test x$ogg_vorbis = xyes; then + AC_DEFINE(OGG_VORBIS,1,[Define if you have ogg/vorbis installed]) + fi +fi + +AM_CONDITIONAL(include_OGG, [test x$ogg_vorbis = xyes]) +dnl === Ogg Vorbis Test - End === diff --git a/plugins/decoder/ogg/k3boggvorbisdecoder.cpp b/plugins/decoder/ogg/k3boggvorbisdecoder.cpp new file mode 100644 index 0000000..15ca665 --- /dev/null +++ b/plugins/decoder/ogg/k3boggvorbisdecoder.cpp @@ -0,0 +1,252 @@ +/* + * + * $Id$ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include <config.h> + +#include "k3boggvorbisdecoder.h" + +#include <k3bpluginfactory.h> + +#include <qfile.h> +#include <qstringlist.h> + +#include <kurl.h> +#include <kdebug.h> +#include <klocale.h> + +#include <stdio.h> +#include <stdlib.h> +#include <vorbis/codec.h> +#include <vorbis/vorbisfile.h> + + +K_EXPORT_COMPONENT_FACTORY( libk3boggvorbisdecoder, K3bPluginFactory<K3bOggVorbisDecoderFactory>( "libk3boggvorbisdecoder" ) ) + + +class K3bOggVorbisDecoder::Private +{ +public: + Private() + : vInfo(0), + vComment(0), + isOpen(false) { + } + + OggVorbis_File oggVorbisFile; + vorbis_info* vInfo; + vorbis_comment* vComment; + bool isOpen; +}; + + +K3bOggVorbisDecoder::K3bOggVorbisDecoder( QObject* parent, const char* name ) + : K3bAudioDecoder( parent, name ) +{ + d = new Private(); +} + + +K3bOggVorbisDecoder::~K3bOggVorbisDecoder() +{ + delete d; +} + + +bool K3bOggVorbisDecoder::openOggVorbisFile() +{ + if( !d->isOpen ) { + FILE* file = fopen( QFile::encodeName(filename()), "r" ); + if( !file ) { + kdDebug() << "(K3bOggVorbisDecoder) Could not open file " << filename() << endl; + return false; + } + else if( ov_open( file, &d->oggVorbisFile, 0, 0 ) ) { + kdDebug() << "(K3bOggVorbisDecoder) " << filename() + << " seems not to to be an ogg vorbis file." << endl; + fclose( file ); + return false; + } + } + + d->isOpen = true; + return true; +} + + +bool K3bOggVorbisDecoder::analyseFileInternal( K3b::Msf& frames, int& samplerate, int& ch ) +{ + cleanup(); + + if( openOggVorbisFile() ) { + // check length of track + double seconds = ov_time_total( &d->oggVorbisFile, -1 ); + if( seconds == OV_EINVAL ) { + kdDebug() << "(K3bOggVorbisDecoder) Could not determine length of file " << filename() << endl; + cleanup(); + return false; + } + else { + + d->vInfo = ov_info( &d->oggVorbisFile, -1 /* current bitstream */ ); + d->vComment = ov_comment( &d->oggVorbisFile, -1 ); + + // add meta tags + for( int i = 0; i < d->vComment->comments; ++i ) { + QString comment = QString::fromUtf8( d->vComment->user_comments[i] ); + QStringList values = QStringList::split( "=", comment ); + if( values.count() > 1 ) { + if( values[0].lower() == "title" ) + addMetaInfo( META_TITLE, values[1] ); + else if( values[0].lower() == "artist" ) + addMetaInfo( META_ARTIST, values[1] ); + else if( values[0].lower() == "description" ) + addMetaInfo( META_COMMENT, values[1] ); + } + } + + + // add technical infos + addTechnicalInfo( i18n("Version"), QString::number(d->vInfo->version) ); + addTechnicalInfo( i18n("Channels"), QString::number(d->vInfo->channels) ); + addTechnicalInfo( i18n("Sampling Rate"), i18n("%1 Hz").arg(d->vInfo->rate) ); + if( d->vInfo->bitrate_upper > 0 ) + addTechnicalInfo( i18n("Bitrate Upper"), i18n( "%1 bps" ).arg(d->vInfo->bitrate_upper) ); + if( d->vInfo->bitrate_nominal > 0 ) + addTechnicalInfo( i18n("Bitrate Nominal"), i18n( "%1 bps" ).arg(d->vInfo->bitrate_nominal) ); + if( d->vInfo->bitrate_lower > 0 ) + addTechnicalInfo( i18n("Bitrate Lower"), i18n( "%1 bps" ).arg(d->vInfo->bitrate_lower) ); + + frames = K3b::Msf::fromSeconds(seconds); + samplerate = d->vInfo->rate; + ch = d->vInfo->channels; + + cleanup(); + + return true; + } + } + else + return false; +} + + +bool K3bOggVorbisDecoder::initDecoderInternal() +{ + cleanup(); + return openOggVorbisFile(); +} + + +int K3bOggVorbisDecoder::decodeInternal( char* data, int maxLen ) +{ + int bitStream = 0; + long bytesRead = ov_read( &d->oggVorbisFile, + data, + maxLen, // max length to be read + 1, // big endian + 2, // word size: 16-bit samples + 1, // signed + &bitStream ); // current bitstream + + if( bitStream != 0 ) { + kdDebug() << "(K3bOggVorbisDecoder) bitstream != 0. Multible bitstreams not supported." << endl; + return -1; + } + + else if( bytesRead == OV_HOLE ) { + kdDebug() << "(K3bOggVorbisDecoder) OV_HOLE" << endl; + // recursive new try + return decodeInternal( data, maxLen ); + } + + else if( bytesRead < 0 ) { + kdDebug() << "(K3bOggVorbisDecoder) Error: " << bytesRead << endl; + return -1; + } + + else if( bytesRead == 0 ) { + kdDebug() << "(K3bOggVorbisDecoder) successfully finished decoding." << endl; + return 0; + } + + else { + return bytesRead; + } +} + + +void K3bOggVorbisDecoder::cleanup() +{ + if( d->isOpen ) + ov_clear( &d->oggVorbisFile ); + d->isOpen = false; + d->vComment = 0; + d->vInfo = 0; +} + + +bool K3bOggVorbisDecoder::seekInternal( const K3b::Msf& pos ) +{ + return ( ov_pcm_seek( &d->oggVorbisFile, pos.pcmSamples() ) == 0 ); +} + + +QString K3bOggVorbisDecoder::fileType() const +{ + return i18n("Ogg-Vorbis"); +} + + +K3bOggVorbisDecoderFactory::K3bOggVorbisDecoderFactory( QObject* parent, const char* name ) + : K3bAudioDecoderFactory( parent, name ) +{ +} + + +K3bOggVorbisDecoderFactory::~K3bOggVorbisDecoderFactory() +{ +} + + +K3bAudioDecoder* K3bOggVorbisDecoderFactory::createDecoder( QObject* parent, + const char* name ) const +{ + return new K3bOggVorbisDecoder( parent, name ); +} + + +bool K3bOggVorbisDecoderFactory::canDecode( const KURL& url ) +{ + FILE* file = fopen( QFile::encodeName(url.path()), "r" ); + if( !file ) { + kdDebug() << "(K3bOggVorbisDecoder) Could not open file " << url.path() << endl; + return false; + } + + OggVorbis_File of; + + if( ov_open( file, &of, 0, 0 ) ) { + fclose( file ); + kdDebug() << "(K3bOggVorbisDecoder) not an Ogg-Vorbis file: " << url.path() << endl; + return false; + } + + ov_clear( &of ); + + return true; +} + + +#include "k3boggvorbisdecoder.moc" diff --git a/plugins/decoder/ogg/k3boggvorbisdecoder.h b/plugins/decoder/ogg/k3boggvorbisdecoder.h new file mode 100644 index 0000000..20ae094 --- /dev/null +++ b/plugins/decoder/ogg/k3boggvorbisdecoder.h @@ -0,0 +1,72 @@ +/* + * + * $Id: k3boggvorbisdecoder.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_OGGVORBIS_DECODER_H_ +#define _K3B_OGGVORBIS_DECODER_H_ + + +#include <k3baudiodecoder.h> + +class KURL; + + +class K3bOggVorbisDecoderFactory : public K3bAudioDecoderFactory +{ + Q_OBJECT + + public: + K3bOggVorbisDecoderFactory( QObject* parent = 0, const char* name = 0 ); + ~K3bOggVorbisDecoderFactory(); + + bool canDecode( const KURL& filename ); + + int pluginSystemVersion() const { return 3; } + + K3bAudioDecoder* createDecoder( QObject* parent = 0, + const char* name = 0 ) const; +}; + + +/** + *@author Sebastian Trueg + */ +class K3bOggVorbisDecoder : public K3bAudioDecoder +{ + Q_OBJECT + + public: + K3bOggVorbisDecoder( QObject* parent = 0, const char* name = 0 ); + ~K3bOggVorbisDecoder(); + + void cleanup(); + + QString fileType() const; + + protected: + bool analyseFileInternal( K3b::Msf& frames, int& samplerate, int& ch ); + bool initDecoderInternal(); + bool seekInternal( const K3b::Msf& ); + + int decodeInternal( char* _data, int maxLen ); + + private: + bool openOggVorbisFile(); + + class Private; + Private* d; +}; + +#endif diff --git a/plugins/decoder/ogg/k3boggvorbisdecoder.plugin b/plugins/decoder/ogg/k3boggvorbisdecoder.plugin new file mode 100644 index 0000000..0f1c48e --- /dev/null +++ b/plugins/decoder/ogg/k3boggvorbisdecoder.plugin @@ -0,0 +1,9 @@ +[K3b Plugin] +Lib=libk3boggvorbisdecoder +Group=AudioDecoder +Name=K3b Ogg Vorbis Decoder +Author=Sebastian Trueg +Email=trueg@k3b.org +Version=3.0 +Comment=Decoding module to decode Ogg Vorbis files +License=GPL diff --git a/plugins/decoder/skeleton.cpp b/plugins/decoder/skeleton.cpp new file mode 100644 index 0000000..940814b --- /dev/null +++ b/plugins/decoder/skeleton.cpp @@ -0,0 +1,101 @@ +/* + * + * $Id: skeleton.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include <config.h> + +#include "k3b<name>decoder.h" + +#include <k3bpluginfactory.h> + + +K_EXPORT_COMPONENT_FACTORY( libk3b<name>decoder, K3bPluginFactory<K3b<name>DecoderFactory>( "libk3b<name>decoder" ) ) + + +K3b<name>DecoderFactory::K3b<name>DecoderFactory( QObject* parent, const char* name ) + : K3bAudioDecoderFactory( parent, name ) +{ +} + + +K3b<name>DecoderFactory::~K3b<name>DecoderFactory() +{ +} + + +K3bAudioDecoder* K3b<name>DecoderFactory::createDecoder( QObject* parent, + const char* name ) const +{ + return new K3b<name>Decoder( parent, name ); +} + + +bool K3b<name>DecoderFactory::canDecode( const KURL& url ) +{ + // PUT YOUR CODE HERE + return false; +} + + + + + + +K3b<name>Decoder::K3b<name>Decoder( QObject* parent, const char* name ) + : K3bAudioDecoder( parent, name ) +{ +} + + +K3b<name>Decoder::~K3b<name>Decoder() +{ +} + + +QString K3b<name>Decoder::fileType() const +{ + // PUT YOUR CODE HERE +} + + +bool K3b<name>Decoder::analyseFileInternal( K3b::Msf& frames, int& samplerate, int& ch ) +{ + // PUT YOUR CODE HERE + // call addTechnicalInfo and addMetaInfo here + return false; +} + + +bool K3b<name>Decoder::initDecoderInternal() +{ + // PUT YOUR CODE HERE + return false; +} + + +bool K3b<name>Decoder::seekInternal( const K3b::Msf& ) +{ + // PUT YOUR CODE HERE + return false; +} + + +int K3b<name>Decoder::decodeInternal( char* _data, int maxLen ) +{ + // PUT YOUR CODE HERE + return -1; +} + + +#include "k3b<name>decoder.moc" diff --git a/plugins/decoder/skeleton.h b/plugins/decoder/skeleton.h new file mode 100644 index 0000000..00f5d15 --- /dev/null +++ b/plugins/decoder/skeleton.h @@ -0,0 +1,57 @@ +/* + * + * $Id: skeleton.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_<name>_DECODER_H_ +#define _K3B_<name>_DECODER_H_ + +#include <k3baudiodecoder.h> + + +class K3b<name>DecoderFactory : public K3bAudioDecoderFactory +{ + Q_OBJECT + + public: + K3b<name>DecoderFactory( QObject* parent = 0, const char* name = 0 ); + ~K3b<name>DecoderFactory(); + + bool canDecode( const KURL& filename ); + + int pluginSystemVersion() const { return 3; } + + K3bAudioDecoder* createDecoder( QObject* parent = 0, + const char* name = 0 ) const; +}; + + +class K3b<name>Decoder : public K3bAudioDecoder +{ + Q_OBJECT + + public: + K3b<name>Decoder( QObject* parent = 0, const char* name = 0 ); + ~K3b<name>Decoder(); + + QString fileType() const; + + protected: + bool analyseFileInternal( K3b::Msf& frames, int& samplerate, int& ch ); + bool initDecoderInternal(); + bool seekInternal( const K3b::Msf& ); + + int decodeInternal( char* _data, int maxLen ); +}; + +#endif diff --git a/plugins/decoder/skeleton.plugin b/plugins/decoder/skeleton.plugin new file mode 100644 index 0000000..c9bc0f4 --- /dev/null +++ b/plugins/decoder/skeleton.plugin @@ -0,0 +1,9 @@ +[K3b Plugin] +Lib=lib<name>decoder +Group=AudioDecoder +Name=K3b ??? Decoder +Author=??? +Email=??? +Version=0.1 +Comment=Decoding module to decode ??? files +License=??? diff --git a/plugins/decoder/wave/Makefile.am b/plugins/decoder/wave/Makefile.am new file mode 100644 index 0000000..5debea1 --- /dev/null +++ b/plugins/decoder/wave/Makefile.am @@ -0,0 +1,13 @@ +AM_CPPFLAGS = -I$(srcdir)/../../../libk3b/plugin -I$(srcdir)/../../../libk3b/core -I$(srcdir)/../../../libk3bdevice $(all_includes) + +kde_module_LTLIBRARIES = libk3bwavedecoder.la + +libk3bwavedecoder_la_SOURCES = k3bwavedecoder.cpp + +libk3bwavedecoder_la_LIBADD = $(LIB_KDECORE) ../../../libk3b/libk3b.la +libk3bwavedecoder_la_LDFLAGS = -avoid-version -module -no-undefined $(all_libraries) + +pluginsdir = $(kde_datadir)/k3b/plugins +plugins_DATA = k3bwavedecoder.plugin + +METASOURCES = AUTO diff --git a/plugins/decoder/wave/k3bwavedecoder.cpp b/plugins/decoder/wave/k3bwavedecoder.cpp new file mode 100644 index 0000000..6494e5c --- /dev/null +++ b/plugins/decoder/wave/k3bwavedecoder.cpp @@ -0,0 +1,392 @@ +/* + * + * $Id: k3bwavedecoder.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include <config.h> + +#include "k3bwavedecoder.h" + +#include <k3bpluginfactory.h> + +#include <qfile.h> +#include <qcstring.h> + +#include <kdebug.h> +#include <klocale.h> + + + +K_EXPORT_COMPONENT_FACTORY( libk3bwavedecoder, K3bPluginFactory<K3bWaveDecoderFactory>( "libk3bwavedecoder" ) ) + + +static unsigned short le_a_to_u_short( unsigned char* a ) { + return ((unsigned short) + ((a[0] & 0xFF) | + (a[1] << 8 & 0xFF00)) ); +} + +static unsigned long le_a_to_u_long( unsigned char* a ) { + return ((unsigned long) + ((a[0] & 0xFF) | + (a[1] << 8 & 0xFF00) | + (a[2] << 16 & 0xFF0000) | + (a[3] << 24 & 0xFF000000)) ); +} + + +/** + * Returns the length of the wave file in bytes + * Otherwise 0 is returned. + * leave file seek pointer past WAV header. + */ +static unsigned long identifyWaveFile( QFile* f, int* samplerate = 0, int* channels = 0, int* samplesize = 0 ) +{ + typedef struct { + unsigned char ckid[4]; + unsigned char cksize[4]; + } chunk_t; + + typedef struct { + unsigned char wave[4]; + } riff_chunk; + + typedef struct { + unsigned char fmt_tag[2]; + unsigned char channels[2]; + unsigned char sample_rate[4]; + unsigned char av_byte_rate[4]; + unsigned char block_size[2]; + unsigned char bits_per_sample[2]; + } fmt_chunk; + + static const char* WAV_RIFF_MAGIC = "RIFF"; // Magic for file format + static const char* WAV_WAVE_MAGIC = "WAVE"; // Magic for Waveform Audio + static const char* WAV_FMT_MAGIC = "fmt "; // Start of Waveform format + static const char* WAV_DATA_MAGIC = "data"; // Start of data chunk + + chunk_t chunk; + riff_chunk riff; + fmt_chunk fmt; + + + // read riff chunk + if( f->readBlock( (char*)&chunk, sizeof(chunk) ) != sizeof(chunk) ) { + kdDebug() << "(K3bWaveDecoder) unable to read from " << f->name() << endl; + return 0; + } + if( qstrncmp( (char*)chunk.ckid, WAV_RIFF_MAGIC, 4 ) ) { + kdDebug() << "(K3bWaveDecoder) " << f->name() << ": not a RIFF file." << endl; + return 0; + } + + // read wave chunk + if( f->readBlock( (char*)&riff, sizeof(riff) ) != sizeof(riff) ) { + kdDebug() << "(K3bWaveDecoder) unable to read from " << f->name() << endl; + return 0; + } + if( qstrncmp( (char*)riff.wave, WAV_WAVE_MAGIC, 4 ) ) { + kdDebug() << "(K3bWaveDecoder) " << f->name() << ": not a WAVE file." << endl; + return 0; + } + + + // read fmt chunk + if( f->readBlock( (char*)&chunk, sizeof(chunk) ) != sizeof(chunk) ) { + kdDebug() << "(K3bWaveDecoder) unable to read from " << f->name() << endl; + return 0; + } + if( qstrncmp( (char*)chunk.ckid, WAV_FMT_MAGIC, 4 ) ) { + kdDebug() << "(K3bWaveDecoder) " << f->name() << ": could not find format chunk." << endl; + return 0; + } + if( f->readBlock( (char*)&fmt, sizeof(fmt) ) != sizeof(fmt) ) { + kdDebug() << "(K3bWaveDecoder) unable to read from " << f->name() << endl; + return 0; + } + if( le_a_to_u_short(fmt.fmt_tag) != 1 || + le_a_to_u_short(fmt.channels) > 2 || + ( le_a_to_u_short(fmt.bits_per_sample) != 16 && + le_a_to_u_short(fmt.bits_per_sample) != 8 ) ) { + kdDebug() << "(K3bWaveDecoder) " << f->name() << ": wrong format:" << endl + << " format: " << le_a_to_u_short(fmt.fmt_tag) << endl + << " channels: " << le_a_to_u_short(fmt.channels) << endl + << " samplerate: " << le_a_to_u_long(fmt.sample_rate) << endl + << " bits/sample: " << le_a_to_u_short(fmt.bits_per_sample) << endl; + return 0; + } + + int sampleRate = le_a_to_u_long(fmt.sample_rate); + int ch = le_a_to_u_short(fmt.channels); + int sampleSize = le_a_to_u_short(fmt.bits_per_sample);; + if( samplerate ) + *samplerate = sampleRate; + if( channels ) + *channels = ch; + if( samplesize ) + *samplesize = sampleSize; + + // skip all other (unknown) format chunk fields + if( !f->at( f->at() + le_a_to_u_long(chunk.cksize) - sizeof(fmt) ) ) { + kdDebug() << "(K3bWaveDecoder) " << f->name() << ": could not seek in file." << endl; + return 0; + } + + + // find data chunk + bool foundData = false; + while( !foundData ) { + if( f->readBlock( (char*)&chunk, sizeof(chunk) ) != sizeof(chunk) ) { + kdDebug() << "(K3bWaveDecoder) unable to read from " << f->name() << endl; + return 0; + } + + // skip chunk data of unknown chunk + if( qstrncmp( (char*)chunk.ckid, WAV_DATA_MAGIC, 4 ) ) { + kdDebug() << "(K3bWaveDecoder) skipping chunk: " << (char*)chunk.ckid << endl; + if( !f->at( f->at() + le_a_to_u_long(chunk.cksize) ) ) { + kdDebug() << "(K3bWaveDecoder) " << f->name() << ": could not seek in file." << endl; + return 0; + } + } + else + foundData = true; + } + + // found data chunk + unsigned long size = le_a_to_u_long(chunk.cksize); + if( f->at() + size > (unsigned long)f->size() ) { + kdDebug() << "(K3bWaveDecoder) " << f->name() << ": file length " << f->size() + << " does not match length from WAVE header " << f->at() << " + " << size + << " - using actual length." << endl; + size = (f->size() - f->at()); + } + + return size; +} + + +class K3bWaveDecoder::Private { +public: + Private() + : buffer(0), + bufferSize(0) { + } + + QFile* file; + + long headerLength; + int sampleRate; + int channels; + int sampleSize; + unsigned long size; + unsigned long alreadyRead; + + char* buffer; + int bufferSize; +}; + + +K3bWaveDecoder::K3bWaveDecoder( QObject* parent, const char* name ) + : K3bAudioDecoder( parent, name ) +{ + d = new Private(); + d->file = new QFile(); +} + + +K3bWaveDecoder::~K3bWaveDecoder() +{ + delete d->file; + delete d; +} + + +int K3bWaveDecoder::decodeInternal( char* _data, int maxLen ) +{ + int read = 0; + + maxLen = QMIN( maxLen, (int)(d->size - d->alreadyRead) ); + + if( d->sampleSize == 16 ) { + read = d->file->readBlock( _data, maxLen ); + if( read > 0 ) { + d->alreadyRead += read; + + if( read % 2 > 0 ) { + kdDebug() << "(K3bWaveDecoder) data length is not a multiple of 2! Cutting data." << endl; + read -= 1; + } + + // swap bytes + char buf; + for( int i = 0; i < read; i+=2 ) { + buf = _data[i]; + _data[i] = _data[i+1]; + _data[i+1] = buf; + } + } + } + else { + if( !d->buffer ) { + d->buffer = new char[maxLen/2]; + d->bufferSize = maxLen/2; + } + + read = d->file->readBlock( d->buffer, QMIN(maxLen/2, d->bufferSize) ); + d->alreadyRead += read; + + // stretch samples to 16 bit + from8BitTo16BitBeSigned( d->buffer, _data, read ); + + read *= 2; + } + + return read; +} + + +bool K3bWaveDecoder::analyseFileInternal( K3b::Msf& frames, int& samplerate, int& channels ) +{ + // handling wave files is very easy... + if( initDecoderInternal() ) { + + // + // d->size is the number of bytes in the wave file + // + unsigned long size = d->size; + if( d->sampleRate != 44100 ) + size = (int)((double)size * 44100.0 / (double)d->sampleRate); + + if( d->sampleSize == 8 ) + size *= 2; + if( d->channels == 1 ) + size *= 2; + + // + // we pad to a multiple of 2352 bytes + // (the actual padding of zero data will be done by the K3bAudioDecoder class) + // + if( (size%2352) > 0 ) + size = (size/2352) + 1; + else + size = size/2352; + + frames = size; + samplerate = d->sampleRate; + channels = d->channels; + return true; + } + else + return false; +} + + +bool K3bWaveDecoder::initDecoderInternal() +{ + cleanup(); + + d->file->setName( filename() ); + if( !d->file->open( IO_ReadOnly ) ) { + kdDebug() << "(K3bWaveDecoder) could not open file." << endl; + return false; + } + + // skip the header + d->size = identifyWaveFile( d->file, &d->sampleRate, &d->channels, &d->sampleSize ); + if( d->size <= 0 ) { + kdDebug() << "(K3bWaveDecoder) no supported wave file." << endl; + cleanup(); + return false; + } + + d->headerLength = d->file->at(); + d->alreadyRead = 0; + + return true; +} + + +bool K3bWaveDecoder::seekInternal( const K3b::Msf& pos ) +{ + return( d->file->at( d->headerLength + (pos.totalFrames()*2352) ) ); +} + + +void K3bWaveDecoder::cleanup() +{ + if( d->file->isOpen() ) + d->file->close(); +} + + +QString K3bWaveDecoder::fileType() const +{ + return i18n("WAVE"); +} + + +QStringList K3bWaveDecoder::supportedTechnicalInfos() const +{ + return QStringList::split( ";", + i18n("Channels") + ";" + + i18n("Sampling Rate") + ";" + + i18n("Sample Size") ); +} + + +QString K3bWaveDecoder::technicalInfo( const QString& name ) const +{ + if( name == i18n("Channels") ) + return QString::number(d->channels); + else if( name == i18n("Sampling Rate") ) + return i18n("%1 Hz").arg(d->sampleRate); + else if( name == i18n("Sample Size") ) + return i18n("%1 bits").arg(d->sampleSize); + else + return QString::null; +} + + +K3bWaveDecoderFactory::K3bWaveDecoderFactory( QObject* parent, const char* name ) + : K3bAudioDecoderFactory( parent, name ) +{ +} + + +K3bWaveDecoderFactory::~K3bWaveDecoderFactory() +{ +} + + +K3bAudioDecoder* K3bWaveDecoderFactory::createDecoder( QObject* parent, + const char* name ) const +{ + return new K3bWaveDecoder( parent, name ); +} + + +bool K3bWaveDecoderFactory::canDecode( const KURL& url ) +{ + QFile f( url.path() ); + if( !f.open( IO_ReadOnly ) ) { + kdDebug() << "(K3bWaveDecoder) could not open file " << url.path() << endl; + return false; + } + + return (identifyWaveFile( &f ) > 0); +} + + + +#include "k3bwavedecoder.moc" diff --git a/plugins/decoder/wave/k3bwavedecoder.h b/plugins/decoder/wave/k3bwavedecoder.h new file mode 100644 index 0000000..3f92e9a --- /dev/null +++ b/plugins/decoder/wave/k3bwavedecoder.h @@ -0,0 +1,74 @@ +/* + * + * $Id: k3bwavedecoder.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_WAVE_DECODER_H_ +#define _K3B_WAVE_DECODER_H_ + +#include <k3baudiodecoder.h> +#include <k3b_export.h> + +#include <kurl.h> +#include <qcstring.h> + + +class QFile; + + +class LIBK3B_EXPORT K3bWaveDecoderFactory : public K3bAudioDecoderFactory +{ + Q_OBJECT + + public: + K3bWaveDecoderFactory( QObject* parent = 0, const char* name = 0 ); + ~K3bWaveDecoderFactory(); + + bool canDecode( const KURL& filename ); + + int pluginSystemVersion() const { return 3; } + + K3bAudioDecoder* createDecoder( QObject* parent = 0, + const char* name = 0 ) const; +}; + + +class LIBK3B_EXPORT K3bWaveDecoder : public K3bAudioDecoder +{ + Q_OBJECT + + public: + K3bWaveDecoder( QObject* parent = 0, const char* name = 0 ); + ~K3bWaveDecoder(); + + void cleanup(); + + bool seekInternal( const K3b::Msf& ); + + QString fileType() const; + + QStringList supportedTechnicalInfos() const; + + QString technicalInfo( const QString& ) const; + + protected: + bool analyseFileInternal( K3b::Msf& frames, int& samplerate, int& channels ); + bool initDecoderInternal(); + int decodeInternal( char* data, int maxLen ); + + private: + class Private; + Private* d; +}; + +#endif diff --git a/plugins/decoder/wave/k3bwavedecoder.plugin b/plugins/decoder/wave/k3bwavedecoder.plugin new file mode 100644 index 0000000..7b0a4f4 --- /dev/null +++ b/plugins/decoder/wave/k3bwavedecoder.plugin @@ -0,0 +1,9 @@ +[K3b Plugin] +Lib=libk3bwavedecoder +Group=AudioDecoder +Name=K3b Wave Decoder +Author=Sebastian Trueg +Email=trueg@k3b.org +Version=3.0 +Comment=Decoding module to decode wave files +License=GPL diff --git a/plugins/encoder/Makefile.am b/plugins/encoder/Makefile.am new file mode 100644 index 0000000..35724e1 --- /dev/null +++ b/plugins/encoder/Makefile.am @@ -0,0 +1,9 @@ +if include_LAME +ENCLAMEDIR = lame +endif + +if include_OGG +ENCOGGDIR = ogg +endif + +SUBDIRS = sox external $(ENCLAMEDIR) $(ENCOGGDIR) diff --git a/plugins/encoder/external/Makefile.am b/plugins/encoder/external/Makefile.am new file mode 100644 index 0000000..a095688 --- /dev/null +++ b/plugins/encoder/external/Makefile.am @@ -0,0 +1,15 @@ +AM_CPPFLAGS = -I$(srcdir)/../../../libk3b/core -I$(srcdir)/../../../libk3b/plugin -I$(srcdir)/../../../libk3b/core -I$(srcdir)/../../../libk3bdevice $(all_includes) + +kde_module_LTLIBRARIES = libk3bexternalencoder.la + +libk3bexternalencoder_la_SOURCES = base_k3bexternalencoderconfigwidget.ui \ + base_k3bexternalencodereditwidget.ui k3bexternalencoder.cpp \ + k3bexternalencoderconfigwidget.cpp k3bexternalencodercommand.cpp + +libk3bexternalencoder_la_LIBADD = ../../../libk3b/libk3b.la $(LIB_KDECORE) +libk3bexternalencoder_la_LDFLAGS = -avoid-version -module -no-undefined $(all_libraries) + +pluginsdir = $(kde_datadir)/k3b/plugins +plugins_DATA = k3bexternalencoder.plugin + +METASOURCES = AUTO diff --git a/plugins/encoder/external/base_k3bexternalencoderconfigwidget.ui b/plugins/encoder/external/base_k3bexternalencoderconfigwidget.ui new file mode 100644 index 0000000..dd32d08 --- /dev/null +++ b/plugins/encoder/external/base_k3bexternalencoderconfigwidget.ui @@ -0,0 +1,148 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>base_K3bExternalEncoderConfigWidget</class> +<author>Sebastian Trueg</author> +<widget class="QWidget"> + <property name="name"> + <cstring>base_K3bExternalEncoderConfigWidget</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>441</width> + <height>354</height> + </rect> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="KActiveLabel"> + <property name="name"> + <cstring>kActiveLabel1</cstring> + </property> + <property name="text"> + <string><p>This dialog can be used to setup external command line applications as audio encoders. These can then be used by K3b to encode audio data (Tracks from an audio CD or the titles from an audio project) to formats that are normally not supported (i.e. no encoder plugin exists). +<p>K3b comes with a selection of predefined external applications that depends on the installed applications.</string> + </property> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox1</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>1</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>Configured Encoders</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QListView"> + <column> + <property name="text"> + <string>Name</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Extension</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Command</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <property name="name"> + <cstring>m_viewEncoders</cstring> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout6</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer3</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>71</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_buttonRemove</cstring> + </property> + <property name="text"> + <string>Remove</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_buttonEdit</cstring> + </property> + <property name="text"> + <string>Edit...</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_buttonAdd</cstring> + </property> + <property name="text"> + <string>Add...</string> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + </vbox> +</widget> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kactivelabel.h</includehint> +</includehints> +</UI> diff --git a/plugins/encoder/external/base_k3bexternalencodereditwidget.ui b/plugins/encoder/external/base_k3bexternalencodereditwidget.ui new file mode 100644 index 0000000..9f3fb5a --- /dev/null +++ b/plugins/encoder/external/base_k3bexternalencodereditwidget.ui @@ -0,0 +1,164 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>base_K3bExternalEncoderEditWidget</class> +<author>Sebastian Trueg</author> +<widget class="QWidget"> + <property name="name"> + <cstring>base_K3bExternalEncoderEditWidget</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>529</width> + <height>514</height> + </rect> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox3</cstring> + </property> + <property name="title"> + <string>General</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KLineEdit" row="1" column="1"> + <property name="name"> + <cstring>m_editExtension</cstring> + </property> + </widget> + <widget class="KLineEdit" row="1" column="0"> + <property name="name"> + <cstring>m_editName</cstring> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Name:</string> + </property> + </widget> + <widget class="QLabel" row="0" column="1"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>Filename extension:</string> + </property> + </widget> + </grid> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox2</cstring> + </property> + <property name="title"> + <string>Command</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KActiveLabel"> + <property name="name"> + <cstring>kActiveLabel2</cstring> + </property> + <property name="text"> + <string><p><b>Command</b><br> +Please insert the command used to encode the audio data. The command has to read raw little endian (see <em>Swap Byte Order</em>) 16bit stereo audio frames from stdin. +<p>The following strings will be replaced by K3b:<br> +<b>%f</b> - The filename of the resulting file. This is where the command has to write its output to.<br> +<em>The following refer to metadata stored for example in the ID3 tag of am mp3 file (Be aware that these values might be empty).</em><br> +<b>%t</b> - Title<br> +<b>%a</b> - Artist<br> +<b>%c</b> - Comment<br> +<b>%n</b> - Track number<br> +<b>%m</b> - Album Title<br> +<b>%r</b> - Album Artist<br> +<b>%x</b> - Album comment<br> +<b>%y</b> - Release Year</string> + </property> + </widget> + <widget class="KLineEdit"> + <property name="name"> + <cstring>m_editCommand</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </vbox> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox4</cstring> + </property> + <property name="title"> + <string>Options</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_checkSwapByteOrder</cstring> + </property> + <property name="text"> + <string>Swap &Byte Order</string> + </property> + <property name="toolTip" stdset="0"> + <string>Swap the byte order of the input data</string> + </property> + <property name="whatsThis" stdset="0"> + <string><p> If this option is checked K3b will swap the byte order of the input data. Thus, the command has to read big endian audio frames. +<p>If the resulting audio file sounds bad it is highly likely that the byte order is wrong and this option has to be checked.</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_checkWriteWaveHeader</cstring> + </property> + <property name="text"> + <string>Write W&ave Header</string> + </property> + <property name="toolTip" stdset="0"> + <string>Create a wave header for the input data</string> + </property> + <property name="whatsThis" stdset="0"> + <string><p>If this option is checked K3b will write a wave header. This is useful in case the encoder application cannot read plain raw audio data.</string> + </property> + </widget> + </vbox> + </widget> + </vbox> +</widget> +<tabstops> + <tabstop>m_editName</tabstop> + <tabstop>m_editExtension</tabstop> + <tabstop>m_editCommand</tabstop> +</tabstops> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>klineedit.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kactivelabel.h</includehint> + <includehint>klineedit.h</includehint> +</includehints> +</UI> diff --git a/plugins/encoder/external/k3bexternalencoder.cpp b/plugins/encoder/external/k3bexternalencoder.cpp new file mode 100644 index 0000000..4eb0218 --- /dev/null +++ b/plugins/encoder/external/k3bexternalencoder.cpp @@ -0,0 +1,380 @@ +/* + * + * $Id: k3bexternalencoder.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include <config.h> + +#include "k3bexternalencoder.h" +#include "k3bexternalencodercommand.h" +#include "k3bexternalencoderconfigwidget.h" + +#include <k3bpluginfactory.h> +#include <k3bprocess.h> +#include <k3bcore.h> + +#include <kdebug.h> +#include <kconfig.h> +#include <klocale.h> +#include <kstandarddirs.h> + +#include <qregexp.h> +#include <qfile.h> + +#include <sys/types.h> +#include <sys/wait.h> + + +K_EXPORT_COMPONENT_FACTORY( libk3bexternalencoder, K3bPluginFactory<K3bExternalEncoder>( "libk3bexternalencoder" ) ) + + +static const char s_riffHeader[] = +{ + 0x52, 0x49, 0x46, 0x46, // 0 "RIFF" + 0x00, 0x00, 0x00, 0x00, // 4 wavSize + 0x57, 0x41, 0x56, 0x45, // 8 "WAVE" + 0x66, 0x6d, 0x74, 0x20, // 12 "fmt " + 0x10, 0x00, 0x00, 0x00, // 16 + 0x01, 0x00, 0x02, 0x00, // 20 + 0x44, 0xac, 0x00, 0x00, // 24 + 0x10, 0xb1, 0x02, 0x00, // 28 + 0x04, 0x00, 0x10, 0x00, // 32 + 0x64, 0x61, 0x74, 0x61, // 36 "data" + 0x00, 0x00, 0x00, 0x00 // 40 byteCount +}; + + + + + +static K3bExternalEncoderCommand commandByExtension( const QString& extension ) +{ + QValueList<K3bExternalEncoderCommand> cmds( K3bExternalEncoderCommand::readCommands() ); + for( QValueList<K3bExternalEncoderCommand>::iterator it = cmds.begin(); it != cmds.end(); ++it ) + if( (*it).extension == extension ) + return *it; + + kdDebug() << "(K3bExternalEncoder) could not find command for extension " << extension << endl; + + return K3bExternalEncoderCommand(); +} + + +class K3bExternalEncoder::Private +{ +public: + Private() + : process(0) { + } + + K3bProcess* process; + QString fileName; + QString extension; + K3b::Msf length; + + K3bExternalEncoderCommand cmd; + + bool initialized; + + // the metaData we support + QString artist; + QString title; + QString comment; + QString trackNumber; + QString cdArtist; + QString cdTitle; + QString cdComment; + QString year; + QString genre; +}; + + +K3bExternalEncoder::K3bExternalEncoder( QObject* parent, const char* name ) + : K3bAudioEncoder( parent, name ) +{ + d = new Private(); +} + + +K3bExternalEncoder::~K3bExternalEncoder() +{ + delete d->process; + delete d; +} + + +void K3bExternalEncoder::setMetaDataInternal( K3bAudioEncoder::MetaDataField f, const QString& value ) +{ + switch( f ) { + case META_TRACK_TITLE: + d->title = value; + break; + case META_TRACK_ARTIST: + d->artist = value; + break; + case META_TRACK_COMMENT: + d->comment = value; + break; + case META_TRACK_NUMBER: + d->trackNumber = value; + break; + case META_ALBUM_TITLE: + d->cdTitle = value; + break; + case META_ALBUM_ARTIST: + d->cdArtist = value; + break; + case META_ALBUM_COMMENT: + d->cdComment = value; + break; + case META_YEAR: + d->year = value; + break; + case META_GENRE: + d->genre = value; + break; + } +} + + +void K3bExternalEncoder::finishEncoderInternal() +{ + if( d->process ) { + if( d->process->isRunning() ) { + ::close( d->process->stdinFd() ); + + // this is kind of evil... + // but we need to be sure the process exited when this method returnes + ::waitpid( d->process->pid(), 0, 0 ); + } + } +} + + +void K3bExternalEncoder::slotExternalProgramFinished( KProcess* p ) +{ + if( !p->normalExit() || p->exitStatus() != 0 ) + kdDebug() << "(K3bExternalEncoder) program exited with error." << endl; +} + + +bool K3bExternalEncoder::openFile( const QString& ext, const QString& filename, const K3b::Msf& length ) +{ + d->fileName = filename; + d->extension = ext; + d->initialized = false; + d->length = length; + + // delete existing files as some programs (like flac for example) might refuse to overwrite files + if( QFile::exists( filename ) ) + QFile::remove( filename ); + + return true; +} + + +void K3bExternalEncoder::closeFile() +{ + finishEncoderInternal(); +} + + +bool K3bExternalEncoder::initEncoderInternal( const QString& extension ) +{ + d->initialized = true; + + // find the correct command + d->cmd = commandByExtension( extension ); + + if( d->cmd.command.isEmpty() ) { + setLastError( i18n("Invalid command: the command is empty.") ); + return false; + } + + // setup the process + delete d->process; + d->process = new K3bProcess(); + d->process->setSplitStdout(true); + d->process->setRawStdin(true); + + connect( d->process, SIGNAL(processExited(KProcess*)), + this, SLOT(slotExternalProgramFinished(KProcess*)) ); + connect( d->process, SIGNAL(stderrLine(const QString&)), + this, SLOT(slotExternalProgramOutputLine(const QString&)) ); + connect( d->process, SIGNAL(stdoutLine(const QString&)), + this, SLOT(slotExternalProgramOutputLine(const QString&)) ); + + + // create the commandline + QStringList params = QStringList::split( ' ', d->cmd.command, false ); + for( QStringList::iterator it = params.begin(); it != params.end(); ++it ) { + (*it).replace( "%f", d->fileName ); + (*it).replace( "%a", d->artist ); + (*it).replace( "%t", d->title ); + (*it).replace( "%c", d->comment ); + (*it).replace( "%y", d->year ); + (*it).replace( "%m", d->cdTitle ); + (*it).replace( "%r", d->cdArtist ); + (*it).replace( "%x", d->cdComment ); + (*it).replace( "%n", d->trackNumber ); + (*it).replace( "%g", d->genre ); + + *d->process << *it; + } + + + kdDebug() << "***** external parameters:" << endl; + const QValueList<QCString>& args = d->process->args(); + QString s; + for( QValueList<QCString>::const_iterator it = args.begin(); it != args.end(); ++it ) { + s += *it + " "; + } + kdDebug() << s << flush << endl; + + // set one general error message + setLastError( i18n("Command failed: %1").arg( s ) ); + + if( d->process->start( KProcess::NotifyOnExit, KProcess::All ) ) { + if( d->cmd.writeWaveHeader ) + return writeWaveHeader(); + else + return true; + } + else { + QString commandName = d->cmd.command.section( QRegExp("\\s+"), 0 ); + if( !KStandardDirs::findExe( commandName ).isEmpty() ) + setLastError( i18n("Could not find program '%1'").arg(commandName) ); + + return false; + } +} + + +bool K3bExternalEncoder::writeWaveHeader() +{ + kdDebug() << "(K3bExternalEncoder) writing wave header" << endl; + + // write the RIFF thing + if( ::write( d->process->stdinFd(), s_riffHeader, 4 ) != 4 ) { + kdDebug() << "(K3bExternalEncoder) failed to write riff header." << endl; + return false; + } + + // write the wave size + Q_INT32 dataSize( d->length.audioBytes() ); + Q_INT32 wavSize( dataSize + 44 - 8 ); + char c[4]; + + c[0] = (wavSize >> 0 ) & 0xff; + c[1] = (wavSize >> 8 ) & 0xff; + c[2] = (wavSize >> 16) & 0xff; + c[3] = (wavSize >> 24) & 0xff; + + if( ::write( d->process->stdinFd(), c, 4 ) != 4 ) { + kdDebug() << "(K3bExternalEncoder) failed to write wave size." << endl; + return false; + } + + // write static part of the header + if( ::write( d->process->stdinFd(), s_riffHeader+8, 32 ) != 32 ) { + kdDebug() << "(K3bExternalEncoder) failed to write wave header." << endl; + return false; + } + + c[0] = (dataSize >> 0 ) & 0xff; + c[1] = (dataSize >> 8 ) & 0xff; + c[2] = (dataSize >> 16) & 0xff; + c[3] = (dataSize >> 24) & 0xff; + + if( ::write( d->process->stdinFd(), c, 4 ) != 4 ) { + kdDebug() << "(K3bExternalEncoder) failed to write data size." << endl; + return false; + } + + return true; +} + + +long K3bExternalEncoder::encodeInternal( const char* data, Q_ULONG len ) +{ + if( !d->initialized ) + if( !initEncoderInternal( d->extension ) ) + return -1; + + if( d->process ) { + if( d->process->isRunning() ) { + + long written = 0; + + // + // we swap the bytes to reduce user irritation ;) + // This is a little confused: We used to swap the byte order + // in older versions of this encoder since little endian seems + // to "feel" more natural. + // So now that we have a swap option we have to invert it to ensure + // compatibility + // + if( !d->cmd.swapByteOrder ) { + char* buffer = new char[len]; + for( unsigned int i = 0; i < len-1; i+=2 ) { + buffer[i] = data[i+1]; + buffer[i+1] = data[i]; + } + + written = ::write( d->process->stdinFd(), (const void*)buffer, len ); + delete [] buffer; + } + else + written = ::write( d->process->stdinFd(), (const void*)data, len ); + + return written; + } + else + return -1; + } + else + return -1; +} + + +void K3bExternalEncoder::slotExternalProgramOutputLine( const QString& line ) +{ + kdDebug() << "(" << d->cmd.name << ") " << line << endl; +} + + +QStringList K3bExternalEncoder::extensions() const +{ + QStringList el; + QValueList<K3bExternalEncoderCommand> cmds( K3bExternalEncoderCommand::readCommands() ); + for( QValueList<K3bExternalEncoderCommand>::iterator it = cmds.begin(); it != cmds.end(); ++it ) + el.append( (*it).extension ); + + return el; +} + + +QString K3bExternalEncoder::fileTypeComment( const QString& ext ) const +{ + return commandByExtension( ext ).name; +} + + +K3bPluginConfigWidget* K3bExternalEncoder::createConfigWidget( QWidget* parent, + const char* name ) const +{ + return new K3bExternalEncoderSettingsWidget( parent, name ); +} + + +#include "k3bexternalencoder.moc" diff --git a/plugins/encoder/external/k3bexternalencoder.h b/plugins/encoder/external/k3bexternalencoder.h new file mode 100644 index 0000000..1612927 --- /dev/null +++ b/plugins/encoder/external/k3bexternalencoder.h @@ -0,0 +1,68 @@ +/* + * + * $Id: k3bexternalencoder.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_EXTERNAL_ENCODER_H_ +#define _K3B_EXTERNAL_ENCODER_H_ + + +#include <k3baudioencoder.h> + + +class base_K3bExternalEncoderConfigWidget; +class KProcess; + + +class K3bExternalEncoder : public K3bAudioEncoder +{ + Q_OBJECT + + public: + K3bExternalEncoder( QObject* parent = 0, const char* name = 0 ); + ~K3bExternalEncoder(); + + QStringList extensions() const; + + QString fileTypeComment( const QString& ) const; + + int pluginSystemVersion() const { return 3; } + + K3bPluginConfigWidget* createConfigWidget( QWidget* parent, + const char* name ) const; + + /** + * reimplemented since the external program is intended to write the file + * TODO: allow writing to stdout. + */ + bool openFile( const QString& ext, const QString& filename, const K3b::Msf& length ); + void closeFile(); + + class Command; + + private slots: + void slotExternalProgramFinished( KProcess* ); + void slotExternalProgramOutputLine( const QString& ); + + private: + void finishEncoderInternal(); + bool initEncoderInternal( const QString& extension ); + long encodeInternal( const char* data, Q_ULONG len ); + void setMetaDataInternal( MetaDataField, const QString& ); + bool writeWaveHeader(); + + class Private; + Private* d; +}; + +#endif diff --git a/plugins/encoder/external/k3bexternalencoder.plugin b/plugins/encoder/external/k3bexternalencoder.plugin new file mode 100644 index 0000000..2faaa3a --- /dev/null +++ b/plugins/encoder/external/k3bexternalencoder.plugin @@ -0,0 +1,9 @@ +[K3b Plugin] +Lib=libk3bexternalencoder +Group=AudioEncoder +Name=K3b External Audio Encoder +Author=Sebastian Trueg +Email=trueg@k3b.org +Version=4.0 +Comment=Encoding module that allows specifying an encoding commmand +License=GPL diff --git a/plugins/encoder/external/k3bexternalencodercommand.cpp b/plugins/encoder/external/k3bexternalencodercommand.cpp new file mode 100644 index 0000000..5dcfb23 --- /dev/null +++ b/plugins/encoder/external/k3bexternalencodercommand.cpp @@ -0,0 +1,110 @@ +/* + * + * $Id: k3bexternalencoder.cpp 567280 2006-07-28 13:26:27Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include <config.h> + +#include "k3bexternalencodercommand.h" + +#include <k3bcore.h> + +#include <kconfig.h> +#include <kstandarddirs.h> + + +QValueList<K3bExternalEncoderCommand> K3bExternalEncoderCommand::readCommands() +{ + KConfig* c = k3bcore->config(); + + c->setGroup( "K3bExternalEncoderPlugin" ); + + QValueList<K3bExternalEncoderCommand> cl; + + QStringList cmds = c->readListEntry( "commands" ); + for( QStringList::iterator it = cmds.begin(); it != cmds.end(); ++it ) { + QStringList cmdString = c->readListEntry( "command_" + *it ); + K3bExternalEncoderCommand cmd; + cmd.name = cmdString[0]; + cmd.extension = cmdString[1]; + cmd.command = cmdString[2]; + for( unsigned int i = 3; i < cmdString.count(); ++i ) { + if( cmdString[i] == "swap" ) + cmd.swapByteOrder = true; + else if( cmdString[i] == "wave" ) + cmd.writeWaveHeader = true; + } + cl.append(cmd); + } + + // some defaults + if( cmds.isEmpty() ) { + // check if the lame encoding plugin has been compiled +#ifndef HAVE_LAME + K3bExternalEncoderCommand lameCmd; + lameCmd.name = "Mp3 (Lame)"; + lameCmd.extension = "mp3"; + lameCmd.command = "lame -h --tt %t --ta %a --tl %m --ty %y --tc %c - %f"; + + cl.append( lameCmd ); +#endif + + if( !KStandardDirs::findExe( "flac" ).isEmpty() ) { + K3bExternalEncoderCommand flacCmd; + flacCmd.name = "Flac"; + flacCmd.extension = "flac"; + flacCmd.command = "flac " + "-V " + "-o %f " + "--force-raw-format " + "--endian=big " + "--channels=2 " + "--sample-rate=44100 " + "--sign=signed " + "--bps=16 " + "-T ARTIST=%a " + "-T TITLE=%t " + "-T TRACKNUMBER=%n " + "-T DATE=%y " + "-T ALBUM=%m " + "-"; + + cl.append( flacCmd ); + } + + if( !KStandardDirs::findExe( "mppenc" ).isEmpty() ) { + K3bExternalEncoderCommand mppCmd; + mppCmd.name = "Musepack"; + mppCmd.extension = "mpc"; + mppCmd.command = "mppenc " + "--standard " + "--overwrite " + "--silent " + "--artist %a " + "--title %t " + "--track %n " + "--album %m " + "--comment %c " + "--year %y " + "- " + "%f"; + mppCmd.swapByteOrder = true; + mppCmd.writeWaveHeader = true; + + cl.append( mppCmd ); + } + } + + return cl; +} + diff --git a/plugins/encoder/external/k3bexternalencodercommand.h b/plugins/encoder/external/k3bexternalencodercommand.h new file mode 100644 index 0000000..3351191 --- /dev/null +++ b/plugins/encoder/external/k3bexternalencodercommand.h @@ -0,0 +1,40 @@ +/* + * + * $Id: k3bexternalencoder.cpp 567280 2006-07-28 13:26:27Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_EXTERNAL_ENCODER_COMMAND_H_ +#define _K3B_EXTERNAL_ENCODER_COMMAND_H_ + +#include <qstring.h> +#include <qvaluelist.h> + +class K3bExternalEncoderCommand +{ +public: + K3bExternalEncoderCommand() + : swapByteOrder(false), + writeWaveHeader(false) { + } + + QString name; + QString extension; + QString command; + + bool swapByteOrder; + bool writeWaveHeader; + + static QValueList<K3bExternalEncoderCommand> readCommands(); +}; + +#endif diff --git a/plugins/encoder/external/k3bexternalencoderconfigwidget.cpp b/plugins/encoder/external/k3bexternalencoderconfigwidget.cpp new file mode 100644 index 0000000..3ab59c7 --- /dev/null +++ b/plugins/encoder/external/k3bexternalencoderconfigwidget.cpp @@ -0,0 +1,228 @@ +/* + * + * $Id: k3bexternalencoder.cpp 567280 2006-07-28 13:26:27Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bexternalencoderconfigwidget.h" + +#include <k3bcore.h> + +#include <qcheckbox.h> +#include <qlayout.h> +#include <qlistview.h> +#include <qpushbutton.h> + +#include <klineedit.h> +#include <kmessagebox.h> +#include <kconfig.h> +#include <klocale.h> + + + + +K3bExternalEncoderEditDialog::K3bExternalEncoderEditDialog( QWidget* parent ) + : KDialogBase( Swallow, + i18n("Editing external audio encoder"), + Ok|Cancel, + Ok, + parent ) +{ + m_editW = new base_K3bExternalEncoderEditWidget( this ); + setMainWidget( m_editW ); +} + + +K3bExternalEncoderEditDialog::~K3bExternalEncoderEditDialog() +{ +} + + +K3bExternalEncoderCommand K3bExternalEncoderEditDialog::currentCommand() const +{ + K3bExternalEncoderCommand cmd; + cmd.name = m_editW->m_editName->text(); + cmd.extension = m_editW->m_editExtension->text(); + cmd.command = m_editW->m_editCommand->text(); + cmd.swapByteOrder = m_editW->m_checkSwapByteOrder->isChecked(); + cmd.writeWaveHeader = m_editW->m_checkWriteWaveHeader->isChecked(); + return cmd; +} + + +void K3bExternalEncoderEditDialog::setCommand( const K3bExternalEncoderCommand& cmd ) +{ + m_editW->m_editName->setText( cmd.name ); + m_editW->m_editExtension->setText( cmd.extension ); + m_editW->m_editCommand->setText( cmd.command ); + m_editW->m_checkSwapByteOrder->setChecked( cmd.swapByteOrder ); + m_editW->m_checkWriteWaveHeader->setChecked( cmd.writeWaveHeader ); +} + + +void K3bExternalEncoderEditDialog::slotOk() +{ + if( m_editW->m_editName->text().isEmpty() ) { + KMessageBox::error( this, + i18n("Please specify a name for the command."), + i18n("No name specified") ); + } + else if( m_editW->m_editExtension->text().isEmpty() ) { + KMessageBox::error( this, + i18n("Please specify an extension for the command."), + i18n("No extension specified") ); + } + else if( m_editW->m_editCommand->text().isEmpty() ) { + KMessageBox::error( this, + i18n("Please specify the command line."), + i18n("No command line specified") ); + } + else if( !m_editW->m_editCommand->text().contains( "%f" ) ) { + KMessageBox::error( this, + i18n("Please add the output filename (%f) to the command line."), + i18n("No filename specified") ); + } + // FIXME: check for name and extension uniqueness + else { + KDialogBase::slotOk(); + } +} + + + + + + +class K3bExternalEncoderSettingsWidget::Private +{ +public: + QMap<QListViewItem*, K3bExternalEncoderCommand> commands; +}; + + +K3bExternalEncoderSettingsWidget::K3bExternalEncoderSettingsWidget( QWidget* parent, const char* name ) + : K3bPluginConfigWidget( parent, name ) +{ + d = new Private(); + + w = new base_K3bExternalEncoderConfigWidget( this ); + QHBoxLayout* lay = new QHBoxLayout( this ); + lay->setMargin( 0 ); + lay->addWidget( w ); + + connect( w->m_viewEncoders, SIGNAL(selectionChanged()), + this, SLOT(slotSelectionChanged()) ); + connect( w->m_buttonAdd, SIGNAL(clicked()), + this, SLOT(slotNewCommand()) ); + connect( w->m_buttonEdit, SIGNAL(clicked()), + this, SLOT(slotEditCommand()) ); + connect( w->m_buttonRemove, SIGNAL(clicked()), + this, SLOT(slotRemoveCommand()) ); + + m_editDlg = new K3bExternalEncoderEditDialog( this ); +} + + +K3bExternalEncoderSettingsWidget::~K3bExternalEncoderSettingsWidget() +{ + delete d; +} + + +void K3bExternalEncoderSettingsWidget::slotNewCommand() +{ + // clear the dialog + m_editDlg->setCommand( K3bExternalEncoderCommand() ); + + if( m_editDlg->exec() == QDialog::Accepted ) { + K3bExternalEncoderCommand cmd = m_editDlg->currentCommand(); + d->commands.insert( new QListViewItem( w->m_viewEncoders, + w->m_viewEncoders->lastItem(), + cmd.name, + cmd.extension, + cmd.command ), + cmd ); + } +} + + +void K3bExternalEncoderSettingsWidget::slotSelectionChanged() +{ + w->m_buttonRemove->setEnabled( w->m_viewEncoders->selectedItem() != 0 ); + w->m_buttonEdit->setEnabled( w->m_viewEncoders->selectedItem() != 0 ); +} + + +void K3bExternalEncoderSettingsWidget::slotEditCommand() +{ + if( QListViewItem* item = w->m_viewEncoders->selectedItem() ) { + m_editDlg->setCommand( d->commands[item] ); + if( m_editDlg->exec() == QDialog::Accepted ) { + d->commands[item] = m_editDlg->currentCommand(); + } + } +} + + +void K3bExternalEncoderSettingsWidget::slotRemoveCommand() +{ + if( QListViewItem* item = w->m_viewEncoders->selectedItem() ) { + d->commands.erase( item ); + delete item; + } +} + + +void K3bExternalEncoderSettingsWidget::loadConfig() +{ + d->commands.clear(); + w->m_viewEncoders->clear(); + + QValueList<K3bExternalEncoderCommand> cmds( K3bExternalEncoderCommand::readCommands() ); + for( QValueList<K3bExternalEncoderCommand>::iterator it = cmds.begin(); + it != cmds.end(); ++it ) { + K3bExternalEncoderCommand& cmd = *it; + d->commands.insert( new QListViewItem( w->m_viewEncoders, + w->m_viewEncoders->lastItem(), + cmd.name, + cmd.extension, + cmd.command ), + cmd ); + } +} + + +void K3bExternalEncoderSettingsWidget::saveConfig() +{ + KConfig* c = k3bcore->config(); + c->deleteGroup( "K3bExternalEncoderPlugin", true ); + c->setGroup( "K3bExternalEncoderPlugin" ); + + QStringList cmdNames; + for( QMapIterator<QListViewItem*, K3bExternalEncoderCommand> it = d->commands.begin(); + it != d->commands.end(); ++it ) { + QStringList cmd; + cmd << it.data().name << it.data().extension << it.data().command; + if( it.data().swapByteOrder ) + cmd << "swap"; + if( it.data().writeWaveHeader ) + cmd << "wave"; + c->writeEntry( "command_" + it.data().name, cmd ); + cmdNames << it.data().name; + } + c->writeEntry( "commands", cmdNames ); +} + + + + +#include "k3bexternalencoderconfigwidget.moc" diff --git a/plugins/encoder/external/k3bexternalencoderconfigwidget.h b/plugins/encoder/external/k3bexternalencoderconfigwidget.h new file mode 100644 index 0000000..4f6dd47 --- /dev/null +++ b/plugins/encoder/external/k3bexternalencoderconfigwidget.h @@ -0,0 +1,72 @@ +/* + * + * $Id: k3bexternalencoder.cpp 567280 2006-07-28 13:26:27Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_EXTERNAL_ENCODER_CONFIG_WIDGET_H_ +#define _K3B_EXTERNAL_ENCODER_CONFIG_WIDGET_H_ + +#include "base_k3bexternalencodereditwidget.h" +#include "base_k3bexternalencoderconfigwidget.h" +#include "k3bexternalencodercommand.h" + +#include <k3bpluginconfigwidget.h> +#include <kdialogbase.h> + + +class K3bExternalEncoderEditDialog : public KDialogBase +{ + Q_OBJECT + + public: + K3bExternalEncoderEditDialog( QWidget* parent ); + ~K3bExternalEncoderEditDialog(); + + K3bExternalEncoderCommand currentCommand() const; + void setCommand( const K3bExternalEncoderCommand& cmd ); + + private slots: + void slotOk(); + + private: + base_K3bExternalEncoderEditWidget* m_editW; +}; + + +class K3bExternalEncoderSettingsWidget : public K3bPluginConfigWidget +{ + Q_OBJECT + + public: + K3bExternalEncoderSettingsWidget( QWidget* parent = 0, const char* name = 0 ); + ~K3bExternalEncoderSettingsWidget(); + + public slots: + void loadConfig(); + void saveConfig(); + + private slots: + void slotSelectionChanged(); + void slotNewCommand(); + void slotEditCommand(); + void slotRemoveCommand(); + + private: + base_K3bExternalEncoderConfigWidget* w; + K3bExternalEncoderEditDialog* m_editDlg; + + class Private; + Private* d; +}; + +#endif diff --git a/plugins/encoder/lame/Makefile.am b/plugins/encoder/lame/Makefile.am new file mode 100644 index 0000000..4a4d61e --- /dev/null +++ b/plugins/encoder/lame/Makefile.am @@ -0,0 +1,15 @@ +AM_CPPFLAGS = -I$(srcdir)/../../../libk3b/core -I$(srcdir)/../../../libk3b/plugin -I$(srcdir)/../../../libk3b/core -I$(srcdir)/../../../libk3bdevice $(all_includes) + +kde_module_LTLIBRARIES = libk3blameencoder.la + +libk3blameencoder_la_SOURCES = base_k3blameencodersettingswidget.ui \ + base_k3bmanualbitratesettingswidget.ui \ + k3blameencoder.cpp + +libk3blameencoder_la_LIBADD = ../../../libk3b/libk3b.la $(LIB_KDECORE) -lmp3lame +libk3blameencoder_la_LDFLAGS = -avoid-version -module -no-undefined $(all_libraries) + +pluginsdir = $(kde_datadir)/k3b/plugins +plugins_DATA = k3blameencoder.plugin + +METASOURCES = AUTO diff --git a/plugins/encoder/lame/base_k3blameencodersettingswidget.ui b/plugins/encoder/lame/base_k3blameencodersettingswidget.ui new file mode 100644 index 0000000..199895e --- /dev/null +++ b/plugins/encoder/lame/base_k3blameencodersettingswidget.ui @@ -0,0 +1,480 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>base_K3bLameEncoderSettingsWidget</class> +<author>Sebastian Trueg</author> +<widget class="QWidget"> + <property name="name"> + <cstring>Form1</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>337</width> + <height>295</height> + </rect> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QTabWidget"> + <property name="name"> + <cstring>m_mainTab</cstring> + </property> + <widget class="QWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string>Settings</string> + </attribute> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QButtonGroup"> + <property name="name"> + <cstring>m_groupVariableBitrate</cstring> + </property> + <property name="title"> + <string>Quality Settings</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout10</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QRadioButton"> + <property name="name"> + <cstring>m_radioQualityLevel</cstring> + </property> + <property name="text"> + <string>Preset:</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>m_labelQualityLevel</cstring> + </property> + <property name="font"> + <font> + <bold>1</bold> + </font> + </property> + <property name="text"> + <string>textLabel1</string> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + </hbox> + </widget> + <widget class="QFrame"> + <property name="name"> + <cstring>m_qualityLevelFrame</cstring> + </property> + <property name="frameShape"> + <enum>StyledPanel</enum> + </property> + <property name="frameShadow"> + <enum>Plain</enum> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <spacer> + <property name="name"> + <cstring>spacer2_2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout8</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="1" column="1"> + <property name="name"> + <cstring>textLabel4</cstring> + </property> + <property name="font"> + <font> + <italic>1</italic> + </font> + </property> + <property name="text"> + <string>high quality</string> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="font"> + <font> + <italic>1</italic> + </font> + </property> + <property name="text"> + <string>small file</string> + </property> + </widget> + <widget class="QSlider" row="0" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>m_sliderQuality</cstring> + </property> + <property name="maxValue"> + <number>9</number> + </property> + <property name="pageStep"> + <number>3</number> + </property> + <property name="value"> + <number>3</number> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + </widget> + </grid> + </widget> + </hbox> + </widget> + <spacer> + <property name="name"> + <cstring>spacer9</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout12</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QRadioButton"> + <property name="name"> + <cstring>m_radioManual</cstring> + </property> + <property name="text"> + <string>Manual settings:</string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>m_labelManualSettings</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="font"> + <font> + <bold>1</bold> + </font> + </property> + <property name="text"> + <string>textLabel2</string> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + </hbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout11</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <spacer> + <property name="name"> + <cstring>spacer2_2_3</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>5</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_buttonManualSettings</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Change Settings...</string> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + </hbox> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string>Advanced</string> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox1</cstring> + </property> + <property name="title"> + <string>Encoder Quality</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="spacing"> + <number>0</number> + </property> + <widget class="KIntNumInput"> + <property name="name"> + <cstring>m_spinEncoderQuality</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>Choose the noise shaping & psycho acoustic algorithm.</string> + </property> + <property name="whatsThis" stdset="0"> + <string><p>Bitrate is of course the main influence on quality. The higher the bitrate, the higher the quality. But for a given bitrate, we have a choice of algorithms to determine the best scalefactors and huffman encoding (noise shaping). +<p>The quality increases from 0 to 9 while the encoding speed drops. +<p>9 uses the slowest & best possible version of all algorithms. +<p><b>7 is the recommended setting</b> while 4 still produced reasonable quality at good speed. +<p>0 disables almost all algorithms including psy-model resulting in poor quality. +<p><b>This setting has no influence on the size of the resulting file.</b></string> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout2</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="font"> + <font> + <italic>1</italic> + </font> + </property> + <property name="text"> + <string>fast encoding</string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="font"> + <font> + <italic>1</italic> + </font> + </property> + <property name="text"> + <string>high quality</string> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox3</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>1</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>Options</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_checkCopyright</cstring> + </property> + <property name="text"> + <string>Mark copyrighted</string> + </property> + <property name="toolTip" stdset="0"> + <string>Mark the encoded file as being copyrighted.</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_checkOriginal</cstring> + </property> + <property name="text"> + <string>Mark as original</string> + </property> + <property name="toolTip" stdset="0"> + <string>Mark the encoded file as being a copy.</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_checkISO</cstring> + </property> + <property name="text"> + <string>Strict ISO compliance</string> + </property> + <property name="toolTip" stdset="0"> + <string>Enforce strict ISO compliance</string> + </property> + <property name="whatsThis" stdset="0"> + <string><p>If this option is checked LAME will enforce the 7680 bit limitation on total frame size.<br> +This results in many wasted bits for high bitrate encodings but will ensure strict ISO compatibility. This compatibility might be important for hardware players.</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_checkError</cstring> + </property> + <property name="text"> + <string>Error protection</string> + </property> + <property name="toolTip" stdset="0"> + <string>Turn on CRC error protection.</string> + </property> + <property name="whatsThis" stdset="0"> + <string><p>If this option is checked a cyclic redundancy check (CRC) code will be added to each frame, allowing transmission errors that could occur on the MP3 stream to be detected; however, it takes 16 bits per frame that would otherwise be used for encoding, thus slightly reducing the sound quality.</string> + </property> + </widget> + </vbox> + </widget> + </vbox> + </widget> + </widget> + </hbox> +</widget> +<customwidgets> +</customwidgets> +<connections> + <connection> + <sender>m_radioManual</sender> + <signal>toggled(bool)</signal> + <receiver>m_buttonManualSettings</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>m_radioQualityLevel</sender> + <signal>toggled(bool)</signal> + <receiver>m_qualityLevelFrame</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>m_radioQualityLevel</sender> + <signal>toggled(bool)</signal> + <receiver>m_labelQualityLevel</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>m_radioManual</sender> + <signal>toggled(bool)</signal> + <receiver>m_labelManualSettings</receiver> + <slot>setEnabled(bool)</slot> + </connection> +</connections> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>knuminput.h</includehint> +</includehints> +</UI> diff --git a/plugins/encoder/lame/base_k3bmanualbitratesettingswidget.ui b/plugins/encoder/lame/base_k3bmanualbitratesettingswidget.ui new file mode 100644 index 0000000..a3bff90 --- /dev/null +++ b/plugins/encoder/lame/base_k3bmanualbitratesettingswidget.ui @@ -0,0 +1,273 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>base_K3bManualBitrateSettingsWidget</class> +<widget class="QWidget"> + <property name="name"> + <cstring>base_K3bManualBitrateSettingsWidget</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>283</width> + <height>298</height> + </rect> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QButtonGroup"> + <property name="name"> + <cstring>buttonGroup2</cstring> + </property> + <property name="title"> + <string>Quality</string> + </property> + <property name="checkable"> + <bool>false</bool> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QRadioButton"> + <property name="name"> + <cstring>m_radioConstantBitrate</cstring> + </property> + <property name="text"> + <string>Constant Bitrate</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout3</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer2_2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="KComboBox"> + <property name="name"> + <cstring>m_comboConstantBitrate</cstring> + </property> + </widget> + </hbox> + </widget> + <widget class="QRadioButton"> + <property name="name"> + <cstring>m_radioVariableBitrate</cstring> + </property> + <property name="text"> + <string>Variable Bitrate</string> + </property> + </widget> + <widget class="QFrame"> + <property name="name"> + <cstring>frame5</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="frameShape"> + <enum>NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>Plain</enum> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="KComboBox" row="2" column="2"> + <property name="name"> + <cstring>m_comboMinimumBitrate</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + </widget> + <spacer row="0" column="0" rowspan="3" colspan="1"> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="KComboBox" row="0" column="2"> + <property name="name"> + <cstring>m_comboMaximumBitrate</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + </widget> + <widget class="QCheckBox" row="0" column="1"> + <property name="name"> + <cstring>m_checkBitrateMaximum</cstring> + </property> + <property name="text"> + <string>Maximum bitrate:</string> + </property> + </widget> + <widget class="QCheckBox" row="2" column="1"> + <property name="name"> + <cstring>m_checkBitrateMinimum</cstring> + </property> + <property name="text"> + <string>Minimum bitrate:</string> + </property> + </widget> + <widget class="QCheckBox" row="1" column="1"> + <property name="name"> + <cstring>m_checkBitrateAverage</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>1</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Average bitrate:</string> + </property> + </widget> + <widget class="QSpinBox" row="1" column="2"> + <property name="name"> + <cstring>m_spinAverageBitrate</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="suffix"> + <string> kbps</string> + </property> + <property name="buttonSymbols"> + <enum>UpDownArrows</enum> + </property> + <property name="maxValue"> + <number>310</number> + </property> + <property name="minValue"> + <number>8</number> + </property> + </widget> + </grid> + </widget> + </vbox> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox2</cstring> + </property> + <property name="title"> + <string>Channel Mode</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KComboBox"> + <item> + <property name="text"> + <string>Stereo</string> + </property> + </item> + <item> + <property name="text"> + <string>Joint Stereo</string> + </property> + </item> + <item> + <property name="text"> + <string>Mono</string> + </property> + </item> + <property name="name"> + <cstring>m_comboMode</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>Select the channel mode.</string> + </property> + <property name="whatsThis" stdset="0"> + <string><p>Select the channel mode of the resulting Mp3 file: +<p><b>Stereo</b><br> +In this mode, the encoder makes no use of potential correlations between the two input channels; it can, however, negotiate the bit demand between both channel, i.e. give one channel more bits if the other contains silence or needs fewer bits because of a lower complexity. +<p><b>Joint-Stereo</b><br> +In this mode, the encoder will make use of correlations between both channels. The signal will be matrixed into a sum ("mid"), computed by L+R, and difference ("side") signal, computed by L-R, and more bits are allocated to the mid channel. This will effectively increase the bandwidth if the signal does not have too much stereo separation, thus giving a significant gain in encoding quality. +<p><b>Mono</b><br> +The input will be encoded as a mono signal. If it was a stereo signal, it will be downsampled to mono. The downmix is calculated as the sum of the left and right channel, attenuated by 6 dB.</string> + </property> + </widget> + </hbox> + </widget> + </vbox> +</widget> +<connections> + <connection> + <sender>m_radioVariableBitrate</sender> + <signal>toggled(bool)</signal> + <receiver>frame5</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>m_radioConstantBitrate</sender> + <signal>toggled(bool)</signal> + <receiver>m_comboConstantBitrate</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>m_checkBitrateMaximum</sender> + <signal>toggled(bool)</signal> + <receiver>m_comboMaximumBitrate</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>m_checkBitrateAverage</sender> + <signal>toggled(bool)</signal> + <receiver>m_spinAverageBitrate</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>m_checkBitrateMinimum</sender> + <signal>toggled(bool)</signal> + <receiver>m_comboMinimumBitrate</receiver> + <slot>setEnabled(bool)</slot> + </connection> +</connections> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/plugins/encoder/lame/configure.in.bot b/plugins/encoder/lame/configure.in.bot new file mode 100644 index 0000000..5bb35c9 --- /dev/null +++ b/plugins/encoder/lame/configure.in.bot @@ -0,0 +1,11 @@ +echo "" + +if test x$have_lame = xyes; then + echo "K3b - Lame Mp3 encoder plugin: yes" +else + echo "K3b - Lame Mp3 encoder plugin no" +if test "$ac_cv_use_lame" = "yes"; then + echo "K3b - You are missing the Lame headers and libraries." + echo "K3b - The Lame Mp3 encoding plugin won't be compiled." +fi +fi diff --git a/plugins/encoder/lame/configure.in.in b/plugins/encoder/lame/configure.in.in new file mode 100644 index 0000000..f2a5283 --- /dev/null +++ b/plugins/encoder/lame/configure.in.in @@ -0,0 +1,20 @@ +dnl === test for LAME - begin ==== +AC_ARG_WITH( + lame, + AS_HELP_STRING([--without-lame], [build K3b without LAME support (default=no)]), + [ac_cv_use_lame=$withval], + [ac_cv_use_lame=yes] +) + +have_lame=no +if test "$ac_cv_use_lame" = "yes"; then + KDE_CHECK_HEADERS(lame/lame.h, [ + AC_CHECK_LIB(mp3lame, lame_init, [ + have_lame=yes + AC_DEFINE(HAVE_LAME,1,[defined if you have the lame header and lib]) + ], [], $all_libraries -lm) + ]) +fi + +AM_CONDITIONAL(include_LAME, [test x$have_lame = xyes]) +dnl === test for LAME - end ==== diff --git a/plugins/encoder/lame/k3blameencoder.cpp b/plugins/encoder/lame/k3blameencoder.cpp new file mode 100644 index 0000000..089c7d0 --- /dev/null +++ b/plugins/encoder/lame/k3blameencoder.cpp @@ -0,0 +1,627 @@ +/* + * + * $Id: k3blameencoder.cpp 653779 2007-04-14 07:58:51Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include <config.h> + +#include "k3blameencoder.h" + +#include <k3bcore.h> +#include <k3bpluginfactory.h> + +#include <klocale.h> +#include <kconfig.h> +#include <kdebug.h> +#include <kinstance.h> +#include <knuminput.h> +#include <kcombobox.h> +#include <kdialogbase.h> + +#include <qlayout.h> +#include <qcstring.h> +#include <qradiobutton.h> +#include <qcheckbox.h> +#include <qspinbox.h> +#include <qgroupbox.h> +#include <qbuttongroup.h> +#include <qtextcodec.h> +#include <qfile.h> +#include <qslider.h> +#include <qlabel.h> +#include <qpushbutton.h> + +#include <stdio.h> +#include <lame/lame.h> + + +K_EXPORT_COMPONENT_FACTORY( libk3blameencoder, K3bPluginFactory<K3bLameEncoder>( "libk3blameencoder" ) ) + + +static const int s_lame_bitrates[] = { + 32, + 40, + 48, + 56, + 64, + 80, + 96, + 112, + 128, + 160, + 192, + 224, + 256, + 320, + 0 // just used for the loops below +}; + + +static const int s_lame_presets[] = { + 56, // ABR for Voice, Radio, Mono, etc. + 90, // + + V6, // ~115 kbps + V5, // ~130 kbps | Portable - small size + V4, // ~160 kbps + + V3, // ~175 kbps + V2, // ~190 kbps | HiFi - for home or quite listening + V1, // ~210 kbps | + V0, // ~230 kbps + + 320 // ABR 320 neary lossless for archiving (not recommended, use flac instead) +}; + + +static const int s_lame_preset_approx_bitrates[] = { + 56, + 90, + 115, + 130, + 160, + 175, + 190, + 210, + 230, + 320 +}; + + +static const char* s_lame_preset_strings[] = { + I18N_NOOP("Low quality (56 kbps)"), + I18N_NOOP("Low quality (90 kbps)"), + + I18N_NOOP("Portable (average 115 kbps)"), + I18N_NOOP("Portable (average 130 kbps)"), + I18N_NOOP("Portable (average 160 kbps)"), + + I18N_NOOP("HiFi (average 175 kbps)"), + I18N_NOOP("HiFi (average 190 kbps)"), + I18N_NOOP("HiFi (average 210 kbps)"), + I18N_NOOP("HiFi (average 230 kbps)"), + + I18N_NOOP("Archiving (320 kbps)"), +}; + + +static const char* s_lame_mode_strings[] = { + I18N_NOOP("Stereo"), + I18N_NOOP("Joint Stereo"), + I18N_NOOP("Mono") +}; + + + +class K3bLameEncoder::Private +{ +public: + Private() + : flags(0), + fid(0) { + } + + lame_global_flags* flags; + + char buffer[8000]; + + QString filename; + FILE* fid; +}; + + + + +K3bLameEncoder::K3bLameEncoder( QObject* parent, const char* name ) + : K3bAudioEncoder( parent, name ) +{ + d = new Private(); +} + + +K3bLameEncoder::~K3bLameEncoder() +{ + closeFile(); + + delete d; +} + + +bool K3bLameEncoder::openFile( const QString& extension, const QString& filename, const K3b::Msf& length ) +{ + closeFile(); + + d->filename = filename; + d->fid = ::fopen( QFile::encodeName( filename ), "w+" ); + if( d->fid ) + return initEncoder( extension, length ); + else + return false; +} + + +bool K3bLameEncoder::isOpen() const +{ + return ( d->fid != 0 ); +} + + +void K3bLameEncoder::closeFile() +{ + if( isOpen() ) { + finishEncoder(); + ::fclose( d->fid ); + d->fid = 0; + d->filename.truncate(0); + } +} + + +const QString& K3bLameEncoder::filename() const +{ + return d->filename; +} + + +bool K3bLameEncoder::initEncoderInternal( const QString&, const K3b::Msf& length ) +{ + KConfig* c = k3bcore->config(); + c->setGroup( "K3bLameEncoderPlugin" ); + + d->flags = lame_init(); + + if( d->flags == 0 ) { + kdDebug() << "(K3bLameEncoder) lame_init failed." << endl; + return false; + } + + // + // set the format of the input data + // + lame_set_num_samples( d->flags, length.lba()*588 ); + lame_set_in_samplerate( d->flags, 44100 ); + lame_set_num_channels( d->flags, 2 ); + + // + // Lame by default determines the samplerate based on the bitrate + // since we have no option for the user to influence this yet + // we just keep to the good old 44.1 khz + // + lame_set_out_samplerate( d->flags, 44100 ); + + // + // Choose the quality level + // + if( c->readBoolEntry( "Manual Bitrate Settings", false ) ) { + // + // Mode + // + QString mode = c->readEntry( "Mode", "stereo" ); + if( mode == "stereo" ) + lame_set_mode( d->flags, STEREO ); + else if( mode == "joint" ) + lame_set_mode( d->flags, JOINT_STEREO ); + else // mono + lame_set_mode( d->flags, MONO ); + + // + // Variable Bitrate + // + if( c->readBoolEntry( "VBR", false ) ) { + // we use the default algorithm here + lame_set_VBR( d->flags, vbr_default ); + + if( c->readBoolEntry( "Use Maximum Bitrate", false ) ) { + lame_set_VBR_max_bitrate_kbps( d->flags, c->readNumEntry( "Maximum Bitrate", 224 ) ); + } + if( c->readBoolEntry( "Use Minimum Bitrate", false ) ) { + lame_set_VBR_min_bitrate_kbps( d->flags, c->readNumEntry( "Minimum Bitrate", 32 ) ); + + // TODO: lame_set_hard_min + } + if( c->readBoolEntry( "Use Average Bitrate", true ) ) { + lame_set_VBR( d->flags, vbr_abr ); + lame_set_VBR_mean_bitrate_kbps( d->flags, c->readNumEntry( "Average Bitrate", 128 ) ); + } + } + + // + // Constant Bitrate + // + else { + lame_set_VBR( d->flags, vbr_off ); + lame_set_brate( d->flags, c->readNumEntry( "Constant Bitrate", 128 ) ); + } + } + + else { + // + // In lame 0 is the highest quality. Since that is just confusing for the user + // if we call the setting "Quality" we simply invert the value. + // + int q = c->readNumEntry( "Quality Level", 5 ); + if( q < 0 ) q = 0; + if( q > 9 ) q = 9; + + kdDebug() << "(K3bLameEncoder) setting preset encoding value to " << q << endl; + + if ( q < 2 || q > 8 ) { + lame_set_VBR( d->flags, vbr_abr ); + } + else { + lame_set_VBR( d->flags, vbr_default ); + } + lame_set_preset( d->flags, s_lame_presets[q] ); + + if( q < 2 ) + lame_set_mode( d->flags, MONO ); + } + + + // + // file options + // + lame_set_copyright( d->flags, c->readBoolEntry( "Copyright", false ) ); + lame_set_original( d->flags, c->readBoolEntry( "Original", true ) ); + lame_set_strict_ISO( d->flags, c->readBoolEntry( "ISO compliance", false ) ); + lame_set_error_protection( d->flags, c->readBoolEntry( "Error Protection", false ) ); + + + // + // Used Algorithm + // + // default to 2 which is the same as the -h lame option + // THIS HAS NO INFLUENCE ON THE SIZE OF THE FILE! + // + // + // In lame 0 is the highest quality. Since that is just confusing for the user + // if we call the setting "Quality" we simply invert the value. + // + int q = c->readNumEntry( "Encoder Quality", 7 ); + if( q < 0 ) q = 0; + if( q > 9 ) q = 9; + lame_set_quality( d->flags, 9-q ); + + // + // ID3 settings + // + // for now we default to both v1 and v2 tags + id3tag_add_v2( d->flags ); + id3tag_pad_v2( d->flags ); + + return( lame_init_params( d->flags ) != -1 ); +} + + +long K3bLameEncoder::encodeInternal( const char* data, Q_ULONG len ) +{ + // FIXME: we may have to swap data here + int size = lame_encode_buffer_interleaved( d->flags, + (short int*)data, + len/4, + (unsigned char*)d->buffer, + 8000 ); + if( size < 0 ) { + kdDebug() << "(K3bLameEncoder) lame_encode_buffer_interleaved failed." << endl; + return -1; + } + + return ::fwrite( d->buffer, 1, size, d->fid ); +} + + +void K3bLameEncoder::finishEncoderInternal() +{ + int size = lame_encode_flush( d->flags, + (unsigned char*)d->buffer, + 8000 ); + if( size > 0 ) + ::fwrite( d->buffer, 1, size, d->fid ); + + lame_mp3_tags_fid( d->flags, d->fid ); + + lame_close( d->flags ); + d->flags = 0; +} + + +void K3bLameEncoder::setMetaDataInternal( K3bAudioEncoder::MetaDataField f, const QString& value ) +{ + // let's not use UTF-8 here since I don't know how to tell lame... + // FIXME: when we use the codec we only get garbage. Why? + QTextCodec* codec = 0;//QTextCodec::codecForName( "ISO8859-1" ); +// if( !codec ) +// kdDebug() << "(K3bLameEncoder) could not find codec ISO8859-1." << endl; + + switch( f ) { + case META_TRACK_TITLE: + id3tag_set_title( d->flags, codec ? codec->fromUnicode(value).data() : value.latin1() ); + break; + case META_TRACK_ARTIST: + id3tag_set_artist( d->flags, codec ? codec->fromUnicode(value).data() : value.latin1() ); + break; + case META_ALBUM_TITLE: + id3tag_set_album( d->flags, codec ? codec->fromUnicode(value).data() : value.latin1() ); + break; + case META_ALBUM_COMMENT: + id3tag_set_comment( d->flags, codec ? codec->fromUnicode(value).data() : value.latin1() ); + break; + case META_YEAR: + id3tag_set_year( d->flags, codec ? codec->fromUnicode(value).data() : value.latin1() ); + break; + case META_TRACK_NUMBER: + id3tag_set_track( d->flags, codec ? codec->fromUnicode(value).data() : value.latin1() ); + break; + case META_GENRE: + if( id3tag_set_genre( d->flags, codec ? codec->fromUnicode(value).data() : value.latin1() ) ) + kdDebug() << "(K3bLameEncoder) unable to set genre." << endl; + break; + default: + return; + } + + if( lame_init_params( d->flags ) < 0 ) + kdDebug() << "(K3bLameEncoder) lame_init_params failed." << endl; +} + + + + + +K3bLameEncoderSettingsWidget::K3bLameEncoderSettingsWidget( QWidget* parent, const char* name ) + : K3bPluginConfigWidget( parent, name ) +{ + m_w = new base_K3bLameEncoderSettingsWidget( this ); + m_w->m_sliderQuality->setRange( 0, 9 ); + m_w->m_spinEncoderQuality->setRange( 0, 9, true ); + + m_manualSettingsDlg = new KDialogBase( this, 0, true, + i18n("(Lame) Manual Quality Settings") ); + m_brW = new base_K3bManualBitrateSettingsWidget( m_manualSettingsDlg ); + m_manualSettingsDlg->setMainWidget( m_brW ); + + for( int i = 0; s_lame_bitrates[i]; ++i ) + m_brW->m_comboMaximumBitrate->insertItem( i18n("%1 kbps" ).arg(s_lame_bitrates[i]) ); + + for( int i = 0; s_lame_bitrates[i]; ++i ) + m_brW->m_comboMinimumBitrate->insertItem( i18n("%1 kbps" ).arg(s_lame_bitrates[i]) ); + + for( int i = 0; s_lame_bitrates[i]; ++i ) + m_brW->m_comboConstantBitrate->insertItem( i18n("%1 kbps" ).arg(s_lame_bitrates[i]) ); + + + QHBoxLayout* lay = new QHBoxLayout( this ); + lay->setMargin( 0 ); + lay->addWidget( m_w ); + + // TODO: add whatsthis help for the quality level. + // QString qualityLevelWhatsThis = i18n("<p>"); + + connect( m_w->m_buttonManualSettings, SIGNAL(clicked()), + this, SLOT(slotShowManualSettings()) ); + connect( m_w->m_sliderQuality, SIGNAL(valueChanged(int)), + this, SLOT(slotQualityLevelChanged(int)) ); + + updateManualSettingsLabel(); + slotQualityLevelChanged( 5 ); +} + + +K3bLameEncoderSettingsWidget::~K3bLameEncoderSettingsWidget() +{ +} + + +void K3bLameEncoderSettingsWidget::slotShowManualSettings() +{ + // save current settings for proper cancellation + bool constant = m_brW->m_radioConstantBitrate->isChecked(); + int constBitrate = m_brW->m_comboConstantBitrate->currentItem(); + int max = m_brW->m_comboMaximumBitrate->currentItem(); + int min = m_brW->m_comboMinimumBitrate->currentItem(); + int av = m_brW->m_spinAverageBitrate->value(); + int mode = m_brW->m_comboMode->currentItem(); + + if( m_manualSettingsDlg->exec() == QDialog::Rejected ) { + m_brW->m_radioConstantBitrate->setChecked( constant ); + m_brW->m_comboConstantBitrate->setCurrentItem( constBitrate ); + m_brW->m_comboMaximumBitrate->setCurrentItem( max ); + m_brW->m_comboMinimumBitrate->setCurrentItem( min ); + m_brW->m_spinAverageBitrate->setValue( av ); + m_brW->m_comboMode->setCurrentItem( mode ); + } + else + updateManualSettingsLabel(); +} + + +void K3bLameEncoderSettingsWidget::updateManualSettingsLabel() +{ + if( m_brW->m_radioConstantBitrate->isChecked() ) + m_w->m_labelManualSettings->setText( i18n("Constant Bitrate: %1 kbps (%2)") + .arg(s_lame_bitrates[m_brW->m_comboConstantBitrate->currentItem()]) + .arg(i18n(s_lame_mode_strings[m_brW->m_comboMode->currentItem()])) ); + else + m_w->m_labelManualSettings->setText( i18n("Variable Bitrate (%1)") + .arg(i18n(s_lame_mode_strings[m_brW->m_comboMode->currentItem()])) ); +} + + +void K3bLameEncoderSettingsWidget::slotQualityLevelChanged( int val ) +{ + m_w->m_labelQualityLevel->setText( i18n(s_lame_preset_strings[val]) ); +} + + +void K3bLameEncoderSettingsWidget::loadConfig() +{ + KConfig* c = k3bcore->config(); + c->setGroup( "K3bLameEncoderPlugin" ); + + QString mode = c->readEntry( "Mode", "stereo" ); + if( mode == "stereo" ) + m_brW->m_comboMode->setCurrentItem( 0 ); + else if( mode == "joint" ) + m_brW->m_comboMode->setCurrentItem( 1 ); + else // mono + m_brW->m_comboMode->setCurrentItem( 2 ); + + bool manual = c->readBoolEntry( "Manual Bitrate Settings", false ); + if( manual ) + m_w->m_radioManual->setChecked(true); + else + m_w->m_radioQualityLevel->setChecked(true); + + if( c->readBoolEntry( "VBR", false ) ) + m_brW->m_radioVariableBitrate->setChecked( true ); + else + m_brW->m_radioConstantBitrate->setChecked( true ); + + m_brW->m_comboConstantBitrate->setCurrentItem( i18n("%1 kbps").arg(c->readNumEntry( "Constant Bitrate", 128 )) ); + m_brW->m_comboMaximumBitrate->setCurrentItem( i18n("%1 kbps").arg(c->readNumEntry( "Maximum Bitrate", 224 )) ); + m_brW->m_comboMinimumBitrate->setCurrentItem( i18n("%1 kbps").arg(c->readNumEntry( "Minimum Bitrate", 32 )) ); + m_brW->m_spinAverageBitrate->setValue( c->readNumEntry( "Average Bitrate", 128) ); + + m_brW->m_checkBitrateMaximum->setChecked( c->readBoolEntry( "Use Maximum Bitrate", false ) ); + m_brW->m_checkBitrateMinimum->setChecked( c->readBoolEntry( "Use Minimum Bitrate", false ) ); + m_brW->m_checkBitrateAverage->setChecked( c->readBoolEntry( "Use Average Bitrate", true ) ); + + m_w->m_sliderQuality->setValue( c->readNumEntry( "Quality Level", 5 ) ); + + m_w->m_checkCopyright->setChecked( c->readBoolEntry( "Copyright", false ) ); + m_w->m_checkOriginal->setChecked( c->readBoolEntry( "Original", true ) ); + m_w->m_checkISO->setChecked( c->readBoolEntry( "ISO compliance", false ) ); + m_w->m_checkError->setChecked( c->readBoolEntry( "Error Protection", false ) ); + + // default to 2 which is the same as the -h lame option + m_w->m_spinEncoderQuality->setValue( c->readNumEntry( "Encoder Quality", 7 ) ); + + updateManualSettingsLabel(); +} + + +void K3bLameEncoderSettingsWidget::saveConfig() +{ + KConfig* c = k3bcore->config(); + c->setGroup( "K3bLameEncoderPlugin" ); + + QString mode; + switch( m_brW->m_comboMode->currentItem() ) { + case 0: + mode = "stereo"; + break; + case 1: + mode = "joint"; + break; + case 2: + mode = "mono"; + break; + } + c->writeEntry( "Mode", mode ); + + c->writeEntry( "Manual Bitrate Settings", m_w->m_radioManual->isChecked() ); + + c->writeEntry( "VBR", !m_brW->m_radioConstantBitrate->isChecked() ); + c->writeEntry( "Constant Bitrate", m_brW->m_comboConstantBitrate->currentText().left(3).toInt() ); + c->writeEntry( "Maximum Bitrate", m_brW->m_comboMaximumBitrate->currentText().left(3).toInt() ); + c->writeEntry( "Minimum Bitrate", m_brW->m_comboMinimumBitrate->currentText().left(3).toInt() ); + c->writeEntry( "Average Bitrate", m_brW->m_spinAverageBitrate->value() ); + + c->writeEntry( "Use Maximum Bitrate", m_brW->m_checkBitrateMaximum->isChecked() ); + c->writeEntry( "Use Minimum Bitrate", m_brW->m_checkBitrateMinimum->isChecked() ); + c->writeEntry( "Use Average Bitrate", m_brW->m_checkBitrateAverage->isChecked() ); + + c->writeEntry( "Quality Level", m_w->m_sliderQuality->value() ); + + c->writeEntry( "Copyright", m_w->m_checkCopyright->isChecked() ); + c->writeEntry( "Original", m_w->m_checkOriginal->isChecked() ); + c->writeEntry( "ISO compliance", m_w->m_checkISO->isChecked() ); + c->writeEntry( "Error Protection", m_w->m_checkError->isChecked() ); + + // default to 2 which is the same as the -h lame option + c->writeEntry( "Encoder Quality", m_w->m_spinEncoderQuality->value() ); +} + + + +QStringList K3bLameEncoder::extensions() const +{ + return QStringList( "mp3" ); +} + + +QString K3bLameEncoder::fileTypeComment( const QString& ) const +{ + return "MPEG1 Layer III (mp3)"; +} + + +long long K3bLameEncoder::fileSize( const QString&, const K3b::Msf& msf ) const +{ + KConfig* c = k3bcore->config(); + c->setGroup( "K3bLameEncoderPlugin" ); + int bitrate = 0; + if( c->readBoolEntry( "Manual Bitrate Settings", false ) ) { + if( c->readBoolEntry( "VBR", false ) ) { + if( c->readBoolEntry( "Use Maximum Bitrate", false ) ) + bitrate = c->readNumEntry( "Maximum Bitrate", 224 ); + if( c->readBoolEntry( "Use Minimum Bitrate", false ) ) + bitrate = ( bitrate > 0 + ? (bitrate - c->readNumEntry( "Minimum Bitrate", 32 )) / 2 + : c->readNumEntry( "Minimum Bitrate", 32 ) ); + if( c->readBoolEntry( "Use Average Bitrate", true ) ) + bitrate = c->readNumEntry( "Average Bitrate", 128 ); + } + else { + bitrate = c->readNumEntry( "Constant Bitrate", 128 ); + } + } + else { + int q = c->readNumEntry( "Quality Level", 5 ); + if( q < 0 ) q = 0; + if( q > 9 ) q = 9; + bitrate = s_lame_preset_approx_bitrates[q]; + } + + return (msf.totalFrames()/75 * bitrate * 1000)/8; +} + + +K3bPluginConfigWidget* K3bLameEncoder::createConfigWidget( QWidget* parent, + const char* name ) const +{ + return new K3bLameEncoderSettingsWidget( parent, name ); +} + + +#include "k3blameencoder.moc" diff --git a/plugins/encoder/lame/k3blameencoder.h b/plugins/encoder/lame/k3blameencoder.h new file mode 100644 index 0000000..424ea64 --- /dev/null +++ b/plugins/encoder/lame/k3blameencoder.h @@ -0,0 +1,88 @@ +/* + * + * $Id: k3blameencoder.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_LAME_ENCODER_H_ +#define _K3B_LAME_ENCODER_H_ + + +#include <k3baudioencoder.h> +#include <k3bpluginconfigwidget.h> + +#include "base_k3blameencodersettingswidget.h" +#include "base_k3bmanualbitratesettingswidget.h" + + +class KDialogBase; + + +class K3bLameEncoder : public K3bAudioEncoder +{ + Q_OBJECT + + public: + K3bLameEncoder( QObject* parent = 0, const char* name = 0 ); + ~K3bLameEncoder(); + + bool openFile( const QString& extension, const QString& filename, const K3b::Msf& length ); + bool isOpen() const; + void closeFile(); + const QString& filename() const; + + QStringList extensions() const; + + QString fileTypeComment( const QString& ) const; + + long long fileSize( const QString&, const K3b::Msf& msf ) const; + + int pluginSystemVersion() const { return 3; } + + K3bPluginConfigWidget* createConfigWidget( QWidget* parent = 0, + const char* name = 0 ) const; + + private: + void finishEncoderInternal(); + bool initEncoderInternal( const QString& extension, const K3b::Msf& length ); + long encodeInternal( const char* data, Q_ULONG len ); + void setMetaDataInternal( MetaDataField, const QString& ); + + class Private; + Private* d; +}; + + +class K3bLameEncoderSettingsWidget : public K3bPluginConfigWidget +{ + Q_OBJECT + + public: + K3bLameEncoderSettingsWidget( QWidget* parent = 0, const char* name = 0 ); + ~K3bLameEncoderSettingsWidget(); + + public slots: + void loadConfig(); + void saveConfig(); + + private slots: + void slotQualityLevelChanged( int val ); + void slotShowManualSettings(); + void updateManualSettingsLabel(); + + private: + base_K3bLameEncoderSettingsWidget* m_w; + base_K3bManualBitrateSettingsWidget* m_brW; + KDialogBase* m_manualSettingsDlg; +}; + +#endif diff --git a/plugins/encoder/lame/k3blameencoder.plugin b/plugins/encoder/lame/k3blameencoder.plugin new file mode 100644 index 0000000..432bc58 --- /dev/null +++ b/plugins/encoder/lame/k3blameencoder.plugin @@ -0,0 +1,9 @@ +[K3b Plugin] +Lib=libk3blameencoder +Group=AudioEncoder +Name=K3b Lame Mp3 Encoder +Author=Sebastian Trueg +Email=trueg@k3b.org +Version=3.0 +Comment=Encoding module to encode MPEG1 Layer III (mp3) files +License=GPL diff --git a/plugins/encoder/ogg/Makefile.am b/plugins/encoder/ogg/Makefile.am new file mode 100644 index 0000000..712adbb --- /dev/null +++ b/plugins/encoder/ogg/Makefile.am @@ -0,0 +1,13 @@ +AM_CPPFLAGS = -I$(srcdir)/../../../libk3b/core -I$(srcdir)/../../../libk3b/plugin -I$(srcdir)/../../../libk3b/core -I$(srcdir)/../../../libk3bdevice $(all_includes) + +kde_module_LTLIBRARIES = libk3boggvorbisencoder.la + +libk3boggvorbisencoder_la_SOURCES = base_k3boggvorbisencodersettingswidget.ui k3boggvorbisencoder.cpp + +libk3boggvorbisencoder_la_LIBADD = ../../../libk3b/libk3b.la $(LIB_KDECORE) -logg -lvorbis -lvorbisenc +libk3boggvorbisencoder_la_LDFLAGS = -avoid-version -module -no-undefined $(all_libraries) + +pluginsdir = $(kde_datadir)/k3b/plugins +plugins_DATA = k3boggvorbisencoder.plugin + +METASOURCES = AUTO diff --git a/plugins/encoder/ogg/base_k3boggvorbisencodersettingswidget.ui b/plugins/encoder/ogg/base_k3boggvorbisencodersettingswidget.ui new file mode 100644 index 0000000..3e31265 --- /dev/null +++ b/plugins/encoder/ogg/base_k3boggvorbisencodersettingswidget.ui @@ -0,0 +1,392 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>base_K3bOggVorbisEncoderSettingsWidget</class> +<author>Sebastian Trueg</author> +<widget class="QWidget"> + <property name="name"> + <cstring>Form1</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>335</width> + <height>271</height> + </rect> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QButtonGroup"> + <property name="name"> + <cstring>buttonGroup1</cstring> + </property> + <property name="title"> + <string>File Quality</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout7</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QRadioButton"> + <property name="name"> + <cstring>m_radioQualityLevel</cstring> + </property> + <property name="text"> + <string>&Quality level:</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + <property name="toolTip" stdset="0"> + <string>Controls the quality of the encoded files</string> + </property> + <property name="whatsThis" stdset="0"> + <string><p>Vorbis' audio quality is not best measured in kilobits per second, but on a scale from -1 to 10 called "quality". <p>For now, quality -1 is roughly equivalent to 45kbps average, 5 is roughly 160kbps, and 10 gives about 400kbps. Most people seeking very-near-CD-quality audio encode at a quality of 5 or, for lossless stereo coupling, 6. The default setting is quality 3, which at approximately 110kbps gives a smaller filesize and significantly better fidelity than .mp3 compression at 128kbps. <p><em>This explanation was copied from the www.vorbis.com FAQ.</em></string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>m_labelQualityLevel</cstring> + </property> + <property name="font"> + <font> + <bold>1</bold> + </font> + </property> + <property name="text"> + <string>textLabel1</string> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + </hbox> + </widget> + <widget class="QFrame"> + <property name="name"> + <cstring>frame6</cstring> + </property> + <property name="frameShape"> + <enum>NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>Plain</enum> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <spacer> + <property name="name"> + <cstring>spacer2_2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout8</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QSlider" row="0" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>m_slideQualityLevel</cstring> + </property> + <property name="minValue"> + <number>-1</number> + </property> + <property name="maxValue"> + <number>10</number> + </property> + <property name="pageStep"> + <number>3</number> + </property> + <property name="value"> + <number>3</number> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + </widget> + <widget class="QLabel" row="1" column="1"> + <property name="name"> + <cstring>textLabel4</cstring> + </property> + <property name="font"> + <font> + <italic>1</italic> + </font> + </property> + <property name="text"> + <string>high quality</string> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel3_2</cstring> + </property> + <property name="font"> + <font> + <italic>1</italic> + </font> + </property> + <property name="text"> + <string>small file</string> + </property> + </widget> + </grid> + </widget> + </hbox> + </widget> + <spacer> + <property name="name"> + <cstring>spacer9</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QRadioButton"> + <property name="name"> + <cstring>m_radioManual</cstring> + </property> + <property name="text"> + <string>M&anual settings:</string> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout6</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>21</height> + </size> + </property> + </spacer> + <widget class="QFrame"> + <property name="name"> + <cstring>frame3</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="frameShape"> + <enum>NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>Raised</enum> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QCheckBox" row="0" column="0"> + <property name="name"> + <cstring>m_checkBitrateUpper</cstring> + </property> + <property name="text"> + <string>&Upper bitrate:</string> + </property> + </widget> + <widget class="QCheckBox" row="2" column="0"> + <property name="name"> + <cstring>m_checkBitrateLower</cstring> + </property> + <property name="text"> + <string>Lower &bitrate:</string> + </property> + </widget> + <widget class="KIntNumInput" row="0" column="1"> + <property name="name"> + <cstring>m_inputBitrateUpper</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="KIntNumInput" row="1" column="1"> + <property name="name"> + <cstring>m_inputBitrateNominal</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="KIntNumInput" row="2" column="1"> + <property name="name"> + <cstring>m_inputBitrateLower</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + </widget> + <widget class="QLabel" row="1" column="2"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>kbps</string> + </property> + </widget> + <widget class="QLabel" row="2" column="2"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>kbps</string> + </property> + </widget> + <widget class="QLabel" row="0" column="2"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>kbps</string> + </property> + </widget> + <widget class="QCheckBox" row="1" column="0"> + <property name="name"> + <cstring>m_checkBitrateNominal</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>1</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>&Nominal bitrate:</string> + </property> + </widget> + </grid> + </widget> + </hbox> + </widget> + </vbox> + </widget> + </vbox> +</widget> +<customwidgets> +</customwidgets> +<connections> + <connection> + <sender>m_radioManual</sender> + <signal>toggled(bool)</signal> + <receiver>frame3</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>m_checkBitrateUpper</sender> + <signal>toggled(bool)</signal> + <receiver>m_inputBitrateUpper</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>m_checkBitrateNominal</sender> + <signal>toggled(bool)</signal> + <receiver>m_inputBitrateNominal</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>m_checkBitrateLower</sender> + <signal>toggled(bool)</signal> + <receiver>m_inputBitrateLower</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>m_radioQualityLevel</sender> + <signal>toggled(bool)</signal> + <receiver>m_labelQualityLevel</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>m_radioQualityLevel</sender> + <signal>toggled(bool)</signal> + <receiver>frame6</receiver> + <slot>setEnabled(bool)</slot> + </connection> +</connections> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>knuminput.h</includehint> + <includehint>knuminput.h</includehint> + <includehint>knuminput.h</includehint> +</includehints> +</UI> diff --git a/plugins/encoder/ogg/k3boggvorbisencoder.cpp b/plugins/encoder/ogg/k3boggvorbisencoder.cpp new file mode 100644 index 0000000..54e6ecb --- /dev/null +++ b/plugins/encoder/ogg/k3boggvorbisencoder.cpp @@ -0,0 +1,555 @@ +/* + * + * $Id: k3boggvorbisencoder.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include <config.h> + +#include "k3boggvorbisencoder.h" +#include "base_k3boggvorbisencodersettingswidget.h" + +#include <k3bcore.h> +#include <k3bpluginfactory.h> + +#include <klocale.h> +#include <kconfig.h> +#include <kdebug.h> +#include <knuminput.h> + +#include <qlayout.h> +#include <qradiobutton.h> +#include <qslider.h> +#include <qlcdnumber.h> +#include <qcheckbox.h> +#include <qcstring.h> +#include <qtooltip.h> +#include <qwhatsthis.h> +#include <qlabel.h> + +#include <vorbis/vorbisenc.h> + +// for the random generator +#include <stdlib.h> +#include <time.h> + + +K_EXPORT_COMPONENT_FACTORY( libk3boggvorbisencoder, K3bPluginFactory<K3bOggVorbisEncoder>( "libk3boggvorbisencoder" ) ) + +// quality levels -1 to 10 map to 0 to 11 +static const int s_rough_average_quality_level_bitrates[] = { + 45, + 64, + 80, + 96, + 112, + 128, + 160, + 192, + 224, + 256, + 320, + 400 +}; + +// quality levels -1 to 10 map to 0 to 11 +// static const char* s_ogg_quality_level_strings[] = { +// I18N_NOOP("Low quality"), +// I18N_NOOP(""), +// I18N_NOOP(""), +// I18N_NOOP(""), +// I18N_NOOP(""), +// I18N_NOOP("targetted %1 kbps"), +// I18N_NOOP("targetted %1 kbps"), +// I18N_NOOP("targetted %1 kbps"), +// I18N_NOOP(""), +// I18N_NOOP(""), +// I18N_NOOP(""), +// I18N_NOOP(""), +// }; + + +// THIS IS BASED ON THE OGG VORBIS LIB EXAMPLE +// BECAUSE OF THE LACK OF DOCUMENTATION + + +class K3bOggVorbisEncoder::Private +{ +public: + Private() + : manualBitrate(false), + qualityLevel(4), + bitrateUpper(-1), + bitrateNominal(-1), + bitrateLower(-1), + // sampleRate(44100), + oggStream(0), + oggPage(0), + oggPacket(0), + vorbisInfo(0), + vorbisComment(0), + vorbisDspState(0), + vorbisBlock(0), + headersWritten(false) { + } + + // encoding settings + bool manualBitrate; + // 0 to 10 -> 0.0 - 1.0 + int qualityLevel; + int bitrateUpper; + int bitrateNominal; + int bitrateLower; + // int sampleRate; + + // encoding structures + ogg_stream_state *oggStream; // take physical pages, weld into a logical stream of packets + ogg_page *oggPage; // one Ogg bitstream page. Vorbis packets are inside + ogg_packet *oggPacket; // one raw packet of data for decode + vorbis_info *vorbisInfo; // struct that stores all the static vorbis bitstream settings + vorbis_comment *vorbisComment; // struct that stores all the user comments + vorbis_dsp_state *vorbisDspState; // central working state for the packet->PCM decoder + vorbis_block *vorbisBlock; // local working space for packet->PCM decode + + bool headersWritten; +}; + + +K3bOggVorbisEncoder::K3bOggVorbisEncoder( QObject* parent, const char* name ) + : K3bAudioEncoder( parent, name ) +{ + d = new Private(); +} + + +K3bOggVorbisEncoder::~K3bOggVorbisEncoder() +{ + cleanup(); + delete d; +} + + +bool K3bOggVorbisEncoder::initEncoderInternal( const QString&, const K3b::Msf& ) +{ + cleanup(); + + // load user settings + loadConfig(); + + d->oggPage = new ogg_page; + d->oggPacket = new ogg_packet; + d->vorbisInfo = new vorbis_info; + + vorbis_info_init( d->vorbisInfo ); + + int ret = 0; + + if( d->manualBitrate ) { + kdDebug() << "(K3bOggVorbisEncoder) calling: " + << "vorbis_encode_init( d->vorbisInfo, 2, 44100, " + << (d->bitrateUpper != -1 ? d->bitrateUpper*1000 : -1) << ", " + << (d->bitrateNominal != -1 ? d->bitrateNominal*1000 : -1) << ", " + << (d->bitrateLower != -1 ? d->bitrateLower*1000 : -1) << " );" << endl; + + ret = vorbis_encode_init( d->vorbisInfo, + 2, // 2 channels: stereo + 44100, + d->bitrateUpper != -1 ? d->bitrateUpper*1000 : -1, + d->bitrateNominal != -1 ? d->bitrateNominal*1000 : -1, + d->bitrateLower != -1 ? d->bitrateLower*1000 : -1 ); + } + else { + if( d->qualityLevel < -1 ) + d->qualityLevel = -1; + else if( d->qualityLevel > 10 ) + d->qualityLevel = 10; + + kdDebug() << "(K3bOggVorbisEncoder) calling: " + << "vorbis_encode_init_vbr( d->vorbisInfo, 2, 44100, " + << (float)d->qualityLevel/10.0 << ");" << endl; + + ret = vorbis_encode_init_vbr( d->vorbisInfo, + 2, // 2 channels: stereo + 44100, + (float)d->qualityLevel/10.0 ); + } + + if( ret ) { + kdDebug() << "(K3bOggVorbisEncoder) vorbis_encode_init failed: " << ret << endl; + cleanup(); + return false; + } + + // init the comment stuff + d->vorbisComment = new vorbis_comment; + vorbis_comment_init( d->vorbisComment ); + + // add the encoder tag (so everybody knows we did it! ;) + vorbis_comment_add_tag( d->vorbisComment, QCString("ENCODER").data(), QCString("K3bOggVorbisEncoderPlugin").data() ); + + // set up the analysis state and auxiliary encoding storage + d->vorbisDspState = new vorbis_dsp_state; + d->vorbisBlock = new vorbis_block; + vorbis_analysis_init( d->vorbisDspState, d->vorbisInfo ); + vorbis_block_init( d->vorbisDspState, d->vorbisBlock ); + + // set up our packet->stream encoder + // pick a random serial number; that way we can more likely build + // chained streams just by concatenation + d->oggStream = new ogg_stream_state; + srand( time(0) ); + ogg_stream_init( d->oggStream, rand() ); + + return true; +} + + +bool K3bOggVorbisEncoder::writeOggHeaders() +{ + if( !d->oggStream ) { + kdDebug() << "(K3bOggVorbisEncoder) call to writeOggHeaders without init." << endl; + return false; + } + if( d->headersWritten ) { + kdDebug() << "(K3bOggVorbisEncoder) headers already written." << endl; + return true; + } + + // + // Vorbis streams begin with three headers; the initial header (with + // most of the codec setup parameters) which is mandated by the Ogg + // bitstream spec. The second header holds any comment fields. The + // third header holds the bitstream codebook. We merely need to + // make the headers, then pass them to libvorbis one at a time; + // libvorbis handles the additional Ogg bitstream constraints + // + ogg_packet header; + ogg_packet header_comm; + ogg_packet header_code; + + vorbis_analysis_headerout( d->vorbisDspState, + d->vorbisComment, + &header, + &header_comm, + &header_code); + + // automatically placed in its own page + ogg_stream_packetin( d->oggStream, &header ); + ogg_stream_packetin( d->oggStream, &header_comm ); + ogg_stream_packetin( d->oggStream, &header_code ); + + // + // This ensures the actual + // audio data will start on a new page, as per spec + // + QByteArray data; + while( ogg_stream_flush( d->oggStream, d->oggPage ) ) { + writeData( (char*)d->oggPage->header, d->oggPage->header_len ); + writeData( (char*)d->oggPage->body, d->oggPage->body_len ); + } + + d->headersWritten = true; + + return true; +} + + +long K3bOggVorbisEncoder::encodeInternal( const char* data, Q_ULONG len ) +{ + if( !d->headersWritten ) + if( !writeOggHeaders() ) + return -1; + + // expose the buffer to submit data + float** buffer = vorbis_analysis_buffer( d->vorbisDspState, len/4 ); + + // uninterleave samples + unsigned long i = 0; + for( i = 0; i < len/4; i++ ) { + buffer[0][i]=( (data[i*4+1]<<8) | (0x00ff&(int)data[i*4]) ) / 32768.f; + buffer[1][i]=( (data[i*4+3]<<8) | (0x00ff&(int)data[i*4+2]) ) / 32768.f; + } + + // tell the library how much we actually submitted + vorbis_analysis_wrote( d->vorbisDspState, i ); + + return flushVorbis(); +} + + +long K3bOggVorbisEncoder::flushVorbis() +{ + // vorbis does some data preanalysis, then divvies up blocks for + // more involved (potentially parallel) processing. Get a single + // block for encoding now + long writtenData = 0; + while( vorbis_analysis_blockout( d->vorbisDspState, d->vorbisBlock ) == 1 ) { + + // analysis + vorbis_analysis( d->vorbisBlock, 0 ); + vorbis_bitrate_addblock( d->vorbisBlock ); + + while( vorbis_bitrate_flushpacket( d->vorbisDspState, d->oggPacket ) ) { + + // weld the packet into the bitstream + ogg_stream_packetin( d->oggStream, d->oggPacket ); + + // write out pages (if any) + while( ogg_stream_pageout( d->oggStream, d->oggPage ) ) { + writeData( (char*)d->oggPage->header, d->oggPage->header_len ); + writeData( (char*)d->oggPage->body, d->oggPage->body_len ); + + writtenData += ( d->oggPage->header_len + d->oggPage->body_len ); + } + } + } + + return writtenData; +} + + +void K3bOggVorbisEncoder::finishEncoderInternal() +{ + if( d->vorbisDspState ) { + vorbis_analysis_wrote( d->vorbisDspState, 0 ); + flushVorbis(); + } + else + kdDebug() << "(K3bOggVorbisEncoder) call to finishEncoderInternal without init." << endl; +} + + +void K3bOggVorbisEncoder::setMetaDataInternal( K3bAudioEncoder::MetaDataField f, const QString& value ) +{ + if( d->vorbisComment ) { + QCString key; + + switch( f ) { + case META_TRACK_TITLE: + key = "TITLE"; + break; + case META_TRACK_ARTIST: + key = "ARTIST"; + break; + case META_ALBUM_TITLE: + key = "ALBUM"; + break; + case META_ALBUM_COMMENT: + key = "DESCRIPTION"; + break; + case META_YEAR: + key = "DATE"; + break; + case META_TRACK_NUMBER: + key = "TRACKNUMBER"; + break; + case META_GENRE: + key = "GENRE"; + break; + default: + return; + } + + vorbis_comment_add_tag( d->vorbisComment, key.data(), value.utf8().data() ); + } + else + kdDebug() << "(K3bOggVorbisEncoder) call to setMetaDataInternal without init." << endl; +} + + +void K3bOggVorbisEncoder::cleanup() +{ + if( d->oggStream ) { + ogg_stream_clear( d->oggStream ); + delete d->oggStream; + d->oggStream = 0; + } + if( d->vorbisBlock ) { + vorbis_block_clear( d->vorbisBlock ); + delete d->vorbisBlock; + d->vorbisBlock = 0; + } + if( d->vorbisDspState ) { + vorbis_dsp_clear( d->vorbisDspState ); + delete d->vorbisDspState; + d->vorbisDspState = 0; + } + if( d->vorbisComment ) { + vorbis_comment_clear( d->vorbisComment ); + delete d->vorbisComment; + d->vorbisComment = 0; + } + if( d->vorbisInfo ) { + vorbis_info_clear( d->vorbisInfo ); + delete d->vorbisInfo; + d->vorbisInfo = 0; + } + + // ogg_page and ogg_packet structs always point to storage in + // libvorbis. They're never freed or manipulated directly + if( d->oggPage ) { + delete d->oggPage; + d->oggPage = 0; + } + if( d->oggPacket ) { + delete d->oggPacket; + d->oggPacket = 0; + } + + d->headersWritten = false; +} + + +void K3bOggVorbisEncoder::loadConfig() +{ + KConfig* c = k3bcore->config(); + + c->setGroup( "K3bOggVorbisEncoderPlugin" ); + + d->manualBitrate = c->readBoolEntry( "manual bitrate", false ); + d->qualityLevel = c->readNumEntry( "quality level", 4 ); + d->bitrateUpper = c->readNumEntry( "bitrate upper", -1 ); + d->bitrateNominal = c->readNumEntry( "bitrate nominal", -1 ); + d->bitrateLower = c->readNumEntry( "bitrate lower", -1 ); + // d->sampleRate = c->readNumEntry( "samplerate", 44100 ); +} + + + + +K3bOggVorbisEncoderSettingsWidget::K3bOggVorbisEncoderSettingsWidget( QWidget* parent, const char* name ) + : K3bPluginConfigWidget( parent, name ) +{ + w = new base_K3bOggVorbisEncoderSettingsWidget( this ); + + QString ttQuality = i18n("Controls the quality of the encoded files."); + QString wsQuality = i18n("<p>Vorbis' audio quality is not best measured in kilobits per second, " + "but on a scale from -1 to 10 called <em>quality</em>." + "<p>For now, quality -1 is roughly equivalent to 45kbps average, " + "5 is roughly 160kbps, and 10 gives about 400kbps. " + "Most people seeking very-near-CD-quality audio encode at a quality of 5 or, " + "for lossless stereo coupling, 6. The quality 3 gives, at " + "approximately 110kbps a smaller filesize and significantly better fidelity " + "than .mp3 compression at 128kbps." + "<p><em>This explanation is based on the one from the www.vorbis.com FAQ.</em>"); + + QToolTip::add( w->m_radioQualityLevel, ttQuality ); + QToolTip::add( w->m_labelQualityLevel, ttQuality ); + QToolTip::add( w->m_slideQualityLevel, ttQuality ); + QWhatsThis::add( w->m_radioQualityLevel, wsQuality ); + QWhatsThis::add( w->m_labelQualityLevel, wsQuality ); + QWhatsThis::add( w->m_slideQualityLevel, wsQuality ); + + + QHBoxLayout* lay = new QHBoxLayout( this ); + lay->setMargin( 0 ); + + lay->addWidget( w ); + + connect( w->m_slideQualityLevel, SIGNAL(valueChanged(int)), + this, SLOT(slotQualityLevelChanged(int)) ); + + slotQualityLevelChanged( 4 ); +} + + +K3bOggVorbisEncoderSettingsWidget::~K3bOggVorbisEncoderSettingsWidget() +{ +} + + +void K3bOggVorbisEncoderSettingsWidget::slotQualityLevelChanged( int val ) +{ + w->m_labelQualityLevel->setText( QString::number(val) + " " + + i18n("(targetted VBR of %1)").arg(s_rough_average_quality_level_bitrates[val+1]) ); +} + + +void K3bOggVorbisEncoderSettingsWidget::loadConfig() +{ + KConfig* c = k3bcore->config(); + + c->setGroup( "K3bOggVorbisEncoderPlugin" ); + + if( c->readBoolEntry( "manual bitrate", false ) ) + w->m_radioManual->setChecked(true); + else + w->m_radioQualityLevel->setChecked(true); + w->m_slideQualityLevel->setValue( c->readNumEntry( "quality level", 4 ) ); + w->m_inputBitrateUpper->setValue( c->readNumEntry( "bitrate upper", -1 ) ); + w->m_checkBitrateUpper->setChecked( c->readNumEntry( "bitrate upper", -1 ) != -1 ); + w->m_inputBitrateNominal->setValue( c->readNumEntry( "bitrate nominal", -1 ) ); + w->m_checkBitrateNominal->setChecked( c->readNumEntry( "bitrate nominal", -1 ) != -1 ); + w->m_inputBitrateLower->setValue( c->readNumEntry( "bitrate lower", -1 ) ); + w->m_checkBitrateLower->setChecked( c->readNumEntry( "bitrate lower", -1 ) != -1 ); + // w->m_inputSamplerate->setValue( c->readNumEntry( "samplerate", 44100 ) ); +} + + +void K3bOggVorbisEncoderSettingsWidget::saveConfig() +{ + KConfig* c = k3bcore->config(); + + c->setGroup( "K3bOggVorbisEncoderPlugin" ); + + c->writeEntry( "manual bitrate", w->m_radioManual->isChecked() ); + c->writeEntry( "quality level", w->m_slideQualityLevel->value() ); + c->writeEntry( "bitrate upper", w->m_checkBitrateUpper->isChecked() ? w->m_inputBitrateUpper->value() : -1 ); + c->writeEntry( "bitrate nominal", w->m_checkBitrateNominal->isChecked() ? w->m_inputBitrateNominal->value() : -1 ); + c->writeEntry( "bitrate lower", w->m_checkBitrateLower->isChecked() ? w->m_inputBitrateLower->value() : -1 ); + // c->writeEntry( "samplerate", w->m_inputSamplerate->value() ); +} + + +QString K3bOggVorbisEncoder::fileTypeComment( const QString& ) const +{ + return i18n("Ogg-Vorbis"); +} + + +long long K3bOggVorbisEncoder::fileSize( const QString&, const K3b::Msf& msf ) const +{ + KConfig* c = k3bcore->config(); + c->setGroup( "K3bOggVorbisEncoderPlugin" ); + + // the following code is based on the size estimation from the audiocd kioslave + // TODO: reimplement. + + if( !c->readBoolEntry( "manual bitrate", false ) ) { + // Estimated numbers based on the Vorbis FAQ: + // http://www.xiph.org/archives/vorbis-faq/200203/0030.html + +// static long vorbis_q_bitrate[] = { 45, 60, 74, 86, 106, 120, 152, +// 183, 207, 239, 309, 440 }; + + int qualityLevel = c->readNumEntry( "quality level", 4 ); + + if( qualityLevel < -1 ) + qualityLevel = -1; + else if( qualityLevel > 10 ) + qualityLevel = 10; + return ( (msf.totalFrames()/75) * s_rough_average_quality_level_bitrates[qualityLevel+1] * 1000 ) / 8; + } + else { + return (msf.totalFrames()/75) * c->readNumEntry( "bitrate nominal", 160 ) * 1000 / 8; + } +} + + +K3bPluginConfigWidget* K3bOggVorbisEncoder::createConfigWidget( QWidget* parent, + const char* name ) const +{ + return new K3bOggVorbisEncoderSettingsWidget( parent, name ); +} + + +#include "k3boggvorbisencoder.moc" diff --git a/plugins/encoder/ogg/k3boggvorbisencoder.h b/plugins/encoder/ogg/k3boggvorbisencoder.h new file mode 100644 index 0000000..0148713 --- /dev/null +++ b/plugins/encoder/ogg/k3boggvorbisencoder.h @@ -0,0 +1,81 @@ +/* + * + * $Id: k3boggvorbisencoder.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_OGG_VORBIS_ENCODER_H_ +#define _K3B_OGG_VORBIS_ENCODER_H_ + + +#include <k3baudioencoder.h> +#include <k3bpluginconfigwidget.h> + + +class base_K3bOggVorbisEncoderSettingsWidget; + + +class K3bOggVorbisEncoder : public K3bAudioEncoder +{ + Q_OBJECT + + public: + K3bOggVorbisEncoder( QObject* parent = 0, const char* name = 0 ); + ~K3bOggVorbisEncoder(); + + QStringList extensions() const { return QStringList("ogg"); } + + QString fileTypeComment( const QString& ) const; + + long long fileSize( const QString&, const K3b::Msf& msf ) const; + + int pluginSystemVersion() const { return 3; } + + K3bPluginConfigWidget* createConfigWidget( QWidget* parent = 0, + const char* name = 0 ) const; + + private: + void loadConfig(); + void finishEncoderInternal(); + bool initEncoderInternal( const QString& extension, const K3b::Msf& length ); + long encodeInternal( const char* data, Q_ULONG len ); + void setMetaDataInternal( MetaDataField, const QString& ); + + bool writeOggHeaders(); + void cleanup(); + long flushVorbis(); + + class Private; + Private* d; +}; + + +class K3bOggVorbisEncoderSettingsWidget : public K3bPluginConfigWidget +{ + Q_OBJECT + + public: + K3bOggVorbisEncoderSettingsWidget( QWidget* parent = 0, const char* name = 0 ); + ~K3bOggVorbisEncoderSettingsWidget(); + + public slots: + void loadConfig(); + void saveConfig(); + + private slots: + void slotQualityLevelChanged( int val ); + + private: + base_K3bOggVorbisEncoderSettingsWidget* w; +}; + +#endif diff --git a/plugins/encoder/ogg/k3boggvorbisencoder.plugin b/plugins/encoder/ogg/k3boggvorbisencoder.plugin new file mode 100644 index 0000000..2f73e8e --- /dev/null +++ b/plugins/encoder/ogg/k3boggvorbisencoder.plugin @@ -0,0 +1,9 @@ +[K3b Plugin] +Lib=libk3boggvorbisencoder +Group=AudioEncoder +Name=K3b Ogg Vorbis Encoder +Author=Sebastian Trueg +Email=trueg@k3b.org +Version=2.1 +Comment=Encoding module to encode Ogg Vorbis files +License=GPL diff --git a/plugins/encoder/skeleton.cpp b/plugins/encoder/skeleton.cpp new file mode 100644 index 0000000..7a46caf --- /dev/null +++ b/plugins/encoder/skeleton.cpp @@ -0,0 +1,123 @@ +/* + * + * $Id: skeleton.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include <config.h> + +#include "k3b<name>encoder.h" + +#include <klocale.h> +#include <kconfig.h> +#include <kdebug.h> + + +K_EXPORT_COMPONENT_FACTORY( libk3b<name>encoder, K3bPluginFactory<K3b<name>Encoder>( "libk3b<name>encoder" ) ) + + +K3b<name>Encoder::K3b<name>Encoder( QObject* parent, const char* name ) + : K3bAudioEncoder( parent, name ) +{ +} + + +K3b<name>Encoder::~K3b<name>Encoder() +{ +} + + +bool K3b<name>Encoder::initEncoderInternal( const QString& ) +{ + // PUT YOUR CODE HERE + return false; +} + + +long K3b<name>Encoder::encodeInternal( const char* data, Q_ULONG len ) +{ + // PUT YOUR CODE HERE + return false; +} + + +void K3b<name>Encoder::finishEncoderInternal() +{ + // PUT YOUR CODE HERE +} + + +void K3b<name>Encoder::setMetaDataInternal( K3bAudioEncoder::MetaDataField f, const QString& value ) +{ + // PUT YOUR CODE HERE +} + + +QStringList K3b<name>Encoder::extensions() const +{ + // PUT YOUR CODE HERE + return QStringList( "" ); +} + + +QString K3b<name>Encoder::fileTypeComment( const QString& ) const +{ + // PUT YOUR CODE HERE + return ""; +} + + +long long K3b<name>Encoder::fileSize( const QString&, const K3b::Msf& msf ) const +{ + // PUT YOUR CODE HERE + return -1; +} + + +K3bPluginConfigWidget* K3b<name>Encoder::createConfigWidget( QWidget* parent, + const char* name ) const +{ + return new K3b<name>EncoderSettingsWidget( parent, name ); +} + + + +K3b<name>EncoderSettingsWidget::K3b<name>EncoderSettingsWidget( QWidget* parent, const char* name ) + : K3bPluginConfigWidget( parent, name ) +{ +} + + +K3b<name>EncoderSettingsWidget::~K3b<name>EncoderSettingsWidget() +{ +} + + +void K3b<name>EncoderSettingsWidget::loadConfig() +{ + KConfig* c = k3bcore->config(); + c->setGroup( "K3b<name>EncoderPlugin" ); + + // PUT YOUR CODE HERE +} + + +void K3b<name>EncoderSettingsWidget::saveConfig() +{ + KConfig* c = k3bcore->config(); + c->setGroup( "K3b<name>EncoderPlugin" ); + + // PUT YOUR CODE HERE +} + + +#include "k3b<name>encoder.moc" diff --git a/plugins/encoder/skeleton.h b/plugins/encoder/skeleton.h new file mode 100644 index 0000000..78c733e --- /dev/null +++ b/plugins/encoder/skeleton.h @@ -0,0 +1,64 @@ +/* + * + * $Id: skeleton.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_<name>_ENCODER_H_ +#define _K3B_<name>_ENCODER_H_ + + +#include <k3baudioencoder.h> +#include <k3bpluginconfigwidget.h> + + +class K3b<name>Encoder : public K3bAudioEncoder +{ + Q_OBJECT + + public: + K3b<name>Encoder( QObject* parent = 0, const char* name = 0 ); + ~K3b<name>Encoder(); + + QStringList extensions() const; + + QString fileTypeComment( const QString& ) const; + + long long fileSize( const QString&, const K3b::Msf& msf ) const; + + int pluginSystemVersion() const { return 3; } + + K3bPluginConfigWidget* createConfigWidget( QWidget* parent = 0, + const char* name = 0 ) const; + + private: + void finishEncoderInternal(); + bool initEncoderInternal( const QString& extension ); + long encodeInternal( const char* data, Q_ULONG len ); + void setMetaDataInternal( MetaDataField, const QString& ); +}; + + +class K3b<name>EncoderSettingsWidget : public K3bPluginConfigWidget +{ + Q_OBJECT + + public: + K3b<name>EncoderSettingsWidget( QWidget* parent = 0, const char* name = 0 ); + ~K3b<name>EncoderSettingsWidget(); + + public slots: + void loadConfig(); + void saveConfig(); +}; + +#endif diff --git a/plugins/encoder/skeleton.plugin b/plugins/encoder/skeleton.plugin new file mode 100644 index 0000000..cf178b7 --- /dev/null +++ b/plugins/encoder/skeleton.plugin @@ -0,0 +1,9 @@ +[K3b Plugin] +Lib=libk3b<name>encoder +Group=AudioEncoder +Name=K3b ??? Encoder +Author=??? +Email=??? +Version=?? +Comment=Encoding module to encode <name> files +License=??? diff --git a/plugins/encoder/sox/Makefile.am b/plugins/encoder/sox/Makefile.am new file mode 100644 index 0000000..535b1c0 --- /dev/null +++ b/plugins/encoder/sox/Makefile.am @@ -0,0 +1,13 @@ +AM_CPPFLAGS = -I$(srcdir)/../../../libk3b/core -I$(srcdir)/../../../libk3b/plugin -I$(srcdir)/../../../libk3b/core -I$(srcdir)/../../../libk3bdevice $(all_includes) + +kde_module_LTLIBRARIES = libk3bsoxencoder.la + +libk3bsoxencoder_la_SOURCES = base_k3bsoxencoderconfigwidget.ui k3bsoxencoder.cpp + +libk3bsoxencoder_la_LIBADD = ../../../libk3b/libk3b.la $(LIB_KDECORE) +libk3bsoxencoder_la_LDFLAGS = -avoid-version -module -no-undefined $(all_libraries) + +pluginsdir = $(kde_datadir)/k3b/plugins +plugins_DATA = k3bsoxencoder.plugin + +METASOURCES = AUTO diff --git a/plugins/encoder/sox/base_k3bsoxencoderconfigwidget.ui b/plugins/encoder/sox/base_k3bsoxencoderconfigwidget.ui new file mode 100644 index 0000000..7d8ee43 --- /dev/null +++ b/plugins/encoder/sox/base_k3bsoxencoderconfigwidget.ui @@ -0,0 +1,258 @@ +<!DOCTYPE UI><UI version="3.1" stdsetdef="1"> +<class>base_K3bSoxEncoderConfigWidget</class> +<author>Sebastian Trueg</author> +<widget class="QWidget"> + <property name="name"> + <cstring>Form1</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>419</width> + <height>201</height> + </rect> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_checkManual</cstring> + </property> + <property name="text"> + <string>Manual settings (used for all file types)</string> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout2</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>10</height> + </size> + </property> + </spacer> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout1</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Sample rate:</string> + </property> + </widget> + <widget class="QComboBox" row="2" column="1"> + <item> + <property name="text"> + <string>Signed Linear</string> + </property> + </item> + <item> + <property name="text"> + <string>Unsigned Linear</string> + </property> + </item> + <item> + <property name="text"> + <string>u-law (logarithmic)</string> + </property> + </item> + <item> + <property name="text"> + <string>A-law (logarithmic)</string> + </property> + </item> + <item> + <property name="text"> + <string>ADPCM</string> + </property> + </item> + <item> + <property name="text"> + <string>IMA_ADPCM</string> + </property> + </item> + <item> + <property name="text"> + <string>GSM</string> + </property> + </item> + <item> + <property name="text"> + <string>Floating-Point</string> + </property> + </item> + <property name="name"> + <cstring>m_comboEncoding</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="whatsThis" stdset="0"> + <string><p>The sample data encoding is signed linear (2's complement), unsigned linear, u-law (logarithmic), A-law (logarithmic), ADPCM, IMA_ADPCM, GSM, or Floating-point.</p> +<p><b>U-law</b> (actually shorthand for mu-law) and <b>A-law</b> are the U.S. and international standards for logarithmic telephone sound compression. When uncompressed u-law has roughly the precision of 14-bit PCM audio and A-law has roughly the precision of 13-bit PCM audio. A-law and u-law data is sometimes encoded using a reversed bit-ordering (i.e. MSB becomes LSB).<br> <b>ADPCM </b> is a form of sound compression that has a good compromise between good sound quality and fast encoding/decoding time. It is used for telephone sound compression and places where full fidelity is not as important. When uncompressed it has roughly the precision of 16-bit PCM audio. Popular versions of ADPCM include G.726, MS ADPCM, and IMA ADPCM. It has different meanings in different file handlers. In .wav files it represents MS ADPCM files, in all others it means G.726 ADPCM. <br> <b>IMA ADPCM</b> is a specific form of ADPCM compression, slightly simpler and slightly lower fidelity than Microsoft's flavor of ADPCM. IMA ADPCM is also called DVI ADPCM.<br> <b>GSM</b> is a standard used for telephone sound compression in European countries and is gaining popularity because of its good quality. It is usually CPU intensive to work with GSM audio data.</p> <p><em>Description based on the SoX manpage</em></p></string> + </property> + </widget> + <widget class="QLineEdit" row="1" column="1"> + <property name="name"> + <cstring>m_editSamplerate</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>14400</string> + </property> + <property name="whatsThis" stdset="0"> + <string></string> + </property> + </widget> + <widget class="QLabel" row="3" column="0"> + <property name="name"> + <cstring>textLabel4</cstring> + </property> + <property name="text"> + <string>Data size:</string> + </property> + </widget> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>Data encoding:</string> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Channels:</string> + </property> + </widget> + <widget class="QComboBox" row="0" column="1"> + <item> + <property name="text"> + <string>1 (mono)</string> + </property> + </item> + <item> + <property name="text"> + <string>2 (stereo)</string> + </property> + </item> + <item> + <property name="text"> + <string>4 (quad sound)</string> + </property> + </item> + <property name="name"> + <cstring>m_comboChannels</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + </widget> + <widget class="QComboBox" row="3" column="1"> + <item> + <property name="text"> + <string>Bytes</string> + </property> + </item> + <item> + <property name="text"> + <string>16-bit Words</string> + </property> + </item> + <item> + <property name="text"> + <string>32-bit Words</string> + </property> + </item> + <property name="name"> + <cstring>m_comboSize</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + </widget> + </grid> + </widget> + </hbox> + </widget> + <spacer> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>250</width> + <height>16</height> + </size> + </property> + </spacer> + </vbox> +</widget> +<connections> + <connection> + <sender>m_checkManual</sender> + <signal>toggled(bool)</signal> + <receiver>m_comboChannels</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>m_checkManual</sender> + <signal>toggled(bool)</signal> + <receiver>m_editSamplerate</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>m_checkManual</sender> + <signal>toggled(bool)</signal> + <receiver>m_comboEncoding</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>m_checkManual</sender> + <signal>toggled(bool)</signal> + <receiver>m_comboSize</receiver> + <slot>setEnabled(bool)</slot> + </connection> +</connections> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/plugins/encoder/sox/k3bsoxencoder.cpp b/plugins/encoder/sox/k3bsoxencoder.cpp new file mode 100644 index 0000000..ecae2e4 --- /dev/null +++ b/plugins/encoder/sox/k3bsoxencoder.cpp @@ -0,0 +1,482 @@ +/* + * + * $Id: k3bsoxencoder.cpp 731310 2007-10-31 10:30:05Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include <config.h> + +#include "k3bsoxencoder.h" +#include "base_k3bsoxencoderconfigwidget.h" + +#include <k3bprocess.h> +#include <k3bcore.h> +#include <k3bexternalbinmanager.h> +#include <k3bpluginfactory.h> + +#include <kdebug.h> +#include <kconfig.h> +#include <klocale.h> + +#include <qfileinfo.h> +#include <qfile.h> +#include <qvalidator.h> +#include <qlineedit.h> +#include <qcombobox.h> +#include <qcheckbox.h> +#include <qlayout.h> + +#include <sys/types.h> +#include <sys/wait.h> + + +K_EXPORT_COMPONENT_FACTORY( libk3bsoxencoder, K3bPluginFactory<K3bSoxEncoder>( "libk3bsoxencoder" ) ) + + +// the sox external program +class K3bSoxProgram : public K3bExternalProgram +{ + public: + K3bSoxProgram() + : K3bExternalProgram( "sox" ) { + } + + bool scan( const QString& p ) { + if( p.isEmpty() ) + return false; + + QString path = p; + QFileInfo fi( path ); + if( fi.isDir() ) { + if( path[path.length()-1] != '/' ) + path.append("/"); + path.append("sox"); + } + + if( !QFile::exists( path ) ) + return false; + + K3bExternalBin* bin = 0; + + // probe version + KProcess vp; + K3bProcessOutputCollector out( &vp ); + + vp << path << "-h"; + if( vp.start( KProcess::Block, KProcess::AllOutput ) ) { + int pos = out.output().find( "sox: SoX Version" ); + if ( pos < 0 ) + pos = out.output().find( "sox: SoX v" ); // newer sox versions + int endPos = out.output().find( "\n", pos ); + if( pos > 0 && endPos > 0 ) { + pos += 17; + bin = new K3bExternalBin( this ); + bin->path = path; + bin->version = out.output().mid( pos, endPos-pos ); + + addBin( bin ); + + return true; + } + else { + pos = out.output().find( "sox: Version" ); + endPos = out.output().find( "\n", pos ); + if( pos > 0 && endPos > 0 ) { + pos += 13; + bin = new K3bExternalBin( this ); + bin->path = path; + bin->version = out.output().mid( pos, endPos-pos ); + + addBin( bin ); + + return true; + } + else + return false; + } + } + else + return false; + } +}; + + +class K3bSoxEncoder::Private +{ +public: + Private() + : process(0) { + } + + K3bProcess* process; + QString fileName; +}; + + +K3bSoxEncoder::K3bSoxEncoder( QObject* parent, const char* name ) + : K3bAudioEncoder( parent, name ) +{ + if( k3bcore->externalBinManager()->program( "sox" ) == 0 ) + k3bcore->externalBinManager()->addProgram( new K3bSoxProgram() ); + + d = new Private(); +} + + +K3bSoxEncoder::~K3bSoxEncoder() +{ + delete d->process; + delete d; +} + + +void K3bSoxEncoder::finishEncoderInternal() +{ + if( d->process ) { + if( d->process->isRunning() ) { + ::close( d->process->stdinFd() ); + + // this is kind of evil... + // but we need to be sure the process exited when this method returnes + ::waitpid( d->process->pid(), 0, 0 ); + } + } +} + + +void K3bSoxEncoder::slotSoxFinished( KProcess* p ) +{ + if( !p->normalExit() || p->exitStatus() != 0 ) + kdDebug() << "(K3bSoxEncoder) sox exited with error." << endl; +} + + +bool K3bSoxEncoder::openFile( const QString& ext, const QString& filename, const K3b::Msf& ) +{ + d->fileName = filename; + return initEncoderInternal( ext ); +} + + +void K3bSoxEncoder::closeFile() +{ + finishEncoderInternal(); +} + + +bool K3bSoxEncoder::initEncoderInternal( const QString& extension ) +{ + const K3bExternalBin* soxBin = k3bcore->externalBinManager()->binObject( "sox" ); + if( soxBin ) { + delete d->process; + d->process = new K3bProcess(); + d->process->setSplitStdout(true); + d->process->setRawStdin(true); + + connect( d->process, SIGNAL(processExited(KProcess*)), + this, SLOT(slotSoxFinished(KProcess*)) ); + connect( d->process, SIGNAL(stderrLine(const QString&)), + this, SLOT(slotSoxOutputLine(const QString&)) ); + connect( d->process, SIGNAL(stdoutLine(const QString&)), + this, SLOT(slotSoxOutputLine(const QString&)) ); + + // input settings + *d->process << soxBin->path + << "-t" << "raw" // raw samples + << "-r" << "44100" // samplerate + << "-s" // signed linear + << "-w" // 16-bit words + << "-c" << "2" // stereo + << "-"; // read from stdin + + // output settings + *d->process << "-t" << extension; + + KConfig* c = k3bcore->config(); + c->setGroup( "K3bSoxEncoderPlugin" ); + if( c->readBoolEntry( "manual settings", false ) ) { + *d->process << "-r" << QString::number( c->readNumEntry( "samplerate", 44100 ) ) + << "-c" << QString::number( c->readNumEntry( "channels", 2 ) ); + + int size = c->readNumEntry( "data size", 16 ); + *d->process << ( size == 8 ? QString("-b") : ( size == 32 ? QString("-l") : QString("-w") ) ); + + QString encoding = c->readEntry( "data encoding", "signed" ); + if( encoding == "unsigned" ) + *d->process << "-u"; + else if( encoding == "u-law" ) + *d->process << "-U"; + else if( encoding == "A-law" ) + *d->process << "-A"; + else if( encoding == "ADPCM" ) + *d->process << "-a"; + else if( encoding == "IMA_ADPCM" ) + *d->process << "-i"; + else if( encoding == "GSM" ) + *d->process << "-g"; + else if( encoding == "Floating-point" ) + *d->process << "-f"; + else + *d->process << "-s"; + } + + *d->process << d->fileName; + + kdDebug() << "***** sox parameters:" << endl; + const QValueList<QCString>& args = d->process->args(); + QString s; + for( QValueList<QCString>::const_iterator it = args.begin(); it != args.end(); ++it ) { + s += *it + " "; + } + kdDebug() << s << flush << endl; + + + return d->process->start( KProcess::NotifyOnExit, KProcess::All ); + } + else { + kdDebug() << "(K3bSoxEncoder) could not find sox bin." << endl; + return false; + } +} + + +long K3bSoxEncoder::encodeInternal( const char* data, Q_ULONG len ) +{ + if( d->process ) { + if( d->process->isRunning() ) + return ::write( d->process->stdinFd(), (const void*)data, len ); + else + return -1; + } + else + return -1; +} + + +void K3bSoxEncoder::slotSoxOutputLine( const QString& line ) +{ + kdDebug() << "(sox) " << line << endl; +} + + +QStringList K3bSoxEncoder::extensions() const +{ + static QStringList s_extensions; + if( s_extensions.isEmpty() ) { + s_extensions << "au" + << "8svx" + << "aiff" + << "avr" + << "cdr" + << "cvs" + << "dat" + << "gsm" + << "hcom" + << "maud" + << "sf" + << "sph" + << "smp" + << "txw" + << "vms" + << "voc" + << "wav" + << "wve" + << "raw"; + } + + if( k3bcore->externalBinManager()->foundBin( "sox" ) ) + return s_extensions; + else + return QStringList(); // no sox -> no encoding +} + + +QString K3bSoxEncoder::fileTypeComment( const QString& ext ) const +{ + if( ext == "au" ) + return i18n("Sun AU"); + else if( ext == "8svx" ) + return i18n("Amiga 8SVX"); + else if( ext == "aiff" ) + return i18n("AIFF"); + else if( ext == "avr" ) + return i18n("Audio Visual Research"); + else if( ext == "cdr" ) + return i18n("CD-R"); + else if( ext == "cvs" ) + return i18n("CVS"); + else if( ext == "dat" ) + return i18n("Text Data"); + else if( ext == "gsm" ) + return i18n("GSM Speech"); + else if( ext == "hcom" ) + return i18n("Macintosh HCOM"); + else if( ext == "maud" ) + return i18n("Maud (Amiga)"); + else if( ext == "sf" ) + return i18n("IRCAM"); + else if( ext == "sph" ) + return i18n("SPHERE"); + else if( ext == "smp" ) + return i18n("Turtle Beach SampleVision"); + else if( ext == "txw" ) + return i18n("Yamaha TX-16W"); + else if( ext == "vms" ) + return i18n("VMS"); + else if( ext == "voc" ) + return i18n("Sound Blaster VOC"); + else if( ext == "wav" ) + return i18n("Wave (Sox)"); + else if( ext == "wve" ) + return i18n("Psion 8-bit A-law"); + else if( ext == "raw" ) + return i18n("Raw"); + else + return i18n("Error"); +} + + +long long K3bSoxEncoder::fileSize( const QString&, const K3b::Msf& msf ) const +{ + // for now we make a rough assumption based on the settings + KConfig* c = k3bcore->config(); + c->setGroup( "K3bSoxEncoderPlugin" ); + if( c->readBoolEntry( "manual settings", false ) ) { + int sr = c->readNumEntry( "samplerate", 44100 ); + int ch = c->readNumEntry( "channels", 2 ); + int wsize = c->readNumEntry( "data size", 16 ); + + return msf.totalFrames()*sr*ch*wsize/75; + } + else { + // fallback to raw + return msf.audioBytes(); + } +} + + +K3bPluginConfigWidget* K3bSoxEncoder::createConfigWidget( QWidget* parent, + const char* name ) const +{ + return new K3bSoxEncoderSettingsWidget( parent, name ); +} + + + +K3bSoxEncoderSettingsWidget::K3bSoxEncoderSettingsWidget( QWidget* parent, const char* name ) + : K3bPluginConfigWidget( parent, name ) +{ + w = new base_K3bSoxEncoderConfigWidget( this ); + w->m_editSamplerate->setValidator( new QIntValidator( w->m_editSamplerate ) ); + + QHBoxLayout* lay = new QHBoxLayout( this ); + lay->setMargin( 0 ); + + lay->addWidget( w ); +} + + +K3bSoxEncoderSettingsWidget::~K3bSoxEncoderSettingsWidget() +{ +} + + +void K3bSoxEncoderSettingsWidget::loadConfig() +{ + KConfig* c = k3bcore->config(); + + c->setGroup( "K3bSoxEncoderPlugin" ); + + w->m_checkManual->setChecked( c->readBoolEntry( "manual settings", false ) ); + + int channels = c->readNumEntry( "channels", 2 ); + w->m_comboChannels->setCurrentItem( channels == 4 ? 2 : channels-1 ); + + w->m_editSamplerate->setText( QString::number( c->readNumEntry( "samplerate", 44100 ) ) ); + + QString encoding = c->readEntry( "data encoding", "signed" ); + if( encoding == "unsigned" ) + w->m_comboEncoding->setCurrentItem(1); + else if( encoding == "u-law" ) + w->m_comboEncoding->setCurrentItem(2); + else if( encoding == "A-law" ) + w->m_comboEncoding->setCurrentItem(3); + else if( encoding == "ADPCM" ) + w->m_comboEncoding->setCurrentItem(4); + else if( encoding == "IMA_ADPCM" ) + w->m_comboEncoding->setCurrentItem(5); + else if( encoding == "GSM" ) + w->m_comboEncoding->setCurrentItem(6); + else if( encoding == "Floating-point" ) + w->m_comboEncoding->setCurrentItem(7); + else + w->m_comboEncoding->setCurrentItem(0); + + int size = c->readNumEntry( "data size", 16 ); + w->m_comboSize->setCurrentItem( size == 8 ? 0 : ( size == 32 ? 2 : 1 ) ); +} + + +void K3bSoxEncoderSettingsWidget::saveConfig() +{ + KConfig* c = k3bcore->config(); + + c->setGroup( "K3bSoxEncoderPlugin" ); + + c->writeEntry( "manual settings", w->m_checkManual->isChecked() ); + + c->writeEntry( "channels", w->m_comboChannels->currentItem() == 0 + ? 1 + : ( w->m_comboChannels->currentItem() == 2 + ? 4 + : 2 ) ); + + c->writeEntry( "data size", w->m_comboSize->currentItem() == 0 + ? 8 + : ( w->m_comboSize->currentItem() == 2 + ? 32 + : 16 ) ); + + c->writeEntry( "samplerate", w->m_editSamplerate->text().toInt() ); + + QString enc; + switch( w->m_comboEncoding->currentItem() ) { + case 1: + enc = "unsigned"; + break; + case 2: + enc = "u-law"; + break; + case 3: + enc = "A-law"; + break; + case 4: + enc = "ADPCM"; + break; + case 5: + enc = "IMA_ADPCM"; + break; + case 6: + enc = "GSM"; + break; + case 7: + enc = "Floating-point"; + break; + default: + enc = "signed"; + break; + } + c->writeEntry( "data encoding", enc ); +} + + +#include "k3bsoxencoder.moc" diff --git a/plugins/encoder/sox/k3bsoxencoder.h b/plugins/encoder/sox/k3bsoxencoder.h new file mode 100644 index 0000000..555f44e --- /dev/null +++ b/plugins/encoder/sox/k3bsoxencoder.h @@ -0,0 +1,82 @@ +/* + * + * $Id: k3bsoxencoder.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_SOX_ENCODER_H_ +#define _K3B_SOX_ENCODER_H_ + + +#include <k3baudioencoder.h> +#include <k3bpluginconfigwidget.h> + + +class base_K3bSoxEncoderConfigWidget; +class KProcess; + +class K3bSoxEncoder : public K3bAudioEncoder +{ + Q_OBJECT + + public: + K3bSoxEncoder( QObject* parent = 0, const char* name = 0 ); + ~K3bSoxEncoder(); + + QStringList extensions() const; + + QString fileTypeComment( const QString& ) const; + + long long fileSize( const QString&, const K3b::Msf& msf ) const; + + int pluginSystemVersion() const { return 3; } + + K3bPluginConfigWidget* createConfigWidget( QWidget* parent = 0, + const char* name = 0 ) const; + + /** + * reimplemented since sox writes the file itself + */ + bool openFile( const QString& ext, const QString& filename, const K3b::Msf& ); + void closeFile(); + + private slots: + void slotSoxFinished( KProcess* ); + void slotSoxOutputLine( const QString& ); + + private: + void finishEncoderInternal(); + bool initEncoderInternal( const QString& extension ); + long encodeInternal( const char* data, Q_ULONG len ); + + class Private; + Private* d; +}; + + +class K3bSoxEncoderSettingsWidget : public K3bPluginConfigWidget +{ + Q_OBJECT + + public: + K3bSoxEncoderSettingsWidget( QWidget* parent = 0, const char* name = 0 ); + ~K3bSoxEncoderSettingsWidget(); + + public slots: + void loadConfig(); + void saveConfig(); + + private: + base_K3bSoxEncoderConfigWidget* w; +}; + +#endif diff --git a/plugins/encoder/sox/k3bsoxencoder.plugin b/plugins/encoder/sox/k3bsoxencoder.plugin new file mode 100644 index 0000000..dd43f7d --- /dev/null +++ b/plugins/encoder/sox/k3bsoxencoder.plugin @@ -0,0 +1,9 @@ +[K3b Plugin] +Lib=libk3bsoxencoder +Group=AudioEncoder +Name=K3b SoX Audio Encoder +Author=Sebastian Trueg +Email=trueg@k3b.org +Version=2.0 +Comment=Encoding module to encode many file formats using SoX +License=GPL diff --git a/plugins/project/Makefile.am b/plugins/project/Makefile.am new file mode 100644 index 0000000..d762841 --- /dev/null +++ b/plugins/project/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = audioprojectcddb audiometainforenamer diff --git a/plugins/project/audiometainforenamer/Makefile.am b/plugins/project/audiometainforenamer/Makefile.am new file mode 100644 index 0000000..6199e50 --- /dev/null +++ b/plugins/project/audiometainforenamer/Makefile.am @@ -0,0 +1,19 @@ +AM_CPPFLAGS = -I$(srcdir)/../../../libk3b/core \ + -I$(srcdir)/../../../libk3b/core \ + -I$(srcdir)/../../../libk3b/plugin \ + -I$(srcdir)/../../../libk3b/tools \ + -I$(srcdir)/../../../libk3b/projects \ + -I$(srcdir)/../../../libk3b/projects/datacd \ + -I$(srcdir)/../../../libk3bdevice \ + $(all_includes) + +kde_module_LTLIBRARIES = libk3baudiometainforenamerplugin.la + +libk3baudiometainforenamerplugin_la_SOURCES = k3baudiometainforenamerplugin.cpp +libk3baudiometainforenamerplugin_la_LIBADD = ../../../libk3b/libk3b.la +libk3baudiometainforenamerplugin_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) + +pluginsdir = $(kde_datadir)/k3b/plugins +plugins_DATA = k3baudiometainforenamerplugin.plugin + +METASOURCES = AUTO diff --git a/plugins/project/audiometainforenamer/k3baudiometainforenamerplugin.cpp b/plugins/project/audiometainforenamer/k3baudiometainforenamerplugin.cpp new file mode 100644 index 0000000..1fb39a6 --- /dev/null +++ b/plugins/project/audiometainforenamer/k3baudiometainforenamerplugin.cpp @@ -0,0 +1,392 @@ +/* + * + * $Id$ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include <config.h> + +#include "k3baudiometainforenamerplugin.h" + +// the k3b stuff we need +#include <k3bcore.h> +#include <k3bdatadoc.h> +#include <k3bdiritem.h> +#include <k3bfileitem.h> +#include <k3blistview.h> +#include <k3bpluginfactory.h> + +#include <kdebug.h> +#include <kinstance.h> +#include <kmessagebox.h> +#include <klocale.h> +#include <kfilemetainfo.h> +#include <kcombobox.h> +#include <kconfig.h> +#include <kmimetype.h> +#include <kdialog.h> + +#include <qstring.h> +#include <qfile.h> +#include <qcheckbox.h> +#include <qradiobutton.h> +#include <qpushbutton.h> +#include <qgroupbox.h> +#include <qlabel.h> +#include <qtooltip.h> +#include <qwhatsthis.h> +#include <qpair.h> +#include <qvaluelist.h> +#include <qlayout.h> +#include <qptrdict.h> + + + +K_EXPORT_COMPONENT_FACTORY( libk3baudiometainforenamerplugin, K3bPluginFactory<K3bAudioMetainfoRenamerPlugin>("libk3baudiometainforenamerplugin") ) + + +class K3bAudioMetainfoRenamerPluginWidget::Private +{ +public: + K3bDataDoc* doc; + QString pattern; + + KComboBox* comboPattern; + K3bListView* viewFiles; + // KProgressDialog* progressDialog; + QPushButton* scanButton; + + QValueList< QPair<K3bFileItem*, QCheckListItem*> > renamableItems; + QPtrDict<QListViewItem> dirItemDict; + +// long long scannedSize; +// int progressCounter; +}; + + +K3bAudioMetainfoRenamerPluginWidget::K3bAudioMetainfoRenamerPluginWidget( K3bDoc* doc, + QWidget* parent, + const char* name ) + : QWidget( parent, name ) +{ + d = new Private(); + d->doc = dynamic_cast<K3bDataDoc*>(doc); + // d->progressDialog = 0; + + // pattern group + QGroupBox* patternGroup = new QGroupBox( 2, Qt::Horizontal, + i18n("Rename Pattern"), this ); + patternGroup->setInsideMargin( KDialog::marginHint() ); + patternGroup->setInsideSpacing( KDialog::spacingHint() ); + + d->comboPattern = new KComboBox( patternGroup ); + d->comboPattern->setEditable( true ); + + d->scanButton = new QPushButton( i18n("Scan"), patternGroup ); + + // the files view + QGroupBox* filesGroup = new QGroupBox( 1, Qt::Horizontal, + i18n("Found Files"), this ); + filesGroup->setInsideMargin( KDialog::marginHint() ); + filesGroup->setInsideSpacing( KDialog::spacingHint() ); + + d->viewFiles = new K3bListView( filesGroup ); + d->viewFiles->addColumn( i18n("New Name") ); + d->viewFiles->addColumn( i18n("Old Name") ); + d->viewFiles->setNoItemText( i18n("Please click the Scan button to search for renameable files.") ); + + // layout + QVBoxLayout* box = new QVBoxLayout( this ); + box->setMargin( 0 ); + box->setSpacing( KDialog::spacingHint() ); + + box->addWidget( patternGroup ); + box->addWidget( filesGroup ); + + connect( d->scanButton, SIGNAL(clicked()), this, SLOT(slotScanClicked()) ); + + QToolTip::add( d->scanButton, i18n("Scan for renamable files") ); + QWhatsThis::add( d->comboPattern, i18n("<qt>This specifies how the files should be renamed. " + "Currently only the special strings <em>%a</em> (Artist), " + "<em>%n</em> (Track number), and <em>%t</em> (Title) ," + "are supported.") ); +} + + +K3bAudioMetainfoRenamerPluginWidget::~K3bAudioMetainfoRenamerPluginWidget() +{ + delete d; +} + + +QString K3bAudioMetainfoRenamerPluginWidget::title() const +{ + return i18n("Rename Audio Files"); +} + + +QString K3bAudioMetainfoRenamerPluginWidget::subTitle() const +{ + return i18n("Based on meta info"); +} + + +void K3bAudioMetainfoRenamerPluginWidget::loadDefaults() +{ + d->comboPattern->setEditText( "%a - %t" ); +} + + +void K3bAudioMetainfoRenamerPluginWidget::readSettings( KConfigBase* c ) +{ + d->comboPattern->setEditText( c->readEntry( "rename pattern", "%a - %t" ) ); +} + + +void K3bAudioMetainfoRenamerPluginWidget::saveSettings( KConfigBase* c ) +{ + c->writeEntry( "rename pattern", d->comboPattern->currentText() ); +} + + +void K3bAudioMetainfoRenamerPluginWidget::slotScanClicked() +{ + d->pattern = d->comboPattern->currentText(); + if( d->pattern.isEmpty() ) { + KMessageBox::error( this, i18n("Please specify a valid pattern.") ); + } + else { +// if( d->progressDialog == 0 ) { +// d->progressDialog = new KProgressDialog( this, "scanning_progress", +// i18n("Scanning..."), +// i18n("Scanning for renameable files."), +// true ); +// d->progressDialog->setAllowCancel(false); +// } + + K3bDirItem* dir = d->doc->root(); + + // clear old searches + d->viewFiles->clear(); + d->renamableItems.clear(); + d->dirItemDict.clear(); +// d->scannedSize = 0; +// d->progressCounter = 0; + + // create root item + KListViewItem* rootItem = new KListViewItem( d->viewFiles, "/" ); + + // d->progressDialog->show(); + scanDir( dir, rootItem ); + // d->progressDialog->close(); + + rootItem->setOpen(true); + + if( d->renamableItems.isEmpty() ) + KMessageBox::sorry( this, i18n("No renameable files found.") ); + } +} + + +void K3bAudioMetainfoRenamerPluginWidget::scanDir( K3bDirItem* dir, QListViewItem* viewRoot ) +{ + kdDebug() << "(K3bAudioMetainfoRenamerPluginWidget) scanning dir " << dir->k3bName() << endl; + + d->dirItemDict.insert( dir, viewRoot ); + + for( QPtrListIterator<K3bDataItem> it( dir->children() ); it.current(); ++it ) { + K3bDataItem* item = it.current(); + + if( item->isFile() ) { + if( item->isRenameable() ) { + QString newName = createNewName( (K3bFileItem*)item ); + if( !newName.isEmpty() ) { + QCheckListItem* fileViewItem = new QCheckListItem( viewRoot, + newName, + QCheckListItem::CheckBox ); + fileViewItem->setText(1, item->k3bName() ); + fileViewItem->setOn(true); + d->renamableItems.append( qMakePair( (K3bFileItem*)item, fileViewItem ) ); + } + } + +// d->scannedSize += item->k3bSize(); +// d->progressCounter++; +// if( d->progressCounter > 50 ) { +// d->progressCounter = 0; +// d->progressDialog->progressBar()->setProgress( 100*d->scannedSize/d->doc->root()->k3bSize() ); +// qApp->processEvents(); +// } + } + else if( item->isDir() ) { + // create dir item + KListViewItem* dirViewItem = new KListViewItem( viewRoot, item->k3bName() ); + scanDir( (K3bDirItem*)item, dirViewItem ); + dirViewItem->setOpen(true); + } + } +} + + +void K3bAudioMetainfoRenamerPluginWidget::activate() +{ + if( d->renamableItems.isEmpty() ) { + KMessageBox::sorry( this, i18n("Please click the Scan button to search for renameable files.") ); + } + else { + for( QValueList< QPair<K3bFileItem*, QCheckListItem*> >::iterator it = d->renamableItems.begin(); + it != d->renamableItems.end(); ++it ) { + QPair<K3bFileItem*, QCheckListItem*>& item = *it; + + if( item.second->isOn() ) + item.first->setK3bName( item.second->text(0) ); + } + + d->viewFiles->clear(); + d->renamableItems.clear(); + + KMessageBox::information( this, i18n("Done.") ); + } +} + + +QString K3bAudioMetainfoRenamerPluginWidget::createNewName( K3bFileItem* item ) +{ + KMimeType::Ptr mimetype = KMimeType::findByPath( item->localPath() ); + // sometimes ogg-vorbis files go as "application/x-ogg" + if( mimetype != 0 && + ( mimetype->name().contains( "audio" ) || mimetype->name().contains("ogg") ) ) { + + QString artist, title, track; + + KFileMetaInfo metaInfo( item->localPath() ); + if( metaInfo.isValid() ) { + + KFileMetaInfoItem artistItem = metaInfo.item( "Artist" ); + KFileMetaInfoItem titleItem = metaInfo.item( "Title" ); + KFileMetaInfoItem trackItem = metaInfo.item( "Tracknumber" ); + + if( artistItem.isValid() ) + artist = artistItem.string().stripWhiteSpace(); + + if( titleItem.isValid() ) + title = titleItem.string().stripWhiteSpace(); + + if( trackItem.isValid() ) + track = track.sprintf("%02d",trackItem.string().toInt()); + } + + QString newName; + for( unsigned int i = 0; i < d->pattern.length(); ++i ) { + + if( d->pattern[i] == '%' ) { + ++i; + + if( i < d->pattern.length() ) { + if( d->pattern[i] == 'a' ) { + if( artist.isEmpty() ) + return QString::null; + newName.append(artist); + } + else if( d->pattern[i] == 'n' ) { + if( title.isEmpty() ) + return QString::null; + newName.append(track); + } + else if( d->pattern[i] == 't' ) { + if( title.isEmpty() ) + return QString::null; + newName.append(title); + } + else { + newName.append( "%" ); + newName.append( d->pattern[i] ); + } + } + else { // end of pattern + newName.append( "%" ); + } + } + else { + newName.append( d->pattern[i] ); + } + } + + // remove white spaces from end and beginning + newName = newName.stripWhiteSpace(); + + QString extension = item->k3bName().mid( item->k3bName().findRev(".") ); + + if( !newName.isEmpty() ) { + // + // Check if files with that name exists and if so append number + // + if( existsOtherItemWithSameName( item, newName + extension ) ) { + kdDebug() << "(K3bAudioMetainfoRenamerPluginWidget) file with name " + << newName << extension << " already exists" << endl; + int i = 1; + while( existsOtherItemWithSameName( item, newName + QString( " (%1)").arg(i) + extension ) ) + i++; + newName.append( QString( " (%1)").arg(i) ); + } + + // append extension + newName.append( extension ); + } + + return newName; + } + else + return QString::null; +} + + +bool K3bAudioMetainfoRenamerPluginWidget::existsOtherItemWithSameName( K3bFileItem* item, const QString& name ) +{ + K3bDirItem* dir = item->parent(); + K3bDataItem* otherItem = dir->find( name ); + if( otherItem && otherItem != item ) + return true; + + QListViewItem* dirViewItem = d->dirItemDict[dir]; + QListViewItem* current = dirViewItem->firstChild(); + while( current && current->parent() == dirViewItem ) { + if( current->text(0) == name ) + return true; + current = current->nextSibling(); + } + + return false; +} + + + +K3bAudioMetainfoRenamerPlugin::K3bAudioMetainfoRenamerPlugin( QObject* parent, + const char* name ) + : K3bProjectPlugin( DATA_PROJECTS, true, parent, name ) +{ + setText( i18n("Rename Audio Files") ); + setToolTip( i18n("Rename audio files based on their meta info.") ); +} + + +K3bAudioMetainfoRenamerPlugin::~K3bAudioMetainfoRenamerPlugin() +{ +} + + +K3bProjectPluginGUIBase* K3bAudioMetainfoRenamerPlugin::createGUI( K3bDoc* doc, QWidget* parent, const char* name ) +{ + return new K3bAudioMetainfoRenamerPluginWidget( doc, parent, name ); +} + +#include "k3baudiometainforenamerplugin.moc" diff --git a/plugins/project/audiometainforenamer/k3baudiometainforenamerplugin.h b/plugins/project/audiometainforenamer/k3baudiometainforenamerplugin.h new file mode 100644 index 0000000..b387aa5 --- /dev/null +++ b/plugins/project/audiometainforenamer/k3baudiometainforenamerplugin.h @@ -0,0 +1,76 @@ +/* + * + * $Id$ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_AUDIO_METAINFO_RENAMER_PLUGIN_H_ +#define _K3B_AUDIO_METAINFO_RENAMER_PLUGIN_H_ + + +#include <k3bprojectplugin.h> +#include <qwidget.h> + + +class K3bDataDoc; +class K3bDirItem; +class K3bFileItem; +class QListViewItem; + + +class K3bAudioMetainfoRenamerPluginWidget : public QWidget, public K3bProjectPluginGUIBase +{ + Q_OBJECT + + public: + K3bAudioMetainfoRenamerPluginWidget( K3bDoc* doc, QWidget* parent = 0, const char* name = 0 ); + ~K3bAudioMetainfoRenamerPluginWidget(); + + QWidget* qWidget() { return this; } + + QString title() const; + QString subTitle() const; + + void loadDefaults(); + void readSettings( KConfigBase* ); + void saveSettings( KConfigBase* ); + + void activate(); + + private slots: + void slotScanClicked(); + + private: + void scanDir( K3bDirItem*, QListViewItem* parent ); + QString createNewName( K3bFileItem* ); + bool existsOtherItemWithSameName( K3bFileItem*, const QString& ); + + class Private; + Private* d; +}; + + +class K3bAudioMetainfoRenamerPlugin : public K3bProjectPlugin +{ + Q_OBJECT + + public: + K3bAudioMetainfoRenamerPlugin( QObject* parent, const char* name ); + ~K3bAudioMetainfoRenamerPlugin(); + + int pluginSystemVersion() const { return 3; } + + K3bProjectPluginGUIBase* createGUI( K3bDoc*, QWidget* = 0, const char* = 0 ); +}; + + +#endif diff --git a/plugins/project/audiometainforenamer/k3baudiometainforenamerplugin.plugin b/plugins/project/audiometainforenamer/k3baudiometainforenamerplugin.plugin new file mode 100644 index 0000000..42c24d8 --- /dev/null +++ b/plugins/project/audiometainforenamer/k3baudiometainforenamerplugin.plugin @@ -0,0 +1,9 @@ +[K3b Plugin] +Lib=libk3baudiometainforenamerplugin +Group=ProjectPlugin +Name=K3b Audio Metainfo Renamer +Author=Sebastian Trueg +Email=trueg@k3b.org +Version=1.0 +Comment=Plugin to rename audio files in a data project based on the meta info. +License=GPL diff --git a/plugins/project/audioprojectcddb/Makefile.am b/plugins/project/audioprojectcddb/Makefile.am new file mode 100644 index 0000000..8af3e67 --- /dev/null +++ b/plugins/project/audioprojectcddb/Makefile.am @@ -0,0 +1,22 @@ +AM_CPPFLAGS = -I$(srcdir)/../../../libk3b/core \ + -I$(srcdir)/../../../libk3b/tools \ + -I$(srcdir)/../../../libk3b/core \ + -I$(srcdir)/../../../libk3b/projects/audiocd \ + -I$(srcdir)/../../../libk3b/projects \ + -I$(srcdir)/../../../libk3bdevice \ + -I$(srcdir)/../../../libk3b/cddb \ + -I$(srcdir)/../../../libk3b/plugin \ + $(all_includes) + +kde_module_LTLIBRARIES = libk3baudioprojectcddbplugin.la + +libk3baudioprojectcddbplugin_la_SOURCES = k3baudioprojectcddbplugin.cpp + +libk3baudioprojectcddbplugin_la_LIBADD = ../../../libk3b/libk3b.la + +libk3baudioprojectcddbplugin_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) + +pluginsdir = $(kde_datadir)/k3b/plugins +plugins_DATA = k3baudioprojectcddbplugin.plugin + +METASOURCES = AUTO diff --git a/plugins/project/audioprojectcddb/k3baudioprojectcddbplugin.cpp b/plugins/project/audioprojectcddb/k3baudioprojectcddbplugin.cpp new file mode 100644 index 0000000..e523eb3 --- /dev/null +++ b/plugins/project/audioprojectcddb/k3baudioprojectcddbplugin.cpp @@ -0,0 +1,151 @@ +/* + * + * $Id$ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include <config.h> + +#include "k3baudioprojectcddbplugin.h" + +// the k3b stuff we need +#include <k3bcore.h> +#include <k3bglobals.h> +#include <k3baudiodoc.h> +#include <k3baudiotrack.h> +#include <k3btoc.h> +#include <k3btrack.h> +#include <k3bmsf.h> +#include <k3bcddb.h> +#include <k3bcddbresult.h> +#include <k3bcddbquery.h> +#include <k3bprogressdialog.h> +#include <k3bpluginfactory.h> + +#include <kdebug.h> +#include <kaction.h> +#include <kinstance.h> +#include <kmessagebox.h> +#include <klocale.h> +#include <kconfig.h> + +#include <qstring.h> + + +K_EXPORT_COMPONENT_FACTORY( libk3baudioprojectcddbplugin, K3bPluginFactory<K3bAudioProjectCddbPlugin>( "libk3baudioprojectcddbplugin" ) ) + + +K3bAudioProjectCddbPlugin::K3bAudioProjectCddbPlugin( QObject* parent, + const char* name ) + : K3bProjectPlugin( AUDIO_CD, false, parent, name ), + m_cddb(0), + m_progress(0) +{ + setText( i18n("Query Cddb") ); + setToolTip( i18n("Query a cddb entry for the current audio project.") ); +} + + +K3bAudioProjectCddbPlugin::~K3bAudioProjectCddbPlugin() +{ + delete m_progress; +} + + +void K3bAudioProjectCddbPlugin::activate( K3bDoc* doc, QWidget* parent ) +{ + m_doc = dynamic_cast<K3bAudioDoc*>( doc ); + m_parentWidget = parent; + m_canceled = false; + + if( !m_doc || m_doc->numOfTracks() == 0 ) { + KMessageBox::sorry( parent, i18n("Please select a non-empty audio project for a cddb query.") ); + } + else { + if( !m_cddb ) { + m_cddb = new K3bCddb( this ); + connect( m_cddb, SIGNAL(queryFinished(int)), + this, SLOT(slotCddbQueryFinished(int)) ); + } + if( !m_progress ) { + m_progress = new K3bProgressDialog( i18n("Query Cddb"), parent, i18n("Audio Project") ); + connect( m_progress, SIGNAL(cancelClicked()), + this, SLOT(slotCancelClicked()) ); + } + + // read the k3b config :) + KConfig* c = k3bcore->config(); + c->setGroup("Cddb"); + m_cddb->readConfig( c ); + + // start the query + m_cddb->query( m_doc->toToc() ); + + m_progress->exec(false); + } +} + + +void K3bAudioProjectCddbPlugin::slotCancelClicked() +{ + m_canceled = true; + m_progress->close(); +} + + +void K3bAudioProjectCddbPlugin::slotCddbQueryFinished( int error ) +{ + if( !m_canceled ) { + m_progress->hide(); + + if( error == K3bCddbQuery::SUCCESS ) { + K3bCddbResultEntry cddbInfo = m_cddb->result(); + + // save the entry locally + KConfig* c = k3bcore->config(); + c->setGroup( "Cddb" ); + if( c->readBoolEntry( "save cddb entries locally", true ) ) + m_cddb->saveEntry( cddbInfo ); + + // save the entry to the doc + m_doc->setTitle( cddbInfo.cdTitle ); + m_doc->setPerformer( cddbInfo.cdArtist ); + m_doc->setCdTextMessage( cddbInfo.cdExtInfo ); + + int i = 0; + for( K3bAudioTrack* track = m_doc->firstTrack(); track; track = track->next() ) { + track->setTitle( cddbInfo.titles[i] ); + track->setPerformer( cddbInfo.artists[i] ); + track->setCdTextMessage( cddbInfo.extInfos[i] ); + + ++i; + } + + // and enable cd-text + m_doc->writeCdText( true ); + } + else if( error == K3bCddbQuery::NO_ENTRY_FOUND ) { + KMessageBox::information( m_parentWidget, i18n("No CDDB entry found."), i18n("CDDB") ); + } + else if( error != K3bCddbQuery::CANCELED ) { + KMessageBox::information( m_parentWidget, m_cddb->errorString(), i18n("Cddb error") ); + } + } + + // make sure the progress dialog does not get deleted by it's parent + delete m_progress; + m_doc = 0; + m_parentWidget = 0; + m_progress = 0; +} + +#include "k3baudioprojectcddbplugin.moc" diff --git a/plugins/project/audioprojectcddb/k3baudioprojectcddbplugin.h b/plugins/project/audioprojectcddb/k3baudioprojectcddbplugin.h new file mode 100644 index 0000000..a0e7880 --- /dev/null +++ b/plugins/project/audioprojectcddb/k3baudioprojectcddbplugin.h @@ -0,0 +1,53 @@ +/* + * + * $Id$ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_AUDIO_PROJECT_CDDB_PLUGIN_H_ +#define _K3B_AUDIO_PROJECT_CDDB_PLUGIN_H_ + + +#include <k3bprojectplugin.h> + +class K3bCddb; +class K3bAudioDoc; +class K3bProgressDialog; +class QWidget; + +class K3bAudioProjectCddbPlugin : public K3bProjectPlugin +{ + Q_OBJECT + + public: + K3bAudioProjectCddbPlugin( QObject* parent, const char* name ); + ~K3bAudioProjectCddbPlugin(); + + int pluginSystemVersion() const { return 3; } + + void activate( K3bDoc* doc, QWidget* parent ); + + private slots: + void slotCddbQueryFinished( int result ); + void slotCancelClicked(); + + private: + K3bCddb* m_cddb; + K3bAudioDoc* m_doc; + K3bProgressDialog* m_progress; + QWidget* m_parentWidget; + + bool m_canceled; +}; + + +#endif diff --git a/plugins/project/audioprojectcddb/k3baudioprojectcddbplugin.plugin b/plugins/project/audioprojectcddb/k3baudioprojectcddbplugin.plugin new file mode 100644 index 0000000..8fbea0f --- /dev/null +++ b/plugins/project/audioprojectcddb/k3baudioprojectcddbplugin.plugin @@ -0,0 +1,9 @@ +[K3b Plugin] +Lib=libk3baudioprojectcddbplugin +Group=ProjectPlugin +Name=K3b Cddb Audio Plugin +Author=Sebastian Trueg +Email=trueg@k3b.org +Version=0.1 +Comment=Plugin to query a cddb server for information about an audio project. +License=GPL diff --git a/src/IDEAS b/src/IDEAS new file mode 100644 index 0000000..f8a2f9c --- /dev/null +++ b/src/IDEAS @@ -0,0 +1,45 @@ +wie in KOffice K3bDoc von KParts::ReadWritePart ableiten +in KOffice ist der view von KParts::PartBase abgeleitet. Warum das? +alle actions, die das doc ndern, auch ins doc packen. +alle actions, die nur fr die ansicht da sind (zb. properties dialog) in den view + +da wir verschiedene projekt-typen fr den gleichen mimetype haben macht ein ReadWritePartWrapper, +der aufgrund des doctypes entscheidet, welches K3bDoc bentigt wird, mehr Sinn. Das hiee, +dass es einen K3bPart gibt, der alle Projekte beinhaltet. Die einzelnen Projekte knnten allerdings auch wieder +dynamisch hinzugeladen werden, so dass immer nur das gerade bentigte K3bDoc im Speicher ist. +Der Wrapper muss dann nur den externalbin- und den devicemanager initialisieren und den kostore ffnen. Dann alle +K3bDocFactories (wenn ein K3bDoc als eine Art plugin dynamisch hinzugeladen werden soll) fragen, ob sie +den projekttyp untersttzen und wenn ja, eine instanz erzeugen und das dokument laden. +Wie sieht es dann mit dem erstellen eines neuen dokumentes aus? Ev. Knnte der Wrapper hier alle Factories nach +dem projecttyp fragen und fr jeden eine Action erstellen. +K3b selber benutzt dann nicht den Wrapper, sondern macht alles selber. Das hiee redundanten Code in K3b und dem +Wrapper. + + +Audiodoc: + tracks und files. + ein track kann mehrere files enthalten + ein file kann vorne und hinten abgeschnitten werden + tracks knnen zusammengefhrt werden (resultiert in einem track mit den files aus den beiden quelltracks) + es gibt track- und filefilter; trackfilter sind das gewohnte und sollten meist benutzt werden, filefilter + filtern nur innerhalb eines tracks (Bsp: normalising nur ber alle files in einem track, wohingegen + normalising als trackfilter ber alle tracks normalisiert) + Das normale verhalten ist wie jetzt: Anlegen eines Tracks mit einem File. Das sollte fr die meisten + Anwender reichen. Wenn ctrl oder sowas gehalten wird kann man files zu einem track hinzufgen + (die gui knnte hier beim drcken von ctrl alle files als kindelemente der tracks anzeigen, auch bei + solchen tracks, die nur ein file enthalten. So wrde deutlich, dass ein file zu einem track hinzugefgt + werden kann.) + +K3bFileSystem: + K3bFsItem + -> K3bFsFile + -> K3bFsDirectory + FileSystem bietet virtuelle Funktionen newFile( filename ) und newDirectory( name ), mit welchen neue + Elemente von den addUrl Funktionen angelegt werden. Jedes Item hat eine size methode, welche die Gre + der Datei angibt. Zustzlich gibt es eine methode, welche die Gesamtgre aller Kinder und Enkel angibt + (nur sinnvoll fr K3bFsDirectory) + K3bFileSystem hat zustzlich ein caching-system, welches inode-basierte Grenberechung erlaubt. + K3bFsItem hat methoden wie isDir() und einen void Zeiger fr zustzliche Daten, wenn man nicht ableiten + mchte. + Von K3bFileSystem knnte man K3bIso9660FileSystem und K3bUdfFileSystem ableiten, welche zustzliche Daten + enthalten. \ No newline at end of file diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..be55a51 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,86 @@ +bin_PROGRAMS = k3b + +k3b_SOURCES = k3bwelcomewidget.cpp k3bapplication.cpp k3bdiroperator.cpp \ + k3bfiletreeview.cpp \ + k3bprojecttabwidget.cpp k3bsplash.cpp \ + k3bfileview.cpp k3bdirview.cpp k3b.cpp main.cpp \ + k3bstatusbarmanager.cpp k3bfiletreecombobox.cpp \ + k3binterface.cpp k3binterface.skel \ + k3bjobinterface.cpp k3bjobinterface.skel \ + k3bprojectinterface.cpp k3bprojectinterface.skel \ + k3bdataprojectinterface.cpp k3bdataprojectinterface.skel \ + k3bsystemproblemdialog.cpp k3bmediacontentsview.cpp \ + k3bsidepanel.cpp k3bcontentsview.cpp \ + k3bjobprogressdialog.cpp k3bburnprogressdialog.cpp k3btempdirselectionwidget.cpp \ + k3bdatamodewidget.cpp k3bwritingmodewidget.cpp k3bwriterselectionwidget.cpp \ + k3binteractiondialog.cpp k3bthememanager.cpp \ + k3bprojectmanager.cpp k3btrm.cpp k3bmusicbrainz.cpp \ + k3baudioprojectinterface.cpp k3bmixedprojectinterface.cpp \ + k3baudioprojectinterface.skel k3bmixedprojectinterface.skel k3bflatbutton.cpp \ + k3bemptydiscwaiter.cpp k3bjobprogressosd.cpp \ + k3bdebuggingoutputdialog.cpp k3bdebuggingoutputfile.cpp k3bappdevicemanager.cpp \ + k3bmediacache.cpp k3bmedium.cpp k3bmediaselectioncombobox.cpp k3btooltip.cpp \ + k3bwidgetshoweffect.cpp k3bmediaselectiondialog.cpp k3bdiskinfoview.cpp \ + k3bpassivepopup.cpp k3btimeoutwidget.cpp k3bminibutton.cpp \ + k3bthemedheader.cpp k3bthemedlabel.cpp k3blsofwrapper.cpp \ + k3blsofwrapperdialog.cpp k3bservicemenuinstaller.cpp k3bfirstrun.cpp + +k3b_LDADD = ./option/liboption.la ./rip/librip.la \ + ./projects/libprojects.la ../libk3bdevice/libk3bdevice.la \ + ../libk3b/libk3b.la ./misc/libmisc.la ./fastscale/libfastscale.la \ + -lkio -lkparts $(CAM_LIB) $(MUSICBRAINZ_LIBS) + +SUBDIRS = option misc rip projects fastscale pics icons konqi mimetypes sounds + +xdg_apps_DATA = k3b.desktop + +silent_DATA = k3b-iso.desktop k3b-cue.desktop +silentdir = $(kde_appsdir)/.hidden/ + +################### +# this 10 paths are KDE specific. Use them: +# kde_htmldir Where your docs should go to. (contains lang subdirs) +# kde_appsdir Where your application file (.kdelnk) should go to. +# kde_icondir Where your icon should go to. +# kde_minidir Where your mini icon should go to. +# kde_datadir Where you install application data. (Use a subdir) +# kde_locale Where translation files should go to.(contains lang subdirs) +# kde_cgidir Where cgi-bin executables should go to. +# kde_confdir Where config files should go to. +# kde_mimedir Where mimetypes should go to. +# kde_toolbardir Where general toolbar icons should go to. +# kde_wallpaperdir Where general wallpapers should go to. + +# set the include path for X, qt and KDE +AM_CPPFLAGS = -I$(srcdir)/../libk3b/tools \ + -I$(srcdir)/../libk3b/core \ + -I$(srcdir)/../libk3b/cddb \ + -I$(srcdir)/../libk3b/videodvd \ + -I$(srcdir)/../libk3b/jobs \ + -I$(srcdir)/../libk3bdevice \ + -I$(srcdir)/../libk3b/projects \ + -I$(srcdir)/../libk3b/projects/datacd \ + -I$(srcdir)/../libk3b/projects/datadvd \ + -I$(srcdir)/../libk3b/projects/audiocd \ + -I$(srcdir)/../libk3b/projects/videocd \ + -I$(srcdir)/../libk3b/projects/mixedcd \ + -I$(srcdir)/../libk3b/projects/movixcd \ + -I$(srcdir)/../libk3b/projects/videodvd \ + -I$(srcdir)/../libk3b/projects/movixdvd \ + -I$(srcdir)/../libk3b/plugin \ + -I$(srcdir)/projects \ + $(all_includes) + +METASOURCES = AUTO + +# the library search path. +k3b_LDFLAGS = $(all_libraries) $(KDE_RPATH) + +rcdir = $(kde_datadir)/k3b +rc_DATA = k3bui.rc eventsrc tips + +messages: rc.cpp + $(EXTRACTRC) `find . -name \*.rc -o -name \*.ui` `find ../plugins -name \*.rc -o -name \*.ui`> rc.cpp + $(PREPARETIPS) > tips.cpp + $(XGETTEXT) `find . -name \*.cpp -o -name \*.h` `find ../plugins -name \*.cpp -o -name \*.h` -o $(podir)/k3b.pot + rm -f tips.cpp diff --git a/src/eventsrc b/src/eventsrc new file mode 100644 index 0000000..a577acb --- /dev/null +++ b/src/eventsrc @@ -0,0 +1,333 @@ +[!Global!] +IconName=k3b +Comment=K3b +Comment[ar]= K3b +Comment[bn]=কে-থ্রি-বি +Comment[hi]=के3बी + +[SuccessfullyFinished] +Name=Process successful +Name[af]=Proses suksesvol +Name[ar]= تمت المعالجة بنجاح +Name[bg]=Процесът е успешен +Name[bn]=প্রসেস সফল +Name[bs]=Proces je uspio +Name[ca]=Procés correcte +Name[cs]=Proces úspěšný +Name[da]=Processen lykkedes +Name[de]=Vorgang erfolgreich +Name[el]=Διεργασία επιτυχής +Name[eo]=Tasko sukcesa +Name[es]=Éxito de proceso +Name[et]=Tegevus oli edukas +Name[fa]=فرآیند موفق +Name[fi]=Suoritettu +Name[fr]=Processus réussi +Name[ga]=D'éirigh leis an bpróiseas +Name[gl]=Proceso exitoso +Name[he]=תהליך מוצלח +Name[hi]=प्रक्रिया सफल +Name[hu]=A művelet sikeresen befejeződött +Name[is]=Velheppnað ferli +Name[it]=Processo riuscito +Name[ja]=プロセス成功 +Name[ka]=პროცესი წარმატებულია +Name[km]=ដំណើរការ​បាន​ជោគជ័យ +Name[lt]=Procesas pavyko +Name[mk]=Процесот е успешен +Name[ms]= Proses berjaya +Name[nb]=Vellykket prosess +Name[nds]=Vörgang is glückt +Name[ne]=प्रक्रिया सफल भयो +Name[nl]=Proces was succesvol +Name[nn]=Vellykka prosess +Name[pa]=ਕਾਰਵਾਈ ਸਫ਼ਲ ਹੋਈ +Name[pl]=Proces zakończony pomyślnie +Name[pt]=Processo com sucesso +Name[pt_BR]=Processo bem-sucedido +Name[ru]=Успешно завершено +Name[sk]=Proces úspešný +Name[sl]=Proces uspešen +Name[sr]=Обрада је успешна +Name[sr@Latn]=Obrada je uspešna +Name[sv]=Processen lyckades +Name[ta]=வெற்றிகரமான தொகுப்பு +Name[tg]=Бомуваффақият ба анҷом расид +Name[tr]=İşlem başarılı +Name[uk]=Процес успішний +Name[uz]=Muvaffaqiyatli jarayon +Name[uz@cyrillic]=Муваффақиятли жараён +Name[zh_CN]=处理成功 +Name[zh_TW]=處理成功 +Comment=Process successfully finished +Comment[af]=Proses het suksesvol klaar gemaak +Comment[ar]=نهاية المعالجة بنجاح +Comment[bg]=Процесът завърши успешно +Comment[bn]=প্রসেস সফলভাবে শেষ হল +Comment[bs]=Proces je uspješno završen +Comment[ca]=Procés finalitzat amb èxit +Comment[cs]=Proces úspěšně dokončen +Comment[da]=Processen afsluttedes korrekt +Comment[de]=Vorgang erfolgreich abgeschlossen +Comment[el]=Η διεργασία ολοκληρώθηκε επιτυχώς +Comment[eo]=Tasko sukcese finis +Comment[es]=Proceso terminado con éxito +Comment[et]=Tegevus lõppes edukalt +Comment[fa]=فرآیند با موفقیت تمام شد +Comment[fi]=Työ on suoritettu +Comment[fr]=Processus terminé avec succès +Comment[gl]=O proceso terminou con éxito +Comment[he]=התהליך הסתיים בהצלחה +Comment[hi]=प्रक्रिया सफलतापूर्वक पूर्ण +Comment[hu]=A művelet sikeresen befejeződött +Comment[is]=Ferli lauk með góðum árangri +Comment[it]=Processo riuscito e terminato +Comment[ja]=プロセス完了 +Comment[ka]=პროცესი წარმატებით დასრულდა +Comment[km]=បាន​បញ្ចប់​ដំណើរការ​ដោយ​ជោគជ័យ +Comment[lt]=Procesas sėkmingai baigtas +Comment[mk]=Процесот заврши успешно +Comment[ms]= Proses selesai dengan jayanya +Comment[nb]=Prosessen ble fullført vellykket +Comment[nds]=Vörgang afslaten +Comment[ne]=प्रक्रिया सफलतापूर्वक समाप्त भयो +Comment[nl]=Proces met succes voltooid +Comment[nn]=Prosessen er fullført +Comment[pa]=ਕਾਰਵਾਈ ਸਫ਼ਲਤਾਪੂਰਕ ਪੂਰੀ ਕੀਤੀ ਗਈ +Comment[pl]=Proces zakończył się pomyślnie +Comment[pt]=O processo terminou com sucesso +Comment[pt_BR]=Processo finalizado com sucesso +Comment[ru]=Процесс завершён успешно +Comment[sk]=Proces úspešne ukončený +Comment[sl]=Proces je uspešno končan +Comment[sr]=Обрада је успешно завршена +Comment[sr@Latn]=Obrada je uspešno završena +Comment[sv]=Processen avslutades med lyckat resultat +Comment[ta]=வெற்றிகரமாக தொகுப்பு முடிந்தது +Comment[tg]=Амалиёт бомуваффақият ба анҷом расид +Comment[tr]=İşlem başarıyla sonuçlandı +Comment[uk]=Процес успішно завершився +Comment[uz]=Jarayon muvaffaqiyatli tugadi +Comment[uz@cyrillic]=Жараён муваффақиятли тугади +Comment[zh_CN]=处理成功完成 +Comment[zh_TW]=成功完成處理 +default_sound=k3b_success1.wav +default_presentation=1 +# None = 0, Sound = 1, Messagebox = 2, Logfile = 4, Stderr = 8, PassivePopup = 16, Execute = 32 + +[FinishedWithError] +Name=Process error +Name[af]=Verwerking fout +Name[ar]= خطأ خلال المعالجة +Name[bg]=Грешка при обработка +Name[bn]=প্রসেস ত্রুটি +Name[bs]=Greška u procesu +Name[ca]=Procés amb error +Name[cs]=Chyba procesu +Name[da]=Procesfejl +Name[de]=Vorgang nicht erfolgreich +Name[el]=Σφάλμα διεργασίας +Name[eo]=Taska eraro +Name[es]=Error de proceso +Name[et]=Tegevuse viga +Name[fa]=خطای فرآیند +Name[fi]=Virhe +Name[fr]=Erreur du processus +Name[gl]=Erro no proceso +Name[he]=שגיאת תהליך +Name[hi]=प्रक्रिया त्रुटि +Name[hu]=A művelet során hiba történt +Name[is]=Villa í ferli +Name[it]=Errore di Processo +Name[ja]=プロセスエラー +Name[ka]=პროცესის შეცდომა +Name[km]=ដំណើរការ​មាន​កំហុស +Name[lt]=Proceso klaida +Name[mk]=Грешка во процесот +Name[ms]=Ralat proses +Name[nb]=Prosessfeil +Name[nds]=Perzessfehler +Name[ne]=प्रक्रिया त्रुटि +Name[nl]=Procesfout +Name[nn]=Prosessfeil +Name[pa]=ਕਾਰਜ ਗਲਤੀ +Name[pl]=Błąd procesu +Name[pt]=Erro no processo +Name[pt_BR]=Erro no processo +Name[ru]=Ошибка +Name[sk]=Chyba procesu +Name[sl]=Napaka procesa +Name[sr]=Грешка у обради +Name[sr@Latn]=Greška u obradi +Name[sv]=Processfel +Name[ta]=தொகுப்புப் பிழை +Name[tg]=Хатогӣ +Name[tr]=İşlemde hata var +Name[uk]=Помилка процесу +Name[uz]=Xatoli jarayon +Name[uz@cyrillic]=Хатоли жараён +Name[zh_CN]=处理错误 +Name[zh_TW]=處理發生錯誤 +Comment=Process finished with errors +Comment[af]=Die proses het met foute klaar gemaak +Comment[ar]= انتهت المعالجة على خطأ +Comment[bg]=Процесът завърши с грешки +Comment[bn]=প্রসেস ত্রুটিপূর্ণভাবে শেষ হল +Comment[bs]=Proces je završen sa greškama +Comment[ca]=Procés finalitzat amb errors +Comment[cs]=Proces ukončen s chybami +Comment[da]=Processen afsluttede med fejl +Comment[de]=Vorgang wurde mit Fehlern beendet +Comment[el]=Η διεργασία ολοκληρώθηκε με σφάλματα +Comment[eo]=Tasko finis erare +Comment[es]=Proceso terminado con errores +Comment[et]=Tegevus lõppes vigadega +Comment[fa]=فرآیند با خطاهایی تمام شد +Comment[fi]=Työtä suoritettaessa tapahtui virheitä +Comment[fr]=Processus terminé avec des erreurs +Comment[gl]=O proceso terminou con erros +Comment[he]=התהליך הסתיים עם שגיאות +Comment[hi]=प्रक्रिया त्रुटि के साथ पूर्ण +Comment[hu]=A művelet hibajelzéssel fejeződött be +Comment[is]=Ferli lauk með villum +Comment[it]=Processo terminato con errori +Comment[ja]=プロセス未了 (エラー) +Comment[ka]=პროცესი შეცდომებით დასრულდა +Comment[km]=បាន​បញ្ចប់​ដំណើរការ​ដោយ​មាន​កំហុស +Comment[lt]=Procesas baigtas su klaidomis +Comment[mk]=Процесот заврши со грешки +Comment[ms]= Proses selesai dengan ralat +Comment[nb]=Prosessen ble fullført med feil +Comment[nds]=Vörgang mit Fehlers afslaten +Comment[ne]=प्रक्रिया त्रुटिसँग समाप्त भयो +Comment[nl]=Proces voltooid met fouten +Comment[nn]=Prosess vart fullført med feil +Comment[pa]=ਕਾਰਵਾਈ ਗਲਤੀਆਂ ਨਾਲ ਪੂਰੀ +Comment[pl]=Proces zakończył się z błędami +Comment[pt]=O processo terminou com erros +Comment[pt_BR]=Processo finalizado com erros +Comment[ru]=Процесс завершён с ошибками +Comment[sk]=Proces ukončený s chybami +Comment[sl]=Proces je končal brez napak +Comment[sr]=Обрада је завршена уз грешке +Comment[sr@Latn]=Obrada je završena uz greške +Comment[sv]=Processen avslutades med fel +Comment[ta]=பிழையுள்ள தொகுப்பு முடிந்தது +Comment[tg]=Амалиёт бо хатогӣ ба анҷом расид +Comment[tr]=İşlem hatayla sonuçlandı +Comment[uk]=Процес завершився з помилками +Comment[uz]=Jarayon xatolar bilan tugadi +Comment[uz@cyrillic]=Жараён хатолар билан тугади +Comment[zh_CN]=处理完成,有错误 +Comment[zh_TW]=完成處理,但發生錯誤 +default_sound=k3b_error1.wav +default_presentation=1 + +[WaitingForMedium] +Name=Waiting for medium +Name[af]=Wag vir medium +Name[ar]= في انتظار الواسطة +Name[bg]=Изчакване за диск +Name[bn]=মাধ্যমের জন্য অপেক্ষারত +Name[br]=Emaon o c'hortoz evit ar vedium +Name[bs]=Čekam medij +Name[ca]=S'està esperant un suport +Name[cs]=Čekám na médium +Name[da]=Venter på mediet +Name[de]=Warten auf Medium +Name[el]=Αναμονή για μέσο +Name[eo]=Atendante ujon +Name[es]=Esperando medio +Name[et]=Andmekandja ootamine +Name[fa]=انتظار برای رسانه +Name[fi]=Odotetaan levyä +Name[fr]=En attente du média +Name[gl]=Á espera do disco +Name[he]=מצפה למדיה +Name[hi]=साधन हेतु प्रतीक्षारत +Name[hu]=Várakozás egy lemezre +Name[is]=Býð eftir miðli +Name[it]=Si è in attesa di un supporto +Name[ja]=メディアを待っています +Name[ka]=ველოდები მატარებელს +Name[km]=កំពុងរង់ចាំ​មេឌៀ +Name[lt]=Laukiama disko +Name[mk]=Исчекување за носач +Name[ms]= Menunggu media +Name[nb]=Venter på medium +Name[nds]=An't Töven op Medium +Name[ne]=माध्यमका लागि प्रतिक्षा गर्दै +Name[nl]=Wacht op medium +Name[nn]=Ventar på medium +Name[pa]=ਲਿਖਣ ਲਈ ਮੀਡਿਆ ਦੀ ਉਡੀਕ +Name[pl]=Oczekiwanie na płytę +Name[pt]=À espera do disco +Name[pt_BR]=Aguardando pela mídia +Name[ru]=Ожидание носителя +Name[sk]=Čakám na médium +Name[sl]=Čakanje na medij +Name[sr]=Чекам на диск +Name[sr@Latn]=Čekam na disk +Name[sv]=Väntar på media +Name[ta]=ஊடகத்திற்காக காத்திருக்கவும் +Name[tg]=Интизори расона +Name[tr]=Ortam bekleniyor +Name[uk]=Очікування носія +Name[uz]=Disk kutilmoqda +Name[uz@cyrillic]=Диск кутилмоқда +Name[zh_CN]=等待存储介质 +Name[zh_TW]=等待插入媒體 +Comment=The user needs to insert a medium +Comment[af]=Die gebruiker moet 'n medium insit +Comment[ar]= يجب على المستعمل ادخال الواسطة +Comment[bg]=Потребителят трябва да постави диск в устройството +Comment[bn]=ব্যবহারকারীর একটি মাধ্যম ভিতরে ঢোকানোর প্রয়োজন +Comment[bs]=Korisnik mora ubaciti medij +Comment[ca]=Cal que l'usuari insereixi un suport +Comment[cs]=Uživatel musí vložit médium +Comment[da]=Brugeren må indsætte et medie +Comment[de]=Der Benutzer muss ein Medium einlegen +Comment[el]=Ο χρήστης πρέπει να εισάγει ένα μέσο +Comment[eo]=La uzanto devas enigi ujon +Comment[es]=El usuario necesita insertar un medio +Comment[et]=Kasutajal tuleb andmekandja sisse panna +Comment[fa]=کاربر نیاز به درج یک رسانه دارد +Comment[fi]=Odotetaan käyttäjän syöttävän levyn +Comment[fr]=L'utilisateur doit insérer un média +Comment[gl]=O usuário debe inserir un disco +Comment[he]=המשתמש חייב להכניס מדיית צריבה +Comment[hi]=उपयोगकर्ता को आवश्यक होगा कि साधन प्रविष्ट करे +Comment[hu]=Be kell helyezni egy lemezt +Comment[is]=Notandi verður að setja inn disk +Comment[it]=L'utente deve inserire un supporto +Comment[ja]=メディアを入れてください +Comment[ka]=მომხმარებელს სჭირდება მატარებლის ჩადება +Comment[km]=អ្នកប្រើ​ត្រូវ​តែ​បញ្ចូល​ឧបករណ៍​ផ្ទុក​មួយ +Comment[lt]=Naudotojas turi įdėti diską +Comment[mk]=Корисникот треба да внесе носач +Comment[ms]=Pengguna perlu menyelitkan media +Comment[nb]=Brukeren må sette inn et medium +Comment[nds]=De Bruker mutt en Medium inleggen +Comment[ne]=प्रयोगकर्तालाई माध्यम घुसाउँन आवश्यक पर्दछ +Comment[nl]=De gebruiker dient een medium in te voeren +Comment[nn]=Brukaren må setja inn eit medium +Comment[pa]=ਉਪਭੋਗੀ ਨੂੰ ਇੱਕ ਮੀਡੀਅਮ ਪਾਉਣ ਦੀ ਲੋੜ ਹੈ +Comment[pl]=Użytkownik musi włożyć płytę +Comment[pt]=O utilizador tem que inserir um disco +Comment[pt_BR]=O usuário precisa inserir uma mídia +Comment[ru]=Необходимо вставить носитель +Comment[sk]=Používateľ má vložiť médium +Comment[sl]=Uporabnik mora vstaviti medij +Comment[sr]=Корисник мора да убаци диск +Comment[sr@Latn]=Korisnik mora da ubaci disk +Comment[sv]=Användaren måste mata in media +Comment[ta]=உபயோகிப்பவர் ஊடகத்தை சொருக வேண்டும் +Comment[tg]=Истифодабаранда бояд расонаро барқарор кунад +Comment[tr]=Kullanıcının bir ortam takması gerekiyor +Comment[uk]=Користувач мусить вставити носій +Comment[uz]=Foydalanuvchi diskni qoʻyishi kerak +Comment[uz@cyrillic]=Фойдаланувчи дискни қўйиши керак +Comment[zh_CN]=用户需要插入存储介质 +Comment[zh_TW]=使用者需要插入媒體 +default_sound=k3b_wait_media1.wav +default_presentation=1 diff --git a/src/fastscale/Makefile.am b/src/fastscale/Makefile.am new file mode 100644 index 0000000..2fafe00 --- /dev/null +++ b/src/fastscale/Makefile.am @@ -0,0 +1,14 @@ +AM_CPPFLAGS = -I$(srcdir) -I$(srcdir)/.. $(all_includes) +AM_CCASFLAGS = -I$(srcdir) $(GV_ASM_DEFS) + +#CXXFLAGS = -fexceptions + +noinst_LTLIBRARIES = libfastscale.la + +libfastscale_la_SOURCES = \ + scale.cpp \ + asm_scale.S + +libfastscale_la_LIBADD = $(LIB_KDECORE) $(LIBQT) $(LIBJPEG) + +METASOURCES = AUTO diff --git a/src/fastscale/README b/src/fastscale/README new file mode 100644 index 0000000..13d4ccc --- /dev/null +++ b/src/fastscale/README @@ -0,0 +1,2 @@ +This directory contains fast scaling algorithms from ImageMagick and Mosfet. +They have been copied from the Gwenview source tree. \ No newline at end of file diff --git a/src/fastscale/asm_scale.S b/src/fastscale/asm_scale.S new file mode 100644 index 0000000..08b43da --- /dev/null +++ b/src/fastscale/asm_scale.S @@ -0,0 +1,810 @@ +#ifdef HAVE_X86_MMX + +#ifdef __EMX__ +/* Due to strange behaviour of as.exe we use this macros */ +/* For all OS/2 coders - please use PGCC to compile this code */ +#define PR_(foo) ___##foo +#define PT_(foo,func) ___##foo,func +#define SIZE(sym) \ + .___end_##sym:; \ + .size ___##sym,.___end_##sym-___##sym; \ + .align 8; +#else +#define PR_(foo) __##foo +#define PT_(foo,func) __##foo,func +#define SIZE(sym) \ + .__end_##sym:; \ + .size __##sym,.__end_##sym-__##sym; \ + .align 8; +#endif + +/*\ +|*| MMX assembly scaling routine for Imlib2 +|*| Written by Willem Monsuwe <willem@stack.nl> +\*/ + +.text + .align 8 +.globl PR_(mimageScale_mmx_AARGBA) +/* .type PT_(mimageScale_mmx_AARGBA,@function) */ + + +/*\ Prototype: __mimageScale_mmx_AARGBA(ImlibScaleInfo *isi, DATA32 *dest, +|*| int dxx, int dyy, int dx, int dy, int dw, int dh, int dow, int sow) +\*/ + +#define isi 8(%ebp) +#define dest 12(%ebp) +#define dxx 16(%ebp) +#define dyy 20(%ebp) +#define dx 24(%ebp) +#define dy 28(%ebp) +#define dw 32(%ebp) +#define dh 36(%ebp) +#define dow 40(%ebp) +#define sow 44(%ebp) + +/*\ Local variables that didn't fit in registers \*/ +#define y -4(%ebp) +#define yp -8(%ebp) +#define yap -12(%ebp) +#define xp -16(%ebp) +#define xap -20(%ebp) +#define Cx -24(%ebp) +#define Mx -28(%ebp) +#define Cy -32(%ebp) +#define My -36(%ebp) +#define sow_4 -40(%ebp) + +/*\ When %edx points to ImlibScaleInfo, these are the members \*/ +#define xpoints (%edx) +#define ypoints 4(%edx) +#define xapoints 8(%edx) +#define yapoints 12(%edx) +#define xup_yup 16(%edx) + +PR_(mimageScale_mmx_AARGBA): + pushl %ebp + movl %esp, %ebp + subl $40, %esp + pushl %ebx + pushl %ecx + pushl %edx + pushl %edi + pushl %esi + movl isi, %edx + + /*\ Check (dw > 0) && (dh > 0) \*/ + cmpl $0, dw + jle .scale_leave + cmpl $0, dh + jle .scale_leave + + /*\ X-based array pointers point to the end; we're looping up to 0 \*/ + /*\ %edi = dest + dow * dy + dx + dw \*/ + movl dow, %eax + imull dy, %eax + addl dx, %eax + addl dw, %eax + movl dest, %edi + leal (%edi, %eax, 4), %edi + /*\ xp = xpoints + dxx + dw \*/ + movl dxx, %ebx + addl dw, %ebx + movl xpoints, %eax + leal (%eax, %ebx, 4), %eax + movl %eax, xp + /*\ xap = xapoints + dxx + dw \*/ + movl xapoints, %eax + leal (%eax, %ebx, 4), %eax + movl %eax, xap + /*\ y = dh \*/ + movl dh, %eax + movl %eax, y + /*\ yp = ypoints + dyy \*/ + movl dyy, %ebx + movl ypoints, %eax + leal (%eax, %ebx, 4), %eax + movl %eax, yp + /*\ yap = yapoints + dyy \*/ + movl yapoints, %eax + leal (%eax, %ebx, 4), %eax + movl %eax, yap + + pxor %mm7, %mm7 + + /*\ Test xup bit \*/ + movl xup_yup, %eax + sarl $1, %eax + jnc .scale_x_down + +.scale_x_up: + /*\ Test yup bit \*/ + sarl $1, %eax + jnc .scale_x_up_y_down + + +/*\ Scaling up both ways \*/ + +.scale_x_up_y_up: + movl sow, %ebx + +.up_up_loop_y: + + /*\ x = -dw \*/ + movl dw, %ecx + negl %ecx + + /*\ %eax = *yap << 4 \*/ + movl yap, %eax + movl (%eax), %eax + sall $4, %eax + jz .up_up_yap_0 + movd %eax, %mm1 + punpcklwd %mm1, %mm1 + punpckldq %mm1, %mm1 + +.up_up_loop1_x: + /*\ %esi = *yp + xp[x] \*/ + movl yp, %eax + movl (%eax), %esi + movl xp, %eax + movl (%eax, %ecx, 4), %eax + leal (%esi, %eax, 4), %esi + + /*\ %eax = xap[x] << 4 \*/ + movl xap, %eax + movl (%eax, %ecx, 4), %eax + sall $4, %eax + jz .up_up_xap_0 + + /*\ %mm0 = xap[x] << 4 \*/ + movd %eax, %mm0 + punpcklwd %mm0, %mm0 + punpckldq %mm0, %mm0 + + /*\ Load and unpack four pixels in parralel + |*| %mm2 = ptr[0], %mm3 = ptr[1] + |*| %mm4 = ptr[sow], %mm5 = ptr[sow + 1] + \*/ + movq (%esi), %mm2 + movq (%esi, %ebx, 4), %mm4 + movq %mm2, %mm3 + movq %mm4, %mm5 + punpcklbw %mm7, %mm2 + punpcklbw %mm7, %mm4 + punpckhbw %mm7, %mm3 + punpckhbw %mm7, %mm5 + + /*\ X interpolation: r = l + (r - l) * xap \*/ + psubw %mm2, %mm3 + psubw %mm4, %mm5 + psllw $4, %mm3 + psllw $4, %mm5 + pmulhw %mm0, %mm3 + pmulhw %mm0, %mm5 + paddw %mm2, %mm3 + paddw %mm4, %mm5 + /*\ Now %mm3 = I(ptr[0], ptr[1]), %mm5 = I(ptr[sow], ptr[sow + 1]) \*/ + jmp .up_up_common +.up_up_xap_0: + /*\ Load and unpack two pixels + |*| %mm3 = ptr[0], %mm5 = ptr[sow] + \*/ + movd (%esi), %mm3 + movd (%esi, %ebx, 4), %mm5 + punpcklbw %mm7, %mm3 + punpcklbw %mm7, %mm5 +.up_up_common: + /*\ Y interpolation: d = u + (d - u) * yap \*/ + psubw %mm3, %mm5 + psllw $4, %mm5 + pmulhw %mm1, %mm5 + paddw %mm3, %mm5 + packuswb %mm5, %mm5 + movd %mm5, (%edi, %ecx, 4) + + /*\ while (++x) \*/ + incl %ecx + jnz .up_up_loop1_x + jmp .up_up_yap_end +.up_up_yap_0: + +.up_up_loop2_x: + /*\ %esi = *yp + xp[x] \*/ + movl yp, %eax + movl (%eax), %esi + movl xp, %eax + movl (%eax, %ecx, 4), %eax + leal (%esi, %eax, 4), %esi + + /*\ %eax = xap[x] << 4 \*/ + movl xap, %eax + movl (%eax, %ecx, 4), %eax + sall $4, %eax + jz .up_up_0 + + /*\ %mm0 = xap[x] << 4 \*/ + movd %eax, %mm0 + punpcklwd %mm0, %mm0 + punpckldq %mm0, %mm0 + + /*\ Load and unpack two pixels in parralel + |*| %mm2 = ptr[0], %mm3 = ptr[1] + \*/ + movq (%esi), %mm2 + movq %mm2, %mm3 + punpcklbw %mm7, %mm2 + punpckhbw %mm7, %mm3 + + /*\ X interpolation: r = l + (r - l) * xap \*/ + psubw %mm2, %mm3 + psllw $4, %mm3 + pmulhw %mm0, %mm3 + paddw %mm2, %mm3 + packuswb %mm3, %mm3 + movd %mm3, (%edi, %ecx, 4) + jmp .up_up_1 +.up_up_0: + /*\ dptr[x] = *sptr \*/ + movl (%esi), %eax + movl %eax, (%edi, %ecx, 4) +.up_up_1: + incl %ecx + jnz .up_up_loop2_x + +.up_up_yap_end: + /*\ dptr += dow \*/ + movl dow, %eax + leal (%edi, %eax, 4), %edi + /*\ yap++; yp++ \*/ + addl $4, yap + addl $4, yp + /*\ while (y--) \*/ + decl y + jnz .up_up_loop_y + + jmp .scale_leave + + +/*\ Scaling down vertically \*/ + +.scale_x_up_y_down: + /*\ sow_4 = sow * 4 \*/ + movl sow, %eax + sall $2, %eax + movl %eax, sow_4 + +.up_down_loop_y: + + /*\ Setup My and Cy \*/ + movl yap, %eax + movzwl (%eax), %ebx + movl %ebx, My + movzwl 2(%eax), %eax + movl %eax, Cy + + /*\ mm4 = Cy \*/ + movd %eax, %mm4 + punpcklwd %mm4, %mm4 + punpckldq %mm4, %mm4 + /*\ mm5 = My \*/ + movd %ebx, %mm5 + punpcklwd %mm5, %mm5 + punpckldq %mm5, %mm5 + + /*\ x = -dw \*/ + movl dw, %ecx + negl %ecx +.up_down_loop_x: + /*\ %esi = *yp + xp[x] \*/ + movl yp, %eax + movl (%eax), %esi + movl xp, %eax + movl (%eax, %ecx, 4), %eax + leal (%esi, %eax, 4), %esi + + movl %esi, %eax + /*\ v = (*p * My) >> 10 \*/ + movd (%eax), %mm0 + punpcklbw %mm7, %mm0 + psllw $6, %mm0 + pmulhw %mm5, %mm0 + + /*\ i = 0x4000 - My \*/ + movl $0x4000, %ebx + subl My, %ebx + jbe 5f + jmp 2f +1: + /*\ p += sow; v += (*p * Cy) >> 10 \*/ + addl sow_4, %eax + movd (%eax), %mm1 + punpcklbw %mm7, %mm1 + psllw $6, %mm1 + pmulhw %mm4, %mm1 + paddw %mm1, %mm0 + + /*\ i -= Cy; while (i > Cy) \*/ + subl Cy, %ebx +2: + cmpl Cy, %ebx + jg 1b + + /*\ mm6 = i \*/ + movd %ebx, %mm6 + punpcklwd %mm6, %mm6 + punpckldq %mm6, %mm6 + + /*\ p += sow; v += (*p * i) >> 10 \*/ + addl sow_4, %eax + movd (%eax), %mm1 + punpcklbw %mm7, %mm1 + psllw $6, %mm1 + pmulhw %mm6, %mm1 + paddw %mm1, %mm0 +5: + /*\ %eax = xap[x] << 5 \*/ + movl xap, %eax + movl (%eax, %ecx, 4), %eax + sall $5, %eax + jz 6f + /*\ mm3 = xap[x] << 5 \*/ + movd %eax, %mm3 + punpcklwd %mm3, %mm3 + punpckldq %mm3, %mm3 + + /*\ p + 1 \*/ + movl %esi, %eax + addl $4, %eax + /*\ vv = (*p * My) >> 10 \*/ + movd (%eax), %mm2 + punpcklbw %mm7, %mm2 + psllw $6, %mm2 + pmulhw %mm5, %mm2 + + /*\ i = 0x4000 - My \*/ + movl $0x4000, %ebx + subl My, %ebx + jbe 5f + jmp 2f +1: + /*\ p += sow; vv += (*p * Cy) >> 10 \*/ + addl sow_4, %eax + movd (%eax), %mm1 + punpcklbw %mm7, %mm1 + psllw $6, %mm1 + pmulhw %mm4, %mm1 + paddw %mm1, %mm2 + + /*\ i -= Cy; while (i > Cy) \*/ + subl Cy, %ebx +2: + cmpl Cy, %ebx + jg 1b + + /*\ p += sow; v += (*p * i) >> 10 \*/ + addl sow_4, %eax + movd (%eax), %mm1 + punpcklbw %mm7, %mm1 + psllw $6, %mm1 + pmulhw %mm6, %mm1 + paddw %mm1, %mm2 +5: + /*\ v = v + (vv - v) * xap \*/ + psubw %mm0, %mm2 + psllw $3, %mm2 + pmulhw %mm3, %mm2 + paddw %mm2, %mm0 +6: + /*\ dest[x] = v >> 4 \*/ + psrlw $4, %mm0 + packuswb %mm0, %mm0 + movd %mm0, (%edi, %ecx, 4) + + /*\ while (++x) \*/ + incl %ecx + jnz .up_down_loop_x + + /*\ dptr += dow \*/ + movl dow, %eax + leal (%edi, %eax, 4), %edi + /*\ yap++; yp++ \*/ + addl $4, yap + addl $4, yp + /*\ while (y--) \*/ + decl y + jnz .up_down_loop_y + + jmp .scale_leave + +.scale_x_down: + /*\ Test yup bit \*/ + sarl $1, %eax + jnc .scale_x_down_y_down + + +/*\ Scaling down horizontally \*/ + +.scale_x_down_y_up: + /*\ sow_4 = sow * 4 \*/ + movl sow, %eax + sall $2, %eax + movl %eax, sow_4 + +.down_up_loop_y: + + /*\ %eax = *yap << 5 \*/ + movl yap, %eax + movl (%eax), %eax + sall $5, %eax + /*\ mm3 = *yap << 5 \*/ + movd %eax, %mm3 + punpcklwd %mm3, %mm3 + punpckldq %mm3, %mm3 + + /*\ x = -dw \*/ + movl dw, %ecx + negl %ecx +.down_up_loop_x: + /*\ %esi = *yp + xp[x] \*/ + movl yp, %eax + movl (%eax), %esi + movl xp, %eax + movl (%eax, %ecx, 4), %eax + leal (%esi, %eax, 4), %esi + + /*\ Setup Mx and Cx \*/ + movl xap, %eax + movzwl (%eax, %ecx, 4), %ebx + movl %ebx, Mx + movzwl 2(%eax, %ecx, 4), %eax + movl %eax, Cx + + /*\ mm4 = Cx \*/ + movd %eax, %mm4 + punpcklwd %mm4, %mm4 + punpckldq %mm4, %mm4 + /*\ mm5 = Mx \*/ + movd %ebx, %mm5 + punpcklwd %mm5, %mm5 + punpckldq %mm5, %mm5 + + movl %esi, %eax + /*\ v = (*p * Mx) >> 10 \*/ + movd (%eax), %mm0 + punpcklbw %mm7, %mm0 + psllw $6, %mm0 + pmulhw %mm5, %mm0 + + /*\ i = 0x4000 - Mx \*/ + movl $0x4000, %ebx + subl Mx, %ebx + jbe 5f + jmp 2f +1: + /*\ p += sow; v += (*p * Cx) >> 10 \*/ + addl $4, %eax + movd (%eax), %mm1 + punpcklbw %mm7, %mm1 + psllw $6, %mm1 + pmulhw %mm4, %mm1 + paddw %mm1, %mm0 + + /*\ i -= Cx; while (i > Cx) \*/ + subl Cx, %ebx +2: + cmpl Cx, %ebx + jg 1b + + /*\ mm6 = i \*/ + movd %ebx, %mm6 + punpcklwd %mm6, %mm6 + punpckldq %mm6, %mm6 + + /*\ p += sow; v += (*p * i) >> 10 \*/ + addl $4, %eax + movd (%eax), %mm1 + punpcklbw %mm7, %mm1 + psllw $6, %mm1 + pmulhw %mm6, %mm1 + paddw %mm1, %mm0 +5: + movd %mm3, %eax + testl %eax, %eax + jz 6f + /*\ p + sow \*/ + movl %esi, %eax + addl sow_4, %eax + /*\ vv = (*p * Mx) >> 10 \*/ + movd (%eax), %mm2 + punpcklbw %mm7, %mm2 + psllw $6, %mm2 + pmulhw %mm5, %mm2 + + /*\ i = 0x4000 - Mx \*/ + movl $0x4000, %ebx + subl Mx, %ebx + jbe 5f + jmp 2f +1: + /*\ p += sow; vv += (*p * Cx) >> 10 \*/ + addl $4, %eax + movd (%eax), %mm1 + punpcklbw %mm7, %mm1 + psllw $6, %mm1 + pmulhw %mm4, %mm1 + paddw %mm1, %mm2 + + /*\ i -= Cx; while (i > Cx) \*/ + subl Cx, %ebx +2: + cmpl Cx, %ebx + jg 1b + + /*\ p += sow; v += (*p * i) >> 10 \*/ + addl $4, %eax + movd (%eax), %mm1 + punpcklbw %mm7, %mm1 + psllw $6, %mm1 + pmulhw %mm6, %mm1 + paddw %mm1, %mm2 +5: + /*\ v = v + (vv - v) * yap \*/ + psubw %mm0, %mm2 + psllw $3, %mm2 + pmulhw %mm3, %mm2 + paddw %mm2, %mm0 +6: + /*\ dest[x] = v >> 4 \*/ + psrlw $4, %mm0 + packuswb %mm0, %mm0 + movd %mm0, (%edi, %ecx, 4) + + /*\ while (++x) \*/ + incl %ecx + jnz .down_up_loop_x + + /*\ dptr += dow \*/ + movl dow, %eax + leal (%edi, %eax, 4), %edi + /*\ yap++; yp++ \*/ + addl $4, yap + addl $4, yp + /*\ while (y--) \*/ + decl y + jnz .down_up_loop_y + + jmp .scale_leave + + +/*\ Scaling down both ways \*/ + +.scale_x_down_y_down: + /*\ sow_4 = sow * 4 \*/ + movl sow, %eax + sall $2, %eax + movl %eax, sow_4 + +.down_down_loop_y: + + /*\ Setup My and Cy \*/ + movl yap, %eax + movzwl (%eax), %ebx + movl %ebx, My + movzwl 2(%eax), %eax + movl %eax, Cy + + /*\ x = -dw \*/ + movl dw, %ecx + negl %ecx +.down_down_loop_x: + /*\ %esi = *yp + xp[x] \*/ + movl yp, %eax + movl (%eax), %esi + movl xp, %eax + movl (%eax, %ecx, 4), %eax + leal (%esi, %eax, 4), %esi + + /*\ Setup Mx and Cx \*/ + movl xap, %eax + movzwl (%eax, %ecx, 4), %ebx + movl %ebx, Mx + movzwl 2(%eax, %ecx, 4), %eax + movl %eax, Cx + + /*\ mm3 = Cx \*/ + movd %eax, %mm3 + punpcklwd %mm3, %mm3 + punpckldq %mm3, %mm3 + /*\ mm5 = Mx \*/ + movd %ebx, %mm5 + punpcklwd %mm5, %mm5 + punpckldq %mm5, %mm5 + + /*\ p = sptr; v = (*p * Mx) >> 9 \*/ + movl %esi, %eax + movd (%eax), %mm0 + punpcklbw %mm7, %mm0 + psllw $7, %mm0 + pmulhw %mm5, %mm0 + + /*\ i = 0x4000 - Mx \*/ + movl $0x4000, %ebx + subl Mx, %ebx + jbe 5f + jmp 2f +1: + /*\ v += (*++p * Cx) >> 9 \*/ + addl $4, %eax + movd (%eax), %mm1 + punpcklbw %mm7, %mm1 + psllw $7, %mm1 + pmulhw %mm3, %mm1 + paddw %mm1, %mm0 + + /*\ i -= Cx; while (i > Cx) \*/ + subl Cx, %ebx +2: + cmpl Cx, %ebx + jg 1b + + /*\ mm6 = i \*/ + movd %ebx, %mm6 + punpcklwd %mm6, %mm6 + punpckldq %mm6, %mm6 + + /*\ v += (*++p * i) >> 9 \*/ + addl $4, %eax + movd (%eax), %mm1 + punpcklbw %mm7, %mm1 + psllw $7, %mm1 + pmulhw %mm6, %mm1 + paddw %mm1, %mm0 +5: + /*\ v *= My \*/ + movd My, %mm4 + punpcklwd %mm4, %mm4 + punpckldq %mm4, %mm4 + psllw $2, %mm0 + pmulhw %mm4, %mm0 + + /*\ j = 0x4000 - My \*/ + movl $0x4000, %edx + subl My, %edx + jbe 6f + jmp 4f +3: + /*\ sptr += sow; p = sptr \*/ + addl sow_4, %esi + movl %esi, %eax + /*\ vx = (*p * Mx) >> 9 \*/ + movd (%eax), %mm1 + punpcklbw %mm7, %mm1 + psllw $7, %mm1 + pmulhw %mm5, %mm1 + + /*\ i = 0x4000 - Mx \*/ + movl $0x4000, %ebx + subl Mx, %ebx + jbe 5f + jmp 2f +1: + /*\ vx += (*++p * Cx) >> 9 \*/ + addl $4, %eax + movd (%eax), %mm2 + punpcklbw %mm7, %mm2 + psllw $7, %mm2 + pmulhw %mm3, %mm2 + paddw %mm2, %mm1 + + /*\ i -= Cx; while (i > Cx) \*/ + subl Cx, %ebx +2: + cmpl Cx, %ebx + jg 1b + + /*\ vx += (*++p * i) >> 9 \*/ + addl $4, %eax + movd (%eax), %mm2 + punpcklbw %mm7, %mm2 + psllw $7, %mm2 + pmulhw %mm6, %mm2 + paddw %mm2, %mm1 +5: + /*\ v += (vx * Cy) >> 14 \*/ + movd Cy, %mm4 + punpcklwd %mm4, %mm4 + punpckldq %mm4, %mm4 + psllw $2, %mm1 + pmulhw %mm4, %mm1 + paddw %mm1, %mm0 + + /*\ j -= Cy; while (j > Cy) \*/ + subl Cy, %edx +4: + cmpl Cy, %edx + jg 3b + + /*\ sptr += sow; p = sptr \*/ + addl sow_4, %esi + movl %esi, %eax + /*\ vx = (*p * Mx) >> 9 \*/ + movd (%eax), %mm1 + punpcklbw %mm7, %mm1 + psllw $7, %mm1 + pmulhw %mm5, %mm1 + + /*\ i = 0x4000 - Mx \*/ + movl $0x4000, %ebx + subl Mx, %ebx + jbe 5f + jmp 2f +1: + /*\ vx += (*++p * Cx) >> 9 \*/ + addl $4, %eax + movd (%eax), %mm2 + punpcklbw %mm7, %mm2 + psllw $7, %mm2 + pmulhw %mm3, %mm2 + paddw %mm2, %mm1 + + /*\ i -= Cx; while (i > Cx) \*/ + subl Cx, %ebx +2: + cmpl Cx, %ebx + jg 1b + + /*\ vx += (*++p * i) >> 9 \*/ + addl $4, %eax + movd (%eax), %mm2 + punpcklbw %mm7, %mm2 + psllw $7, %mm2 + pmulhw %mm6, %mm2 + paddw %mm2, %mm1 +5: + /*\ v += (vx * j) >> 14 \*/ + movd %edx, %mm4 + punpcklwd %mm4, %mm4 + punpckldq %mm4, %mm4 + psllw $2, %mm1 + pmulhw %mm4, %mm1 + paddw %mm1, %mm0 +6: + /*\ dptr[x] = mm0 >> 5 \*/ + psrlw $5, %mm0 + packuswb %mm0, %mm0 + movd %mm0, (%edi, %ecx, 4) + + /*\ while (++x) \*/ + incl %ecx + jnz .down_down_loop_x + + /*\ dptr += dow \*/ + movl dow, %eax + leal (%edi, %eax, 4), %edi + /*\ yap++; yp++ \*/ + addl $4, yap + addl $4, yp + /*\ while (y--) \*/ + decl y + jnz .down_down_loop_y + + jmp .scale_leave + +.scale_leave: + emms + popl %esi + popl %edi + popl %edx + popl %ecx + popl %ebx + movl %ebp, %esp + popl %ebp + ret + +SIZE(mimageScale_mmx_AARGBA) + +#endif + +.section .note.GNU-stack,"",%progbits diff --git a/src/fastscale/configure.in.in b/src/fastscale/configure.in.in new file mode 100644 index 0000000..a1a5f28 --- /dev/null +++ b/src/fastscale/configure.in.in @@ -0,0 +1,63 @@ +# +# Imlib/Mosfet scaling +# +AM_PROG_AS + +# MMX test duped from kdelibs/kdefx - it should be probably moved to admin/ +dnl ----------------------------------------------------- +dnl IA32 checks +dnl ----------------------------------------------------- + +gv_asm_defs= +case $host_cpu in + i*86 ) + AC_MSG_CHECKING(for assembler support for IA32 extensions) + + dnl MMX check + AC_TRY_COMPILE(, [ __asm__("pxor %mm0, %mm0") ], + [ + echo $ECHO_N "MMX yes$ECHO_C" + AC_DEFINE_UNQUOTED(HAVE_X86_MMX, 1, [Define to 1 if the assembler supports MMX instructions.]) + gv_asm_defs="$gv_asm_defs -DHAVE_X86_MMX" + ], [ echo $ECHO_N "MMX no$ECHO_C" ]) + + dnl SSE check + AC_TRY_COMPILE(,[ __asm__("xorps %xmm0, %xmm0") ], + [ + echo $ECHO_N ", SSE yes$ECHO_C" + AC_DEFINE_UNQUOTED(HAVE_X86_SSE, 1, [Define to 1 if the assembler supports SSE instructions.]) + gv_asm_defs="$gv_asm_defs -DHAVE_X86_SSE" + ], [ echo $ECHO_N ", SSE no$ECHO_C" ]) + + dnl SSE2 check + AC_TRY_COMPILE(, [ __asm__("xorpd %xmm0, %xmm0") ], + [ + echo $ECHO_N ", SSE2 yes$ECHO_C" + AC_DEFINE_UNQUOTED(HAVE_X86_SSE2, 1, [Define to 1 if the assembler supports SSE2 instructions.]) + gv_asm_defs="$gv_asm_defs -DHAVE_X86_SSE2" + ], [ echo $ECHO_N ", SSE2 no$ECHO_C" ]) + + dnl 3DNOW check + AC_TRY_COMPILE(, [ __asm__("femms") ], + [ + echo $ECHO_N ", 3DNOW yes$ECHO_C" + AC_DEFINE_UNQUOTED(HAVE_X86_3DNOW, 1, [Define to 1 if the assembler supports 3DNOW instructions.]) + gv_asm_defs="$gv_asm_defs -DHAVE_X86_3DNOW" + ], [ echo $ECHO_N ", 3DNOW no$ECHO_C" ]) + echo + ;; + powerpc ) + AC_MSG_CHECKING(for assembler support for AltiVec instructions) + dnl AltiVec check + AC_TRY_COMPILE(, [ __asm__("mtspr 256, %0\n\t" "vand %%v0, %%v0, %%v0" : : "r"(-1) ) ], + [ + echo $ECHO_N " yes$ECHO_C" + AC_DEFINE_UNQUOTED(HAVE_PPC_ALTIVEC, 1, [Define to 1 if the assembler supports AltiVec instructions.]) + gv_asm_defs="$gv_asm_defs -DHAVE_PPC_ALTIVEC" + ], [ echo $ECHO_N ", AltiVec no$ECHO_C" ]) + echo + ;; +esac + +GV_ASM_DEFS="$gv_asm_defs" +AC_SUBST(GV_ASM_DEFS) diff --git a/src/fastscale/scale.cpp b/src/fastscale/scale.cpp new file mode 100644 index 0000000..e2332fe --- /dev/null +++ b/src/fastscale/scale.cpp @@ -0,0 +1,1975 @@ +// This file includes code for scaling images, in two versions. +// One ported from ImageMagick (slower, but can achieve better quality), +// and from Imlib2 ported by Mosfet (very fast). + + +// ImageMagick code begin +// ---------------------- + +// This code is ImageMagick's resize code, adapted for QImage, with +// fastfloat class added as an optimization. +// The original license text follows. + +/* +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % +% % +% RRRR EEEEE SSSSS IIIII ZZZZZ EEEEE % +% R R E SS I ZZ E % +% RRRR EEE SSS I ZZZ EEE % +% R R E SS I ZZ E % +% R R EEEEE SSSSS IIIII ZZZZZ EEEEE % +% % +% ImageMagick Image Resize Methods % +% % +% % +% Software Design % +% John Cristy % +% July 1992 % +% % +% % +% Copyright (C) 2003 ImageMagick Studio, a non-profit organization dedicated % +% to making software imaging solutions freely available. % +% % +% Permission is hereby granted, free of charge, to any person obtaining a % +% copy of this software and associated documentation files ("ImageMagick"), % +% to deal in ImageMagick without restriction, including without limitation % +% the rights to use, copy, modify, merge, publish, distribute, sublicense, % +% and/or sell copies of ImageMagick, and to permit persons to whom the % +% ImageMagick is furnished to do so, subject to the following conditions: % +% % +% The above copyright notice and this permission notice shall be included in % +% all copies or substantial portions of ImageMagick. % +% % +% The software is provided "as is", without warranty of any kind, express or % +% implied, including but not limited to the warranties of merchantability, % +% fitness for a particular purpose and noninfringement. In no event shall % +% ImageMagick Studio be liable for any claim, damages or other liability, % +% whether in an action of contract, tort or otherwise, arising from, out of % +% or in connection with ImageMagick or the use or other dealings in % +% ImageMagick. % +% % +% Except as contained in this notice, the name of the ImageMagick Studio % +% shall not be used in advertising or otherwise to promote the sale, use or % +% other dealings in ImageMagick without prior written authorization from the % +% ImageMagick Studio. % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% +*/ +#include "config.h" + +// System +#ifdef HAVE_ENDIAN_H +#include <endian.h> +#else +#ifdef HAVE_SYS_ENDIAN_H +#include <sys/endian.h> +#endif +#endif + +// Qt +#include <qimage.h> +#include <qcolor.h> + +#include <kdeversion.h> +#include <kcpuinfo.h> + +#include <string.h> +#include <stdlib.h> + +// Local +#include "scale.h" + +// everything in namespace +namespace ImageUtils { + + +#define Max QMAX +#define Min QMIN + +// mustn't be less than used precision (i.e. 1/fastfloat::RATIO) +#define MagickEpsilon 0.0002 + +// fastfloat begin +// this class stores floating point numbers as integers, with BITS shift, +// i.e. value XYZ is stored as XYZ * RATIO +struct fastfloat + { + private: + enum { BITS = 12, RATIO = 4096 }; + public: + fastfloat() {} + fastfloat( long v ) : value( v << BITS ) {} + fastfloat( int v ) : value( v << BITS ) {} + fastfloat( double v ) : value( static_cast< long >( v * RATIO + 0.5 )) {} + double toDouble() const { return static_cast< double >( value ) / RATIO; } + long toLong() const { return value >> BITS; } + fastfloat& operator += ( fastfloat r ) { value += r.value; return *this; } + fastfloat& operator -= ( fastfloat r ) { value -= r.value; return *this; } + fastfloat& operator *= ( fastfloat r ) { value = static_cast< long long >( value ) * r.value >> BITS; return *this; } + fastfloat& operator /= ( fastfloat r ) { value = ( static_cast< long long >( value ) << BITS ) / r.value; return *this; } + bool operator< ( fastfloat r ) const { return value < r.value; } + bool operator<= ( fastfloat r ) const { return value <= r.value; } + bool operator> ( fastfloat r ) const { return value > r.value; } + bool operator>= ( fastfloat r ) const { return value >= r.value; } + bool operator== ( fastfloat r ) const { return value == r.value; } + bool operator!= ( fastfloat r ) const { return value != r.value; } + fastfloat operator-() const { return fastfloat( -value, false ); } + private: + fastfloat( long v, bool ) : value( v ) {} // for operator-() + long value; + }; + +inline fastfloat operator+ ( fastfloat l, fastfloat r ) { return fastfloat( l ) += r; } +inline fastfloat operator- ( fastfloat l, fastfloat r ) { return fastfloat( l ) -= r; } +inline fastfloat operator* ( fastfloat l, fastfloat r ) { return fastfloat( l ) *= r; } +inline fastfloat operator/ ( fastfloat l, fastfloat r ) { return fastfloat( l ) /= r; } + +inline bool operator< ( fastfloat l, double r ) { return l < fastfloat( r ); } +inline bool operator<= ( fastfloat l, double r ) { return l <= fastfloat( r ); } +inline bool operator> ( fastfloat l, double r ) { return l > fastfloat( r ); } +inline bool operator>= ( fastfloat l, double r ) { return l >= fastfloat( r ); } +inline bool operator== ( fastfloat l, double r ) { return l == fastfloat( r ); } +inline bool operator!= ( fastfloat l, double r ) { return l != fastfloat( r ); } + +inline bool operator< ( double l, fastfloat r ) { return fastfloat( l ) < r ; } +inline bool operator<= ( double l, fastfloat r ) { return fastfloat( l ) <= r ; } +inline bool operator> ( double l, fastfloat r ) { return fastfloat( l ) > r ; } +inline bool operator>= ( double l, fastfloat r ) { return fastfloat( l ) >= r ; } +inline bool operator== ( double l, fastfloat r ) { return fastfloat( l ) == r ; } +inline bool operator!= ( double l, fastfloat r ) { return fastfloat( l ) != r ; } + +inline double fasttodouble( fastfloat v ) { return v.toDouble(); } +inline long fasttolong( fastfloat v ) { return v.toLong(); } + +#if 1 // change to 0 to turn fastfloat usage off +#else +#define fastfloat double +#define fasttodouble( v ) double( v ) +#define fasttolong( v ) long( v ) +#endif + +//fastfloat end + + +typedef fastfloat (*Filter)(const fastfloat, const fastfloat); + +typedef struct _ContributionInfo +{ + fastfloat + weight; + + long + pixel; +} ContributionInfo; + + +/* +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % +% % +% % +% R e s i z e I m a g e % +% % +% % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% ResizeImage() scales an image to the desired dimensions with one of these +% filters: +% +% Bessel Blackman Box +% Catrom Cubic Gaussian +% Hanning Hermite Lanczos +% Mitchell Point Quandratic +% Sinc Triangle +% +% Most of the filters are FIR (finite impulse response), however, Bessel, +% Gaussian, and Sinc are IIR (infinite impulse response). Bessel and Sinc +% are windowed (brought down to zero) with the Blackman filter. +% +% ResizeImage() was inspired by Paul Heckbert's zoom program. +% +% The format of the ResizeImage method is: +% +% Image *ResizeImage(Image *image,const unsigned long columns, +% const unsigned long rows,const FilterTypes filter,const double blur, +% ExceptionInfo *exception) +% +% A description of each parameter follows: +% +% o image: The image. +% +% o columns: The number of columns in the scaled image. +% +% o rows: The number of rows in the scaled image. +% +% o filter: Image filter to use. +% +% o blur: The blur factor where > 1 is blurry, < 1 is sharp. +% +% o exception: Return any errors or warnings in this structure. +% +% +*/ + +#if 0 +static fastfloat Bessel(const fastfloat x,const fastfloat) +{ + if (x == 0.0) + return(MagickPI/4.0); + return(BesselOrderOne(MagickPI*x)/(2.0*x)); +} + +static fastfloat Sinc(const fastfloat x,const fastfloat) +{ + if (x == 0.0) + return(1.0); + return(sin(MagickPI*x)/(MagickPI*x)); +} + +static fastfloat Blackman(const fastfloat x,const fastfloat) +{ + return(0.42+0.5*cos(MagickPI*x)+0.08*cos(2*MagickPI*x)); +} + +static fastfloat BlackmanBessel(const fastfloat x,const fastfloat) +{ + return(Blackman(x/support,support)*Bessel(x,support)); +} + +static fastfloat BlackmanSinc(const fastfloat x,const fastfloat) +{ + return(Blackman(x/support,support)*Sinc(x,support)); +} +#endif + +static fastfloat Box(const fastfloat x,const fastfloat) +{ + if (x < -0.5) + return(0.0); + if (x < 0.5) + return(1.0); + return(0.0); +} + +#if 0 +static fastfloat Catrom(const fastfloat x,const fastfloat) +{ + if (x < -2.0) + return(0.0); + if (x < -1.0) + return(0.5*(4.0+x*(8.0+x*(5.0+x)))); + if (x < 0.0) + return(0.5*(2.0+x*x*(-5.0-3.0*x))); + if (x < 1.0) + return(0.5*(2.0+x*x*(-5.0+3.0*x))); + if (x < 2.0) + return(0.5*(4.0+x*(-8.0+x*(5.0-x)))); + return(0.0); +} + +static fastfloat Cubic(const fastfloat x,const fastfloat) +{ + if (x < -2.0) + return(0.0); + if (x < -1.0) + return((2.0+x)*(2.0+x)*(2.0+x)/6.0); + if (x < 0.0) + return((4.0+x*x*(-6.0-3.0*x))/6.0); + if (x < 1.0) + return((4.0+x*x*(-6.0+3.0*x))/6.0); + if (x < 2.0) + return((2.0-x)*(2.0-x)*(2.0-x)/6.0); + return(0.0); +} + +static fastfloat Gaussian(const fastfloat x,const fastfloat) +{ + return(exp(-2.0*x*x)*sqrt(2.0/MagickPI)); +} + +static fastfloat Hanning(const fastfloat x,const fastfloat) +{ + return(0.5+0.5*cos(MagickPI*x)); +} + +static fastfloat Hamming(const fastfloat x,const fastfloat) +{ + return(0.54+0.46*cos(MagickPI*x)); +} + +static fastfloat Hermite(const fastfloat x,const fastfloat) +{ + if (x < -1.0) + return(0.0); + if (x < 0.0) + return((2.0*(-x)-3.0)*(-x)*(-x)+1.0); + if (x < 1.0) + return((2.0*x-3.0)*x*x+1.0); + return(0.0); +} + +static fastfloat Lanczos(const fastfloat x,const fastfloat support) +{ + if (x < -3.0) + return(0.0); + if (x < 0.0) + return(Sinc(-x,support)*Sinc(-x/3.0,support)); + if (x < 3.0) + return(Sinc(x,support)*Sinc(x/3.0,support)); + return(0.0); +} + +static fastfloat Mitchell(const fastfloat x,const fastfloat) +{ +#define B (1.0/3.0) +#define C (1.0/3.0) +#define P0 (( 6.0- 2.0*B )/6.0) +#define P2 ((-18.0+12.0*B+ 6.0*C)/6.0) +#define P3 (( 12.0- 9.0*B- 6.0*C)/6.0) +#define Q0 (( 8.0*B+24.0*C)/6.0) +#define Q1 (( -12.0*B-48.0*C)/6.0) +#define Q2 (( 6.0*B+30.0*C)/6.0) +#define Q3 (( - 1.0*B- 6.0*C)/6.0) + + if (x < -2.0) + return(0.0); + if (x < -1.0) + return(Q0-x*(Q1-x*(Q2-x*Q3))); + if (x < 0.0) + return(P0+x*x*(P2-x*P3)); + if (x < 1.0) + return(P0+x*x*(P2+x*P3)); + if (x < 2.0) + return(Q0+x*(Q1+x*(Q2+x*Q3))); + return(0.0); + +#undef B +#undef C +#undef P0 +#undef P2 +#undef P3 +#undef Q0 +#undef Q1 +#undef Q2 +#undef Q3 +} +#endif + +// this is the same like Mitchell, but it has different values +// for B and C, resulting in sharper images +// http://sourceforge.net/mailarchive/forum.php?thread_id=7445822&forum_id=1210 +static fastfloat Bicubic(const fastfloat x,const fastfloat) +{ +#define B (0.0/3.0) +#define C (2.0/3.0) +#define P0 (( 6.0- 2.0*B )/6.0) +#define P2 ((-18.0+12.0*B+ 6.0*C)/6.0) +#define P3 (( 12.0- 9.0*B- 6.0*C)/6.0) +#define Q0 (( 8.0*B+24.0*C)/6.0) +#define Q1 (( -12.0*B-48.0*C)/6.0) +#define Q2 (( 6.0*B+30.0*C)/6.0) +#define Q3 (( - 1.0*B- 6.0*C)/6.0) + + if (x < -2.0) + return(0.0); + if (x < -1.0) + return(Q0-x*(Q1-x*(Q2-x*Q3))); + if (x < 0.0) + return(P0+x*x*(P2-x*P3)); + if (x < 1.0) + return(P0+x*x*(P2+x*P3)); + if (x < 2.0) + return(Q0+x*(Q1+x*(Q2+x*Q3))); + return(0.0); + +#undef B +#undef C +#undef P0 +#undef P2 +#undef P3 +#undef Q0 +#undef Q1 +#undef Q2 +#undef Q3 +} + +#if 0 +static fastfloat Quadratic(const fastfloat x,const fastfloat) +{ + if (x < -1.5) + return(0.0); + if (x < -0.5) + return(0.5*(x+1.5)*(x+1.5)); + if (x < 0.5) + return(0.75-x*x); + if (x < 1.5) + return(0.5*(x-1.5)*(x-1.5)); + return(0.0); +} +#endif + +static fastfloat Triangle(const fastfloat x,const fastfloat) +{ + if (x < -1.0) + return(0.0); + if (x < 0.0) + return(1.0+x); + if (x < 1.0) + return(1.0-x); + return(0.0); +} + +static void HorizontalFilter(const QImage& source,QImage& destination, + const fastfloat x_factor,const fastfloat blur, + ContributionInfo *contribution, Filter filter, fastfloat filtersupport) +{ + fastfloat + center, + density, + scale, + support; + + long + n, + start, + stop, + y; + + register long + i, + x; + + /* + Apply filter to resize horizontally from source to destination. + */ + scale=blur*Max(1.0/x_factor,1.0); + support=scale* filtersupport; + if (support <= 0.5) + { + /* + Reduce to point sampling. + */ + support=0.5+MagickEpsilon; + scale=1.0; + } + scale=1.0/scale; + for (x=0; x < (long) destination.width(); x++) + { + center=(fastfloat) (x+0.5)/x_factor; + start= fasttolong(Max(center-support+0.5,0)); + stop= fasttolong(Min(center+support+0.5,source.width())); + density=0.0; + for (n=0; n < (stop-start); n++) + { + contribution[n].pixel=start+n; + contribution[n].weight= + filter (scale*(start+n-center+0.5), filtersupport ); + density+=contribution[n].weight; + } + if ((density != 0.0) && (density != 1.0)) + { + /* + Normalize. + */ + density=1.0/density; + for (i=0; i < n; i++) + contribution[i].weight*=density; + } +// p=AcquireImagePixels(source,contribution[0].pixel,0,contribution[n-1].pixel- +// contribution[0].pixel+1,source->rows,exception); +// q=SetImagePixels(destination,x,0,1,destination->rows); + for (y=0; y < (long) destination.height(); y++) + { + fastfloat red = 0; + fastfloat green = 0; + fastfloat blue = 0; + fastfloat alpha = 0; + for (i=0; i < n; i++) + { + int px = contribution[i].pixel; + int py = y; + QRgb p = reinterpret_cast< QRgb* >( source.jumpTable()[ py ])[ px ]; + red+=contribution[i].weight*qRed(p); + green+=contribution[i].weight*qGreen(p); + blue+=contribution[i].weight*qBlue(p); + alpha+=contribution[i].weight*qAlpha(p); + } + QRgb pix = qRgba( + fasttolong( red < 0 ? 0 : red > 255 ? 255 : red + 0.5 ), + fasttolong( green < 0 ? 0 : green > 255 ? 255 : green + 0.5 ), + fasttolong( blue < 0 ? 0 : blue > 255 ? 255 : blue + 0.5 ), + fasttolong( alpha < 0 ? 0 : alpha > 255 ? 255 : alpha + 0.5 )); + reinterpret_cast< QRgb* >( destination.jumpTable()[ y ])[ x ] = pix; + } + } +} + +static void VerticalFilter(const QImage& source,QImage& destination, + const fastfloat y_factor,const fastfloat blur, + ContributionInfo *contribution, Filter filter, fastfloat filtersupport ) +{ + fastfloat + center, + density, + scale, + support; + + long + n, + start, + stop, + x; + + register long + i, + y; + + /* + Apply filter to resize vertically from source to destination. + */ + scale=blur*Max(1.0/y_factor,1.0); + support=scale* filtersupport; + if (support <= 0.5) + { + /* + Reduce to point sampling. + */ + support=0.5+MagickEpsilon; + scale=1.0; + } + scale=1.0/scale; + for (y=0; y < (long) destination.height(); y++) + { + center=(fastfloat) (y+0.5)/y_factor; + start= fasttolong(Max(center-support+0.5,0)); + stop= fasttolong(Min(center+support+0.5,source.height())); + density=0.0; + for (n=0; n < (stop-start); n++) + { + contribution[n].pixel=start+n; + contribution[n].weight= + filter (scale*(start+n-center+0.5), filtersupport); + density+=contribution[n].weight; + } + if ((density != 0.0) && (density != 1.0)) + { + /* + Normalize. + */ + density=1.0/density; + for (i=0; i < n; i++) + contribution[i].weight*=density; + } +// p=AcquireImagePixels(source,0,contribution[0].pixel,source->columns, +// contribution[n-1].pixel-contribution[0].pixel+1,exception); +// q=SetImagePixels(destination,0,y,destination->columns,1); + for (x=0; x < (long) destination.width(); x++) + { + fastfloat red = 0; + fastfloat green = 0; + fastfloat blue = 0; + fastfloat alpha = 0; + for (i=0; i < n; i++) + { + int px = x; + int py = contribution[i].pixel; + QRgb p = reinterpret_cast< QRgb* >( source.jumpTable()[ py ])[ px ]; + red+=contribution[i].weight*qRed(p); + green+=contribution[i].weight*qGreen(p); + blue+=contribution[i].weight*qBlue(p); + alpha+=contribution[i].weight*qAlpha(p); + } + QRgb pix = qRgba( + fasttolong( red < 0 ? 0 : red > 255 ? 255 : red + 0.5 ), + fasttolong( green < 0 ? 0 : green > 255 ? 255 : green + 0.5 ), + fasttolong( blue < 0 ? 0 : blue > 255 ? 255 : blue + 0.5 ), + fasttolong( alpha < 0 ? 0 : alpha > 255 ? 255 : alpha + 0.5 )); + reinterpret_cast< QRgb* >( destination.jumpTable()[ y ])[ x ] = pix; + } + } +} + +static QImage ResizeImage(const QImage& image,const int columns, + const int rows, Filter filter, fastfloat filtersupport, double blur) +{ + ContributionInfo + *contribution; + + fastfloat + support, + x_factor, + x_support, + y_factor, + y_support; + + /* + Initialize resize image attributes. + */ + if ((columns == image.width()) && (rows == image.height()) && (blur == 1.0)) + return image.copy(); + QImage resize_image( columns, rows, 32 ); + resize_image.setAlphaBuffer( image.hasAlphaBuffer()); + /* + Allocate filter contribution info. + */ + x_factor=(fastfloat) resize_image.width()/image.width(); + y_factor=(fastfloat) resize_image.height()/image.height(); +// i=(long) LanczosFilter; +// if (image->filter != UndefinedFilter) +// i=(long) image->filter; +// else +// if ((image->storage_class == PseudoClass) || image->matte || +// ((x_factor*y_factor) > 1.0)) +// i=(long) MitchellFilter; + x_support=blur*Max(1.0/x_factor,1.0)*filtersupport; + y_support=blur*Max(1.0/y_factor,1.0)*filtersupport; + support=Max(x_support,y_support); + if (support < filtersupport) + support=filtersupport; + contribution=new ContributionInfo[ fasttolong( 2.0*Max(support,0.5)+3 ) ]; + Q_CHECK_PTR( contribution ); + /* + Resize image. + */ + if (((fastfloat) columns*(image.height()+rows)) > + ((fastfloat) rows*(image.width()+columns))) + { + QImage source_image( columns, image.height(), 32 ); + source_image.setAlphaBuffer( image.hasAlphaBuffer()); + HorizontalFilter(image,source_image,x_factor,blur, + contribution,filter,filtersupport); + VerticalFilter(source_image,resize_image,y_factor, + blur,contribution,filter,filtersupport); + } + else + { + QImage source_image( image.width(), rows, 32 ); + source_image.setAlphaBuffer( image.hasAlphaBuffer()); + VerticalFilter(image,source_image,y_factor,blur, + contribution,filter,filtersupport); + HorizontalFilter(source_image,resize_image,x_factor, + blur,contribution,filter,filtersupport); + } + /* + Free allocated memory. + */ + delete[] contribution; + return(resize_image); +} + + +#undef Max +#undef Min +#undef MagickEpsilon + + +// filters and their matching support values +#if 0 + static const FilterInfo + filters[SincFilter+1] = + { + { Box, 0.0 }, + { Box, 0.0 }, + { Box, 0.5 }, + { Triangle, 1.0 }, + { Hermite, 1.0 }, + { Hanning, 1.0 }, + { Hamming, 1.0 }, + { Blackman, 1.0 }, + { Gaussian, 1.25 }, + { Quadratic, 1.5 }, + { Cubic, 2.0 }, + { Catrom, 2.0 }, + { Mitchell, 2.0 }, + { Lanczos, 3.0 }, + { BlackmanBessel, 3.2383 }, + { BlackmanSinc, 4.0 } + }; +#endif + + +/* +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % +% % +% % +% S a m p l e I m a g e % +% % +% % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% SampleImage() scales an image to the desired dimensions with pixel +% sampling. Unlike other scaling methods, this method does not introduce +% any additional color into the scaled image. +% +% The format of the SampleImage method is: +% +% Image *SampleImage(const Image *image,const unsigned long columns, +% const unsigned long rows,ExceptionInfo *exception) +% +% A description of each parameter follows: +% +% o image: The image. +% +% o columns: The number of columns in the sampled image. +% +% o rows: The number of rows in the sampled image. +% +% o exception: Return any errors or warnings in this structure. +% +% +*/ +QImage SampleImage(const QImage& image,const int columns, + const int rows) +{ + int + *x_offset, + *y_offset; + + long + j, + y; + + uchar + *pixels; + + register const uchar + *p; + + register long + x; + + register uchar + *q; + + /* + Initialize sampled image attributes. + */ + if ((columns == image.width()) && (rows == image.height())) + return image; + // This function is modified to handle any image depth, not only + // 32bit like the ImageMagick original. This avoids the relatively + // expensive conversion. + const int d = image.depth() / 8; + QImage sample_image( columns, rows, image.depth()); + sample_image.setAlphaBuffer( image.hasAlphaBuffer()); + /* + Allocate scan line buffer and column offset buffers. + */ + pixels= new uchar[ image.width() * d ]; + x_offset= new int[ sample_image.width() ]; + y_offset= new int[ sample_image.height() ]; + /* + Initialize pixel offsets. + */ +// In the following several code 0.5 needs to be added, otherwise the image +// would be moved by half a pixel to bottom-right, just like +// with Qt's QImage::scale() + for (x=0; x < (long) sample_image.width(); x++) + { + x_offset[x]=int((x+0.5)*image.width()/sample_image.width()); + } + for (y=0; y < (long) sample_image.height(); y++) + { + y_offset[y]=int((y+0.5)*image.height()/sample_image.height()); + } + /* + Sample each row. + */ + j=(-1); + for (y=0; y < (long) sample_image.height(); y++) + { + q= sample_image.scanLine( y ); + if (j != y_offset[y] ) + { + /* + Read a scan line. + */ + j= y_offset[y]; + p= image.scanLine( j ); + (void) memcpy(pixels,p,image.width()*d); + } + /* + Sample each column. + */ + switch( d ) + { + case 1: // 8bit + for (x=0; x < (long) sample_image.width(); x++) + { + *q++=pixels[ x_offset[x] ]; + } + break; + case 4: // 32bit + for (x=0; x < (long) sample_image.width(); x++) + { + *(QRgb*)q=((QRgb*)pixels)[ x_offset[x] ]; + q += d; + } + break; + default: + for (x=0; x < (long) sample_image.width(); x++) + { + memcpy( q, pixels + x_offset[x] * d, d ); + q += d; + } + break; + } + } + if( d != 4 ) // != 32bit + { + sample_image.setNumColors( image.numColors()); + for( int i = 0; i < image.numColors(); ++i ) + sample_image.setColor( i, image.color( i )); + } + delete[] y_offset; + delete[] x_offset; + delete[] pixels; + return sample_image; +} + + +// ImageMagick code end + + +// Imlib2/Mosfet code begin +// ------------------------ + +// This code is Imlib2 code, additionally modified by Mosfet, and with few small +// modifications for Gwenview. The MMX scaling code also belongs to it. + +// The original license texts follow. + +/** + * This is the normal smoothscale method, based on Imlib2's smoothscale. + * + * Originally I took the algorithm used in NetPBM and Qt and added MMX/3dnow + * optimizations. It ran in about 1/2 the time as Qt. Then I ported Imlib's + * C algorithm and it ran at about the same speed as my MMX optimized one... + * Finally I ported Imlib's MMX version and it ran in less than half the + * time as my MMX algorithm, (taking only a quarter of the time Qt does). + * + * Changes include formatting, namespaces and other C++'ings, removal of old + * #ifdef'ed code, and removal of unneeded border calculation code. + * + * Imlib2 is (C) Carsten Haitzler and various contributors. The MMX code + * is by Willem Monsuwe <willem@stack.nl>. All other modifications are + * (C) Daniel M. Duley. + */ + +/* + Copyright (C) 2004 Daniel M. Duley <dan.duley@verizon.net> + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +/* +Copyright (C) 2000 Carsten Haitzler and various contributors (see AUTHORS) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies of the Software and its Copyright notices. In addition publicly +documented acknowledgment must be given that this software has been used if no +source code of this software is made available publicly. This includes +acknowledgments in either Copyright notices, Manuals, Publicity and Marketing +documents or any documentation provided with any product containing this +software. This License does not apply to any software that links to the +libraries provided by this software (statically or dynamically), but only to +the software provided. + +Please see the COPYING.PLAIN for a plain-english explanation of this notice +and it's intent. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +namespace MImageScale{ + typedef struct __mimage_scale_info + { + int *xpoints; + unsigned int **ypoints; + int *xapoints, *yapoints; + int xup_yup; + } MImageScaleInfo; + + unsigned int** mimageCalcYPoints(unsigned int *src, int sow, int sh, + int dh); + int* mimageCalcXPoints(int sw, int dw); + int* mimageCalcApoints(int s, int d, int up); + MImageScaleInfo* mimageFreeScaleInfo(MImageScaleInfo *isi); + MImageScaleInfo *mimageCalcScaleInfo(QImage &img, int sw, int sh, + int dw, int dh, char aa, int sow); + void mimageSampleRGBA(MImageScaleInfo *isi, unsigned int *dest, int dxx, + int dyy, int dx, int dy, int dw, int dh, int dow); + void mimageScaleAARGBA(MImageScaleInfo *isi, unsigned int *dest, int dxx, + int dyy, int dx, int dy, int dw, int dh, int dow, + int sow); + void mimageScaleAARGB(MImageScaleInfo *isi, unsigned int *dest, int dxx, + int dyy, int dx, int dy, int dw, int dh, int dow, int + sow); + QImage smoothScale(const QImage& img, int dw, int dh); +} + +#ifdef HAVE_X86_MMX +extern "C" { + void __mimageScale_mmx_AARGBA(MImageScale::MImageScaleInfo *isi, + unsigned int *dest, int dxx, int dyy, + int dx, int dy, int dw, int dh, + int dow, int sow); +} +#endif + +using namespace MImageScale; + +QImage MImageScale::smoothScale(const QImage& image, int dw, int dh) +{ + QImage img = image.depth() < 32 ? image.convertDepth( 32 ) : image; + int w = img.width(); + int h = img.height(); + + int sow = img.bytesPerLine(); + // handle CroppedQImage + if( img.height() > 1 && sow != img.scanLine( 1 ) - img.scanLine( 0 )) + sow = img.scanLine( 1 ) - img.scanLine( 0 ); + sow = sow / ( img.depth() / 8 ); + + MImageScaleInfo *scaleinfo = + mimageCalcScaleInfo(img, w, h, dw, dh, true, sow); + if(!scaleinfo) + return QImage(); + + QImage buffer(dw, dh, 32); + buffer.setAlphaBuffer(img.hasAlphaBuffer()); + +#ifdef HAVE_X86_MMX +//#warning Using MMX Smoothscale + bool haveMMX = KCPUInfo::haveExtension( KCPUInfo::IntelMMX ); + if(haveMMX){ + __mimageScale_mmx_AARGBA(scaleinfo, (unsigned int *)buffer.scanLine(0), + 0, 0, 0, 0, dw, dh, dw, sow); + } + else +#endif + { + if(img.hasAlphaBuffer()) + mimageScaleAARGBA(scaleinfo, (unsigned int *)buffer.scanLine(0), 0, 0, + 0, 0, dw, dh, dw, sow); + else + mimageScaleAARGB(scaleinfo, (unsigned int *)buffer.scanLine(0), 0, 0, + 0, 0, dw, dh, dw, sow); + } + mimageFreeScaleInfo(scaleinfo); + return(buffer); +} + +// +// Code ported from Imlib... +// + +// FIXME: replace with mRed, etc... These work on pointers to pixels, not +// pixel values +#if BYTE_ORDER == BIG_ENDIAN +#define A_VAL(p) ((unsigned char *)(p))[0] +#define R_VAL(p) ((unsigned char *)(p))[1] +#define G_VAL(p) ((unsigned char *)(p))[2] +#define B_VAL(p) ((unsigned char *)(p))[3] +#elif BYTE_ORDER == LITTLE_ENDIAN +#define A_VAL(p) ((unsigned char *)(p))[3] +#define R_VAL(p) ((unsigned char *)(p))[2] +#define G_VAL(p) ((unsigned char *)(p))[1] +#define B_VAL(p) ((unsigned char *)(p))[0] +#else +#error "BYTE_ORDER is not defined" +#endif + +#define INV_XAP (256 - xapoints[x]) +#define XAP (xapoints[x]) +#define INV_YAP (256 - yapoints[dyy + y]) +#define YAP (yapoints[dyy + y]) + +unsigned int** MImageScale::mimageCalcYPoints(unsigned int *src, + int sow, int sh, int dh) +{ + unsigned int **p; + int i, j = 0; + int val, inc, rv = 0; + + if(dh < 0){ + dh = -dh; + rv = 1; + } + p = new unsigned int* [dh+1]; + + val = 0; + inc = (sh << 16) / dh; + for(i = 0; i < dh; i++){ + p[j++] = src + ((val >> 16) * sow); + val += inc; + } + if(rv){ + for(i = dh / 2; --i >= 0; ){ + unsigned int *tmp = p[i]; + p[i] = p[dh - i - 1]; + p[dh - i - 1] = tmp; + } + } + return(p); +} + +int* MImageScale::mimageCalcXPoints(int sw, int dw) +{ + int *p, i, j = 0; + int val, inc, rv = 0; + + if(dw < 0){ + dw = -dw; + rv = 1; + } + p = new int[dw+1]; + + val = 0; + inc = (sw << 16) / dw; + for(i = 0; i < dw; i++){ + p[j++] = (val >> 16); + val += inc; + } + + if(rv){ + for(i = dw / 2; --i >= 0; ){ + int tmp = p[i]; + p[i] = p[dw - i - 1]; + p[dw - i - 1] = tmp; + } + } + return(p); +} + +int* MImageScale::mimageCalcApoints(int s, int d, int up) +{ + int *p, i, j = 0, rv = 0; + + if(d < 0){ + rv = 1; + d = -d; + } + p = new int[d]; + + /* scaling up */ + if(up){ + int val, inc; + + val = 0; + inc = (s << 16) / d; + for(i = 0; i < d; i++){ + p[j++] = (val >> 8) - ((val >> 8) & 0xffffff00); + if((val >> 16) >= (s - 1)) + p[j - 1] = 0; + val += inc; + } + } + /* scaling down */ + else{ + int val, inc, ap, Cp; + val = 0; + inc = (s << 16) / d; + Cp = ((d << 14) / s) + 1; + for(i = 0; i < d; i++){ + ap = ((0x100 - ((val >> 8) & 0xff)) * Cp) >> 8; + p[j] = ap | (Cp << 16); + j++; + val += inc; + } + } + if(rv){ + int tmp; + for(i = d / 2; --i >= 0; ){ + tmp = p[i]; + p[i] = p[d - i - 1]; + p[d - i - 1] = tmp; + } + } + return(p); +} + +MImageScaleInfo* MImageScale::mimageFreeScaleInfo(MImageScaleInfo *isi) +{ + if(isi){ + delete[] isi->xpoints; + delete[] isi->ypoints; + delete[] isi->xapoints; + delete[] isi->yapoints; + delete isi; + } + return(NULL); +} + +MImageScaleInfo* MImageScale::mimageCalcScaleInfo(QImage &img, int sw, int sh, + int dw, int dh, char aa, int sow) +{ + MImageScaleInfo *isi; + int scw, sch; + + scw = dw * img.width() / sw; + sch = dh * img.height() / sh; + + isi = new MImageScaleInfo; + if(!isi) + return(NULL); + memset(isi, 0, sizeof(MImageScaleInfo)); + + isi->xup_yup = (abs(dw) >= sw) + ((abs(dh) >= sh) << 1); + + isi->xpoints = mimageCalcXPoints(img.width(), scw); + if(!isi->xpoints) + return(mimageFreeScaleInfo(isi)); + isi->ypoints = mimageCalcYPoints((unsigned int *)img.scanLine(0), + sow, img.height(), sch ); + if (!isi->ypoints) + return(mimageFreeScaleInfo(isi)); + if(aa){ + isi->xapoints = mimageCalcApoints(img.width(), scw, isi->xup_yup & 1); + if(!isi->xapoints) + return(mimageFreeScaleInfo(isi)); + isi->yapoints = mimageCalcApoints(img.height(), sch, isi->xup_yup & 2); + if(!isi->yapoints) + return(mimageFreeScaleInfo(isi)); + } + return(isi); +} + +/* scale by pixel sampling only */ +void MImageScale::mimageSampleRGBA(MImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, int dw, + int dh, int dow) +{ + unsigned int *sptr, *dptr; + int x, y, end; + unsigned int **ypoints = isi->ypoints; + int *xpoints = isi->xpoints; + + /* whats the last pixel ont he line so we stop there */ + end = dxx + dw; + /* go through every scanline in the output buffer */ + for(y = 0; y < dh; y++){ + /* get the pointer to the start of the destination scanline */ + dptr = dest + dx + ((y + dy) * dow); + /* calculate the source line we'll scan from */ + sptr = ypoints[dyy + y]; + /* go thru the scanline and copy across */ + for(x = dxx; x < end; x++) + *dptr++ = sptr[xpoints[x]]; + } +} + +/* FIXME: NEED to optimise ScaleAARGBA - currently its "ok" but needs work*/ + +/* scale by area sampling */ +void MImageScale::mimageScaleAARGBA(MImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, int dw, + int dh, int dow, int sow) +{ + unsigned int *sptr, *dptr; + int x, y, end; + unsigned int **ypoints = isi->ypoints; + int *xpoints = isi->xpoints; + int *xapoints = isi->xapoints; + int *yapoints = isi->yapoints; + + end = dxx + dw; + /* scaling up both ways */ + if(isi->xup_yup == 3){ + /* go through every scanline in the output buffer */ + for(y = 0; y < dh; y++){ + /* calculate the source line we'll scan from */ + dptr = dest + dx + ((y + dy) * dow); + sptr = ypoints[dyy + y]; + if(YAP > 0){ + for(x = dxx; x < end; x++){ + int r, g, b, a; + int rr, gg, bb, aa; + unsigned int *pix; + + if(XAP > 0){ + pix = ypoints[dyy + y] + xpoints[x]; + r = R_VAL(pix) * INV_XAP; + g = G_VAL(pix) * INV_XAP; + b = B_VAL(pix) * INV_XAP; + a = A_VAL(pix) * INV_XAP; + pix++; + r += R_VAL(pix) * XAP; + g += G_VAL(pix) * XAP; + b += B_VAL(pix) * XAP; + a += A_VAL(pix) * XAP; + pix += sow; + rr = R_VAL(pix) * XAP; + gg = G_VAL(pix) * XAP; + bb = B_VAL(pix) * XAP; + aa = A_VAL(pix) * XAP; + pix--; + rr += R_VAL(pix) * INV_XAP; + gg += G_VAL(pix) * INV_XAP; + bb += B_VAL(pix) * INV_XAP; + aa += A_VAL(pix) * INV_XAP; + r = ((rr * YAP) + (r * INV_YAP)) >> 16; + g = ((gg * YAP) + (g * INV_YAP)) >> 16; + b = ((bb * YAP) + (b * INV_YAP)) >> 16; + a = ((aa * YAP) + (a * INV_YAP)) >> 16; + *dptr++ = qRgba(r, g, b, a); + } + else{ + pix = ypoints[dyy + y] + xpoints[x]; + r = R_VAL(pix) * INV_YAP; + g = G_VAL(pix) * INV_YAP; + b = B_VAL(pix) * INV_YAP; + a = A_VAL(pix) * INV_YAP; + pix += sow; + r += R_VAL(pix) * YAP; + g += G_VAL(pix) * YAP; + b += B_VAL(pix) * YAP; + a += A_VAL(pix) * YAP; + r >>= 8; + g >>= 8; + b >>= 8; + a >>= 8; + *dptr++ = qRgba(r, g, b, a); + } + } + } + else{ + for(x = dxx; x < end; x++){ + int r, g, b, a; + unsigned int *pix; + + if(XAP > 0){ + pix = ypoints[dyy + y] + xpoints[x]; + r = R_VAL(pix) * INV_XAP; + g = G_VAL(pix) * INV_XAP; + b = B_VAL(pix) * INV_XAP; + a = A_VAL(pix) * INV_XAP; + pix++; + r += R_VAL(pix) * XAP; + g += G_VAL(pix) * XAP; + b += B_VAL(pix) * XAP; + a += A_VAL(pix) * XAP; + r >>= 8; + g >>= 8; + b >>= 8; + a >>= 8; + *dptr++ = qRgba(r, g, b, a); + } + else + *dptr++ = sptr[xpoints[x] ]; + } + } + } + } + /* if we're scaling down vertically */ + else if(isi->xup_yup == 1){ + /*\ 'Correct' version, with math units prepared for MMXification \*/ + int Cy, j; + unsigned int *pix; + int r, g, b, a, rr, gg, bb, aa; + int yap; + + /* go through every scanline in the output buffer */ + for(y = 0; y < dh; y++){ + Cy = YAP >> 16; + yap = YAP & 0xffff; + + dptr = dest + dx + ((y + dy) * dow); + for(x = dxx; x < end; x++){ + pix = ypoints[dyy + y] + xpoints[x]; + r = (R_VAL(pix) * yap) >> 10; + g = (G_VAL(pix) * yap) >> 10; + b = (B_VAL(pix) * yap) >> 10; + a = (A_VAL(pix) * yap) >> 10; + for(j = (1 << 14) - yap; j > Cy; j -= Cy){ + pix += sow; + r += (R_VAL(pix) * Cy) >> 10; + g += (G_VAL(pix) * Cy) >> 10; + b += (B_VAL(pix) * Cy) >> 10; + a += (A_VAL(pix) * Cy) >> 10; + } + if(j > 0){ + pix += sow; + r += (R_VAL(pix) * j) >> 10; + g += (G_VAL(pix) * j) >> 10; + b += (B_VAL(pix) * j) >> 10; + a += (A_VAL(pix) * j) >> 10; + } + if(XAP > 0){ + pix = ypoints[dyy + y] + xpoints[x] + 1; + rr = (R_VAL(pix) * yap) >> 10; + gg = (G_VAL(pix) * yap) >> 10; + bb = (B_VAL(pix) * yap) >> 10; + aa = (A_VAL(pix) * yap) >> 10; + for(j = (1 << 14) - yap; j > Cy; j -= Cy){ + pix += sow; + rr += (R_VAL(pix) * Cy) >> 10; + gg += (G_VAL(pix) * Cy) >> 10; + bb += (B_VAL(pix) * Cy) >> 10; + aa += (A_VAL(pix) * Cy) >> 10; + } + if(j > 0){ + pix += sow; + rr += (R_VAL(pix) * j) >> 10; + gg += (G_VAL(pix) * j) >> 10; + bb += (B_VAL(pix) * j) >> 10; + aa += (A_VAL(pix) * j) >> 10; + } + r = r * INV_XAP; + g = g * INV_XAP; + b = b * INV_XAP; + a = a * INV_XAP; + r = (r + ((rr * XAP))) >> 12; + g = (g + ((gg * XAP))) >> 12; + b = (b + ((bb * XAP))) >> 12; + a = (a + ((aa * XAP))) >> 12; + } + else{ + r >>= 4; + g >>= 4; + b >>= 4; + a >>= 4; + } + *dptr = qRgba(r, g, b, a); + dptr++; + } + } + } + /* if we're scaling down horizontally */ + else if(isi->xup_yup == 2){ + /*\ 'Correct' version, with math units prepared for MMXification \*/ + int Cx, j; + unsigned int *pix; + int r, g, b, a, rr, gg, bb, aa; + int xap; + + /* go through every scanline in the output buffer */ + for(y = 0; y < dh; y++){ + dptr = dest + dx + ((y + dy) * dow); + for(x = dxx; x < end; x++){ + Cx = XAP >> 16; + xap = XAP & 0xffff; + + pix = ypoints[dyy + y] + xpoints[x]; + r = (R_VAL(pix) * xap) >> 10; + g = (G_VAL(pix) * xap) >> 10; + b = (B_VAL(pix) * xap) >> 10; + a = (A_VAL(pix) * xap) >> 10; + for(j = (1 << 14) - xap; j > Cx; j -= Cx){ + pix++; + r += (R_VAL(pix) * Cx) >> 10; + g += (G_VAL(pix) * Cx) >> 10; + b += (B_VAL(pix) * Cx) >> 10; + a += (A_VAL(pix) * Cx) >> 10; + } + if(j > 0){ + pix++; + r += (R_VAL(pix) * j) >> 10; + g += (G_VAL(pix) * j) >> 10; + b += (B_VAL(pix) * j) >> 10; + a += (A_VAL(pix) * j) >> 10; + } + if(YAP > 0){ + pix = ypoints[dyy + y] + xpoints[x] + sow; + rr = (R_VAL(pix) * xap) >> 10; + gg = (G_VAL(pix) * xap) >> 10; + bb = (B_VAL(pix) * xap) >> 10; + aa = (A_VAL(pix) * xap) >> 10; + for(j = (1 << 14) - xap; j > Cx; j -= Cx){ + pix++; + rr += (R_VAL(pix) * Cx) >> 10; + gg += (G_VAL(pix) * Cx) >> 10; + bb += (B_VAL(pix) * Cx) >> 10; + aa += (A_VAL(pix) * Cx) >> 10; + } + if(j > 0){ + pix++; + rr += (R_VAL(pix) * j) >> 10; + gg += (G_VAL(pix) * j) >> 10; + bb += (B_VAL(pix) * j) >> 10; + aa += (A_VAL(pix) * j) >> 10; + } + r = r * INV_YAP; + g = g * INV_YAP; + b = b * INV_YAP; + a = a * INV_YAP; + r = (r + ((rr * YAP))) >> 12; + g = (g + ((gg * YAP))) >> 12; + b = (b + ((bb * YAP))) >> 12; + a = (a + ((aa * YAP))) >> 12; + } + else{ + r >>= 4; + g >>= 4; + b >>= 4; + a >>= 4; + } + *dptr = qRgba(r, g, b, a); + dptr++; + } + } + } + /* if we're scaling down horizontally & vertically */ + else{ + /*\ 'Correct' version, with math units prepared for MMXification: + |*| The operation 'b = (b * c) >> 16' translates to pmulhw, + |*| so the operation 'b = (b * c) >> d' would translate to + |*| psllw (16 - d), %mmb; pmulh %mmc, %mmb + \*/ + int Cx, Cy, i, j; + unsigned int *pix; + int a, r, g, b, ax, rx, gx, bx; + int xap, yap; + + for(y = 0; y < dh; y++){ + Cy = YAP >> 16; + yap = YAP & 0xffff; + + dptr = dest + dx + ((y + dy) * dow); + for(x = dxx; x < end; x++){ + Cx = XAP >> 16; + xap = XAP & 0xffff; + + sptr = ypoints[dyy + y] + xpoints[x]; + pix = sptr; + sptr += sow; + rx = (R_VAL(pix) * xap) >> 9; + gx = (G_VAL(pix) * xap) >> 9; + bx = (B_VAL(pix) * xap) >> 9; + ax = (A_VAL(pix) * xap) >> 9; + pix++; + for(i = (1 << 14) - xap; i > Cx; i -= Cx){ + rx += (R_VAL(pix) * Cx) >> 9; + gx += (G_VAL(pix) * Cx) >> 9; + bx += (B_VAL(pix) * Cx) >> 9; + ax += (A_VAL(pix) * Cx) >> 9; + pix++; + } + if(i > 0){ + rx += (R_VAL(pix) * i) >> 9; + gx += (G_VAL(pix) * i) >> 9; + bx += (B_VAL(pix) * i) >> 9; + ax += (A_VAL(pix) * i) >> 9; + } + + r = (rx * yap) >> 14; + g = (gx * yap) >> 14; + b = (bx * yap) >> 14; + a = (ax * yap) >> 14; + + for(j = (1 << 14) - yap; j > Cy; j -= Cy){ + pix = sptr; + sptr += sow; + rx = (R_VAL(pix) * xap) >> 9; + gx = (G_VAL(pix) * xap) >> 9; + bx = (B_VAL(pix) * xap) >> 9; + ax = (A_VAL(pix) * xap) >> 9; + pix++; + for(i = (1 << 14) - xap; i > Cx; i -= Cx){ + rx += (R_VAL(pix) * Cx) >> 9; + gx += (G_VAL(pix) * Cx) >> 9; + bx += (B_VAL(pix) * Cx) >> 9; + ax += (A_VAL(pix) * Cx) >> 9; + pix++; + } + if(i > 0){ + rx += (R_VAL(pix) * i) >> 9; + gx += (G_VAL(pix) * i) >> 9; + bx += (B_VAL(pix) * i) >> 9; + ax += (A_VAL(pix) * i) >> 9; + } + + r += (rx * Cy) >> 14; + g += (gx * Cy) >> 14; + b += (bx * Cy) >> 14; + a += (ax * Cy) >> 14; + } + if(j > 0){ + pix = sptr; + sptr += sow; + rx = (R_VAL(pix) * xap) >> 9; + gx = (G_VAL(pix) * xap) >> 9; + bx = (B_VAL(pix) * xap) >> 9; + ax = (A_VAL(pix) * xap) >> 9; + pix++; + for(i = (1 << 14) - xap; i > Cx; i -= Cx){ + rx += (R_VAL(pix) * Cx) >> 9; + gx += (G_VAL(pix) * Cx) >> 9; + bx += (B_VAL(pix) * Cx) >> 9; + ax += (A_VAL(pix) * Cx) >> 9; + pix++; + } + if(i > 0){ + rx += (R_VAL(pix) * i) >> 9; + gx += (G_VAL(pix) * i) >> 9; + bx += (B_VAL(pix) * i) >> 9; + ax += (A_VAL(pix) * i) >> 9; + } + + r += (rx * j) >> 14; + g += (gx * j) >> 14; + b += (bx * j) >> 14; + a += (ax * j) >> 14; + } + + R_VAL(dptr) = r >> 5; + G_VAL(dptr) = g >> 5; + B_VAL(dptr) = b >> 5; + A_VAL(dptr) = a >> 5; + dptr++; + } + } + } +} + +/* scale by area sampling - IGNORE the ALPHA byte*/ +void MImageScale::mimageScaleAARGB(MImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, int dw, + int dh, int dow, int sow) +{ + unsigned int *sptr, *dptr; + int x, y, end; + unsigned int **ypoints = isi->ypoints; + int *xpoints = isi->xpoints; + int *xapoints = isi->xapoints; + int *yapoints = isi->yapoints; + + end = dxx + dw; + /* scaling up both ways */ + if(isi->xup_yup == 3){ + /* go through every scanline in the output buffer */ + for(y = 0; y < dh; y++){ + /* calculate the source line we'll scan from */ + dptr = dest + dx + ((y + dy) * dow); + sptr = ypoints[dyy + y]; + if(YAP > 0){ + for(x = dxx; x < end; x++){ + int r = 0, g = 0, b = 0; + int rr = 0, gg = 0, bb = 0; + unsigned int *pix; + + if(XAP > 0){ + pix = ypoints[dyy + y] + xpoints[x]; + r = R_VAL(pix) * INV_XAP; + g = G_VAL(pix) * INV_XAP; + b = B_VAL(pix) * INV_XAP; + pix++; + r += R_VAL(pix) * XAP; + g += G_VAL(pix) * XAP; + b += B_VAL(pix) * XAP; + pix += sow; + rr = R_VAL(pix) * XAP; + gg = G_VAL(pix) * XAP; + bb = B_VAL(pix) * XAP; + pix --; + rr += R_VAL(pix) * INV_XAP; + gg += G_VAL(pix) * INV_XAP; + bb += B_VAL(pix) * INV_XAP; + r = ((rr * YAP) + (r * INV_YAP)) >> 16; + g = ((gg * YAP) + (g * INV_YAP)) >> 16; + b = ((bb * YAP) + (b * INV_YAP)) >> 16; + *dptr++ = qRgba(r, g, b, 0xff); + } + else{ + pix = ypoints[dyy + y] + xpoints[x]; + r = R_VAL(pix) * INV_YAP; + g = G_VAL(pix) * INV_YAP; + b = B_VAL(pix) * INV_YAP; + pix += sow; + r += R_VAL(pix) * YAP; + g += G_VAL(pix) * YAP; + b += B_VAL(pix) * YAP; + r >>= 8; + g >>= 8; + b >>= 8; + *dptr++ = qRgba(r, g, b, 0xff); + } + } + } + else{ + for(x = dxx; x < end; x++){ + int r = 0, g = 0, b = 0; + unsigned int *pix; + + if(XAP > 0){ + pix = ypoints[dyy + y] + xpoints[x]; + r = R_VAL(pix) * INV_XAP; + g = G_VAL(pix) * INV_XAP; + b = B_VAL(pix) * INV_XAP; + pix++; + r += R_VAL(pix) * XAP; + g += G_VAL(pix) * XAP; + b += B_VAL(pix) * XAP; + r >>= 8; + g >>= 8; + b >>= 8; + *dptr++ = qRgba(r, g, b, 0xff); + } + else + *dptr++ = sptr[xpoints[x] ]; + } + } + } + } + /* if we're scaling down vertically */ + else if(isi->xup_yup == 1){ + /*\ 'Correct' version, with math units prepared for MMXification \*/ + int Cy, j; + unsigned int *pix; + int r, g, b, rr, gg, bb; + int yap; + + /* go through every scanline in the output buffer */ + for(y = 0; y < dh; y++){ + Cy = YAP >> 16; + yap = YAP & 0xffff; + + dptr = dest + dx + ((y + dy) * dow); + for(x = dxx; x < end; x++){ + pix = ypoints[dyy + y] + xpoints[x]; + r = (R_VAL(pix) * yap) >> 10; + g = (G_VAL(pix) * yap) >> 10; + b = (B_VAL(pix) * yap) >> 10; + pix += sow; + for(j = (1 << 14) - yap; j > Cy; j -= Cy){ + r += (R_VAL(pix) * Cy) >> 10; + g += (G_VAL(pix) * Cy) >> 10; + b += (B_VAL(pix) * Cy) >> 10; + pix += sow; + } + if(j > 0){ + r += (R_VAL(pix) * j) >> 10; + g += (G_VAL(pix) * j) >> 10; + b += (B_VAL(pix) * j) >> 10; + } + if(XAP > 0){ + pix = ypoints[dyy + y] + xpoints[x] + 1; + rr = (R_VAL(pix) * yap) >> 10; + gg = (G_VAL(pix) * yap) >> 10; + bb = (B_VAL(pix) * yap) >> 10; + pix += sow; + for(j = (1 << 14) - yap; j > Cy; j -= Cy){ + rr += (R_VAL(pix) * Cy) >> 10; + gg += (G_VAL(pix) * Cy) >> 10; + bb += (B_VAL(pix) * Cy) >> 10; + pix += sow; + } + if(j > 0){ + rr += (R_VAL(pix) * j) >> 10; + gg += (G_VAL(pix) * j) >> 10; + bb += (B_VAL(pix) * j) >> 10; + } + r = r * INV_XAP; + g = g * INV_XAP; + b = b * INV_XAP; + r = (r + ((rr * XAP))) >> 12; + g = (g + ((gg * XAP))) >> 12; + b = (b + ((bb * XAP))) >> 12; + } + else{ + r >>= 4; + g >>= 4; + b >>= 4; + } + *dptr = qRgba(r, g, b, 0xff); + dptr++; + } + } + } + /* if we're scaling down horizontally */ + else if(isi->xup_yup == 2){ + /*\ 'Correct' version, with math units prepared for MMXification \*/ + int Cx, j; + unsigned int *pix; + int r, g, b, rr, gg, bb; + int xap; + + /* go through every scanline in the output buffer */ + for(y = 0; y < dh; y++){ + dptr = dest + dx + ((y + dy) * dow); + for(x = dxx; x < end; x++){ + Cx = XAP >> 16; + xap = XAP & 0xffff; + + pix = ypoints[dyy + y] + xpoints[x]; + r = (R_VAL(pix) * xap) >> 10; + g = (G_VAL(pix) * xap) >> 10; + b = (B_VAL(pix) * xap) >> 10; + pix++; + for(j = (1 << 14) - xap; j > Cx; j -= Cx){ + r += (R_VAL(pix) * Cx) >> 10; + g += (G_VAL(pix) * Cx) >> 10; + b += (B_VAL(pix) * Cx) >> 10; + pix++; + } + if(j > 0){ + r += (R_VAL(pix) * j) >> 10; + g += (G_VAL(pix) * j) >> 10; + b += (B_VAL(pix) * j) >> 10; + } + if(YAP > 0){ + pix = ypoints[dyy + y] + xpoints[x] + sow; + rr = (R_VAL(pix) * xap) >> 10; + gg = (G_VAL(pix) * xap) >> 10; + bb = (B_VAL(pix) * xap) >> 10; + pix++; + for(j = (1 << 14) - xap; j > Cx; j -= Cx){ + rr += (R_VAL(pix) * Cx) >> 10; + gg += (G_VAL(pix) * Cx) >> 10; + bb += (B_VAL(pix) * Cx) >> 10; + pix++; + } + if(j > 0){ + rr += (R_VAL(pix) * j) >> 10; + gg += (G_VAL(pix) * j) >> 10; + bb += (B_VAL(pix) * j) >> 10; + } + r = r * INV_YAP; + g = g * INV_YAP; + b = b * INV_YAP; + r = (r + ((rr * YAP))) >> 12; + g = (g + ((gg * YAP))) >> 12; + b = (b + ((bb * YAP))) >> 12; + } + else{ + r >>= 4; + g >>= 4; + b >>= 4; + } + *dptr = qRgba(r, g, b, 0xff); + dptr++; + } + } + } + /* fully optimized (i think) - onyl change of algorithm can help */ + /* if we're scaling down horizontally & vertically */ + else{ + /*\ 'Correct' version, with math units prepared for MMXification \*/ + int Cx, Cy, i, j; + unsigned int *pix; + int r, g, b, rx, gx, bx; + int xap, yap; + + for(y = 0; y < dh; y++){ + Cy = YAP >> 16; + yap = YAP & 0xffff; + + dptr = dest + dx + ((y + dy) * dow); + for(x = dxx; x < end; x++){ + Cx = XAP >> 16; + xap = XAP & 0xffff; + + sptr = ypoints[dyy + y] + xpoints[x]; + pix = sptr; + sptr += sow; + rx = (R_VAL(pix) * xap) >> 9; + gx = (G_VAL(pix) * xap) >> 9; + bx = (B_VAL(pix) * xap) >> 9; + pix++; + for(i = (1 << 14) - xap; i > Cx; i -= Cx){ + rx += (R_VAL(pix) * Cx) >> 9; + gx += (G_VAL(pix) * Cx) >> 9; + bx += (B_VAL(pix) * Cx) >> 9; + pix++; + } + if(i > 0){ + rx += (R_VAL(pix) * i) >> 9; + gx += (G_VAL(pix) * i) >> 9; + bx += (B_VAL(pix) * i) >> 9; + } + + r = (rx * yap) >> 14; + g = (gx * yap) >> 14; + b = (bx * yap) >> 14; + + for(j = (1 << 14) - yap; j > Cy; j -= Cy){ + pix = sptr; + sptr += sow; + rx = (R_VAL(pix) * xap) >> 9; + gx = (G_VAL(pix) * xap) >> 9; + bx = (B_VAL(pix) * xap) >> 9; + pix++; + for(i = (1 << 14) - xap; i > Cx; i -= Cx){ + rx += (R_VAL(pix) * Cx) >> 9; + gx += (G_VAL(pix) * Cx) >> 9; + bx += (B_VAL(pix) * Cx) >> 9; + pix++; + } + if(i > 0){ + rx += (R_VAL(pix) * i) >> 9; + gx += (G_VAL(pix) * i) >> 9; + bx += (B_VAL(pix) * i) >> 9; + } + + r += (rx * Cy) >> 14; + g += (gx * Cy) >> 14; + b += (bx * Cy) >> 14; + } + if(j > 0){ + pix = sptr; + sptr += sow; + rx = (R_VAL(pix) * xap) >> 9; + gx = (G_VAL(pix) * xap) >> 9; + bx = (B_VAL(pix) * xap) >> 9; + pix++; + for(i = (1 << 14) - xap; i > Cx; i -= Cx){ + rx += (R_VAL(pix) * Cx) >> 9; + gx += (G_VAL(pix) * Cx) >> 9; + bx += (B_VAL(pix) * Cx) >> 9; + pix++; + } + if(i > 0){ + rx += (R_VAL(pix) * i) >> 9; + gx += (G_VAL(pix) * i) >> 9; + bx += (B_VAL(pix) * i) >> 9; + } + + r += (rx * j) >> 14; + g += (gx * j) >> 14; + b += (bx * j) >> 14; + } + + R_VAL(dptr) = r >> 5; + G_VAL(dptr) = g >> 5; + B_VAL(dptr) = b >> 5; + dptr++; + } + } + } +} + +// Imlib2/Mosfet code end + + +// public functions : +// ------------------ + +// This function returns how many pixels around the zoomed area should be +// included in the image. This is used when doing incremental painting, because +// some smoothing algorithms use surrounding pixels and not including them +// could sometimes make the edges between incremental steps visible. +// int extraScalePixels( SmoothAlgorithm alg, double zoom, double blur ) +// { +// double filtersupport = 0; +// Filter filter = NULL; +// switch( alg ) { +// case SMOOTH_NONE: +// filter = NULL; +// filtersupport = 0.0; +// break; +// case SMOOTH_FAST: +// filter = Box; +// filtersupport = 0.5; +// break; +// case SMOOTH_NORMAL: +// filter = Triangle; +// filtersupport = 1.0; +// break; +// case SMOOTH_BEST: +// // filter = Mitchell; +// filter = Bicubic; +// filtersupport = 2.0; +// break; +// } +// if( zoom == 1.0 || filtersupport == 0.0 ) return 0; +// // Imlib2/Mosfet scale - I have really no idea how many pixels it needs +// if( filter == Box && blur == 1.0 ) return int( 3 / zoom + 1 ); +// // This is support size for ImageMagick's scaling. +// double scale=blur*QMAX(1.0/zoom,1.0); +// double support=scale* filtersupport; +// if (support <= 0.5) support=0.5+0.000001; +// return int( support + 1 ); +// } + +QImage scale(const QImage& image, int width, int height, + SmoothAlgorithm alg, QImage::ScaleMode mode, double blur ) +{ + if( image.isNull()) return image.copy(); + + QSize newSize( image.size() ); + newSize.scale( QSize( width, height ), (QSize::ScaleMode)mode ); // ### remove cast in Qt 4.0 + newSize = newSize.expandedTo( QSize( 1, 1 )); // make sure it doesn't become null + + if ( newSize == image.size() ) return image.copy(); + + width = newSize.width(); + height = newSize.height(); + Filter filter = NULL; + fastfloat filtersupport; + + switch( alg ) { + case SMOOTH_NONE: + filter = NULL; + filtersupport = 0.0; + break; + case SMOOTH_FAST: + filter = Box; + filtersupport = 0.5; + break; + case SMOOTH_NORMAL: + default: + filter = Triangle; + filtersupport = 1.0; + break; + case SMOOTH_BEST: +// filter = Mitchell; + filter = Bicubic; + filtersupport = 2.0; + break; + } + + if( filter == Box && blur == 1.0 ) + return MImageScale::smoothScale( image, width, height ); + + if( filter == Box && width > image.width() && height > image.height() && blur == 1.0 ) { + filter = NULL; // Box doesn't really smooth when enlarging + } + + if( filter == NULL ) { + return SampleImage( image, width, height ); // doesn't need 32bit + } + + return ResizeImage( image.convertDepth( 32 ), width, height, filter, filtersupport, blur ); + // unlike Qt's smoothScale() this function introduces new colors to grayscale images ... oh well +} + + +} // namespace diff --git a/src/fastscale/scale.h b/src/fastscale/scale.h new file mode 100644 index 0000000..299ac16 --- /dev/null +++ b/src/fastscale/scale.h @@ -0,0 +1,34 @@ +// vim: set tabstop=4 shiftwidth=4 noexpandtab +/* +Gwenview - A simple image viewer for KDE +Copyright 2000-2004 Aurlien Gteau + + 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 2 + 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, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ +#ifndef FAST_SCALE_H +#define FAST_SCALE_H + +// Qt +#include <qimage.h> + +namespace ImageUtils { + enum SmoothAlgorithm { SMOOTH_NONE, SMOOTH_FAST, SMOOTH_NORMAL, SMOOTH_BEST }; + + QImage scale(const QImage& image, int width, int height, + SmoothAlgorithm alg, QImage::ScaleMode mode = QImage::ScaleFree, double blur = 1.0); +} + +#endif diff --git a/src/icons/Makefile.am b/src/icons/Makefile.am new file mode 100644 index 0000000..c7abccf --- /dev/null +++ b/src/icons/Makefile.am @@ -0,0 +1,2 @@ +KDE_ICON = AUTO +SUBDIRS = actions diff --git a/src/icons/actions/Makefile.am b/src/icons/actions/Makefile.am new file mode 100644 index 0000000..a8f669e --- /dev/null +++ b/src/icons/actions/Makefile.am @@ -0,0 +1,2 @@ +k3bicondir = $(kde_datadir)/k3b/icons +k3bicon_ICON = AUTO diff --git a/src/icons/actions/cr16-action-greenled.png b/src/icons/actions/cr16-action-greenled.png new file mode 100644 index 0000000..bf2a36c Binary files /dev/null and b/src/icons/actions/cr16-action-greenled.png differ diff --git a/src/icons/actions/cr16-action-redled.png b/src/icons/actions/cr16-action-redled.png new file mode 100644 index 0000000..04db8ff Binary files /dev/null and b/src/icons/actions/cr16-action-redled.png differ diff --git a/src/icons/actions/cr16-action-yellowinfo.png b/src/icons/actions/cr16-action-yellowinfo.png new file mode 100644 index 0000000..5a464f3 Binary files /dev/null and b/src/icons/actions/cr16-action-yellowinfo.png differ diff --git a/src/icons/actions/cr16-action-yellowled.png b/src/icons/actions/cr16-action-yellowled.png new file mode 100644 index 0000000..a0e8f87 Binary files /dev/null and b/src/icons/actions/cr16-action-yellowled.png differ diff --git a/src/icons/actions/hi16-action-audiocd.png b/src/icons/actions/hi16-action-audiocd.png new file mode 100644 index 0000000..d452cdc Binary files /dev/null and b/src/icons/actions/hi16-action-audiocd.png differ diff --git a/src/icons/actions/hi16-action-burn_cdimage.png b/src/icons/actions/hi16-action-burn_cdimage.png new file mode 100644 index 0000000..b9821b3 Binary files /dev/null and b/src/icons/actions/hi16-action-burn_cdimage.png differ diff --git a/src/icons/actions/hi16-action-burn_dvdimage.png b/src/icons/actions/hi16-action-burn_dvdimage.png new file mode 100644 index 0000000..28a8fbc Binary files /dev/null and b/src/icons/actions/hi16-action-burn_dvdimage.png differ diff --git a/src/icons/actions/hi16-action-cdburn.png b/src/icons/actions/hi16-action-cdburn.png new file mode 100644 index 0000000..4e1e406 Binary files /dev/null and b/src/icons/actions/hi16-action-cdburn.png differ diff --git a/src/icons/actions/hi16-action-cdcopy.png b/src/icons/actions/hi16-action-cdcopy.png new file mode 100644 index 0000000..49a7505 Binary files /dev/null and b/src/icons/actions/hi16-action-cdcopy.png differ diff --git a/src/icons/actions/hi16-action-cddarip.png b/src/icons/actions/hi16-action-cddarip.png new file mode 100644 index 0000000..ab28c17 Binary files /dev/null and b/src/icons/actions/hi16-action-cddarip.png differ diff --git a/src/icons/actions/hi16-action-datacd.png b/src/icons/actions/hi16-action-datacd.png new file mode 100644 index 0000000..a0cd3a7 Binary files /dev/null and b/src/icons/actions/hi16-action-datacd.png differ diff --git a/src/icons/actions/hi16-action-datadvd.png b/src/icons/actions/hi16-action-datadvd.png new file mode 100644 index 0000000..78fa410 Binary files /dev/null and b/src/icons/actions/hi16-action-datadvd.png differ diff --git a/src/icons/actions/hi16-action-dvdcopy.png b/src/icons/actions/hi16-action-dvdcopy.png new file mode 100644 index 0000000..52012d0 Binary files /dev/null and b/src/icons/actions/hi16-action-dvdcopy.png differ diff --git a/src/icons/actions/hi16-action-emovix.png b/src/icons/actions/hi16-action-emovix.png new file mode 100644 index 0000000..5242645 Binary files /dev/null and b/src/icons/actions/hi16-action-emovix.png differ diff --git a/src/icons/actions/hi16-action-erasecd.png b/src/icons/actions/hi16-action-erasecd.png new file mode 100644 index 0000000..1d08a42 Binary files /dev/null and b/src/icons/actions/hi16-action-erasecd.png differ diff --git a/src/icons/actions/hi16-action-formatdvd.png b/src/icons/actions/hi16-action-formatdvd.png new file mode 100644 index 0000000..ecc8153 Binary files /dev/null and b/src/icons/actions/hi16-action-formatdvd.png differ diff --git a/src/icons/actions/hi16-action-mixedcd.png b/src/icons/actions/hi16-action-mixedcd.png new file mode 100644 index 0000000..514bb3e Binary files /dev/null and b/src/icons/actions/hi16-action-mixedcd.png differ diff --git a/src/icons/actions/hi16-action-mp3cd.png b/src/icons/actions/hi16-action-mp3cd.png new file mode 100644 index 0000000..378d072 Binary files /dev/null and b/src/icons/actions/hi16-action-mp3cd.png differ diff --git a/src/icons/actions/hi16-action-musicbrainz.png b/src/icons/actions/hi16-action-musicbrainz.png new file mode 100644 index 0000000..0608908 Binary files /dev/null and b/src/icons/actions/hi16-action-musicbrainz.png differ diff --git a/src/icons/actions/hi16-action-videocd.png b/src/icons/actions/hi16-action-videocd.png new file mode 100644 index 0000000..b9e8c18 Binary files /dev/null and b/src/icons/actions/hi16-action-videocd.png differ diff --git a/src/icons/actions/hi16-action-videodvd.png b/src/icons/actions/hi16-action-videodvd.png new file mode 100644 index 0000000..8bb3470 Binary files /dev/null and b/src/icons/actions/hi16-action-videodvd.png differ diff --git a/src/icons/actions/hi22-action-audiocd.png b/src/icons/actions/hi22-action-audiocd.png new file mode 100644 index 0000000..46762b4 Binary files /dev/null and b/src/icons/actions/hi22-action-audiocd.png differ diff --git a/src/icons/actions/hi22-action-burn_cdimage.png b/src/icons/actions/hi22-action-burn_cdimage.png new file mode 100644 index 0000000..f5e1b0d Binary files /dev/null and b/src/icons/actions/hi22-action-burn_cdimage.png differ diff --git a/src/icons/actions/hi22-action-burn_dvdimage.png b/src/icons/actions/hi22-action-burn_dvdimage.png new file mode 100644 index 0000000..6e6b94b Binary files /dev/null and b/src/icons/actions/hi22-action-burn_dvdimage.png differ diff --git a/src/icons/actions/hi22-action-cdburn.png b/src/icons/actions/hi22-action-cdburn.png new file mode 100644 index 0000000..7862d9e Binary files /dev/null and b/src/icons/actions/hi22-action-cdburn.png differ diff --git a/src/icons/actions/hi22-action-cdcopy.png b/src/icons/actions/hi22-action-cdcopy.png new file mode 100644 index 0000000..0269b7e Binary files /dev/null and b/src/icons/actions/hi22-action-cdcopy.png differ diff --git a/src/icons/actions/hi22-action-cddarip.png b/src/icons/actions/hi22-action-cddarip.png new file mode 100644 index 0000000..6bbc468 Binary files /dev/null and b/src/icons/actions/hi22-action-cddarip.png differ diff --git a/src/icons/actions/hi22-action-datacd.png b/src/icons/actions/hi22-action-datacd.png new file mode 100644 index 0000000..cfc2e69 Binary files /dev/null and b/src/icons/actions/hi22-action-datacd.png differ diff --git a/src/icons/actions/hi22-action-datadvd.png b/src/icons/actions/hi22-action-datadvd.png new file mode 100644 index 0000000..c1cb979 Binary files /dev/null and b/src/icons/actions/hi22-action-datadvd.png differ diff --git a/src/icons/actions/hi22-action-dvdcopy.png b/src/icons/actions/hi22-action-dvdcopy.png new file mode 100644 index 0000000..b05714c Binary files /dev/null and b/src/icons/actions/hi22-action-dvdcopy.png differ diff --git a/src/icons/actions/hi22-action-emovix.png b/src/icons/actions/hi22-action-emovix.png new file mode 100644 index 0000000..04f6478 Binary files /dev/null and b/src/icons/actions/hi22-action-emovix.png differ diff --git a/src/icons/actions/hi22-action-erasecd.png b/src/icons/actions/hi22-action-erasecd.png new file mode 100644 index 0000000..6619f67 Binary files /dev/null and b/src/icons/actions/hi22-action-erasecd.png differ diff --git a/src/icons/actions/hi22-action-formatdvd.png b/src/icons/actions/hi22-action-formatdvd.png new file mode 100644 index 0000000..8d419f4 Binary files /dev/null and b/src/icons/actions/hi22-action-formatdvd.png differ diff --git a/src/icons/actions/hi22-action-mixedcd.png b/src/icons/actions/hi22-action-mixedcd.png new file mode 100644 index 0000000..13cbf7f Binary files /dev/null and b/src/icons/actions/hi22-action-mixedcd.png differ diff --git a/src/icons/actions/hi22-action-mp3cd.png b/src/icons/actions/hi22-action-mp3cd.png new file mode 100644 index 0000000..653129d Binary files /dev/null and b/src/icons/actions/hi22-action-mp3cd.png differ diff --git a/src/icons/actions/hi22-action-videocd.png b/src/icons/actions/hi22-action-videocd.png new file mode 100644 index 0000000..0ebe179 Binary files /dev/null and b/src/icons/actions/hi22-action-videocd.png differ diff --git a/src/icons/actions/hi22-action-videodvd.png b/src/icons/actions/hi22-action-videodvd.png new file mode 100644 index 0000000..6ca9619 Binary files /dev/null and b/src/icons/actions/hi22-action-videodvd.png differ diff --git a/src/icons/actions/hi32-action-audiocd.png b/src/icons/actions/hi32-action-audiocd.png new file mode 100644 index 0000000..6509ef7 Binary files /dev/null and b/src/icons/actions/hi32-action-audiocd.png differ diff --git a/src/icons/actions/hi32-action-burn_cdimage.png b/src/icons/actions/hi32-action-burn_cdimage.png new file mode 100644 index 0000000..5bdcbf0 Binary files /dev/null and b/src/icons/actions/hi32-action-burn_cdimage.png differ diff --git a/src/icons/actions/hi32-action-burn_dvdimage.png b/src/icons/actions/hi32-action-burn_dvdimage.png new file mode 100644 index 0000000..647d9b1 Binary files /dev/null and b/src/icons/actions/hi32-action-burn_dvdimage.png differ diff --git a/src/icons/actions/hi32-action-cdburn.png b/src/icons/actions/hi32-action-cdburn.png new file mode 100644 index 0000000..3150417 Binary files /dev/null and b/src/icons/actions/hi32-action-cdburn.png differ diff --git a/src/icons/actions/hi32-action-cdcopy.png b/src/icons/actions/hi32-action-cdcopy.png new file mode 100644 index 0000000..4c650ce Binary files /dev/null and b/src/icons/actions/hi32-action-cdcopy.png differ diff --git a/src/icons/actions/hi32-action-cddarip.png b/src/icons/actions/hi32-action-cddarip.png new file mode 100644 index 0000000..e0af956 Binary files /dev/null and b/src/icons/actions/hi32-action-cddarip.png differ diff --git a/src/icons/actions/hi32-action-datacd.png b/src/icons/actions/hi32-action-datacd.png new file mode 100644 index 0000000..fec1dd3 Binary files /dev/null and b/src/icons/actions/hi32-action-datacd.png differ diff --git a/src/icons/actions/hi32-action-datadvd.png b/src/icons/actions/hi32-action-datadvd.png new file mode 100644 index 0000000..730fdb0 Binary files /dev/null and b/src/icons/actions/hi32-action-datadvd.png differ diff --git a/src/icons/actions/hi32-action-dvdcopy.png b/src/icons/actions/hi32-action-dvdcopy.png new file mode 100644 index 0000000..0ffc7b9 Binary files /dev/null and b/src/icons/actions/hi32-action-dvdcopy.png differ diff --git a/src/icons/actions/hi32-action-emovix.png b/src/icons/actions/hi32-action-emovix.png new file mode 100644 index 0000000..779159e Binary files /dev/null and b/src/icons/actions/hi32-action-emovix.png differ diff --git a/src/icons/actions/hi32-action-erasecd.png b/src/icons/actions/hi32-action-erasecd.png new file mode 100644 index 0000000..e699d07 Binary files /dev/null and b/src/icons/actions/hi32-action-erasecd.png differ diff --git a/src/icons/actions/hi32-action-formatdvd.png b/src/icons/actions/hi32-action-formatdvd.png new file mode 100644 index 0000000..4e4c044 Binary files /dev/null and b/src/icons/actions/hi32-action-formatdvd.png differ diff --git a/src/icons/actions/hi32-action-mixedcd.png b/src/icons/actions/hi32-action-mixedcd.png new file mode 100644 index 0000000..7f842c8 Binary files /dev/null and b/src/icons/actions/hi32-action-mixedcd.png differ diff --git a/src/icons/actions/hi32-action-mp3cd.png b/src/icons/actions/hi32-action-mp3cd.png new file mode 100644 index 0000000..98a9787 Binary files /dev/null and b/src/icons/actions/hi32-action-mp3cd.png differ diff --git a/src/icons/actions/hi32-action-videocd.png b/src/icons/actions/hi32-action-videocd.png new file mode 100644 index 0000000..93b5838 Binary files /dev/null and b/src/icons/actions/hi32-action-videocd.png differ diff --git a/src/icons/actions/hi32-action-videodvd.png b/src/icons/actions/hi32-action-videodvd.png new file mode 100644 index 0000000..3b1ed2d Binary files /dev/null and b/src/icons/actions/hi32-action-videodvd.png differ diff --git a/src/icons/actions/hi48-action-audiocd.png b/src/icons/actions/hi48-action-audiocd.png new file mode 100644 index 0000000..a609713 Binary files /dev/null and b/src/icons/actions/hi48-action-audiocd.png differ diff --git a/src/icons/actions/hi48-action-burn_cdimage.png b/src/icons/actions/hi48-action-burn_cdimage.png new file mode 100644 index 0000000..1d91604 Binary files /dev/null and b/src/icons/actions/hi48-action-burn_cdimage.png differ diff --git a/src/icons/actions/hi48-action-burn_dvdimage.png b/src/icons/actions/hi48-action-burn_dvdimage.png new file mode 100644 index 0000000..36d24a6 Binary files /dev/null and b/src/icons/actions/hi48-action-burn_dvdimage.png differ diff --git a/src/icons/actions/hi48-action-cdburn.png b/src/icons/actions/hi48-action-cdburn.png new file mode 100644 index 0000000..d4c8c7b Binary files /dev/null and b/src/icons/actions/hi48-action-cdburn.png differ diff --git a/src/icons/actions/hi48-action-cdcopy.png b/src/icons/actions/hi48-action-cdcopy.png new file mode 100644 index 0000000..a2ca951 Binary files /dev/null and b/src/icons/actions/hi48-action-cdcopy.png differ diff --git a/src/icons/actions/hi48-action-cddarip.png b/src/icons/actions/hi48-action-cddarip.png new file mode 100644 index 0000000..d21b6f0 Binary files /dev/null and b/src/icons/actions/hi48-action-cddarip.png differ diff --git a/src/icons/actions/hi48-action-datacd.png b/src/icons/actions/hi48-action-datacd.png new file mode 100644 index 0000000..77740bb Binary files /dev/null and b/src/icons/actions/hi48-action-datacd.png differ diff --git a/src/icons/actions/hi48-action-datadvd.png b/src/icons/actions/hi48-action-datadvd.png new file mode 100644 index 0000000..12e2ae6 Binary files /dev/null and b/src/icons/actions/hi48-action-datadvd.png differ diff --git a/src/icons/actions/hi48-action-dvdcopy.png b/src/icons/actions/hi48-action-dvdcopy.png new file mode 100644 index 0000000..c2b39ef Binary files /dev/null and b/src/icons/actions/hi48-action-dvdcopy.png differ diff --git a/src/icons/actions/hi48-action-emovix.png b/src/icons/actions/hi48-action-emovix.png new file mode 100644 index 0000000..cec838a Binary files /dev/null and b/src/icons/actions/hi48-action-emovix.png differ diff --git a/src/icons/actions/hi48-action-erasecd.png b/src/icons/actions/hi48-action-erasecd.png new file mode 100644 index 0000000..8a47870 Binary files /dev/null and b/src/icons/actions/hi48-action-erasecd.png differ diff --git a/src/icons/actions/hi48-action-formatdvd.png b/src/icons/actions/hi48-action-formatdvd.png new file mode 100644 index 0000000..1f536f1 Binary files /dev/null and b/src/icons/actions/hi48-action-formatdvd.png differ diff --git a/src/icons/actions/hi48-action-mixedcd.png b/src/icons/actions/hi48-action-mixedcd.png new file mode 100644 index 0000000..77e2202 Binary files /dev/null and b/src/icons/actions/hi48-action-mixedcd.png differ diff --git a/src/icons/actions/hi48-action-mp3cd.png b/src/icons/actions/hi48-action-mp3cd.png new file mode 100644 index 0000000..665e431 Binary files /dev/null and b/src/icons/actions/hi48-action-mp3cd.png differ diff --git a/src/icons/actions/hi48-action-videocd.png b/src/icons/actions/hi48-action-videocd.png new file mode 100644 index 0000000..55bccd4 Binary files /dev/null and b/src/icons/actions/hi48-action-videocd.png differ diff --git a/src/icons/actions/hi48-action-videodvd.png b/src/icons/actions/hi48-action-videodvd.png new file mode 100644 index 0000000..2078bec Binary files /dev/null and b/src/icons/actions/hi48-action-videodvd.png differ diff --git a/src/icons/actions/hi64-action-musicbrainz.png b/src/icons/actions/hi64-action-musicbrainz.png new file mode 100644 index 0000000..f5074c6 Binary files /dev/null and b/src/icons/actions/hi64-action-musicbrainz.png differ diff --git a/src/icons/actions/hisc-action-audiocd.svgz b/src/icons/actions/hisc-action-audiocd.svgz new file mode 100644 index 0000000..cb05f70 Binary files /dev/null and b/src/icons/actions/hisc-action-audiocd.svgz differ diff --git a/src/icons/actions/hisc-action-burn_cdimage.svgz b/src/icons/actions/hisc-action-burn_cdimage.svgz new file mode 100644 index 0000000..b0a8fde Binary files /dev/null and b/src/icons/actions/hisc-action-burn_cdimage.svgz differ diff --git a/src/icons/actions/hisc-action-burn_dvdimage.svgz b/src/icons/actions/hisc-action-burn_dvdimage.svgz new file mode 100644 index 0000000..b89af60 Binary files /dev/null and b/src/icons/actions/hisc-action-burn_dvdimage.svgz differ diff --git a/src/icons/actions/hisc-action-cdburn.svgz b/src/icons/actions/hisc-action-cdburn.svgz new file mode 100644 index 0000000..014f1b8 Binary files /dev/null and b/src/icons/actions/hisc-action-cdburn.svgz differ diff --git a/src/icons/actions/hisc-action-cdcopy.svgz b/src/icons/actions/hisc-action-cdcopy.svgz new file mode 100644 index 0000000..9143b8d Binary files /dev/null and b/src/icons/actions/hisc-action-cdcopy.svgz differ diff --git a/src/icons/actions/hisc-action-cddarip.svgz b/src/icons/actions/hisc-action-cddarip.svgz new file mode 100644 index 0000000..2a86c86 Binary files /dev/null and b/src/icons/actions/hisc-action-cddarip.svgz differ diff --git a/src/icons/actions/hisc-action-datacd.svgz b/src/icons/actions/hisc-action-datacd.svgz new file mode 100644 index 0000000..e2f0f2a Binary files /dev/null and b/src/icons/actions/hisc-action-datacd.svgz differ diff --git a/src/icons/actions/hisc-action-datadvd.svgz b/src/icons/actions/hisc-action-datadvd.svgz new file mode 100644 index 0000000..332b73c Binary files /dev/null and b/src/icons/actions/hisc-action-datadvd.svgz differ diff --git a/src/icons/actions/hisc-action-dvdcopy.svgz b/src/icons/actions/hisc-action-dvdcopy.svgz new file mode 100644 index 0000000..b8efe33 Binary files /dev/null and b/src/icons/actions/hisc-action-dvdcopy.svgz differ diff --git a/src/icons/actions/hisc-action-emovix.svgz b/src/icons/actions/hisc-action-emovix.svgz new file mode 100644 index 0000000..5053e3d Binary files /dev/null and b/src/icons/actions/hisc-action-emovix.svgz differ diff --git a/src/icons/actions/hisc-action-erasecd.svgz b/src/icons/actions/hisc-action-erasecd.svgz new file mode 100644 index 0000000..7a99c82 Binary files /dev/null and b/src/icons/actions/hisc-action-erasecd.svgz differ diff --git a/src/icons/actions/hisc-action-formatdvd.svgz b/src/icons/actions/hisc-action-formatdvd.svgz new file mode 100644 index 0000000..33e4877 Binary files /dev/null and b/src/icons/actions/hisc-action-formatdvd.svgz differ diff --git a/src/icons/actions/hisc-action-mixedcd.svgz b/src/icons/actions/hisc-action-mixedcd.svgz new file mode 100644 index 0000000..fa10365 Binary files /dev/null and b/src/icons/actions/hisc-action-mixedcd.svgz differ diff --git a/src/icons/actions/hisc-action-mp3cd.svgz b/src/icons/actions/hisc-action-mp3cd.svgz new file mode 100644 index 0000000..5142c80 Binary files /dev/null and b/src/icons/actions/hisc-action-mp3cd.svgz differ diff --git a/src/icons/actions/hisc-action-videocd.svgz b/src/icons/actions/hisc-action-videocd.svgz new file mode 100644 index 0000000..9af309f Binary files /dev/null and b/src/icons/actions/hisc-action-videocd.svgz differ diff --git a/src/icons/actions/hisc-action-videodvd.svgz b/src/icons/actions/hisc-action-videodvd.svgz new file mode 100644 index 0000000..1ec5b1f Binary files /dev/null and b/src/icons/actions/hisc-action-videodvd.svgz differ diff --git a/src/icons/hi128-app-k3b.png b/src/icons/hi128-app-k3b.png new file mode 100644 index 0000000..278d6b1 Binary files /dev/null and b/src/icons/hi128-app-k3b.png differ diff --git a/src/icons/hi16-app-k3b.png b/src/icons/hi16-app-k3b.png new file mode 100644 index 0000000..7891dc0 Binary files /dev/null and b/src/icons/hi16-app-k3b.png differ diff --git a/src/icons/hi22-app-k3b.png b/src/icons/hi22-app-k3b.png new file mode 100644 index 0000000..43bf2f2 Binary files /dev/null and b/src/icons/hi22-app-k3b.png differ diff --git a/src/icons/hi32-app-k3b.png b/src/icons/hi32-app-k3b.png new file mode 100644 index 0000000..5c1cd8e Binary files /dev/null and b/src/icons/hi32-app-k3b.png differ diff --git a/src/icons/hi48-app-k3b.png b/src/icons/hi48-app-k3b.png new file mode 100644 index 0000000..04c40a1 Binary files /dev/null and b/src/icons/hi48-app-k3b.png differ diff --git a/src/icons/hi64-app-k3b.png b/src/icons/hi64-app-k3b.png new file mode 100644 index 0000000..f1354cb Binary files /dev/null and b/src/icons/hi64-app-k3b.png differ diff --git a/src/k3b-cue.desktop b/src/k3b-cue.desktop new file mode 100644 index 0000000..e1743f6 --- /dev/null +++ b/src/k3b-cue.desktop @@ -0,0 +1,14 @@ +# KDE Config File +[Desktop Entry] +Type=Application +NoDisplay=true +Exec=k3b --cdimage %U +Icon=k3b +Terminal=false +Name=K3b +Name[ar]= K3b +Name[bn]=কে-থ্রি-বি +Name[hi]=के3बी +MimeType=application/x-cue; + +Encoding=UTF-8 diff --git a/src/k3b-iso.desktop b/src/k3b-iso.desktop new file mode 100644 index 0000000..ff97f3e --- /dev/null +++ b/src/k3b-iso.desktop @@ -0,0 +1,13 @@ +# KDE Config File +[Desktop Entry] +Type=Application +NoDisplay=true +Exec=k3b --image %U +Icon=k3b +Terminal=false +Name=K3b +Name[ar]= K3b +Name[bn]=কে-থ্রি-বি +Name[hi]=के3बी +MimeType=application/x-iso; +Encoding=UTF-8 diff --git a/src/k3b.cpp b/src/k3b.cpp new file mode 100644 index 0000000..23a5cd6 --- /dev/null +++ b/src/k3b.cpp @@ -0,0 +1,1630 @@ +/* + * + * $Id: k3b.cpp 642063 2007-03-13 09:40:13Z trueg $ + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include <config.h> + + +// include files for QT +#include <qdir.h> +#include <qfile.h> +#include <qfileinfo.h> +#include <qlayout.h> +#include <qwhatsthis.h> +#include <qtooltip.h> +#include <qtoolbutton.h> +#include <qstring.h> +#include <qsplitter.h> +#include <qevent.h> +#include <qvaluelist.h> +#include <qfont.h> +#include <qpalette.h> +#include <qwidgetstack.h> +#include <qtimer.h> + +#include <kdockwidget.h> +#include <kkeydialog.h> +// include files for KDE +#include <kiconloader.h> +#include <kmessagebox.h> +#include <kfiledialog.h> +#include <kmenubar.h> +#include <klocale.h> +#include <kconfig.h> +#include <kstdaction.h> +#include <klineeditdlg.h> +#include <kstandarddirs.h> +#include <kprocess.h> +#include <kurl.h> +#include <kurllabel.h> +#include <ktoolbar.h> +#include <kstatusbar.h> +#include <kglobalsettings.h> +#include <kdialog.h> +#include <kedittoolbar.h> +#include <ksystemtray.h> +#include <kaboutdata.h> +#include <ktip.h> +#include <kxmlguifactory.h> +#include <kstdguiitem.h> +#include <kio/global.h> +#include <kio/netaccess.h> +#include <krecentdocument.h> + +#include <stdlib.h> + +// application specific includes +#include "k3b.h" +#include "k3bapplication.h" +#include <k3bglobals.h> +#include "k3bview.h" +#include "k3bdirview.h" +#include <k3baudiodoc.h> +#include "k3baudioview.h" +#include "k3bappdevicemanager.h" +#include "k3baudiotrackdialog.h" +#include "option/k3boptiondialog.h" +#include "k3bprojectburndialog.h" +#include <k3bdatadoc.h> +#include "k3bdataview.h" +#include <k3bdvddoc.h> +#include "k3bdvdview.h" +#include <k3bvideodvddoc.h> +#include "k3bvideodvdview.h" +#include <k3bmixeddoc.h> +#include "k3bmixedview.h" +#include <k3bvcddoc.h> +#include "k3bvcdview.h" +#include <k3bmovixdoc.h> +#include "k3bmovixview.h" +#include <k3bmovixdvddoc.h> +#include "k3bmovixdvdview.h" +#include "misc/k3bblankingdialog.h" +#include "misc/k3bcdimagewritingdialog.h" +#include "misc/k3bisoimagewritingdialog.h" +#include <k3bexternalbinmanager.h> +#include "k3bprojecttabwidget.h" +#include "misc/k3bcdcopydialog.h" +#include "k3btempdirselectionwidget.h" +#include "k3bstatusbarmanager.h" +#include "k3bfiletreecombobox.h" +#include "k3bfiletreeview.h" +#include "k3bsidepanel.h" +#include "k3bstdguiitems.h" +#include "misc/k3bdvdformattingdialog.h" +#include "misc/k3bdvdcopydialog.h" +//#include "dvdcopy/k3bvideodvdcopydialog.h" +#include "k3bprojectmanager.h" +#include "k3bwelcomewidget.h" +#include <k3bpluginmanager.h> +#include <k3bplugin.h> +#include "k3bsystemproblemdialog.h" +#include <k3baudiodecoder.h> +#include <k3bthememanager.h> +#include <k3biso9660.h> +#include <k3bcuefileparser.h> +#include <k3bdeviceselectiondialog.h> +#include <k3bjob.h> +#include <k3bsignalwaiter.h> +#include "k3bmediaselectiondialog.h" +#include "k3bmediacache.h" +#include "k3bmedium.h" +#include "projects/k3bdatasessionimportdialog.h" +#include "k3bpassivepopup.h" +#include "k3bthemedheader.h" +#include <k3baudioserver.h> + + +class K3bMainWindow::Private +{ +public: + K3bDoc* lastDoc; + + QWidgetStack* documentStack; + K3bWelcomeWidget* welcomeWidget; + QWidget* documentHull; + + QLabel* leftDocPicLabel; + QLabel* centerDocLabel; + QLabel* rightDocPicLabel; +}; + + +K3bMainWindow::K3bMainWindow() + : DockMainWindow(0,"K3bMainwindow") +{ + //setup splitter behavior + manager()->setSplitterHighResolution(true); + manager()->setSplitterOpaqueResize(true); + manager()->setSplitterKeepSize(true); + + d = new Private; + d->lastDoc = 0; + + setPlainCaption( i18n("K3b - The CD and DVD Kreator") ); + + m_config = kapp->config(); + + /////////////////////////////////////////////////////////////////// + // call inits to invoke all other construction parts + initActions(); + initView(); + initStatusBar(); + createGUI(0L); + + // we need the actions for the welcomewidget + d->welcomeWidget->loadConfig( config() ); + + // fill the tabs action menu + m_documentTab->insertAction( actionFileSave ); + m_documentTab->insertAction( actionFileSaveAs ); + m_documentTab->insertAction( actionFileClose ); + + // ///////////////////////////////////////////////////////////////// + // disable actions at startup + slotStateChanged( "state_project_active", KXMLGUIClient::StateReverse ); + + connect( k3bappcore->projectManager(), SIGNAL(newProject(K3bDoc*)), this, SLOT(createClient(K3bDoc*)) ); + connect( k3bcore->deviceManager(), SIGNAL(changed()), this, SLOT(slotCheckSystemTimed()) ); + connect( K3bAudioServer::instance(), SIGNAL(error(const QString&)), this, SLOT(slotAudioServerError(const QString&)) ); + + // FIXME: now make sure the welcome screen is displayed completely + resize( 780, 550 ); +// getMainDockWidget()->resize( getMainDockWidget()->size().expandedTo( d->welcomeWidget->sizeHint() ) ); +// m_dirTreeDock->resize( QSize( m_dirTreeDock->sizeHint().width(), m_dirTreeDock->height() ) ); + + readOptions(); +} + +K3bMainWindow::~K3bMainWindow() +{ + delete mainDock; + delete m_contentsDock; + + delete d; +} + + +void K3bMainWindow::showEvent( QShowEvent* e ) +{ + slotCheckDockWidgetStatus(); + KDockMainWindow::showEvent( e ); +} + + +void K3bMainWindow::initActions() +{ + // merge in the device actions from the device manager + // operator+= is deprecated but I know no other way to do this. Why does the KDE app framework + // need to have all actions in the mainwindow's actioncollection anyway (or am I just to stupid to + // see the correct solution?) + *actionCollection() += *k3bappcore->appDeviceManager()->actionCollection(); + + actionFileOpen = KStdAction::open(this, SLOT(slotFileOpen()), actionCollection()); + actionFileOpenRecent = KStdAction::openRecent(this, SLOT(slotFileOpenRecent(const KURL&)), actionCollection()); + actionFileSave = KStdAction::save(this, SLOT(slotFileSave()), actionCollection()); + actionFileSaveAs = KStdAction::saveAs(this, SLOT(slotFileSaveAs()), actionCollection()); + actionFileSaveAll = new KAction( i18n("Save All"), "save_all", 0, this, SLOT(slotFileSaveAll()), + actionCollection(), "file_save_all" ); + actionFileClose = KStdAction::close(this, SLOT(slotFileClose()), actionCollection()); + actionFileCloseAll = new KAction( i18n("Close All"), 0, 0, this, SLOT(slotFileCloseAll()), + actionCollection(), "file_close_all" ); + actionFileQuit = KStdAction::quit(this, SLOT(slotFileQuit()), actionCollection()); + actionViewStatusBar = KStdAction::showStatusbar(this, SLOT(slotViewStatusBar()), actionCollection()); + actionSettingsConfigure = KStdAction::preferences(this, SLOT(slotSettingsConfigure()), actionCollection() ); + + // the tip action + (void)KStdAction::tipOfDay(this, SLOT(slotShowTips()), actionCollection() ); + (void)KStdAction::keyBindings( this, SLOT( slotConfigureKeys() ), actionCollection() ); + + KStdAction::configureToolbars(this, SLOT(slotEditToolbars()), actionCollection()); + setStandardToolBarMenuEnabled(true); + KStdAction::showMenubar( this, SLOT(slotShowMenuBar()), actionCollection() ); + + actionFileNewMenu = new KActionMenu( i18n("&New Project"), "filenew", actionCollection(), "file_new" ); + actionFileNewAudio = new KAction(i18n("New &Audio CD Project"), "audiocd", 0, this, SLOT(slotNewAudioDoc()), + actionCollection(), "file_new_audio"); + actionFileNewData = new KAction(i18n("New Data &CD Project"), "datacd", 0, this, SLOT(slotNewDataDoc()), + actionCollection(), "file_new_data"); + actionFileNewMixed = new KAction(i18n("New &Mixed Mode CD Project"), "mixedcd", 0, this, SLOT(slotNewMixedDoc()), + actionCollection(), "file_new_mixed"); + actionFileNewVcd = new KAction(i18n("New &Video CD Project"), "videocd", 0, this, SLOT(slotNewVcdDoc()), + actionCollection(), "file_new_vcd"); + actionFileNewMovix = new KAction(i18n("New &eMovix CD Project"), "emovix", 0, this, SLOT(slotNewMovixDoc()), + actionCollection(), "file_new_movix"); + actionFileNewMovixDvd = new KAction(i18n("New &eMovix DVD Project"), "emovix", 0, this, SLOT(slotNewMovixDvdDoc()), + actionCollection(), "file_new_movix_dvd"); + actionFileNewDvd = new KAction(i18n("New Data &DVD Project"), "datadvd", 0, this, SLOT(slotNewDvdDoc()), + actionCollection(), "file_new_dvd"); + actionFileNewVideoDvd = new KAction(i18n("New V&ideo DVD Project"), "videodvd", 0, this, SLOT(slotNewVideoDvdDoc()), + actionCollection(), "file_new_video_dvd"); + actionFileContinueMultisession = new KAction( i18n("Continue Multisession Project"), "datacd", 0, this, SLOT(slotContinueMultisession()), + actionCollection(), "file_continue_multisession" ); + + actionFileNewMenu->setDelayed( false ); + actionFileNewMenu->insert( actionFileNewData ); + actionFileNewMenu->insert( actionFileNewDvd ); + actionFileNewMenu->insert( actionFileContinueMultisession ); + actionFileNewMenu->insert( new KActionSeparator( this ) ); + actionFileNewMenu->insert( actionFileNewAudio ); + actionFileNewMenu->insert( new KActionSeparator( this ) ); + actionFileNewMenu->insert( actionFileNewMixed ); + actionFileNewMenu->insert( new KActionSeparator( this ) ); + actionFileNewMenu->insert( actionFileNewVcd ); + actionFileNewMenu->insert( actionFileNewVideoDvd ); + actionFileNewMenu->insert( new KActionSeparator( this ) ); + actionFileNewMenu->insert( actionFileNewMovix ); + actionFileNewMenu->insert( actionFileNewMovixDvd ); + + + + + + actionProjectAddFiles = new KAction( i18n("&Add Files..."), "filenew", 0, this, SLOT(slotProjectAddFiles()), + actionCollection(), "project_add_files"); + + KAction* actionClearProject = new KAction( i18n("&Clear Project"), QApplication::reverseLayout() ? "clear_left" : "locationbar_erase", 0, + this, SLOT(slotClearProject()), actionCollection(), "project_clear_project" ); + + actionViewDirTreeView = new KToggleAction(i18n("Show Directories"), 0, this, SLOT(slotShowDirTreeView()), + actionCollection(), "view_dir_tree"); + + actionViewContentsView = new KToggleAction(i18n("Show Contents"), 0, this, SLOT(slotShowContentsView()), + actionCollection(), "view_contents"); + + actionViewDocumentHeader = new KToggleAction(i18n("Show Document Header"), 0, this, SLOT(slotViewDocumentHeader()), + actionCollection(), "view_document_header"); + + actionToolsBlankCdrw = new KAction( i18n("&Erase CD-RW..."), "erasecd", 0, this, SLOT(slotBlankCdrw()), + actionCollection(), "tools_blank_cdrw" ); + KAction* actionToolsFormatDVD = new KAction( i18n("&Format DVD%1RW...").arg(""), "formatdvd", 0, this, + SLOT(slotFormatDvd()), actionCollection(), "tools_format_dvd" ); + actionToolsWriteCdImage = new KAction(i18n("&Burn CD Image..."), "burn_cdimage", 0, this, SLOT(slotWriteCdImage()), + actionCollection(), "tools_write_cd_image" ); + KAction* actionToolsWriteDvdImage = new KAction(i18n("&Burn DVD ISO Image..."), "burn_dvdimage", 0, this, SLOT(slotWriteDvdIsoImage()), + actionCollection(), "tools_write_dvd_iso" ); + + actionCdCopy = new KAction(i18n("&Copy CD..."), "cdcopy", 0, this, SLOT(slotCdCopy()), + actionCollection(), "tools_copy_cd" ); + + KAction* actionToolsDvdCopy = new KAction(i18n("Copy &DVD..."), "dvdcopy", 0, this, SLOT(slotDvdCopy()), + actionCollection(), "tools_copy_dvd" ); + + actionToolsCddaRip = new KAction( i18n("Rip Audio CD..."), "cddarip", 0, this, SLOT(slotCddaRip()), + actionCollection(), "tools_cdda_rip" ); + actionToolsVideoDvdRip = new KAction( i18n("Rip Video DVD..."), "videodvd", 0, this, SLOT(slotVideoDvdRip()), + actionCollection(), "tools_videodvd_rip" ); + actionToolsVideoCdRip = new KAction( i18n("Rip Video CD..."), "videocd", 0, this, SLOT(slotVideoCdRip()), + actionCollection(), "tools_videocd_rip" ); + + (void)new KAction( i18n("System Check"), 0, 0, this, SLOT(slotCheckSystem()), + actionCollection(), "help_check_system" ); + +#ifdef HAVE_K3BSETUP + actionSettingsK3bSetup = new KAction(i18n("&Setup System Permissions..."), "configure", 0, this, SLOT(slotK3bSetup()), + actionCollection(), "settings_k3bsetup" ); +#endif + +#ifdef K3B_DEBUG + (void)new KAction( "Test Media Selection ComboBox", 0, 0, this, + SLOT(slotMediaSelectionTester()), actionCollection(), + "test_media_selection" ); +#endif + + actionFileNewMenu->setToolTip(i18n("Creates a new project")); + actionFileNewData->setToolTip( i18n("Creates a new data CD project") ); + actionFileNewAudio->setToolTip( i18n("Creates a new audio CD project") ); + actionFileNewMovixDvd->setToolTip( i18n("Creates a new eMovix DVD project") ); + actionFileNewDvd->setToolTip( i18n("Creates a new data DVD project") ); + actionFileNewMovix->setToolTip( i18n("Creates a new eMovix CD project") ); + actionFileNewVcd->setToolTip( i18n("Creates a new Video CD project") ); + actionToolsBlankCdrw->setToolTip( i18n("Open the CD-RW erasing dialog") ); + actionToolsFormatDVD->setToolTip( i18n("Open the DVD%1RW formatting dialog").arg("") ); + actionCdCopy->setToolTip( i18n("Open the CD copy dialog") ); + actionToolsWriteCdImage->setToolTip( i18n("Write an Iso9660, cue/bin, or cdrecord clone image to CD") ); + actionToolsWriteDvdImage->setToolTip( i18n("Write an Iso9660 image to DVD") ); + actionToolsDvdCopy->setToolTip( i18n("Open the DVD copy dialog") ); + actionFileOpen->setToolTip(i18n("Opens an existing project")); + actionFileOpenRecent->setToolTip(i18n("Opens a recently used file")); + actionFileSave->setToolTip(i18n("Saves the current project")); + actionFileSaveAs->setToolTip(i18n("Saves the current project to a new url")); + actionFileSaveAll->setToolTip(i18n("Saves all open projects")); + actionFileClose->setToolTip(i18n("Closes the current project")); + actionFileCloseAll->setToolTip(i18n("Closes all open projects")); + actionFileQuit->setToolTip(i18n("Quits the application")); + actionSettingsConfigure->setToolTip( i18n("Configure K3b settings") ); +#ifdef HAVE_K3BSETUP + actionSettingsK3bSetup->setToolTip( i18n("Setup the system permissions (requires root privileges)") ); +#endif + actionToolsCddaRip->setToolTip( i18n("Digitally extract tracks from an audio CD") ); + actionToolsVideoDvdRip->setToolTip( i18n("Transcode Video DVD titles") ); + actionToolsVideoCdRip->setToolTip( i18n("Extract tracks from a Video CD") ); + actionProjectAddFiles->setToolTip( i18n("Add files to the current project") ); + actionClearProject->setToolTip( i18n("Clear the current project") ); + + // make sure the tooltips are used for the menu + actionCollection()->setHighlightingEnabled( true ); +} + + + +const QPtrList<K3bDoc>& K3bMainWindow::projects() const +{ + return k3bappcore->projectManager()->projects(); +} + + +void K3bMainWindow::slotConfigureKeys() +{ + KKeyDialog::configure( actionCollection(), this ); +} + +void K3bMainWindow::initStatusBar() +{ + m_statusBarManager = new K3bStatusBarManager( this ); +} + + +void K3bMainWindow::initView() +{ + // setup main docking things + mainDock = createDockWidget( "project_view", SmallIcon("idea"), 0, + kapp->makeStdCaption( i18n("Project View") ), i18n("Project View") ); + mainDock->setDockSite( KDockWidget::DockCorner ); + mainDock->setEnableDocking( KDockWidget::DockNone ); + setView( mainDock ); + setMainDockWidget( mainDock ); + + // --- Document Dock ---------------------------------------------------------------------------- + d->documentStack = new QWidgetStack( mainDock ); + mainDock->setWidget( d->documentStack ); + + d->documentHull = new QWidget( d->documentStack ); + d->documentStack->addWidget( d->documentHull ); + QGridLayout* documentHullLayout = new QGridLayout( d->documentHull ); + documentHullLayout->setMargin( 2 ); + documentHullLayout->setSpacing( 0 ); + + m_documentHeader = new K3bThemedHeader( d->documentHull ); + m_documentHeader->setTitle( i18n("Current Projects") ); + m_documentHeader->setAlignment( Qt::AlignHCenter | Qt::AlignVCenter ); + m_documentHeader->setLeftPixmap( K3bTheme::PROJECT_LEFT ); + m_documentHeader->setRightPixmap( K3bTheme::PROJECT_RIGHT ); + + // add the document tab to the styled document box + m_documentTab = new K3bProjectTabWidget( d->documentHull ); + + documentHullLayout->addWidget( m_documentHeader, 0, 0 ); + documentHullLayout->addWidget( m_documentTab, 1, 0 ); + + connect( m_documentTab, SIGNAL(currentChanged(QWidget*)), this, SLOT(slotCurrentDocChanged()) ); + + d->welcomeWidget = new K3bWelcomeWidget( this, m_documentTab ); + m_documentTab->addTab( d->welcomeWidget, i18n("Quickstart") ); + +// d->documentStack->addWidget( d->welcomeWidget ); +// d->documentStack->raiseWidget( d->welcomeWidget ); + // --------------------------------------------------------------------------------------------- + + // --- Directory Dock -------------------------------------------------------------------------- + m_dirTreeDock = createDockWidget( "directory_tree", SmallIcon("folder"), 0, + kapp->makeStdCaption( i18n("Sidepanel") ), i18n("Sidepanel") ); + m_dirTreeDock->setEnableDocking( KDockWidget::DockCorner ); + + K3bFileTreeView* sidePanel = new K3bFileTreeView( m_dirTreeDock ); + //K3bSidePanel* sidePanel = new K3bSidePanel( this, m_dirTreeDock, "sidePanel" ); + + m_dirTreeDock->setWidget( sidePanel ); + m_dirTreeDock->manualDock( mainDock, KDockWidget::DockTop, 4000 ); + connect( m_dirTreeDock, SIGNAL(iMBeingClosed()), this, SLOT(slotDirTreeDockHidden()) ); + connect( m_dirTreeDock, SIGNAL(hasUndocked()), this, SLOT(slotDirTreeDockHidden()) ); + // --------------------------------------------------------------------------------------------- + + // --- Contents Dock --------------------------------------------------------------------------- + m_contentsDock = createDockWidget( "contents_view", SmallIcon("idea"), 0, + kapp->makeStdCaption( i18n("Contents View") ), i18n("Contents View") ); + m_contentsDock->setEnableDocking( KDockWidget::DockCorner ); + m_dirView = new K3bDirView( sidePanel/*->fileTreeView()*/, m_contentsDock ); + m_contentsDock->setWidget( m_dirView ); + m_contentsDock->manualDock( m_dirTreeDock, KDockWidget::DockRight, 2000 ); + + connect( m_contentsDock, SIGNAL(iMBeingClosed()), this, SLOT(slotContentsDockHidden()) ); + connect( m_contentsDock, SIGNAL(hasUndocked()), this, SLOT(slotContentsDockHidden()) ); + // --------------------------------------------------------------------------------------------- + + // --- filetreecombobox-toolbar ---------------------------------------------------------------- + K3bFileTreeComboBox* m_fileTreeComboBox = new K3bFileTreeComboBox( 0 ); + connect( m_fileTreeComboBox, SIGNAL(urlExecuted(const KURL&)), m_dirView, SLOT(showUrl(const KURL& )) ); + connect( m_fileTreeComboBox, SIGNAL(deviceExecuted(K3bDevice::Device*)), m_dirView, + SLOT(showDevice(K3bDevice::Device* )) ); + connect( m_dirView, SIGNAL(urlEntered(const KURL&)), m_fileTreeComboBox, SLOT(setUrl(const KURL&)) ); + connect( m_dirView, SIGNAL(deviceSelected(K3bDevice::Device*)), m_fileTreeComboBox, SLOT(setDevice(K3bDevice::Device*)) ); + + KWidgetAction* fileTreeComboAction = new KWidgetAction( m_fileTreeComboBox, + i18n("&Quick Dir Selector"), + 0, 0, 0, + actionCollection(), "quick_dir_selector" ); + fileTreeComboAction->setAutoSized(true); + (void)new KAction( i18n("Go"), "key_enter", 0, m_fileTreeComboBox, SLOT(slotGoUrl()), actionCollection(), "go_url" ); + // --------------------------------------------------------------------------------------------- +} + + +void K3bMainWindow::createClient( K3bDoc* doc ) +{ + // create the proper K3bView (maybe we should put this into some other class like K3bProjectManager) + K3bView* view = 0; + switch( doc->type() ) { + case K3bDoc::AUDIO: + view = new K3bAudioView( static_cast<K3bAudioDoc*>(doc), m_documentTab ); + break; + case K3bDoc::DATA: + view = new K3bDataView( static_cast<K3bDataDoc*>(doc), m_documentTab ); + break; + case K3bDoc::MIXED: + { + K3bMixedDoc* mixedDoc = static_cast<K3bMixedDoc*>(doc); + view = new K3bMixedView( mixedDoc, m_documentTab ); + mixedDoc->dataDoc()->setView( view ); + mixedDoc->audioDoc()->setView( view ); + break; + } + case K3bDoc::VCD: + view = new K3bVcdView( static_cast<K3bVcdDoc*>(doc), m_documentTab ); + break; + case K3bDoc::MOVIX: + view = new K3bMovixView( static_cast<K3bMovixDoc*>(doc), m_documentTab ); + break; + case K3bDoc::MOVIX_DVD: + view = new K3bMovixDvdView( static_cast<K3bMovixDvdDoc*>(doc), m_documentTab ); + break; + case K3bDoc::DVD: + view = new K3bDvdView( static_cast<K3bDvdDoc*>(doc), m_documentTab ); + break; + case K3bDoc::VIDEODVD: + view = new K3bVideoDvdView( static_cast<K3bVideoDvdDoc*>(doc), m_documentTab ); + break; + } + + doc->setView( view ); + view->setCaption( doc->URL().fileName() ); + + m_documentTab->insertTab( doc ); + m_documentTab->showPage( view ); + + slotCurrentDocChanged(); +} + + +K3bView* K3bMainWindow::activeView() const +{ + QWidget* w = m_documentTab->currentPage(); + if( K3bView* view = dynamic_cast<K3bView*>(w) ) + return view; + else + return 0; +} + + +K3bDoc* K3bMainWindow::activeDoc() const +{ + if( activeView() ) + return activeView()->getDocument(); + else + return 0; +} + + +K3bDoc* K3bMainWindow::openDocument(const KURL& url) +{ + slotStatusMsg(i18n("Opening file...")); + + // + // First we check if this is an iso image in case someone wants to open one this way + // + if( !isCdDvdImageAndIfSoOpenDialog( url ) ) { + + // see if it's an audio cue file + K3bCueFileParser parser( url.path() ); + if( parser.isValid() && parser.toc().contentType() == K3bDevice::AUDIO ) { + K3bDoc* doc = k3bappcore->projectManager()->createProject( K3bDoc::AUDIO ); + doc->addUrl( url ); + return doc; + } + else { + // check, if document already open. If yes, set the focus to the first view + K3bDoc* doc = k3bappcore->projectManager()->findByUrl( url ); + if( doc ) { + doc->view()->setFocus(); + return doc; + } + + doc = k3bappcore->projectManager()->openProject( url ); + + if( doc == 0 ) { + KMessageBox::error (this,i18n("Could not open document!"), i18n("Error!")); + return 0; + } + + actionFileOpenRecent->addURL(url); + + return doc; + } + } + else + return 0; +} + + +void K3bMainWindow::saveOptions() +{ + actionFileOpenRecent->saveEntries( config(), "Recent Files" ); + + // save dock positions! + manager()->writeConfig( config(), "Docking Config" ); + + m_dirView->saveConfig( config() ); + + saveMainWindowSettings( config(), "main_window_settings" ); + + k3bcore->saveSettings( config() ); + + d->welcomeWidget->saveConfig( config() ); + + KConfigGroup grp( m_config, "General Options" ); + grp.writeEntry( "Show Document Header", actionViewDocumentHeader->isChecked() ); +} + + +void K3bMainWindow::readOptions() +{ + KConfigGroup grp( m_config, "General Options" ); + + bool bViewDocumentHeader = grp.readBoolEntry("Show Document Header", true); + actionViewDocumentHeader->setChecked(bViewDocumentHeader); + + // initialize the recent file list + actionFileOpenRecent->loadEntries( config(), "Recent Files" ); + + // do not read dock-positions from a config that has been saved by an old version + K3bVersion configVersion( grp.readEntry( "config version", "0.1" ) ); + if( configVersion >= K3bVersion("0.12") ) + manager()->readConfig( config(), "Docking Config" ); + else + kdDebug() << "(K3bMainWindow) ignoring docking config from K3b version " << configVersion << endl; + + applyMainWindowSettings( config(), "main_window_settings" ); + + m_dirView->readConfig( config() ); + + slotViewDocumentHeader(); + slotCheckDockWidgetStatus(); +} + + +void K3bMainWindow::saveProperties( KConfig* c ) +{ + // 1. put saved projects in the config + // 2. save every modified project in "~/.kde/share/apps/k3b/sessions/" + KApp->sessionId() + // 3. save the url of the project (might be something like "AudioCD1") in the config + // 4. save the status of every project (modified/saved) + + QString saveDir = KGlobal::dirs()->saveLocation( "appdata", "sessions/" + qApp->sessionId() + "/", true ); + + // FIXME: for some reason the config entries are not properly stored when using the default + // KMainWindow session config. Since I was not able to find the bug I use another config object + // ---------------------------------------------------------- + c = new KSimpleConfig( saveDir + "list", false ); + c->setGroup( "Saved Session" ); + // ---------------------------------------------------------- + + const QPtrList<K3bDoc>& docs = k3bappcore->projectManager()->projects(); + c->writeEntry( "Number of projects", docs.count() ); + + int cnt = 1; + for( QPtrListIterator<K3bDoc> it( docs ); *it; ++it ) { + // the "name" of the project (or the original url if isSaved()) + c->writePathEntry( QString("%1 url").arg(cnt), (*it)->URL().url() ); + + // is the doc modified + c->writeEntry( QString("%1 modified").arg(cnt), (*it)->isModified() ); + + // has the doc already been saved? + c->writeEntry( QString("%1 saved").arg(cnt), (*it)->isSaved() ); + + // where does the session management save it? If it's not modified and saved this is + // the same as the url + KURL saveUrl = (*it)->URL(); + if( !(*it)->isSaved() || (*it)->isModified() ) + saveUrl = KURL::fromPathOrURL( saveDir + QString::number(cnt) ); + c->writePathEntry( QString("%1 saveurl").arg(cnt), saveUrl.url() ); + + // finally save it + k3bappcore->projectManager()->saveProject( *it, saveUrl ); + + ++cnt; + } + + // FIXME: for some reason the config entries are not properly stored when using the default + // KMainWindow session config. Since I was not able to find the bug I use another config object + // ---------------------------------------------------------- + delete c; + // ---------------------------------------------------------- +} + + +// FIXME:move this to K3bProjectManager +void K3bMainWindow::readProperties( KConfig* c ) +{ + // FIXME: do not delete the files here. rather do it when the app is exited normally + // since that's when we can be sure we never need the session stuff again. + + // 1. read all projects from the config + // 2. simply open all of themg + // 3. reset the saved urls and the modified state + // 4. delete "~/.kde/share/apps/k3b/sessions/" + KApp->sessionId() + + QString saveDir = KGlobal::dirs()->saveLocation( "appdata", "sessions/" + qApp->sessionId() + "/", true ); + + // FIXME: for some reason the config entries are not properly stored when using the default + // KMainWindow session config. Since I was not able to find the bug I use another config object + // ---------------------------------------------------------- + c = new KSimpleConfig( saveDir + "list", true ); + c->setGroup( "Saved Session" ); + // ---------------------------------------------------------- + + int cnt = c->readNumEntry( "Number of projects", 0 ); + kdDebug() << "(K3bMainWindow::readProperties) number of projects from last session in " << saveDir << ": " << cnt << endl + << " read from config group " << c->group() << endl; + + for( int i = 1; i <= cnt; ++i ) { + // in this case the constructor works since we saved as url() + KURL url = c->readPathEntry( QString("%1 url").arg(i) ); + + bool modified = c->readBoolEntry( QString("%1 modified").arg(i) ); + + bool saved = c->readBoolEntry( QString("%1 saved").arg(i) ); + + KURL saveUrl = c->readPathEntry( QString("%1 saveurl").arg(i) ); + + // now load the project + if( K3bDoc* doc = k3bappcore->projectManager()->openProject( saveUrl ) ) { + + // reset the url + doc->setURL( url ); + doc->setModified( modified ); + doc->setSaved( saved ); + } + else + kdDebug() << "(K3bMainWindow) could not open session saved doc " << url.path() << endl; + + // remove the temp file + if( !saved || modified ) + QFile::remove( saveUrl.path() ); + } + + // and now remove the temp dir + KIO::del( KURL::fromPathOrURL(saveDir), false, false ); + + // FIXME: for some reason the config entries are not properly stored when using the default + // KMainWindow session config. Since I was not able to find the bug I use another config object + // ---------------------------------------------------------- + delete c; + // ---------------------------------------------------------- +} + + +bool K3bMainWindow::queryClose() +{ + // + // Check if a job is currently running + // For now K3b only allows for one major job at a time which means that we only need to cancel + // this one job. + // + if( k3bcore->jobsRunning() ) { + + // pitty, but I see no possibility to make this work. It always crashes because of the event + // management thing mentioned below. So until I find a solution K3b simply will refuse to close + // while a job i running + return false; + +// kdDebug() << "(K3bMainWindow::queryClose) jobs running." << endl; +// K3bJob* job = k3bcore->runningJobs().getFirst(); + +// // now search for the major job (to be on the safe side although for now no subjobs register with the k3bcore) +// K3bJobHandler* jh = job->jobHandler(); +// while( jh->isJob() ) { +// job = static_cast<K3bJob*>( jh ); +// jh = job->jobHandler(); +// } + +// kdDebug() << "(K3bMainWindow::queryClose) main job found: " << job->jobDescription() << endl; + +// // now job is the major job and jh should be a widget +// QWidget* progressDialog = dynamic_cast<QWidget*>( jh ); + +// kdDebug() << "(K3bMainWindow::queryClose) job active: " << job->active() << endl; + +// // now ask the user if he/she really wants to cancel this job +// if( job->active() ) { +// if( KMessageBox::questionYesNo( progressDialog ? progressDialog : this, +// i18n("Do you really want to cancel?"), +// i18n("Cancel") ) == KMessageBox::Yes ) { +// // cancel the job +// kdDebug() << "(K3bMainWindow::queryClose) canceling job." << endl; +// job->cancel(); + +// // wait for the job to finish +// kdDebug() << "(K3bMainWindow::queryClose) waiting for job to finish." << endl; +// K3bSignalWaiter::waitForJob( job ); + +// // close the progress dialog +// if( progressDialog ) { +// kdDebug() << "(K3bMainWindow::queryClose) closing progress dialog." << endl; +// progressDialog->close(); +// // +// // now here we have the problem that due to the whole Qt event thing the exec call (or +// // in this case most likely the startJob call) does not return until we leave this method. +// // That means that the progress dialog might be deleted by it's parent below (when we +// // close docs) before it is deleted by the creator (most likely a projectburndialog). +// // That would result in a double deletion and thus a crash. +// // So we just reparent the dialog to 0 here so it's (former) parent won't delete it. +// // +// progressDialog->reparent( 0, QPoint(0,0) ); +// } + +// kdDebug() << "(K3bMainWindow::queryClose) job cleanup done." << endl; +// } +// else +// return false; +// } + } + + // + // if we are closed by the session manager everything is fine since we store the + // current state in saveProperties + // + if( kapp->sessionSaving() ) + return true; + + // FIXME: do not close the docs here. Just ask for them to be saved and return false + // if the user chose cancel for some doc + + // --------------------------------- + // we need to manually close all the views to ensure that + // each of them receives a close-event and + // the user is asked for every modified doc to save the changes + // --------------------------------- + + while( K3bView* view = activeView() ) { + if( !canCloseDocument(view->doc()) ) + return false; + closeProject(view->doc()); + } + + return true; +} + + +bool K3bMainWindow::canCloseDocument( K3bDoc* doc ) +{ + if( !doc->isModified() ) + return true; + + if( !KConfigGroup( config(), "General Options" ).readBoolEntry( "ask_for_saving_changes_on_exit", true ) ) + return true; + + switch ( KMessageBox::warningYesNoCancel( this, + i18n("%1 has unsaved data.").arg( doc->URL().fileName() ), + i18n("Closing Project"), + KStdGuiItem::save(), + KGuiItem( i18n("&Discard"), "editshred" ) ) ) + { + case KMessageBox::Yes: + fileSave( doc ); + case KMessageBox::No: + return true; + + default: + return false; + } +} + +bool K3bMainWindow::queryExit() +{ + // TODO: call this in K3bApplication somewhere + saveOptions(); + return true; +} + + + +///////////////////////////////////////////////////////////////////// +// SLOT IMPLEMENTATION +///////////////////////////////////////////////////////////////////// + + +void K3bMainWindow::slotFileOpen() +{ + slotStatusMsg(i18n("Opening file...")); + + KURL::List urls = KFileDialog::getOpenURLs( ":k3b-projects-folder", + i18n("*.k3b|K3b Projects"), + this, + i18n("Open Files") ); + for( KURL::List::iterator it = urls.begin(); it != urls.end(); ++it ) { + openDocument( *it ); + actionFileOpenRecent->addURL( *it ); + } +} + +void K3bMainWindow::slotFileOpenRecent(const KURL& url) +{ + slotStatusMsg(i18n("Opening file...")); + + openDocument(url); +} + + +void K3bMainWindow::slotFileSaveAll() +{ + for( QPtrListIterator<K3bDoc> it( k3bappcore->projectManager()->projects() ); + *it; ++it ) { + fileSave( *it ); + } +} + + +void K3bMainWindow::slotFileSave() +{ + if( K3bDoc* doc = activeDoc() ) { + fileSave( doc ); + } +} + +void K3bMainWindow::fileSave( K3bDoc* doc ) +{ + slotStatusMsg(i18n("Saving file...")); + + if( doc == 0 ) { + doc = activeDoc(); + } + if( doc != 0 ) { + if( !doc->isSaved() ) + fileSaveAs( doc ); + else if( !k3bappcore->projectManager()->saveProject( doc, doc->URL()) ) + KMessageBox::error (this,i18n("Could not save the current document!"), i18n("I/O Error")); + } +} + + +void K3bMainWindow::slotFileSaveAs() +{ + if( K3bDoc* doc = activeDoc() ) { + fileSaveAs( doc ); + } +} + + +void K3bMainWindow::fileSaveAs( K3bDoc* doc ) +{ + slotStatusMsg(i18n("Saving file with a new filename...")); + + if( doc == 0 ) { + doc = activeDoc(); + } + + if( doc != 0 ) { + // we do not use the static KFileDialog method here to be able to specify a filename suggestion + KFileDialog dlg( ":k3b-projects-folder", i18n("*.k3b|K3b Projects"), this, "filedialog", true ); + dlg.setCaption( i18n("Save As") ); + dlg.setOperationMode( KFileDialog::Saving ); + dlg.setSelection( doc->name() ); + dlg.exec(); + KURL url = dlg.selectedURL(); + + if( url.isValid() ) { + KRecentDocument::add( url ); + + bool exists = KIO::NetAccess::exists( url, false, 0 ); + if( !exists || + ( exists && + KMessageBox::warningContinueCancel( this, i18n("Do you want to overwrite %1?").arg( url.prettyURL() ), + i18n("File Exists"), i18n("Overwrite") ) + == KMessageBox::Continue ) ) { + + if( !k3bappcore->projectManager()->saveProject( doc, url ) ) { + KMessageBox::error (this,i18n("Could not save the current document!"), i18n("I/O Error")); + return; + } + else + actionFileOpenRecent->addURL(url); + } + } + } +} + + +void K3bMainWindow::slotFileClose() +{ + slotStatusMsg(i18n("Closing file...")); + if( K3bView* pView = activeView() ) { + if( pView ) { + K3bDoc* pDoc = pView->doc(); + + if( canCloseDocument(pDoc) ) { + closeProject(pDoc); + } + } + } + + slotCurrentDocChanged(); +} + + +void K3bMainWindow::slotFileCloseAll() +{ + while( K3bView* pView = activeView() ) { + if( pView ) { + K3bDoc* pDoc = pView->doc(); + + if( canCloseDocument(pDoc) ) + closeProject(pDoc); + else + break; + } + } + + slotCurrentDocChanged(); +} + + +void K3bMainWindow::closeProject( K3bDoc* doc ) +{ + // unplug the actions + if( factory() ) { + if( d->lastDoc == doc ) { + factory()->removeClient( static_cast<K3bView*>(d->lastDoc->view()) ); + d->lastDoc = 0; + } + } + + // remove the view from the project tab + m_documentTab->removePage( doc->view() ); + + // remove the project from the manager + k3bappcore->projectManager()->removeProject( doc ); + + // delete view and doc + delete doc->view(); + delete doc; +} + + +void K3bMainWindow::slotFileQuit() +{ + close(); +} + + +void K3bMainWindow::slotViewStatusBar() +{ + //turn Statusbar on or off + if(actionViewStatusBar->isChecked()) { + statusBar()->show(); + } + else { + statusBar()->hide(); + } +} + + +void K3bMainWindow::slotStatusMsg(const QString &text) +{ + /////////////////////////////////////////////////////////////////// + // change status message permanently +// statusBar()->clear(); +// statusBar()->changeItem(text,1); + + statusBar()->message( text, 2000 ); +} + + +void K3bMainWindow::slotSettingsConfigure() +{ + K3bOptionDialog d( this, "SettingsDialog", true ); + + d.exec(); + + // emit a changed signal every time since we do not know if the user selected + // "apply" and "cancel" or "ok" + emit configChanged( m_config ); +} + + +void K3bMainWindow::showOptionDialog( int index ) +{ + K3bOptionDialog d( this, "SettingsDialog", true ); + + d.showPage( index ); + + d.exec(); + + // emit a changed signal every time since we do not know if the user selected + // "apply" and "cancel" or "ok" + emit configChanged( m_config ); +} + + +K3bDoc* K3bMainWindow::slotNewAudioDoc() +{ + slotStatusMsg(i18n("Creating new Audio CD Project.")); + + K3bDoc* doc = k3bappcore->projectManager()->createProject( K3bDoc::AUDIO ); + + return doc; +} + +K3bDoc* K3bMainWindow::slotNewDataDoc() +{ + slotStatusMsg(i18n("Creating new Data CD Project.")); + + K3bDoc* doc = k3bappcore->projectManager()->createProject( K3bDoc::DATA ); + + return doc; +} + + +K3bDoc* K3bMainWindow::slotNewDvdDoc() +{ + slotStatusMsg(i18n("Creating new Data DVD Project.")); + + K3bDoc* doc = k3bappcore->projectManager()->createProject( K3bDoc::DVD ); + + return doc; +} + + +K3bDoc* K3bMainWindow::slotContinueMultisession() +{ + return K3bDataSessionImportDialog::importSession( 0, this ); +} + + +K3bDoc* K3bMainWindow::slotNewVideoDvdDoc() +{ + slotStatusMsg(i18n("Creating new VideoDVD Project.")); + + K3bDoc* doc = k3bappcore->projectManager()->createProject( K3bDoc::VIDEODVD ); + + return doc; +} + + +K3bDoc* K3bMainWindow::slotNewMixedDoc() +{ + slotStatusMsg(i18n("Creating new Mixed Mode CD Project.")); + + K3bDoc* doc = k3bappcore->projectManager()->createProject( K3bDoc::MIXED ); + + return doc; +} + +K3bDoc* K3bMainWindow::slotNewVcdDoc() +{ + slotStatusMsg(i18n("Creating new Video CD Project.")); + + K3bDoc* doc = k3bappcore->projectManager()->createProject( K3bDoc::VCD ); + + return doc; +} + + +K3bDoc* K3bMainWindow::slotNewMovixDoc() +{ + slotStatusMsg(i18n("Creating new eMovix CD Project.")); + + K3bDoc* doc = k3bappcore->projectManager()->createProject( K3bDoc::MOVIX ); + + return doc; +} + + +K3bDoc* K3bMainWindow::slotNewMovixDvdDoc() +{ + slotStatusMsg(i18n("Creating new eMovix DVD Project.")); + + K3bDoc* doc = k3bappcore->projectManager()->createProject( K3bDoc::MOVIX_DVD ); + + return doc; +} + + +void K3bMainWindow::slotCurrentDocChanged() +{ + // check the doctype + K3bView* v = activeView(); + if( v ) { + k3bappcore->projectManager()->setActive( v->doc() ); + + // + // There are two possiblities to plug the project actions: + // 1. Through KXMLGUIClient::plugActionList + // This way we just ask the View for the actionCollection (which it should merge with + // the doc's) and plug it into the project menu. + // Advantage: easy and clear to handle + // Disadvantage: we may only plug all actions at once into one menu + // + // 2. Through merging the doc as a KXMLGUIClient + // This way every view is a KXMLGUIClient and it's GUI is just merged into the MainWindow's. + // Advantage: flexible + // Disadvantage: every view needs it's own XML file + // + // + + if( factory() ) { + if( d->lastDoc ) + factory()->removeClient( static_cast<K3bView*>(d->lastDoc->view()) ); + factory()->addClient( v ); + d->lastDoc = v->doc(); + } + else + kdDebug() << "(K3bMainWindow) ERROR: could not get KXMLGUIFactory instance." << endl; + } + else + k3bappcore->projectManager()->setActive( 0L ); + + if( k3bappcore->projectManager()->isEmpty() ) { + slotStateChanged( "state_project_active", KXMLGUIClient::StateReverse ); + } + else { + d->documentStack->raiseWidget( d->documentHull ); + slotStateChanged( "state_project_active", KXMLGUIClient::StateNoReverse ); + } + + // make sure the document header is shown (or not) + slotViewDocumentHeader(); +} + + +void K3bMainWindow::slotEditToolbars() +{ + saveMainWindowSettings( m_config, "main_window_settings" ); + KEditToolbar dlg( factory() ); + connect(&dlg, SIGNAL(newToolbarConfig()), SLOT(slotNewToolBarConfig())); + dlg.exec(); +} + + +void K3bMainWindow::slotNewToolBarConfig() +{ + applyMainWindowSettings( m_config, "main_window_settings" ); +} + + +bool K3bMainWindow::eject() +{ + KConfigGroup c( config(), "General Options" ); + return !c.readBoolEntry( "No cd eject", false ); +} + + +void K3bMainWindow::slotErrorMessage(const QString& message) +{ + KMessageBox::error( this, message ); +} + + +void K3bMainWindow::slotWarningMessage(const QString& message) +{ + KMessageBox::sorry( this, message ); +} + + +void K3bMainWindow::slotWriteCdImage() +{ + K3bCdImageWritingDialog d( this ); + d.exec(false); +} + + +void K3bMainWindow::slotWriteDvdIsoImage() +{ + K3bIsoImageWritingDialog d( this ); + d.exec(false); +} + + +void K3bMainWindow::slotWriteDvdIsoImage( const KURL& url ) +{ + K3bIsoImageWritingDialog d( this ); + d.setImage( url ); + d.exec(false); +} + + +void K3bMainWindow::slotWriteCdImage( const KURL& url ) +{ + K3bCdImageWritingDialog d( this ); + d.setImage( url ); + d.exec(false); +} + + +void K3bMainWindow::slotProjectAddFiles() +{ + K3bView* view = activeView(); + + if( view ) { + QStringList files = KFileDialog::getOpenFileNames( ":k3b-project-add-files", + i18n("*|All Files"), + this, + i18n("Select Files to Add to Project") ); + + KURL::List urls; + for( QStringList::ConstIterator it = files.begin(); + it != files.end(); it++ ) { + KURL url; + url.setPath(*it); + urls.append( url ); + } + + if( !urls.isEmpty() ) + view->addUrls( urls ); + } + else + KMessageBox::error( this, i18n("Please create a project before adding files"), i18n("No Active Project")); +} + + +void K3bMainWindow::slotK3bSetup() +{ + KProcess p; + p << "kdesu" << "kcmshell k3bsetup2 --lang " + KGlobal::locale()->language(); + if( !p.start( KProcess::DontCare ) ) + KMessageBox::error( 0, i18n("Could not find kdesu to run K3bSetup with root privileges. " + "Please run it manually as root.") ); +} + + +void K3bMainWindow::blankCdrw( K3bDevice::Device* dev ) +{ + K3bBlankingDialog dlg( this, "blankingdialog" ); + dlg.setDevice( dev ); + dlg.exec(false); +} + + +void K3bMainWindow::slotBlankCdrw() +{ + blankCdrw( 0 ); +} + + +void K3bMainWindow::formatDvd( K3bDevice::Device* dev ) +{ + K3bDvdFormattingDialog d( this ); + d.setDevice( dev ); + d.exec(false); +} + + +void K3bMainWindow::slotFormatDvd() +{ + formatDvd( 0 ); +} + + +void K3bMainWindow::cdCopy( K3bDevice::Device* dev ) +{ + K3bCdCopyDialog d( this ); + d.setReadingDevice( dev ); + d.exec(false); +} + + +void K3bMainWindow::slotCdCopy() +{ + cdCopy( 0 ); +} + + +void K3bMainWindow::dvdCopy( K3bDevice::Device* dev ) +{ + K3bDvdCopyDialog d( this ); + d.setReadingDevice( dev ); + d.exec(false); +} + + +void K3bMainWindow::slotDvdCopy() +{ + dvdCopy( 0 ); +} + + +// void K3bMainWindow::slotVideoDvdCopy() +// { +// K3bVideoDvdCopyDialog d( this ); +// d.exec(); +// } + + +void K3bMainWindow::slotShowDirTreeView() +{ + m_dirTreeDock->changeHideShowState(); + slotCheckDockWidgetStatus(); +} + + +void K3bMainWindow::slotShowContentsView() +{ + m_contentsDock->changeHideShowState(); + slotCheckDockWidgetStatus(); +} + + +void K3bMainWindow::slotShowMenuBar() +{ + if( menuBar()->isVisible() ) + menuBar()->hide(); + else + menuBar()->show(); +} + + +void K3bMainWindow::slotShowTips() +{ + KTipDialog::showTip( this, QString::null, true ); +} + + +void K3bMainWindow::slotDirTreeDockHidden() +{ + actionViewDirTreeView->setChecked( false ); +} + + +void K3bMainWindow::slotContentsDockHidden() +{ + actionViewContentsView->setChecked( false ); +} + + +void K3bMainWindow::slotCheckDockWidgetStatus() +{ + actionViewContentsView->setChecked( m_contentsDock->isVisible() ); + actionViewDirTreeView->setChecked( m_dirTreeDock->isVisible() ); +} + + +void K3bMainWindow::slotViewDocumentHeader() +{ + if( actionViewDocumentHeader->isChecked() && + !k3bappcore->projectManager()->isEmpty() ) { + m_documentHeader->show(); + } + else { + m_documentHeader->hide(); + } +} + + +K3bExternalBinManager* K3bMainWindow::externalBinManager() const +{ + return k3bcore->externalBinManager(); +} + + +K3bDevice::DeviceManager* K3bMainWindow::deviceManager() const +{ + return k3bcore->deviceManager(); +} + + +void K3bMainWindow::slotDataImportSession() +{ + if( activeView() ) { + if( K3bDataView* view = dynamic_cast<K3bDataView*>(activeView()) ) { + view->importSession(); + } + } +} + + +void K3bMainWindow::slotDataClearImportedSession() +{ + if( activeView() ) { + if( K3bDataView* view = dynamic_cast<K3bDataView*>(activeView()) ) { + view->clearImportedSession(); + } + } +} + + +void K3bMainWindow::slotEditBootImages() +{ + if( activeView() ) { + if( K3bDataView* view = dynamic_cast<K3bDataView*>(activeView()) ) { + view->editBootImages(); + } + } +} + + +void K3bMainWindow::slotCheckSystemTimed() +{ + // run the system check from the event queue so we do not + // mess with the device state resetting throughout the app + // when called from K3bDeviceManager::changed + QTimer::singleShot( 0, this, SLOT(slotCheckSystem()) ); +} + + +void K3bMainWindow::slotCheckSystem() +{ + K3bSystemProblemDialog::checkSystem( this ); +} + + +void K3bMainWindow::addUrls( const KURL::List& urls ) +{ + if( K3bView* view = activeView() ) { + view->addUrls( urls ); + } + else { + // check if the files are all audio we can handle. If so create an audio project + bool audio = true; + QPtrList<K3bPlugin> fl = k3bcore->pluginManager()->plugins( "AudioDecoder" ); + for( KURL::List::const_iterator it = urls.begin(); it != urls.end(); ++it ) { + const KURL& url = *it; + + if( QFileInfo(url.path()).isDir() ) { + audio = false; + break; + } + + bool a = false; + for( QPtrListIterator<K3bPlugin> it( fl ); it.current(); ++it ) { + if( static_cast<K3bAudioDecoderFactory*>(it.current())->canDecode( url ) ) { + a = true; + break; + } + } + if( !a ) { + audio = a; + break; + } + } + + if( !audio && urls.count() == 1 ) { + // see if it's an audio cue file + K3bCueFileParser parser( urls.first().path() ); + if( parser.isValid() && parser.toc().contentType() == K3bDevice::AUDIO ) { + audio = true; + } + } + + if( audio ) + static_cast<K3bView*>(slotNewAudioDoc()->view())->addUrls( urls ); + else if( urls.count() > 1 || !isCdDvdImageAndIfSoOpenDialog( urls.first() ) ) + static_cast<K3bView*>(slotNewDataDoc()->view())->addUrls( urls ); + } +} + + +void K3bMainWindow::slotClearProject() +{ + K3bDoc* doc = k3bappcore->projectManager()->activeDoc(); + if( doc ) { + if( KMessageBox::warningContinueCancel( this, + i18n("Do you really want to clear the current project?"), + i18n("Clear Project"), + i18n("Clear"), + "clear_current_project_dontAskAgain" ) == KMessageBox::Continue ) { + doc->newDocument(); + k3bappcore->projectManager()->loadDefaults( doc ); + } + } +} + + +bool K3bMainWindow::isCdDvdImageAndIfSoOpenDialog( const KURL& url ) +{ + K3bIso9660 iso( url.path() ); + if( iso.open() ) { + iso.close(); + // very rough dvd image size test + if( K3b::filesize( url ) > 1000*1024*1024 ) + slotWriteDvdIsoImage( url ); + else + slotWriteCdImage( url ); + + return true; + } + else + return false; +} + + +void K3bMainWindow::slotCddaRip() +{ + cddaRip( 0 ); +} + + +void K3bMainWindow::cddaRip( K3bDevice::Device* dev ) +{ + if( !dev || + !(k3bappcore->mediaCache()->medium( dev ).content() & K3bMedium::CONTENT_AUDIO ) ) + dev = K3bMediaSelectionDialog::selectMedium( K3bDevice::MEDIA_CD_ALL, + K3bDevice::STATE_COMPLETE|K3bDevice::STATE_INCOMPLETE, + K3bMedium::CONTENT_AUDIO, + this, + i18n("Audio CD Rip") ); + + if( dev ) + m_dirView->showDevice( dev ); +} + + +void K3bMainWindow::videoDvdRip( K3bDevice::Device* dev ) +{ + if( !dev || + !(k3bappcore->mediaCache()->medium( dev ).content() & K3bMedium::CONTENT_VIDEO_DVD ) ) + dev = K3bMediaSelectionDialog::selectMedium( K3bDevice::MEDIA_DVD_ALL, + K3bDevice::STATE_COMPLETE, + K3bMedium::CONTENT_VIDEO_DVD, + this, + i18n("Video DVD Rip") ); + + if( dev ) + m_dirView->showDevice( dev ); +} + + +void K3bMainWindow::slotVideoDvdRip() +{ + videoDvdRip( 0 ); +} + + +void K3bMainWindow::videoCdRip( K3bDevice::Device* dev ) +{ + if( !dev || + !(k3bappcore->mediaCache()->medium( dev ).content() & K3bMedium::CONTENT_VIDEO_CD ) ) + dev = K3bMediaSelectionDialog::selectMedium( K3bDevice::MEDIA_CD_ALL, + K3bDevice::STATE_COMPLETE, + K3bMedium::CONTENT_VIDEO_CD, + this, + i18n("Video CD Rip") ); + + if( dev ) + m_dirView->showDevice( dev ); +} + + +void K3bMainWindow::slotVideoCdRip() +{ + videoCdRip( 0 ); +} + + +void K3bMainWindow::slotAudioServerError( const QString& error ) +{ + K3bPassivePopup::showPopup( error, i18n("Audio Output Problem") ); +} + +#include "k3b.moc" + diff --git a/src/k3b.desktop b/src/k3b.desktop new file mode 100644 index 0000000..e6c107b --- /dev/null +++ b/src/k3b.desktop @@ -0,0 +1,123 @@ +[Desktop Entry] +Type=Application +Exec=k3b %U +Icon=k3b +DocPath=k3b/index.html +GenericName=CD & DVD Burning +GenericName[af]=CD & DVD Skrywer +GenericName[ar]= اعداد كتابة القرص المدمج(CD) و القرص المرئي الرقمي (DVD) +GenericName[bg]=Запис на CD и DVD +GenericName[bn]=সিডি এবং ডিভিডি লিখন +GenericName[br]=Skrivañ CD ha DVD +GenericName[bs]=CD & DVD prženje +GenericName[ca]=Programa per gravar CDs i DVDs +GenericName[cs]=Vypalování CD a DVD +GenericName[da]=Cd & dvd-skriveprogram +GenericName[de]=CD & DVD-Brennen +GenericName[el]=Εγγραφή CD & DVD +GenericName[eo]=KD & DVD enskribo +GenericName[es]=Grabación de CD y DVD +GenericName[et]=CD ja DVD kirjutamine +GenericName[fa]=سوزاندن دیسک فشرده و دی وی دی +GenericName[fi]=Poltto-ohjelma +GenericName[fr]=Gravure de CD et DVD +GenericName[gl]=Gravazón de CDs e DVDs +GenericName[he]=צרינת תקליטורי CD & DVD +GenericName[hi]=सीडी & डीवीडी बर्निंग +GenericName[hu]=CD- és DVD-író +GenericName[is]=CD og DVD brennsla +GenericName[it]=Masterizzazione CD e DVD +GenericName[ja]=CD / DVD 作成 +GenericName[ka]=CD-ის და DVD-ის ჩანაწერა +GenericName[km]=ការ​ដុត​ស៊ីឌី & ឌីវីឌី +GenericName[lt]=CD ir DVD kūrimas +GenericName[mk]=Снимање на CD и DVD +GenericName[ms]=Membakar CD & DVD +GenericName[nb]=CD- og DVD-brenning +GenericName[nds]=Brennen vun CD & DVD +GenericName[ne]=सीडी र डीभीडी बर्निङ +GenericName[nl]=CD- en dvd-brandprogramma +GenericName[nn]=CD- og DVD-brenning +GenericName[pa]=CD & DVD ਲਿਖਣ ਲਈ +GenericName[pl]=Nagrywanie płyt CD i DVD +GenericName[pt]=Gravação de CDs e DVDs +GenericName[pt_BR]=Queima de CD & DVD +GenericName[ru]=Запись CD и DVD +GenericName[sk]=Napaľovanie CD & DVD +GenericName[sl]=Pisanje CD-jev in DVD-jev +GenericName[sr]=Резање CD-а и DVD-а +GenericName[sr@Latn]=Rezanje CD-a i DVD-a +GenericName[sv]=Cd och dvd-brännprogram +GenericName[ta]=சிடி எழுதும் தகவல் +GenericName[tg]=Сабти CD ва DVD +GenericName[tr]=CD ve DVD Kaydedici +GenericName[uk]=Запис КД та DVD +GenericName[uz]=CD va DVD disklarga yozish +GenericName[uz@cyrillic]=CD ва DVD дискларга ёзиш +GenericName[zh_CN]=CD & DVD 烧录程序 +GenericName[zh_TW]=CD & DVD 燒錄 +Comment=CD writing program +Comment[af]=CD skryf program +Comment[ar]=برنامج لكتابة الاقراص المدمجة CD +Comment[bg]=Програма за запис на CD +Comment[bn]=সিডি লিখন প্রোগ্র্যাম +Comment[br]=Program skriver CD +Comment[bs]=Program za prženje CDova +Comment[ca]=Programa gravador de CDs +Comment[cs]=Program pro vypalování CD +Comment[da]=Cd-skriveprogram +Comment[de]=CD-Brennprogramm +Comment[el]=Πρόγραμμα εγγραφής CD +Comment[eo]=KD skribilo +Comment[es]=Programa de grabación de CD +Comment[et]=CD kirjutamise rakendus +Comment[fa]=برنامۀ نوشتن دیسک فشرده +Comment[fi]=Poltto-ohjelma +Comment[fr]=Programme de gravure de CD +Comment[gl]=Un programa de gravazón de CDs +Comment[he]=תוכנית צריבת תקליטורים +Comment[hi]=सीडी लिखने का प्रोग्राम +Comment[hu]=CD-író program +Comment[is]=CD skrifunarforrit +Comment[it]=Programma di masterizzazione +Comment[ja]=CD 書き込みプログラム +Comment[ka]=CD-ის ჩამწერი პროგრამა +Comment[km]=កម្មវិធី​សរសេរ​ស៊ីឌី +Comment[lt]=CD įrašymo programa +Comment[mk]=Програма за снимање на CD +Comment[ms]=Program menulis CD +Comment[nb]=CD-brenningsprogram +Comment[nds]=CD-Schriefprogramm +Comment[ne]=सीडी लेख्ने कार्यक्रम +Comment[nl]=CD-brandprogramma +Comment[nn]=CD-brenneprogram +Comment[pa]=CD ਲਿਖਣ ਕਾਰਜ +Comment[pl]=Program do nagrywania płyt CD +Comment[pt]=Um programa de gravação de CDs +Comment[pt_BR]=Programa de gravação em CD +Comment[ru]=Программа записи на CD +Comment[sk]=CD vypaľovací program +Comment[sl]=Program za pisanje CD-jev +Comment[sr]=Програм за писање CD-а +Comment[sr@Latn]=Program za pisanje CD-a +Comment[sv]=Cd-brännprogram +Comment[ta]=குறுந்தகட்டில் எழுதும் நிரல் +Comment[tg]=Барномаи сабти компакт-дискҳо +Comment[tr]=CD yazdırma programı +Comment[uk]=Програма запису КД +Comment[uz]=Kompakt-diskka yozish dasturi +Comment[uz@cyrillic]=Компакт-дискка ёзиш дастури +Comment[xh]=Ubhalo lwe Cd lodweiso Iwenkqubo +Comment[zh_CN]=CD 刻录程序 +Comment[zh_TW]=CD 燒錄程式 +Comment[zu]=Uhlelo lwemisebenzi olubhala i-CD +Terminal=false +Name=K3b +Name[ar]= K3b +Name[bn]=কে-থ্রি-বি +Name[hi]=के3बी +MimeType=application/x-k3b;application/x-iso;application/x-cue +X-KDE-StartupNotify=true +X-KDE-NativeMimeType=application/x-k3b;application/x-iso;application/x-cue +Categories=KDE;Application;AudioVideo;DiscBurning; +X-DCOP-ServiceType=Unique diff --git a/src/k3b.h b/src/k3b.h new file mode 100644 index 0000000..37532b0 --- /dev/null +++ b/src/k3b.h @@ -0,0 +1,330 @@ +/* + * + * $Id: k3b.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + + +#ifndef K3B_H +#define K3B_H + + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +// include files for Qt +#include <qstrlist.h> +#include <qworkspace.h> +#include <qptrlist.h> + +// include files for KDE +#include <kapplication.h> +#include <kparts/dockmainwindow.h> +#include <kdockwidget.h> +#include <kaction.h> +#include <kurl.h> + +class QVBox; + + +// forward declaration of the K3b classes +class K3bMainWindow; +class K3bDoc; +class K3bView; +class K3bDirView; +class K3bExternalBinManager; +class K3bOptionDialog; +class K3bJob; +class K3bProjectTabWidget; +class K3bSongManager; +class KSystemTray; +class K3bStatusBarManager; +class K3bProjectInterface; +class K3bThemedHeader; + +namespace K3bDevice { + class DeviceManager; + class Device; +} + + +class K3bMainWindow : public KParts::DockMainWindow +{ + Q_OBJECT + + public: + /** construtor of K3bMainWindow, calls all init functions to create the application. + * @see initMenuBar initToolBar + */ + K3bMainWindow(); + ~K3bMainWindow(); + + /** opens a file specified by commandline option */ + K3bDoc* openDocument( const KURL& url = KURL() ); + + K3bDevice::DeviceManager* deviceManager() const; + K3bExternalBinManager* externalBinManager() const; + KConfig* config() const { return m_config; } + // return main window with browser/cd/dvd view, used for DND + K3bDirView* mainWindow() const { return m_dirView; } + /** + * @returns a pointer to the currently visible view or 0 if no project was created + */ + K3bView* activeView() const; + /** + * @returns a pointer to the doc associated with the currently visible view or 0 if no project was created + */ + K3bDoc* activeDoc() const; + + const QPtrList<K3bDoc>& projects() const; + + bool eject(); + void showOptionDialog( int = 0 ); + + /** Creates the main view of the KDockMainWindow instance and initializes the MDI view area including any needed + * connections. + * must be called after construction + */ + void initView(); + + KSystemTray* systemTray() const { return m_systemTray; } + + public slots: + K3bDoc* slotNewAudioDoc(); + K3bDoc* slotNewDataDoc(); + K3bDoc* slotNewMixedDoc(); + K3bDoc* slotNewVcdDoc(); + K3bDoc* slotNewMovixDoc(); + K3bDoc* slotNewMovixDvdDoc(); + K3bDoc* slotNewDvdDoc(); + K3bDoc* slotNewVideoDvdDoc(); + K3bDoc* slotContinueMultisession(); + + void slotClearProject(); + + void blankCdrw( K3bDevice::Device* ); + void slotBlankCdrw(); + void formatDvd( K3bDevice::Device* ); + void slotFormatDvd(); + void slotWriteCdImage(); + void slotWriteCdImage( const KURL& url ); + void slotWriteDvdIsoImage(); + void slotWriteDvdIsoImage( const KURL& url ); + void cdCopy( K3bDevice::Device* ); + void slotCdCopy(); + void dvdCopy( K3bDevice::Device* ); + void slotDvdCopy(); + void cddaRip( K3bDevice::Device* ); + void slotCddaRip(); + void videoDvdRip( K3bDevice::Device* ); + void slotVideoDvdRip(); + void videoCdRip( K3bDevice::Device* ); + void slotVideoCdRip(); + void slotK3bSetup(); + + void slotErrorMessage(const QString&); + void slotWarningMessage(const QString&); + + void slotConfigureKeys(); + void slotShowTips(); + void slotCheckSystem(); + + void addUrls( const KURL::List& urls ); + + signals: + void initializationInfo( const QString& ); + void configChanged( KConfig* c ); + + protected: + /** queryClose is called by KTMainWindow on each closeEvent of a window. Against the + * default implementation (only returns true), this overridden function retrieves all modified documents + * from the open document list and asks the user to select which files to save before exiting the application. + * @see KTMainWindow#queryClose + * @see KTMainWindow#closeEvent + */ + virtual bool queryClose(); + + /** queryExit is called by KTMainWindow when the last window of the application is going to be closed during the closeEvent(). + * Against the default implementation that just returns true, this calls saveOptions() to save the settings of the last window's + * properties. + * @see KTMainWindow#queryExit + * @see KTMainWindow#closeEvent + */ + virtual bool queryExit(); + + /** saves the window properties for each open window during session end to the session config file, including saving the currently + * opened file by a temporary filename provided by KApplication. + * @see KTMainWindow#saveProperties + */ + virtual void saveProperties(KConfig *_cfg); + + /** reads the session config file and restores the application's state including the last opened files and documents by reading the + * temporary files saved by saveProperties() + * @see KTMainWindow#readProperties + */ + virtual void readProperties(KConfig *_cfg); + + /** + * checks if doc is modified and asks the user for saving if so. + * returns false if the user chose cancel. + */ + bool canCloseDocument( K3bDoc* ); + + virtual void showEvent( QShowEvent* e ); + + private slots: + /** open a file and load it into the document*/ + void slotFileOpen(); + /** opens a file from the recent files menu */ + void slotFileOpenRecent(const KURL& url); + /** save a document */ + void slotFileSave(); + /** save a document by a new filename*/ + void slotFileSaveAs(); + void slotFileSaveAll(); + /** asks for saving if the file is modified, then closes the actual file and window*/ + void slotFileClose(); + void slotFileCloseAll(); + + void slotDirTreeDockHidden(); + void slotContentsDockHidden(); + + void slotSettingsConfigure(); + + /** checks if the currently visible tab is a k3bview + or not and dis- or enables some actions */ + void slotCurrentDocChanged(); + + void slotFileQuit(); + + /** toggles the statusbar + */ + void slotViewStatusBar(); + + void slotViewDocumentHeader(); + + void slotCheckDockWidgetStatus(); + + /** changes the statusbar contents for the standard label permanently, used to indicate current actions. + * @param text the text that is displayed in the statusbar + */ + void slotStatusMsg(const QString &text); + + void slotShowDirTreeView(); + void slotShowContentsView(); + void slotShowMenuBar(); + + void slotProjectAddFiles(); + + void slotEditToolbars(); + void slotNewToolBarConfig(); + + void slotDataImportSession(); + void slotDataClearImportedSession(); + void slotEditBootImages(); + + void slotAudioServerError( const QString& error ); + + void createClient(K3bDoc* doc); + + /** + * Run slotCheckSystem with a timer + */ + void slotCheckSystemTimed(); + + private: + void fileSave( K3bDoc* doc = 0 ); + void fileSaveAs( K3bDoc* doc = 0 ); + void closeProject( K3bDoc* ); + + /** save general Options like all bar positions and status as well as the geometry and the recent file list to the configuration + * file + */ + void saveOptions(); + /** read general Options again and initialize all variables like the recent file list */ + void readOptions(); + + /** initializes the KActions of the application */ + void initActions(); + + /** sets up the statusbar for the main window by initialzing a statuslabel. + */ + void initStatusBar(); + + bool isCdDvdImageAndIfSoOpenDialog( const KURL& url ); + + /** the configuration object of the application */ + KConfig *m_config; + + /** The MDI-Interface is managed by this tabbed view */ + K3bProjectTabWidget* m_documentTab; + + // KAction pointers to enable/disable actions + KActionMenu* actionFileNewMenu; + KAction* actionFileNewAudio; + KAction* actionFileNewData; + KAction* actionFileNewMixed; + KAction* actionFileNewVcd; + KAction* actionFileNewMovix; + KAction* actionFileNewMovixDvd; + KAction* actionFileNewDvd; + KAction* actionFileNewVideoDvd; + KAction* actionFileContinueMultisession; + KAction* actionFileOpen; + KRecentFilesAction* actionFileOpenRecent; + KAction* actionFileSave; + KAction* actionFileSaveAs; + KAction* actionFileSaveAll; + KAction* actionFileClose; + KAction* actionFileCloseAll; + KAction* actionFileQuit; + KAction* actionSettingsConfigure; + KAction* actionSettingsK3bSetup; + KAction* actionToolsBlankCdrw; + KAction* actionToolsWriteCdImage; + KAction* actionToolsCddaRip; + KAction* actionToolsVideoDvdRip; + KAction* actionToolsVideoCdRip; + KAction* actionCdCopy; + KAction* actionProjectAddFiles; + KToggleAction* actionViewStatusBar; + KToggleAction* actionViewDirTreeView; + KToggleAction* actionViewContentsView; + KToggleAction* actionViewDocumentHeader; + + // project actions + QPtrList<KAction> m_dataProjectActions; + + KDockWidget* mainDock; + KDockWidget* m_contentsDock; + KDockWidget* m_dirTreeDock; + + // The K3b-specific widgets + K3bDirView* m_dirView; + K3bOptionDialog* m_optionDialog; + + K3bStatusBarManager* m_statusBarManager; + + KSystemTray* m_systemTray; + + bool m_initialized; + + // the funny header + K3bThemedHeader* m_documentHeader; + + class Private; + Private* d; +}; + +#endif // K3B_H diff --git a/src/k3bappdevicemanager.cpp b/src/k3bappdevicemanager.cpp new file mode 100644 index 0000000..c21f746 --- /dev/null +++ b/src/k3bappdevicemanager.cpp @@ -0,0 +1,304 @@ +/* + * + * $Id: sourceheader 380067 2005-01-19 13:03:46Z trueg $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bappdevicemanager.h" + +#include <k3bdevice.h> +#include <k3bdevicehandler.h> +#include <k3bglobals.h> +#include <k3bapplication.h> +#include <k3bmediacache.h> + +#include <kaction.h> +#include <kinputdialog.h> +#include <kmessagebox.h> +#include <kinputdialog.h> +#include <kio/job.h> +#include <klocale.h> +#include <kio/global.h> +#include <kpopupmenu.h> + + +K3bAppDeviceManager::K3bAppDeviceManager( QObject* parent, const char* name ) + : K3bDevice::DeviceManager( parent, name ), + m_currentDevice(0), + m_ejectRequested(false) +{ + // FIXME: should we pass the mainwindow as watch window here? + // Is there a proper way to insert this actioncollection into the mainwindow's? + m_actionCollection = new KActionCollection( this ); + + // setup actions + KActionMenu* devicePopupMenu = new KActionMenu( m_actionCollection, "device_popup" ); + m_actionDiskInfo = new KAction( i18n("Media &Info"), "info", 0, this, SLOT(diskInfo()), + m_actionCollection, "device_diskinfo"); + m_actionUnmount = new KAction( i18n("&Unmount"), "cdrom_unmount", 0, this, SLOT(unmountDisk()), + m_actionCollection, "device_unmount"); + m_actionMount = new KAction( i18n("&Mount"), "cdrom_mount", 0, this, SLOT(mountDisk()), + m_actionCollection, "device_mount"); + m_actionEject = new KAction( i18n("&Eject"), "", 0, this, SLOT(ejectDisk()), + m_actionCollection, "device_eject"); + m_actionLoad = new KAction( i18n("L&oad"), "", 0, this, SLOT(loadDisk()), + m_actionCollection, "device_load"); +// KAction* actionUnlock = new KAction( i18n("Un&lock"), "", 0, this, SLOT(unlockDevice()), +// m_actionCollection, "device_unlock" ); +// KAction* actionlock = new KAction( i18n("Loc&k"), "", 0, this, SLOT(lockDevice()), +// m_actionCollection, "device_lock" ); + m_actionSetReadSpeed = new KAction( i18n("Set Read Speed..."), "", 0, this, SLOT(setReadSpeed()), + m_actionCollection, "device_set_read_speed" ); + + m_actionDiskInfo->setToolTip( i18n("Display generic medium information") ); + m_actionUnmount->setToolTip( i18n("Unmount the medium") ); + m_actionMount->setToolTip( i18n("Mount the medium") ); + m_actionEject->setToolTip( i18n("Eject the medium") ); + m_actionLoad->setToolTip( i18n("(Re)Load the medium") ); + m_actionSetReadSpeed->setToolTip( i18n("Force the drive's read speed") ); + + devicePopupMenu->insert( m_actionDiskInfo ); + devicePopupMenu->insert( new KActionSeparator( this ) ); + devicePopupMenu->insert( m_actionUnmount ); + devicePopupMenu->insert( m_actionMount ); + devicePopupMenu->insert( new KActionSeparator( this ) ); + devicePopupMenu->insert( m_actionEject ); + devicePopupMenu->insert( m_actionLoad ); +// devicePopupMenu->insert( new KActionSeparator( this ) ); +// devicePopupMenu->insert( actionUnlock ); +// devicePopupMenu->insert( actionlock ); + devicePopupMenu->insert( new KActionSeparator( this ) ); + devicePopupMenu->insert( m_actionSetReadSpeed ); + + setCurrentDevice( 0 ); +} + + +void K3bAppDeviceManager::setMediaCache( K3bMediaCache* c ) +{ + connect( c, SIGNAL(mediumChanged(K3bDevice::Device*)), + this, SLOT(slotMediumChanged(K3bDevice::Device*)) ); +} + + +int K3bAppDeviceManager::scanBus() +{ + return K3bDevice::DeviceManager::scanBus(); +} + + +K3bDevice::Device* K3bAppDeviceManager::currentDevice() const +{ + return m_currentDevice; +} + + +void K3bAppDeviceManager::clear() +{ + // make sure we do not use a deleted device + m_currentDevice = 0; + K3bDevice::DeviceManager::clear(); +} + + +void K3bAppDeviceManager::removeDevice( const QString& dev ) +{ + if( m_currentDevice == findDevice(dev) ) + m_currentDevice = 0; + + K3bDevice::DeviceManager::removeDevice( dev ); + + if( !m_currentDevice ) + setCurrentDevice( allDevices().getFirst() ); +} + + +K3bAppDeviceManager::~K3bAppDeviceManager() +{ +} + + +void K3bAppDeviceManager::slotMediumChanged( K3bDevice::Device* dev ) +{ + m_actionDiskInfo->setEnabled( dev != 0 ); + m_actionUnmount->setEnabled( dev != 0 ); + m_actionMount->setEnabled( dev != 0 ); + m_actionEject->setEnabled( dev != 0 ); + m_actionLoad->setEnabled( dev != 0 ); + m_actionSetReadSpeed->setEnabled( dev != 0 ); + + if( dev && dev == currentDevice() ) { + bool mounted = K3b::isMounted( dev ); + bool mediumMountable = k3bappcore->mediaCache()->medium( dev ).content() & K3bMedium::CONTENT_DATA; + m_actionMount->setEnabled( !mounted && mediumMountable ); + m_actionUnmount->setEnabled( mounted ); + } +} + + +void K3bAppDeviceManager::setCurrentDevice( K3bDevice::Device* dev ) +{ + if( dev && dev != m_currentDevice ) { + m_currentDevice = dev; + emit currentDeviceChanged( dev ); + } + + slotMediumChanged( dev ); +} + + +void K3bAppDeviceManager::diskInfo() +{ + if( currentDevice() ) { + emit detectingDiskInfo( currentDevice() ); + } +} + + +void K3bAppDeviceManager::unlockDevice() +{ + if( currentDevice() ) + K3bDevice::unblock( currentDevice() ); +} + + +void K3bAppDeviceManager::lockDevice() +{ + if( currentDevice() ) + K3bDevice::block( currentDevice() ); +} + + +void K3bAppDeviceManager::mountDisk() +{ + if ( currentDevice() ) { + // FIXME: make this non-blocking + if( !K3b::isMounted( currentDevice() ) ) + K3b::mount( currentDevice() ); + + emit mountFinished( KIO::findDeviceMountPoint( currentDevice()->blockDeviceName() ) ); + } +} + + +void K3bAppDeviceManager::unmountDisk() +{ + if ( currentDevice() ) { + // FIXME: make this non-blocking + if( K3b::isMounted( currentDevice() ) ) + emit unmountFinished( K3b::unmount( currentDevice() ) ); + else + emit unmountFinished( true ); + } +} + + +void K3bAppDeviceManager::ejectDisk() +{ + // FIXME: make this non-blocking + if ( currentDevice() ) + K3b::eject( currentDevice() ); // just ignore errors here +} + + +void K3bAppDeviceManager::loadDisk() +{ + if( currentDevice() ) + K3bDevice::reload( currentDevice() ); +} + + +void K3bAppDeviceManager::setReadSpeed() +{ + if( currentDevice() ) { + bool ok = false; + int s = KInputDialog::getInteger( i18n("CD Read Speed"), + i18n("<p>Please enter the preferred read speed for <b>%1</b>. " + "This speed will be used for the currently mounted " + "medium." + "<p>This is especially useful to slow down the drive when " + "watching movies which are read directly from the drive " + "and the spinning noise is intrusive." + "<p>Be aware that this has no influence on K3b since it will " + "change the reading speed again when copying CDs or DVDs.") + .arg(currentDevice()->vendor() + " " + currentDevice()->description()), + 12, + 1, + currentDevice()->maxReadSpeed(), + 1, + 10, + &ok, + 0 ); + if( ok ) { + if( !currentDevice()->setSpeed( s*175, 0xFFFF ) ) + KMessageBox::error( 0, i18n("Setting the read speed failed.") ); + } + } +} + + +void K3bAppDeviceManager::diskInfo( K3bDevice::Device* dev ) +{ + setCurrentDevice( dev ); + diskInfo(); +} + + +void K3bAppDeviceManager::unlockDevice( K3bDevice::Device* dev ) +{ + setCurrentDevice( dev ); + unlockDevice(); +} + + +void K3bAppDeviceManager::lockDevice( K3bDevice::Device* dev ) +{ + setCurrentDevice( dev ); + lockDevice(); +} + + +void K3bAppDeviceManager::mountDisk( K3bDevice::Device* dev ) +{ + setCurrentDevice( dev ); + mountDisk(); +} + + +void K3bAppDeviceManager::unmountDisk( K3bDevice::Device* dev ) +{ + setCurrentDevice( dev ); + unmountDisk(); +} + + +void K3bAppDeviceManager::ejectDisk( K3bDevice::Device* dev ) +{ + setCurrentDevice( dev ); + ejectDisk(); +} + + +void K3bAppDeviceManager::loadDisk( K3bDevice::Device* dev ) +{ + setCurrentDevice( dev ); + loadDisk(); +} + + +void K3bAppDeviceManager::setReadSpeed( K3bDevice::Device* dev ) +{ + setCurrentDevice( dev ); + setReadSpeed(); +} + +#include "k3bappdevicemanager.moc" diff --git a/src/k3bappdevicemanager.h b/src/k3bappdevicemanager.h new file mode 100644 index 0000000..419a8b3 --- /dev/null +++ b/src/k3bappdevicemanager.h @@ -0,0 +1,119 @@ +/* + * + * $Id: sourceheader 380067 2005-01-19 13:03:46Z trueg $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_APP_DEVICE_MANAGER_H_ +#define _K3B_APP_DEVICE_MANAGER_H_ + +class KActionCollection; +class KAction; +class K3bMediaCache; + +namespace K3bDevice { + class Device; + class DiskInfo; + class DiskInfoDetector; +} + +namespace KIO { + class Job; +} + +#include <k3bdevicemanager.h> + + +/** + * Enhanced device manager which can do some additional actions + * and maintains a current device + */ +class K3bAppDeviceManager : public K3bDevice::DeviceManager +{ + Q_OBJECT + + public: + K3bAppDeviceManager( QObject* parent = 0, const char* name = 0 ); + ~K3bAppDeviceManager(); + + K3bDevice::Device* currentDevice() const; + KActionCollection* actionCollection() const { return m_actionCollection; } + void setMediaCache( K3bMediaCache* c ); + + signals: + void currentDeviceChanged( K3bDevice::Device* ); + + /** + * Emitted when starting to detect the diskinfo. This may be used to show some info + * to the user since deteting the diskinfo might take some time. + */ + void detectingDiskInfo( K3bDevice::Device* ); + void diskInfoReady( K3bDevice::DiskInfoDetector* ); + + void mountFinished( const QString& mountPoint ); + void unmountFinished( bool success ); + + public slots: + /** + * \reimplemeted for internal reasons. The API is unaffected. + */ + void clear(); + + /** + * \reimplemeted for internal reasons. The API is unaffected. + */ + void removeDevice( const QString& ); + + /** + * \reimplemeted for internal reasons. The API is unaffected. + */ + int scanBus(); + + void setCurrentDevice( K3bDevice::Device* ); + + void diskInfo(); + void unlockDevice(); + void lockDevice(); + void mountDisk(); + void unmountDisk(); + void ejectDisk(); + void loadDisk(); + void setReadSpeed(); + + void diskInfo( K3bDevice::Device* ); + void unlockDevice( K3bDevice::Device* ); + void lockDevice( K3bDevice::Device* ); + void mountDisk( K3bDevice::Device* ); + void unmountDisk( K3bDevice::Device* ); + void ejectDisk( K3bDevice::Device* ); + void loadDisk( K3bDevice::Device* ); + void setReadSpeed( K3bDevice::Device* ); + + private slots: + void slotMediumChanged( K3bDevice::Device* dev ); + + private: + KAction* m_actionDiskInfo; + KAction* m_actionUnmount; + KAction* m_actionMount; + KAction* m_actionEject; + KAction* m_actionLoad; + KAction* m_actionSetReadSpeed; + + mutable K3bDevice::Device* m_currentDevice; + KActionCollection* m_actionCollection; + K3bDevice::DiskInfoDetector* m_diskInfoDetector; + + bool m_ejectRequested; +}; + +#endif diff --git a/src/k3bapplication.cpp b/src/k3bapplication.cpp new file mode 100644 index 0000000..4b517ea --- /dev/null +++ b/src/k3bapplication.cpp @@ -0,0 +1,451 @@ +/* + * + * $Id: k3bapplication.cpp 802344 2008-04-29 07:45:46Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bapplication.h" +#include "k3b.h" +#include "k3bsplash.h" +#include "k3baudioserver.h" +#include "k3binterface.h" +#include "k3bjobinterface.h" +#include "k3bprojectmanager.h" +#include "k3bappdevicemanager.h" +#include "k3bmediacache.h" +#include "k3bpassivepopup.h" +#include "k3blsofwrapperdialog.h" +#include "k3bfirstrun.h" + +#include <k3bcore.h> +#include <k3bdevicemanager.h> +#include <k3bhalconnection.h> +#include <k3bexternalbinmanager.h> +#include <k3bdefaultexternalprograms.h> +#include <k3bglobals.h> +#include <k3bversion.h> +#include <k3bdoc.h> +#include "k3bsystemproblemdialog.h" +#include <k3bthread.h> +#include <k3bpluginmanager.h> +#include <k3bthememanager.h> +#include <k3bmsf.h> +#include <k3bmovixprogram.h> +#include <k3bview.h> +#include <k3bjob.h> + +#include <ktip.h> +#include <klocale.h> +#include <kconfig.h> +#include <kaboutdata.h> +#include <kcmdlineargs.h> +#include <dcopclient.h> +#include <kstandarddirs.h> +#include <kstartupinfo.h> +#include <kmessagebox.h> + +#include <qguardedptr.h> +#include <qtimer.h> +#include <qvaluelist.h> +#include <qcstring.h> + + +K3bApplication::Core* K3bApplication::Core::s_k3bAppCore = 0; + + +K3bApplication::K3bApplication() + : KUniqueApplication(), + m_mainWindow(0), + m_needToInit(true) +{ + // insert library i18n data + KGlobal::locale()->insertCatalogue( "libk3bdevice" ); + KGlobal::locale()->insertCatalogue( "libk3b" ); + + m_core = new Core( this ); + + // TODO: move to K3bCore? + // from this point on available through K3bAudioServer::instance() + m_audioServer = new K3bAudioServer( this, "K3bAudioServer" ); + + connect( m_core, SIGNAL(initializationInfo(const QString&)), + SIGNAL(initializationInfo(const QString&)) ); + + connect( this, SIGNAL(shutDown()), SLOT(slotShutDown()) ); +} + + +K3bApplication::~K3bApplication() +{ + // we must not delete m_mainWindow here, QApplication takes care of it +} + + +void K3bApplication::init() +{ + KConfigGroup generalOptions( config(), "General Options" ); + + QGuardedPtr<K3bSplash> splash; + if( !isRestored() ) { + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + if( generalOptions.readBoolEntry("Show splash", true) && args->isSet( "splash" ) ) { + // we need the correct splash pic + m_core->m_themeManager->readConfig( config() ); + + splash = new K3bSplash( 0 ); + splash->connect( this, SIGNAL(initializationInfo(const QString&)), SLOT(addInfo(const QString&)) ); + + // kill the splash after 5 seconds + QTimer::singleShot( 5000, splash, SLOT(close()) ); + + splash->show(); + qApp->processEvents(); + } + } + + // + // Load device, external programs, and stuff. + // + m_core->init(); + m_core->readSettings( config() ); + + m_core->deviceManager()->printDevices(); + + m_audioServer->setOutputMethod( generalOptions.readEntry( "Audio Output System", "arts" ).local8Bit() ); + + emit initializationInfo( i18n("Creating GUI...") ); + + m_mainWindow = new K3bMainWindow(); + m_core->m_mainWindow = m_mainWindow; + m_core->interface()->setMainWindow( m_mainWindow ); + + if( isRestored() ) { + // we only have one single mainwindow to restore + m_mainWindow->restore(1); + } + else { + setMainWidget( m_mainWindow ); + + m_mainWindow->show(); + + emit initializationInfo( i18n("Ready.") ); + + emit initializationDone(); + + //K3bFirstRun::run( m_mainWindow ); + + if( K3bSystemProblemDialog::readCheckSystemConfig() ) { + emit initializationInfo( i18n("Checking System") ); + K3bSystemProblemDialog::checkSystem( m_mainWindow ); + } + + if( processCmdLineArgs() ) + KTipDialog::showTip( m_mainWindow ); + } + + // write the current version to make sure checks such as K3bSystemProblemDialog::readCheckSystemConfig + // use a proper value + generalOptions.writeEntry( "config version", m_core->version() ); +} + + +int K3bApplication::newInstance() +{ + if( m_needToInit ) { + // init(); + m_needToInit = false; + } + else + processCmdLineArgs(); + + return KUniqueApplication::newInstance(); +} + + +bool K3bApplication::processCmdLineArgs() +{ + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + bool showTips = true; + bool dialogOpen = false; + + if( k3bcore->jobsRunning() > 0 ) { + K3bPassivePopup::showPopup( i18n("K3b is currently busy and cannot start any other operations."), + i18n("K3b is busy"), + K3bPassivePopup::Information ); + return true; + } + + K3bDoc* doc = 0; + if( args->isSet( "datacd" ) ) { + doc = m_mainWindow->slotNewDataDoc(); + } + else if( args->isSet( "audiocd" ) ) { + doc = m_mainWindow->slotNewAudioDoc(); + } + else if( args->isSet( "mixedcd" ) ) { + doc = m_mainWindow->slotNewMixedDoc(); + } + else if( args->isSet( "videocd" ) ) { + doc = m_mainWindow->slotNewVcdDoc(); + } + else if( args->isSet( "emovixcd" ) ) { + doc = m_mainWindow->slotNewMovixDoc(); + } + else if( args->isSet( "datadvd" ) ) { + doc = m_mainWindow->slotNewDvdDoc(); + } + else if( args->isSet( "emovixdvd" ) ) { + doc = m_mainWindow->slotNewMovixDvdDoc(); + } + else if( args->isSet( "videodvd" ) ) { + doc = m_mainWindow->slotNewVideoDvdDoc(); + } + + // if we created a doc the urls are used to populate it + if( doc ) { + KURL::List urls; + for( int i = 0; i < args->count(); i++ ) + urls.append( args->url(i) ); + dynamic_cast<K3bView*>( doc->view() )->addUrls( urls ); + } + // otherwise we open them as documents + else { + for( int i = 0; i < args->count(); i++ ) { + m_mainWindow->openDocument( args->url(i) ); + } + } + + // we only allow one dialog to be opened + if( args->isSet( "cdimage" ) ) { + showTips = false; + dialogOpen = true; + if( k3bcore->jobsRunning() == 0 ) { + m_mainWindow->slotWriteCdImage( KURL::fromPathOrURL( QFile::decodeName( args->getOption( "cdimage" ) ) ) ); + } + } + else if( args->isSet( "dvdimage" ) ) { + showTips = false; + dialogOpen = true; + if( k3bcore->jobsRunning() == 0 ) { + m_mainWindow->slotWriteDvdIsoImage( KURL::fromPathOrURL( QFile::decodeName( args->getOption( "dvdimage" ) ) ) ); + } + } + else if( args->isSet( "image" ) ) { + showTips = false; + dialogOpen = true; + KURL url = KURL::fromPathOrURL( QFile::decodeName( args->getOption( "image" ) ) ); + if( k3bcore->jobsRunning() == 0 ) { + if( K3b::filesize( url ) > 1000*1024*1024 ) + m_mainWindow->slotWriteDvdIsoImage( url ); + else + m_mainWindow->slotWriteCdImage( url ); + } + } + else if( args->isSet("copycd") ) { + showTips = false; + dialogOpen = true; + qApp->processEvents(); + m_mainWindow->cdCopy( K3b::urlToDevice( KURL::fromPathOrURL( QFile::decodeName( args->getOption( "copycd" ) ) ) ) ); + } + else if( args->isSet("copydvd") ) { + showTips = false; + dialogOpen = true; + m_mainWindow->dvdCopy( K3b::urlToDevice( KURL::fromPathOrURL( QFile::decodeName( args->getOption( "copydvd" ) ) ) ) ); + } + else if( args->isSet("erasecd") ) { + showTips = false; + dialogOpen = true; + m_mainWindow->blankCdrw( K3b::urlToDevice( KURL::fromPathOrURL( QFile::decodeName( args->getOption( "erasecd" ) ) ) ) ); + } + else if( args->isSet("formatdvd") ) { + showTips = false; + dialogOpen = true; + m_mainWindow->formatDvd( K3b::urlToDevice( KURL::fromPathOrURL( QFile::decodeName( args->getOption( "formatdvd" ) ) ) ) ); + } + + // no dialog used here + if( args->isSet( "cddarip" ) ) { + m_mainWindow->cddaRip( K3b::urlToDevice( KURL::fromPathOrURL( QFile::decodeName( args->getOption( "cddarip" ) ) ) ) ); + } + else if( args->isSet( "videodvdrip" ) ) { + m_mainWindow->videoDvdRip( K3b::urlToDevice( KURL::fromPathOrURL( QFile::decodeName( args->getOption( "videodvdrip" ) ) ) ) ); + } + else if( args->isSet( "videocdrip" ) ) { + m_mainWindow->videoCdRip( K3b::urlToDevice( KURL::fromPathOrURL( QFile::decodeName( args->getOption( "videocdrip" ) ) ) ) ); + } + + if( !dialogOpen && args->isSet( "burn" ) ) { + if( m_core->projectManager()->activeDoc() ) { + showTips = false; + dialogOpen = true; + static_cast<K3bView*>( m_core->projectManager()->activeDoc()->view() )->slotBurn(); + } + } + + // FIXME: seems not like the right place... + if( args->isSet( "ao" ) ) + if( !m_audioServer->setOutputMethod( args->getOption( "ao" ) ) ) + K3bPassivePopup::showPopup( i18n("Could not find Audio Output plugin '%1'").arg( args->getOption("ao") ), + i18n("Initialization Problem"), + K3bPassivePopup::Warning ); + + args->clear(); + + return showTips; +} + + +void K3bApplication::slotShutDown() +{ + k3bappcore->mediaCache()->clearDeviceList(); + K3bThread::waitUntilFinished(); +} + + + +K3bApplication::Core::Core( QObject* parent ) + : K3bCore( parent ), + m_appDeviceManager(0), + m_mediaCache(0) +{ + s_k3bAppCore = this; + m_themeManager = new K3bThemeManager( this ); + m_projectManager = new K3bProjectManager( this ); + // we need the themes on startup (loading them is fast anyway :) + m_themeManager->loadThemes(); + + m_jobInterface = new K3bJobInterface( this ); + m_interface = new K3bInterface(); + dcopClient()->setDefaultObject( m_interface->objId() ); +} + + +K3bApplication::Core::~Core() +{ +} + + +void K3bApplication::Core::initDeviceManager() +{ + if( !m_appDeviceManager ) { + // our very own special device manager + m_appDeviceManager = new K3bAppDeviceManager( this ); + } + if( !m_mediaCache ) { + // create the media cache but do not connect it to the device manager + // yet to speed up application start. We connect it in init() + // once the devicemanager has scanned for devices. + m_mediaCache = new K3bMediaCache( this ); + } + + m_appDeviceManager->setMediaCache( m_mediaCache ); +} + + +K3bDevice::DeviceManager* K3bApplication::Core::deviceManager() const +{ + return appDeviceManager(); +} + + +KConfig* K3bApplication::Core::config() const +{ + return kapp->config(); +} + + +void K3bApplication::Core::init() +{ + // + // The eMovix program is a special case which is not part of + // the default programs handled by K3bCore + // + initExternalBinManager(); + externalBinManager()->addProgram( new K3bMovixProgram() ); + externalBinManager()->addProgram( new K3bNormalizeProgram() ); + K3b::addTranscodePrograms( externalBinManager() ); + K3b::addVcdimagerPrograms( externalBinManager() ); + + K3bCore::init(); + + mediaCache()->buildDeviceList( deviceManager() ); + + connect( deviceManager(), SIGNAL(changed(K3bDevice::DeviceManager*)), + mediaCache(), SLOT(buildDeviceList(K3bDevice::DeviceManager*)) ); +} + + +void K3bApplication::Core::readSettings( KConfig* cnf ) +{ + K3bCore::readSettings( cnf ); + + KConfig* c = cnf; + if( !c ) + c = config(); + + m_themeManager->readConfig( config() ); +} + + +void K3bApplication::Core::saveSettings( KConfig* cnf ) +{ + if( !cnf ) + cnf = config(); + + K3bCore::saveSettings( cnf ); + m_themeManager->saveConfig( cnf ); +} + + +bool K3bApplication::Core::internalBlockDevice( K3bDevice::Device* dev ) +{ + if( K3bCore::internalBlockDevice( dev ) ) { + if( mediaCache() ) { + m_deviceBlockMap[dev] = mediaCache()->blockDevice( dev ); + } + +#ifdef HAVE_HAL + if( K3bDevice::HalConnection::instance()->lock( dev ) != K3bDevice::HalConnection::org_freedesktop_Hal_Success ) + kdDebug() << "(K3bInterferingSystemsHandler) HAL lock failed." << endl; +#endif + + // + // Check if the device is in use + // + // FIXME: Use the top level widget as parent + K3bLsofWrapperDialog::checkDevice( dev ); + + return true; + } + else + return false; +} + + +void K3bApplication::Core::internalUnblockDevice( K3bDevice::Device* dev ) +{ + if( mediaCache() ) { + mediaCache()->unblockDevice( dev, m_deviceBlockMap[dev] ); + m_deviceBlockMap.erase( dev ); + } + +#ifdef HAVE_HAL + K3bDevice::HalConnection::instance()->unlock( dev ); +#endif + + K3bCore::internalUnblockDevice( dev ); +} + +#include "k3bapplication.moc" diff --git a/src/k3bapplication.h b/src/k3bapplication.h new file mode 100644 index 0000000..8dafac1 --- /dev/null +++ b/src/k3bapplication.h @@ -0,0 +1,156 @@ +/* + * + * $Id: k3bapplication.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_APPLICATION_H_ +#define _K3B_APPLICATION_H_ + +#include <kuniqueapplication.h> +#include <k3bcore.h> + +#include <qmap.h> + +#define k3bappcore K3bApplication::Core::k3bAppCore() + + +class K3bMainWindow; +class K3bInterface; +class K3bJobInterface; +class K3bAudioServer; +class K3bThemeManager; +class K3bProjectManager; +class K3bAppDeviceManager; +class K3bMediaCache; + + +class K3bApplication : public KUniqueApplication +{ + Q_OBJECT + + public: + K3bApplication(); + ~K3bApplication(); + + int newInstance(); + + class Core; + + public slots: + void init(); + + signals: + void initializationInfo( const QString& ); + void initializationDone(); + + private slots: + void slotShutDown(); + + private: + bool processCmdLineArgs(); + + Core* m_core; + K3bAudioServer* m_audioServer; + K3bMainWindow* m_mainWindow; + + bool m_needToInit; +}; + + +/** + * The application's core which extends K3bCore with some additional features + * like the thememanager or an enhanced device manager. + */ +class K3bApplication::Core : public K3bCore +{ + Q_OBJECT + + public: + Core( QObject* parent ); + ~Core(); + + void init(); + + // make sure the libk3b uses the same configuration + // needed since the lib still depends on K3bCore::config + // the goal is to make the lib independent from the config + KConfig* config() const; + + void readSettings( KConfig* c = 0 ); + void saveSettings( KConfig* c = 0 ); + + /** + * \reimplemented from K3bCore. We use our own devicemanager here. + */ + K3bDevice::DeviceManager* deviceManager() const; + + K3bAppDeviceManager* appDeviceManager() const { return m_appDeviceManager; } + + K3bThemeManager* themeManager() const { return m_themeManager; } + + K3bProjectManager* projectManager() const { return m_projectManager; } + + K3bMediaCache* mediaCache() const { return m_mediaCache; } + + K3bMainWindow* k3bMainWindow() const { return m_mainWindow; } + + K3bInterface* interface() const { return m_interface; } + + K3bJobInterface* jobInterface() const { return m_jobInterface; } + + static Core* k3bAppCore() { return s_k3bAppCore; } + + signals: + /** + * This is used for showing info in the K3b splashscreen + */ + void initializationInfo( const QString& ); + + /** + * Any component may request busy info + * In the K3b main app this will be displayed + * as a moving square in the taskbar + * + * FIXME: this is bad design + */ + void busyInfoRequested( const QString& ); + + /** + * FIXME: this is bad design + */ + void busyFinishRequested(); + + private: + void initDeviceManager(); + + bool internalBlockDevice( K3bDevice::Device* ); + void internalUnblockDevice( K3bDevice::Device* ); + + K3bInterface* m_interface; + K3bJobInterface* m_jobInterface; + + K3bThemeManager* m_themeManager; + K3bMainWindow* m_mainWindow; + K3bProjectManager* m_projectManager; + K3bAppDeviceManager* m_appDeviceManager; + K3bMediaCache* m_mediaCache; + + QMap<K3bDevice::Device*, int> m_deviceBlockMap; + + static Core* s_k3bAppCore; + + friend class K3bApplication; +}; + +#endif diff --git a/src/k3baudioplayer.cpp b/src/k3baudioplayer.cpp new file mode 100644 index 0000000..645b3cf --- /dev/null +++ b/src/k3baudioplayer.cpp @@ -0,0 +1,663 @@ +/* + * + * $Id: k3baudioplayer.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3baudioplayer.h" +#include <k3bmsf.h> +#include "kcutlabel.h" + +#include <qlabel.h> +#include <qtoolbutton.h> +#include <qlayout.h> +#include <qtimer.h> +#include <qdatetime.h> +#include <qfont.h> +#include <qslider.h> +#include <qlistview.h> +#include <qfile.h> +#include <qpalette.h> +#include <qheader.h> +#include <qevent.h> +#include <qdragobject.h> +#include <qptrlist.h> +#include <kurldrag.h> + +#include <kiconloader.h> +#include <klocale.h> +#include <kurl.h> +#include <kaction.h> + +#include <string.h> + +#ifdef WITH_ARTS +#include <arts/artsflow.h> +#endif + +#include <kdebug.h> + +using namespace std; + +K3bPlayListViewItem::K3bPlayListViewItem( const QString& filename, QListView* parent ) + : KListViewItem( parent ), m_filename( filename ) +{ + m_length = 0; + m_bActive = false; +} + + +K3bPlayListViewItem::K3bPlayListViewItem( const QString& filename, QListView* parent, QListViewItem* after ) + : KListViewItem( parent, after ), m_filename( filename ) +{ + m_length = 0; + m_bActive = false; +} + + +K3bPlayListViewItem::~K3bPlayListViewItem() +{ +} + + +QString K3bPlayListViewItem::text( int c ) const +{ + switch( c ) { + case 0: + { + int pos = m_filename.findRev("/"); + if( pos >= 0 ) + return m_filename.mid(pos+1); + return m_filename; + } + + case 1: + if( m_length > 0 ) + return K3b::Msf(m_length).toString(false); + + default: + return ""; + } +} + + +void K3bPlayListViewItem::paintCell( QPainter* p, const QColorGroup& cg, int c, int w, int a ) +{ + if( m_bActive ) { + // change the color of the text: + // change roles: Text, HighlightedText, HighLight + QColorGroup newCg( cg ); + + // we assume the user has not configured a very dark color as base color + newCg.setColor( QColorGroup::Text, red ); + newCg.setColor( QColorGroup::Highlight, red ); + newCg.setColor( QColorGroup::HighlightedText, white ); + + KListViewItem::paintCell( p, newCg, c, w, a ); + } + else + KListViewItem::paintCell( p, cg, c, w, a ); +} + + +K3bPlayListView::K3bPlayListView( QWidget* parent, const char* name ) + : KListView( parent, name ) +{ + addColumn( i18n("Filename") ); + addColumn( i18n("Length") ); + setAllColumnsShowFocus( true ); + setAcceptDrops( true ); + setDropVisualizer( true ); + setDragEnabled(true); + setItemsMovable( true ); + header()->setClickEnabled( false ); + setSorting( -1 ); +} + + +K3bPlayListView::~K3bPlayListView() +{ +} + + +bool K3bPlayListView::acceptDrag( QDropEvent* e ) const +{ + // we accept textdrag (urls) and moved items (supported by KListView) + return KURLDrag::canDecode(e) || KListView::acceptDrag(e); +} + + +QDragObject* K3bPlayListView::dragObject() +{ + QPtrList<QListViewItem> list = selectedItems(); + + if( list.isEmpty() ) + return 0; + + QPtrListIterator<QListViewItem> it(list); + KURL::List urls; + + for( ; it.current(); ++it ) + urls.append( KURL( ((K3bPlayListViewItem*)it.current())->filename() ) ); + + return KURLDrag::newDrag( urls, viewport() ); +} + + +K3bAudioPlayer::K3bAudioPlayer( QWidget* parent, const char* name ) + : QWidget( parent, name ) +#ifdef WITH_ARTS +, m_playObject( Arts::PlayObject::null() ) +#endif +{ + m_currentItem = 0L; + // initialize + // ------------------------------------------------------------------------ + m_labelFilename = new KCutLabel( i18n("no file"), this ); + m_labelOverallTime = new QLabel( "00:00", this ); + m_labelCurrentTime = new QLabel( "00:00", this ); + + m_viewPlayList = new K3bPlayListView( this ); + + m_labelOverallTime->setAlignment( AlignHCenter | AlignVCenter ); + m_labelCurrentTime->setAlignment( AlignHCenter | AlignVCenter ); + m_labelOverallTime->setFrameStyle( QFrame::StyledPanel | QFrame::Plain ); + m_labelCurrentTime->setFrameStyle( QFrame::StyledPanel | QFrame::Plain ); + m_labelFilename->setFrameStyle( QFrame::StyledPanel | QFrame::Plain ); + m_labelOverallTime->setPalette( QPalette( QColor(238, 238, 205) ) ); + m_labelCurrentTime->setPalette( QPalette( QColor(238, 238, 205) ) ); + m_labelFilename->setPalette( QPalette( QColor(238, 238, 205) ) ); + + m_buttonPlay = new QToolButton( this ); + m_buttonPause = new QToolButton( this ); + m_buttonStop = new QToolButton( this ); + m_buttonPlay->setIconSet( SmallIconSet("player_play") ); + m_buttonPause->setIconSet( SmallIconSet("player_pause") ); + m_buttonStop->setIconSet( SmallIconSet("player_stop") ); + m_buttonForward = new QToolButton( this ); + m_buttonBack = new QToolButton( this ); + m_buttonForward->setIconSet( SmallIconSet("player_end") ); + m_buttonBack->setIconSet( SmallIconSet("player_start") ); + + m_seekSlider = new QSlider( QSlider::Horizontal, this ); + + m_updateTimer = new QTimer( this ); + // ------------------------------------------------------------------------ + + // layout + // ------------------------------------------------------------------------ + QGridLayout* grid = new QGridLayout( this ); + grid->setSpacing( 2 ); + grid->setMargin( 0 ); + + grid->addWidget( m_buttonPlay, 1, 0 ); + grid->addWidget( m_buttonPause, 1, 1 ); + grid->addWidget( m_buttonStop, 1, 2 ); + grid->addColSpacing( 3, 5 ); + grid->addWidget( m_buttonBack, 1, 4 ); + grid->addWidget( m_buttonForward, 1, 5 ); + + grid->addMultiCellWidget( m_labelFilename, 0, 0, 0, 6 ); + + grid->addMultiCellWidget( m_seekSlider, 1, 1, 6, 8 ); + + grid->addWidget( m_labelCurrentTime, 0, 7 ); + grid->addWidget( m_labelOverallTime, 0, 8 ); + + grid->addMultiCellWidget( m_viewPlayList, 2, 2, 0, 8 ); + grid->setRowStretch( 2, 1 ); + grid->setColStretch( 6, 1 ); + // ------------------------------------------------------------------------ + + + // actions + // ------------------------------------------------------------------------ + m_actionRemove = new KAction( i18n( "Remove" ), "editdelete", + Key_Delete, this, SLOT(slotRemoveSelected()), + this, "audioplayer_remove" ); + m_actionClear = new KAction( i18n( "Clear List" ), "editclear", + 0, this, SLOT(clear()), + this, "audioplayer_clear" ); + + m_contextMenu = new KActionMenu( this, "audio_player_menu" ); + m_contextMenu->insert(m_actionRemove); + m_contextMenu->insert(m_actionClear); + // ------------------------------------------------------------------------ + + + // connections + // ------------------------------------------------------------------------ + connect( m_viewPlayList, SIGNAL(contextMenu(KListView*, QListViewItem*, const QPoint&)), + this, SLOT(slotShowContextMenu(KListView*, QListViewItem*, const QPoint&)) ); + + connect( m_buttonPlay, SIGNAL(clicked()), this, SLOT(play()) ); + connect( m_buttonStop, SIGNAL(clicked()), this, SLOT(stop()) ); + connect( m_buttonPause, SIGNAL(clicked()), this, SLOT(pause()) ); + + connect( m_buttonForward, SIGNAL(clicked()), this, SLOT(forward()) ); + connect( m_buttonBack, SIGNAL(clicked()), this, SLOT(back()) ); + + connect( m_seekSlider, SIGNAL(sliderMoved(int)), this, SLOT(seek(int)) ); + connect( m_seekSlider, SIGNAL(valueChanged(int)), this, SLOT(slotUpdateCurrentTime(int)) ); + + connect( m_updateTimer, SIGNAL(timeout()), this, SLOT(slotUpdateDisplay()) ); + connect( m_updateTimer, SIGNAL(timeout()), this, SLOT(slotCheckEnd()) ); + + connect( m_viewPlayList, SIGNAL(doubleClicked(QListViewItem*)), + this, SLOT(slotPlayItem(QListViewItem*)) ); + connect( m_viewPlayList, SIGNAL(dropped(QDropEvent*,QListViewItem*)), + this, SLOT(slotDropped(QDropEvent*,QListViewItem*)) ); + // ------------------------------------------------------------------------ + + + m_bLengthReady = false; +} + + +K3bAudioPlayer::~K3bAudioPlayer() +{ + // we remove the reference to the play object + // if we don't do this it won't be removed and K3b will crash (not sure why) +#ifdef WITH_ARTS + m_playObject = Arts::PlayObject::null(); +#endif +} + + +int K3bAudioPlayer::state() +{ +#ifdef WITH_ARTS + if( !m_playObject.isNull() ) { + switch( m_playObject.state() ) { + case Arts::posIdle: + return STOPPED; + case Arts::posPlaying: + return PLAYING; + case Arts::posPaused: + return PAUSED; + } + } + else if( m_currentItem ) + return STOPPED; +#endif + + return EMPTY; +} + + +void K3bAudioPlayer::playFile( const QString& filename ) +{ + clear(); + if( QFile::exists( filename ) ) { + K3bPlayListViewItem* item = new K3bPlayListViewItem( filename, m_viewPlayList ); + setCurrentItem( item ); + play(); + emit started( filename ); + } +} + + +void K3bAudioPlayer::playFiles( const QStringList& files ) +{ + clear(); + QStringList::ConstIterator it = files.begin(); + playFile( *it ); + ++it; + + for( ; it != files.end(); ++it ) + enqueueFile( *it ); +} + + +void K3bAudioPlayer::enqueueFile( const QString& filename ) +{ + if( QFile::exists( filename ) ) + (void)new K3bPlayListViewItem( filename, m_viewPlayList, m_viewPlayList->lastChild() ); +} + + +void K3bAudioPlayer::enqueueFiles( const QStringList& files ) +{ + for( QStringList::ConstIterator it = files.begin(); it != files.end(); ++it ) + enqueueFile( *it ); +} + + +void K3bAudioPlayer::play() +{ +#ifdef WITH_ARTS + if( !m_currentItem ) { + setCurrentItem( m_viewPlayList->firstChild() ); + } + + if( m_currentItem ) { + if( m_playObject.isNull() ) { + Arts::PlayObjectFactory factory = Arts::Reference("global:Arts_PlayObjectFactory"); + if( factory.isNull() ) { + kdDebug() << "(K3bAudioPlayer) could not create PlayObjectFactory. Possibly no artsd running." << endl; + m_labelFilename->setText( i18n("No running aRtsd found") ); + return; + } + + m_playObject = factory.createPlayObject( string(QFile::encodeName(m_currentItem->filename()) ) ); + if( m_playObject.isNull() ) { + kdDebug() << "(K3bAudioPlayer) no aRts module available for: " << m_currentItem->filename() << endl; + m_labelFilename->setText( i18n("Unknown file format") ); + + // play the next if there is any + if( m_currentItem->itemBelow() ) { + setCurrentItem( m_currentItem->itemBelow() ); + play(); + } + return; + } + } + if( m_playObject.state() != Arts::posPlaying ) { + m_playObject.play(); + emit started(); + m_updateTimer->start( 1000 ); + } + + slotUpdateFilename(); + } +#endif +} + + +void K3bAudioPlayer::slotPlayItem( QListViewItem* item ) +{ + setCurrentItem( item ); + play(); +} + + +void K3bAudioPlayer::stop() +{ +#ifdef WITH_ARTS + if( !m_playObject.isNull() ) { + m_updateTimer->stop(); + m_playObject.halt(); + m_playObject = Arts::PlayObject::null(); + m_bLengthReady = false; + + emit stopped(); + } +#endif + + m_seekSlider->setValue(0); + slotUpdateFilename(); + slotUpdateCurrentTime(0); +} + + +void K3bAudioPlayer::pause() +{ +#ifdef WITH_ARTS + if( !m_playObject.isNull() ) { + if( m_playObject.state() == Arts::posPlaying ) { + m_updateTimer->stop(); + m_playObject.pause(); + emit paused(); + } + + slotUpdateFilename(); + } +#endif +} + + +void K3bAudioPlayer::seek( long pos ) +{ +#ifdef WITH_ARTS + if( !m_playObject.isNull() ) { + if( m_playObject.state() != Arts::posIdle ) { + if( pos < 0 ) { + m_playObject.seek( Arts::poTime() ); + } + else if( m_playObject.overallTime().seconds < pos ) { + m_playObject.seek( m_playObject.overallTime() ); + } + else if( pos != m_playObject.currentTime().seconds ) { + m_playObject.seek( Arts::poTime( pos, 0, -1, "" ) ); + } + } + } + else { + m_seekSlider->setValue(0); + slotUpdateCurrentTime(0); + } +#endif +} + + + +void K3bAudioPlayer::seek( int pos ) +{ + seek( (long)pos ); +} + + +void K3bAudioPlayer::forward() +{ + if( m_currentItem ) { + if( m_currentItem->itemBelow() ) { + bool bPlay = false; + if( state() == PLAYING ) + bPlay = true; + + setCurrentItem( m_currentItem->itemBelow() ); + + if( bPlay ) + play(); + } + } +} + + +void K3bAudioPlayer::back() +{ + if( m_currentItem ) { + if( m_currentItem->itemAbove() ) { + bool bPlay = false; + if( state() == PLAYING ) + bPlay = true; + + setCurrentItem( m_currentItem->itemAbove() ); + + if( bPlay ) + play(); + } + } +} + + +void K3bAudioPlayer::clear() +{ + setCurrentItem( 0 ); + m_viewPlayList->clear(); +} + + +long K3bAudioPlayer::length() +{ +#ifdef WITH_ARTS + if( !m_playObject.isNull() ) { + return m_playObject.overallTime().seconds; + } +#endif + return 0; +} + + +long K3bAudioPlayer::position() +{ +#ifdef WITH_ARTS + if( !m_playObject.isNull() ) { + return m_playObject.currentTime().seconds; + } +#endif + return 0; +} + + +// FIXME: let my do some useful stuff! +bool K3bAudioPlayer::supportsMimetype( const QString& mimetype ) +{ + if( mimetype.contains("audio") || mimetype.contains("ogg") ) + return true; + else + return false; +} + + +void K3bAudioPlayer::slotCheckEnd() +{ +#ifdef WITH_ARTS + if( !m_playObject.isNull() ) { + if( m_playObject.state() == Arts::posIdle ) { + if( m_currentItem->nextSibling() ) { + setCurrentItem( m_currentItem->nextSibling() ); + play(); + } + else { + stop(); + } + emit ended(); + } + } +#endif +} + + +void K3bAudioPlayer::setCurrentItem( QListViewItem* item ) +{ + if( item == 0 ) { + stop(); + m_labelOverallTime->setText("00:00"); + m_labelFilename->setText( i18n("no file") ); + m_currentItem = 0; + } + else if( K3bPlayListViewItem* playItem = dynamic_cast<K3bPlayListViewItem*>(item) ) { + if( m_currentItem ) { + // reset m_currentItem + m_currentItem->setActive( false ); + stop(); + } + m_currentItem = playItem; + m_currentItem->setActive( true ); + + // paint the activity changes + m_viewPlayList->viewport()->update(); + + slotUpdateFilename(); + } +} + + +void K3bAudioPlayer::slotUpdateCurrentTime( int time ) +{ + m_labelCurrentTime->setText( K3b::Msf( time*75 ).toString(false) ); +} + + +void K3bAudioPlayer::slotUpdateLength( long time ) +{ + m_labelOverallTime->setText( K3b::Msf( time*75 ).toString(false) ); +} + + +void K3bAudioPlayer::slotUpdateFilename() +{ + if( m_currentItem ) { + QString display = m_currentItem->filename(); + int pos = display.findRev("/"); + if( pos >= 0 ) + display = display.mid(pos+1); + + switch( state() ) { + case PLAYING: + display.prepend( QString("(%1) ").arg(i18n("playing")) ); + break; + case PAUSED: + display.prepend( QString("(%1) ").arg(i18n("paused")) ); + break; + case STOPPED: + display.prepend( QString("(%1) ").arg(i18n("stopped")) ); + break; + default: + break; + } + + m_labelFilename->setText( display ); + } +} + + +void K3bAudioPlayer::slotUpdateDisplay() +{ + if( m_currentItem ) { + // we need to set the length here because sometimes it is not ready in the beginning (?) + if( !m_bLengthReady && length() > 0 ) { + slotUpdateLength( length() ); + m_seekSlider->setMaxValue( length() ); + m_currentItem->setLength( 75 * length() ); + m_bLengthReady = true; + + m_viewPlayList->viewport()->update(); + } + + m_seekSlider->setValue( position() ); + } +} + + +void K3bAudioPlayer::slotDropped( QDropEvent* e, QListViewItem* after ) +{ + if( !after ) + after = m_viewPlayList->lastChild(); + + KURL::List urls; + KURLDrag::decode( e, urls ); + + for( KURL::List::ConstIterator it = urls.begin(); it != urls.end(); ++it ) { + if( QFile::exists( (*it).path() ) ) { + QListViewItem* newItem = new K3bPlayListViewItem( (*it).path(), m_viewPlayList, after ); + after = newItem; + } + } +} + + +void K3bAudioPlayer::slotRemoveSelected() +{ + QPtrList<QListViewItem> selected = m_viewPlayList->selectedItems(); + for( QListViewItem* item = selected.first(); item; item = selected.next() ) { + if( item == m_currentItem ) + setCurrentItem(0); + delete item; + } +} + + +void K3bAudioPlayer::slotShowContextMenu( KListView*, QListViewItem* item, const QPoint& p ) +{ + if( item ) + m_actionRemove->setEnabled( true ); + else + m_actionRemove->setEnabled( false ); + + m_contextMenu->popup(p); +} + + +#include "k3baudioplayer.moc" diff --git a/src/k3baudioplayer.h b/src/k3baudioplayer.h new file mode 100644 index 0000000..1bc28a9 --- /dev/null +++ b/src/k3baudioplayer.h @@ -0,0 +1,208 @@ +/* + * + * $Id: k3baudioplayer.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BAUDIOPLAYER_H +#define K3BAUDIOPLAYER_H + +#include <klistview.h> + +#include <config.h> + +#ifdef WITH_ARTS +#include <arts/kmedia2.h> +#include <arts/kartsdispatcher.h> +#endif + +class QTimer; +class QLabel; +class QToolButton; +class QSlider; +class QPainter; +class QColorGroup; +class QDropEvent; +class QDragObject; +class KAction; +class KActionMenu; + + +/** + * Special ListViewItem for the K3bAudioPlayer playlist + * @author Sebastian Trueg + */ +class K3bPlayListViewItem : public KListViewItem +{ + public: + K3bPlayListViewItem( const QString&, QListView* parent ); + K3bPlayListViewItem( const QString&, QListView* parent, QListViewItem* after ); + ~K3bPlayListViewItem(); + + /** @returns the filename for the first column and the + * length in format 00:00.00 for the second column + */ + virtual QString text( int c ) const; + + void setLength( unsigned long l ) { m_length = l; } + unsigned long length() const { return m_length; } + const QString& filename() const { return m_filename; } + + /** + * reimplemented from QListViewItem + * takes the m_bActive flag into account. + */ + virtual void paintCell( QPainter*, const QColorGroup&, int, int, int ); + + void setActive( bool a ) { m_bActive = a; } + + protected: + /** path to the associated file */ + QString m_filename; + + /** length in frames (1/75 second) */ + unsigned long m_length; + + bool m_bActive; +}; + + + +/** + * Playlistview just needed to accept + * url drags + */ +class K3bPlayListView : public KListView +{ +Q_OBJECT + + public: + K3bPlayListView( QWidget* parent = 0, const char* name = 0 ); + ~K3bPlayListView(); + + protected: + bool acceptDrag( QDropEvent* e ) const; + QDragObject* dragObject(); +}; + + + + +/** + * @author Sebastian Trueg + */ +class K3bAudioPlayer : public QWidget +{ +Q_OBJECT + + public: + K3bAudioPlayer( QWidget* parent = 0, const char* name = 0 ); + ~K3bAudioPlayer(); + + bool supportsMimetype( const QString& mimetype ); + + /** + * length of current playing in seconds + */ + long length(); + + /** + * current position in seconds + */ + long position(); + + /** + * EMPTY - no file loaded + */ + enum player_state { PLAYING, PAUSED, STOPPED, EMPTY }; + + int state(); + + signals: + void started( const QString& filename ); + void started(); + void stopped(); + void paused(); + void ended(); + + public slots: + void playFile( const QString& filename ); + void playFiles( const QStringList& files ); + void enqueueFile( const QString& filename ); + void enqueueFiles( const QStringList& files ); + + /** clears the playlist */ + void clear(); + void play(); + void forward(); + void back(); + void stop(); + void pause(); + void seek( long pos ); + void seek( int pos ); + +/* protected: */ +/* void dragEnterEvent( QDragEnterEvent* e ); */ +/* void dropEvent( QDropEvent* e ); */ + + private slots: + void slotCheckEnd(); + void slotUpdateDisplay(); + void slotUpdateCurrentTime( int time ); + void slotUpdateLength( long time ); + void slotUpdateFilename(); + void slotPlayItem( QListViewItem* item ); + void slotDropped( QDropEvent* e, QListViewItem* after ); + + /** + * set the actual item. Will set m_currentItem and + * handle highlighting of the current item + */ + void setCurrentItem( QListViewItem* item ); + void slotRemoveSelected(); + void slotShowContextMenu( KListView*, QListViewItem* item, const QPoint& p ); + + private: +#ifdef WITH_ARTS + Arts::PlayObject m_playObject; + KArtsDispatcher m_dispatcher; +#endif + QString m_filename; + + QLabel* m_labelFilename; + QLabel* m_labelCurrentTime; + QLabel* m_labelOverallTime; + + QToolButton* m_buttonPlay; + QToolButton* m_buttonPause; + QToolButton* m_buttonStop; + QToolButton* m_buttonForward; + QToolButton* m_buttonBack; + + K3bPlayListView* m_viewPlayList; + + QSlider* m_seekSlider; + + QTimer* m_updateTimer; + + K3bPlayListViewItem* m_currentItem; + + bool m_bLengthReady; + + KAction* m_actionRemove; + KAction* m_actionClear; + KActionMenu* m_contextMenu; +}; + + +#endif diff --git a/src/k3baudioprojectinterface.cpp b/src/k3baudioprojectinterface.cpp new file mode 100644 index 0000000..1d06d5a --- /dev/null +++ b/src/k3baudioprojectinterface.cpp @@ -0,0 +1,92 @@ +/* + * + * $Id: k3baudioprojectinterface.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3baudioprojectinterface.h" + +#include <k3baudiodoc.h> +#include <k3baudiotrack.h> + + +K3bAudioProjectInterface::K3bAudioProjectInterface( K3bAudioDoc* doc, const char* name ) + : K3bProjectInterface( doc, name ), + m_audioDoc(doc) +{ +} + + +int K3bAudioProjectInterface::trackCount() const +{ + return m_audioDoc->numOfTracks(); +} + + +QString K3bAudioProjectInterface::title() const +{ + return m_audioDoc->title(); +} + + +QString K3bAudioProjectInterface::artist() const +{ + return m_audioDoc->artist(); +} + + +QString K3bAudioProjectInterface::trackTitle( int trackNum ) const +{ + K3bAudioTrack* track = m_audioDoc->getTrack( trackNum ); + if( track ) + return track->title(); + else + return QString::null; +} + + +QString K3bAudioProjectInterface::trackArtist( int trackNum ) const +{ + K3bAudioTrack* track = m_audioDoc->getTrack( trackNum ); + if( track ) + return track->artist(); + else + return QString::null; +} + + +void K3bAudioProjectInterface::setTitle( const QString& title ) +{ + m_audioDoc->setTitle( title ); +} + + +void K3bAudioProjectInterface::setArtist( const QString& artist ) +{ + m_audioDoc->setArtist( artist ); +} + + +void K3bAudioProjectInterface::setTrackTitle( int trackNum, const QString& title ) +{ + K3bAudioTrack* track = m_audioDoc->getTrack( trackNum ); + if( track ) + track->setTitle( title ); +} + + +void K3bAudioProjectInterface::setTrackArtist( int trackNum, const QString& artist ) +{ + K3bAudioTrack* track = m_audioDoc->getTrack( trackNum ); + if( track ) + track->setArtist( artist ); +} diff --git a/src/k3baudioprojectinterface.h b/src/k3baudioprojectinterface.h new file mode 100644 index 0000000..e7d649e --- /dev/null +++ b/src/k3baudioprojectinterface.h @@ -0,0 +1,63 @@ +/* + * + * $Id: k3baudioprojectinterface.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_AUDIO_PROJECT_INTERFACE_H_ +#define _K3B_AUDIO_PROJECT_INTERFACE_H_ + +#include "k3bprojectinterface.h" + +class K3bAudioDoc; + + +class K3bAudioProjectInterface : public K3bProjectInterface +{ + K_DCOP + + public: + K3bAudioProjectInterface( K3bAudioDoc*, const char* name = 0 ); + + k_dcop: + int trackCount() const; + QString title() const; + QString artist() const; + QString trackTitle( int trackNum ) const; + QString trackArtist( int trackNum ) const; + + /** + * Set the global CD-Text title field. + */ + void setTitle( const QString& title ); + + /** + * Set the global CD-Text artist field. + */ + void setArtist( const QString& artist ); + + /** + * Set the track CD-Text title field. + */ + void setTrackTitle( int trackNum, const QString& title ); + + /** + * Set the track CD-Text artist field. + */ + void setTrackArtist( int trackNum, const QString& artist ); + + private: + K3bAudioDoc* m_audioDoc; +}; + +#endif diff --git a/src/k3bburnprogressdialog.cpp b/src/k3bburnprogressdialog.cpp new file mode 100644 index 0000000..a5ad3a4 --- /dev/null +++ b/src/k3bburnprogressdialog.cpp @@ -0,0 +1,134 @@ +/* + * + * $Id$ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bburnprogressdialog.h" + +#include "k3bapplication.h" +#include "k3bjob.h" +#include <k3bdevice.h> +#include "k3bstdguiitems.h" +#include "k3bthemedlabel.h" +#include <k3bthememanager.h> + +#include <kglobal.h> +#include <kprogress.h> +#include <klocale.h> + +#include <qgroupbox.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qframe.h> + + +K3bBurnProgressDialog::K3bBurnProgressDialog( QWidget *parent, const char *name, bool showSubProgress, + bool modal, WFlags wf ) + : K3bJobProgressDialog(parent,name, showSubProgress, modal, wf) +{ + m_labelWritingSpeed = new QLabel( m_frameExtraInfo, "m_labelWritingSpeed" ); + // m_labelWritingSpeed->setAlignment( int( QLabel::AlignVCenter | QLabel::AlignRight ) ); + + m_frameExtraInfoLayout->addWidget( m_labelWritingSpeed, 2, 0 ); + m_frameExtraInfoLayout->addWidget( new QLabel( i18n("Estimated writing speed:"), m_frameExtraInfo ), 1, 0 ); + + m_labelWriter = new K3bThemedLabel( m_frameExtraInfo ); + m_labelWriter->setFrameShape( QFrame::StyledPanel ); + m_labelWriter->setFrameShadow( QFrame::Sunken ); + m_labelWriter->setLineWidth( 1 ); + m_labelWriter->setMargin( 5 ); + QFont textLabel14_font( m_labelWriter->font() ); + textLabel14_font.setBold( true ); + m_labelWriter->setFont( textLabel14_font ); + + m_frameExtraInfoLayout->addMultiCellWidget( m_labelWriter, 0, 0, 0, 3 ); + m_frameExtraInfoLayout->addWidget( new QLabel( i18n("Software buffer:"), m_frameExtraInfo ), 1, 2 ); + m_frameExtraInfoLayout->addWidget( new QLabel( i18n("Device buffer:"), m_frameExtraInfo ), 2, 2 ); + + m_progressWritingBuffer = new KProgress( m_frameExtraInfo, "m_progressWritingBuffer" ); + m_frameExtraInfoLayout->addWidget( m_progressWritingBuffer, 1, 3 ); + + m_progressDeviceBuffer = new KProgress( m_frameExtraInfo ); + m_frameExtraInfoLayout->addWidget( m_progressDeviceBuffer, 2, 3 ); + m_frameExtraInfoLayout->addMultiCellWidget( K3bStdGuiItems::verticalLine( m_frameExtraInfo ), 1, 2, 1, 1 ); +} + +K3bBurnProgressDialog::~K3bBurnProgressDialog() +{ +} + + +void K3bBurnProgressDialog::setJob( K3bJob* job ) +{ + if( K3bBurnJob* burnJob = dynamic_cast<K3bBurnJob*>(job) ) + setBurnJob(burnJob); + else + K3bJobProgressDialog::setJob(job); +} + + +void K3bBurnProgressDialog::setBurnJob( K3bBurnJob* burnJob ) +{ + K3bJobProgressDialog::setJob(burnJob); + + if( burnJob ) { + connect( burnJob, SIGNAL(bufferStatus(int)), this, SLOT(slotBufferStatus(int)) ); + connect( burnJob, SIGNAL(deviceBuffer(int)), this, SLOT(slotDeviceBuffer(int)) ); + connect( burnJob, SIGNAL(writeSpeed(int, int)), this, SLOT(slotWriteSpeed(int, int)) ); + connect( burnJob, SIGNAL(burning(bool)), m_progressWritingBuffer, SLOT(setEnabled(bool)) ); + connect( burnJob, SIGNAL(burning(bool)), m_progressDeviceBuffer, SLOT(setEnabled(bool)) ); + connect( burnJob, SIGNAL(burning(bool)), m_labelWritingSpeed, SLOT(setEnabled(bool)) ); + + if( burnJob->writer() ) + m_labelWriter->setText( i18n("Writer: %1 %2").arg(burnJob->writer()->vendor()). + arg(burnJob->writer()->description()) ); + + m_labelWritingSpeed->setText( i18n("no info") ); + m_progressWritingBuffer->setFormat( i18n("no info") ); + m_progressDeviceBuffer->setFormat( i18n("no info") ); + } +} + + +void K3bBurnProgressDialog::slotFinished( bool success ) +{ + K3bJobProgressDialog::slotFinished( success ); + if( success ) { + m_labelWritingSpeed->setEnabled( false ); + m_progressWritingBuffer->setEnabled( false ); + m_progressDeviceBuffer->setEnabled( false ); + } +} + + +void K3bBurnProgressDialog::slotBufferStatus( int b ) +{ + m_progressWritingBuffer->setFormat( "%p%" ); + m_progressWritingBuffer->setValue( b ); +} + + +void K3bBurnProgressDialog::slotDeviceBuffer( int b ) +{ + m_progressDeviceBuffer->setFormat( "%p%" ); + m_progressDeviceBuffer->setValue( b ); +} + + +void K3bBurnProgressDialog::slotWriteSpeed( int s, int multiplicator ) +{ + m_labelWritingSpeed->setText( QString("%1 KB/s (%2x)").arg(s).arg(KGlobal::locale()->formatNumber((double)s/(double)multiplicator,2)) ); +} + +#include "k3bburnprogressdialog.moc" diff --git a/src/k3bburnprogressdialog.h b/src/k3bburnprogressdialog.h new file mode 100644 index 0000000..db27ddb --- /dev/null +++ b/src/k3bburnprogressdialog.h @@ -0,0 +1,55 @@ +/* + * + * $Id: k3bburnprogressdialog.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BBURNPROGRESSDIALOG_H +#define K3BBURNPROGRESSDIALOG_H + +#include <k3bjobprogressdialog.h> + +class K3bBurnJob; +class KProgress; +class QLabel; + + +/** + *@author Sebastian Trueg + */ +class K3bBurnProgressDialog : public K3bJobProgressDialog { + + Q_OBJECT + + public: + K3bBurnProgressDialog( QWidget* parent = 0, const char* name = 0, bool showSubProgress = true, + bool modal = true, WFlags = 0 ); + ~K3bBurnProgressDialog(); + + void setJob( K3bJob* ); + void setBurnJob( K3bBurnJob* ); + + protected slots: + void slotWriteSpeed( int, int ); + void slotBufferStatus( int ); + void slotDeviceBuffer( int ); + void slotFinished(bool); + + protected: + QLabel* m_labelWriter; + KProgress* m_progressWritingBuffer; + KProgress* m_progressDeviceBuffer; + QLabel* m_labelWritingSpeed; +}; + +#endif diff --git a/src/k3bcontentsview.cpp b/src/k3bcontentsview.cpp new file mode 100644 index 0000000..304ae0d --- /dev/null +++ b/src/k3bcontentsview.cpp @@ -0,0 +1,86 @@ +/* + * + * $Id: k3bcdcontentsview.cpp 582796 2006-09-10 15:31:38Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bcontentsview.h" + +#include <k3bthemedheader.h> + +#include <qlabel.h> +#include <qlayout.h> +#include <qpixmap.h> + + +K3bContentsView::K3bContentsView( bool withHeader, + QWidget* parent, + const char* name ) + : QWidget( parent, name ), + m_header(0), + m_centerWidget(0) +{ + if( withHeader ) { + QVBoxLayout* lay = new QVBoxLayout( this ); + lay->setMargin( 2 ); + lay->setSpacing( 0 ); + + m_header = new K3bThemedHeader( this ); + lay->addWidget( m_header ); + + m_header->setLeftPixmap( K3bTheme::MEDIA_LEFT ); + m_header->setRightPixmap( K3bTheme::MEDIA_NONE ); + } +} + + +K3bContentsView::~K3bContentsView() +{ +} + + +void K3bContentsView::setMainWidget( QWidget* w ) +{ + m_centerWidget = w; + ((QVBoxLayout*)layout())->addWidget( w ); +} + + +QWidget* K3bContentsView::mainWidget() +{ + if( !m_centerWidget ) + setMainWidget( new QWidget( this ) ); + return m_centerWidget; +} + + +void K3bContentsView::setTitle( const QString& s ) +{ + if( m_header ) + m_header->setTitle( s ); +} + + +void K3bContentsView::setLeftPixmap( K3bTheme::PixmapType s ) +{ + if( m_header ) + m_header->setLeftPixmap( s ); +} + + +void K3bContentsView::setRightPixmap( K3bTheme::PixmapType s ) +{ + if( m_header ) + m_header->setRightPixmap( s ); +} + +#include "k3bcontentsview.moc" diff --git a/src/k3bcontentsview.h b/src/k3bcontentsview.h new file mode 100644 index 0000000..a3b6f45 --- /dev/null +++ b/src/k3bcontentsview.h @@ -0,0 +1,49 @@ +/* + * + * $Id: k3bcdcontentsview.h 576315 2006-08-23 19:32:42Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_CONTENTS_VIEW_H_ +#define _K3B_CONTENTS_VIEW_H_ + +#include <qwidget.h> +#include <k3bthememanager.h> + +class K3bThemedHeader; + + +class K3bContentsView : public QWidget +{ + Q_OBJECT + + public: + virtual ~K3bContentsView(); + + protected: + K3bContentsView( bool withHeader, + QWidget* parent = 0, + const char* name = 0 ); + + QWidget* mainWidget(); + void setMainWidget( QWidget* ); + void setTitle( const QString& ); + void setLeftPixmap( K3bTheme::PixmapType ); + void setRightPixmap( K3bTheme::PixmapType ); + + private: + K3bThemedHeader* m_header; + QWidget* m_centerWidget; +}; + +#endif diff --git a/src/k3bdatamodewidget.cpp b/src/k3bdatamodewidget.cpp new file mode 100644 index 0000000..669da59 --- /dev/null +++ b/src/k3bdatamodewidget.cpp @@ -0,0 +1,106 @@ +/* + * + * $Id: k3bdatamodewidget.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bdatamodewidget.h" +#include <k3bglobals.h> + +#include <klocale.h> +#include <kconfig.h> + +#include <qwhatsthis.h> +#include <qtooltip.h> + +static const int s_autoIndex = 0; +static const int s_mode1Index = 1; +static const int s_mode2Index = 2; + + +K3bDataModeWidget::K3bDataModeWidget( QWidget* parent, const char* name ) + : QComboBox( false, parent, name ) +{ + insertItem( i18n("Auto"), s_autoIndex ); + insertItem( i18n("Mode1"), s_mode1Index ); + insertItem( i18n("Mode2"), s_mode2Index ); + + QToolTip::add( this,i18n("Select the mode for the data-track") ); + QWhatsThis::add( this, i18n("<p><b>Data Mode</b>" + "<p>Data tracks may be written in two different modes:</p>" + "<p><b>Auto</b><br>" + "Let K3b select the best suited data mode.</p>" + "<p><b>Mode 1</b><br>" + "This is the <em>original</em> writing mode as introduced in the " + "<em>Yellow Book</em> standard. It is the preferred mode when writing " + "pure data CDs.</p>" + "<p><b>Mode 2</b><br>" + "To be exact <em>XA Mode 2 Form 1</em>, but since the " + "other modes are rarely used it is common to refer to it as <em>Mode 2</em>.</p>" + "<p><b>Be aware:</b> Do not mix different modes on one CD. " + "Some older drives may have problems reading mode 1 multisession CDs.") ); +} + + +K3bDataModeWidget::~K3bDataModeWidget() +{ +} + + +int K3bDataModeWidget::dataMode() const +{ + if( currentItem() == s_autoIndex ) + return K3b::DATA_MODE_AUTO; + else if( currentItem() == s_mode1Index ) + return K3b::MODE1; + else + return K3b::MODE2; +} + + +void K3bDataModeWidget::setDataMode( int mode ) +{ + if( mode == K3b::MODE1 ) + setCurrentItem( s_mode1Index ); + else if( mode == K3b::MODE2 ) + setCurrentItem( s_mode2Index ); + else + setCurrentItem( s_autoIndex ); +} + + +void K3bDataModeWidget::saveConfig( KConfigBase* c ) +{ + QString datamode; + if( dataMode() == K3b::MODE1 ) + datamode = "mode1"; + else if( dataMode() == K3b::MODE2 ) + datamode = "mode2"; + else + datamode = "auto"; + c->writeEntry( "data_track_mode", datamode ); +} + + +void K3bDataModeWidget::loadConfig( KConfigBase* c ) +{ + QString datamode = c->readEntry( "data_track_mode" ); + if( datamode == "mode1" ) + setDataMode( K3b::MODE1 ); + else if( datamode == "mode2" ) + setDataMode( K3b::MODE2 ); + else + setDataMode( K3b::DATA_MODE_AUTO ); +} + +#include "k3bdatamodewidget.moc" diff --git a/src/k3bdatamodewidget.h b/src/k3bdatamodewidget.h new file mode 100644 index 0000000..647225f --- /dev/null +++ b/src/k3bdatamodewidget.h @@ -0,0 +1,46 @@ +/* + * + * $Id: k3bdatamodewidget.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_DATAMODE_WIDGET_H_ +#define _K3B_DATAMODE_WIDGET_H_ + +#include <qcombobox.h> + + +class KConfigBase; + + +class K3bDataModeWidget : public QComboBox +{ + Q_OBJECT + + public: + K3bDataModeWidget( QWidget* parent = 0, const char* name = 0 ); + ~K3bDataModeWidget(); + + /** + * returnes K3b::DataMode + */ + int dataMode() const; + + void saveConfig( KConfigBase* ); + void loadConfig( KConfigBase* ); + + public slots: + void setDataMode( int ); +}; + +#endif diff --git a/src/k3bdataprojectinterface.cpp b/src/k3bdataprojectinterface.cpp new file mode 100644 index 0000000..6adf07d --- /dev/null +++ b/src/k3bdataprojectinterface.cpp @@ -0,0 +1,128 @@ +/* + * + * $Id: k3bdataprojectinterface.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bdataprojectinterface.h" + +#include <k3bdatadoc.h> +#include <k3bdiritem.h> +#include <k3bisooptions.h> + + +K3bDataProjectInterface::K3bDataProjectInterface( K3bDataDoc* doc, const char* name ) + : K3bProjectInterface( doc, name ), + m_dataDoc(doc) +{ +} + + +K3bDataProjectInterface::~K3bDataProjectInterface() +{ +} + + +bool K3bDataProjectInterface::createFolder( const QString& name ) +{ + return createFolder( name, "/" ); +} + + +bool K3bDataProjectInterface::createFolder( const QString& name, const QString& parent ) +{ + K3bDataItem* p = m_dataDoc->root()->findByPath( parent ); + if( p && p->isDir() && !static_cast<K3bDirItem*>(p)->find( name ) ) { + m_dataDoc->addEmptyDir( name, static_cast<K3bDirItem*>(p) ); + return true; + } + return false; +} + + +void K3bDataProjectInterface::addUrl( const QString& url, const QString& parent ) +{ + addUrls( QStringList(url), parent ); +} + + +void K3bDataProjectInterface::addUrls( const QStringList& urls, const QString& parent ) +{ + K3bDataItem* p = m_dataDoc->root()->findByPath( parent ); + if( p && p->isDir() ) + m_dataDoc->addUrls( KURL::List(urls), static_cast<K3bDirItem*>(p) ); +} + + +bool K3bDataProjectInterface::removeItem( const QString& path ) +{ + K3bDataItem* p = m_dataDoc->root()->findByPath( path ); + if( p && p->isRemoveable() ) { + m_dataDoc->removeItem( p ); + return true; + } + else + return false; +} + + +bool K3bDataProjectInterface::renameItem( const QString& path, const QString& newName ) +{ + K3bDataItem* p = m_dataDoc->root()->findByPath( path ); + if( p && p->isRenameable() && !newName.isEmpty() ) { + p->setK3bName( newName ); + return true; + } + else + return false; +} + + +void K3bDataProjectInterface::setVolumeID( const QString& id ) +{ + m_dataDoc->setVolumeID( id ); +} + +bool K3bDataProjectInterface::isFolder( const QString& path ) const +{ + K3bDataItem* p = m_dataDoc->root()->findByPath( path ); + if( p ) + return p->isDir(); + else + return false; +} + + +QStringList K3bDataProjectInterface::children( const QString& path ) const +{ + QStringList l; + K3bDataItem* item = m_dataDoc->root()->findByPath( path ); + if( item && item->isDir() ) { + const QPtrList<K3bDataItem>& cl = static_cast<K3bDirItem*>(item)->children(); + for( QPtrListIterator<K3bDataItem> it( cl ); *it; ++it ) + l.append( it.current()->k3bName() ); + } + + return l; +} + + +bool K3bDataProjectInterface::setSortWeight( const QString& path, long weight ) const +{ + K3bDataItem* item = m_dataDoc->root()->findByPath( path ); + if( item ) { + item->setSortWeight( weight ); + return true; + } + else + return false; +} diff --git a/src/k3bdataprojectinterface.h b/src/k3bdataprojectinterface.h new file mode 100644 index 0000000..689455b --- /dev/null +++ b/src/k3bdataprojectinterface.h @@ -0,0 +1,105 @@ +/* + * + * $Id: k3bdataprojectinterface.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_DATA_PROJECT_INTERFACE_H_ +#define _K3B_DATA_PROJECT_INTERFACE_H_ + +#include "k3bprojectinterface.h" + +#include <qstringlist.h> + +class K3bDataDoc; + + +class K3bDataProjectInterface : public K3bProjectInterface +{ + K_DCOP + + public: + K3bDataProjectInterface( K3bDataDoc*, const char* name = 0 ); + ~K3bDataProjectInterface(); + + k_dcop: + /** + * Create a new folder in the root of the doc. + * This is the same as calling createFolder( name, "/" ) + */ + bool createFolder( const QString& name ); + + /** + * Create a new folder with name @p name in the folder with the + * absolute path @p parent. + * + * \return true if the folder was created successfully, false if + * an item with the same name already exists or the parent + * directory could not be found. + * + * Example: createFolder( "test", "/foo/bar" ) will create the + * folder /foo/bar/test. + */ + bool createFolder( const QString& name, const QString& parent ); + + /** + * Add urls to a specific folder in the project. + * + * Example: addUrl( "test.txt", "/foo/bar" ) will add the file test.txt + * to folder /foo/bar. + */ + void addUrl( const QString& url, const QString& parent ); + + void addUrls( const QStringList& urls, const QString& parent ); + + /** + * Remove an item + * \return true if the item was successfully removed. + */ + bool removeItem( const QString& path ); + + /** + * Rename an item + * \return true if the item was successfully renamed, false if + * no item could be found at \p path, \p newName is empty, + * or the item cannot be renamed for some reason. + */ + bool renameItem( const QString& path, const QString& newName ); + + /** + * Set the volume ID of the data project. This is the name shown by Windows + * when the CD is inserted. + */ + void setVolumeID( const QString& id ); + + /** + * \return true if the specified path exists in the project and it is a folder. + */ + bool isFolder( const QString& path ) const; + + /** + * \return the names of the child elements of the item determined by path. + */ + QStringList children( const QString& path ) const; + + /** + * Set the sort weight of an item + * \return false if the item at \p could not be found. + */ + bool setSortWeight( const QString& path, long weight ) const; + + private: + K3bDataDoc* m_dataDoc; +}; + +#endif diff --git a/src/k3bdebuggingoutputdialog.cpp b/src/k3bdebuggingoutputdialog.cpp new file mode 100644 index 0000000..7ffe84c --- /dev/null +++ b/src/k3bdebuggingoutputdialog.cpp @@ -0,0 +1,162 @@ +/* + * + * $Id: k3bdebuggingoutputdialog.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bdebuggingoutputdialog.h" + +#include <k3bdevicemanager.h> +#include <k3bdevice.h> +#include <k3bdeviceglobals.h> +#include <k3bcore.h> +#include <k3bversion.h> +#include <k3bglobals.h> + +#include <qtextedit.h> +#include <qcursor.h> +#include <qfile.h> +#include <qclipboard.h> + +#include <klocale.h> +#include <kstdguiitem.h> +#include <kglobalsettings.h> +#include <kapplication.h> +#include <kfiledialog.h> +#include <kmessagebox.h> + + +K3bDebuggingOutputDialog::K3bDebuggingOutputDialog( QWidget* parent ) + : KDialogBase( parent, "debugViewDialog", true, i18n("Debugging Output"), Close|User1|User2, Close, + false, + KStdGuiItem::saveAs(), + KGuiItem( i18n("Copy"), "editcopy" ) ) +{ + setButtonTip( User1, i18n("Save to file") ); + setButtonTip( User2, i18n("Copy to clipboard") ); + + debugView = new QTextEdit( this ); + debugView->setReadOnly(true); + debugView->setTextFormat( QTextEdit::PlainText ); + debugView->setCurrentFont( KGlobalSettings::fixedFont() ); + debugView->setWordWrap( QTextEdit::NoWrap ); + + setMainWidget( debugView ); + + resize( 600, 300 ); +} + + +void K3bDebuggingOutputDialog::setOutput( const QMap<QString, QStringList>& map ) +{ + // the following may take some time + QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); + + clear(); + + // add the debugging output + for( QMap<QString, QStringList>::ConstIterator itMap = map.begin(); itMap != map.end(); ++itMap ) { + const QStringList& list = itMap.data(); + debugView->append( itMap.key() + "\n" ); + debugView->append( "-----------------------\n" ); + for( QStringList::ConstIterator it = list.begin(); it != list.end(); ++it ) { + QStringList lines = QStringList::split( "\n", *it ); + // do every line + QStringList::ConstIterator end( lines.end() ); + for( QStringList::ConstIterator str = lines.begin(); str != end; ++str ) + debugView->append( *str + "\n" ); + } + m_paragraphMap[itMap.key()] = debugView->paragraphs(); + debugView->append( "\n" ); + } + + QApplication::restoreOverrideCursor(); +} + + +void K3bDebuggingOutputDialog::addOutput( const QString& app, const QString& msg ) +{ + QMap<QString, int>::Iterator it = m_paragraphMap.find( app ); + + if( it == m_paragraphMap.end() ) { + // create new section + debugView->append( app + "\n" ); + debugView->append( "-----------------------\n" ); + debugView->append( msg + "\n" ); + m_paragraphMap[app] = debugView->paragraphs(); + debugView->append( "\n" ); + } + else { + debugView->insertParagraph( msg, *it ); + // update the paragraphs map + // FIXME: we cannot count on the map to be sorted properly! + while( it != m_paragraphMap.end() ) { + it.data() += 1; + ++it; + } + } +} + + +void K3bDebuggingOutputDialog::clear() +{ + debugView->clear(); + m_paragraphMap.clear(); + + addOutput( "System", "K3b Version: " + k3bcore->version() ); + addOutput( "System", "KDE Version: " + QString(KDE::versionString()) ); + addOutput( "System", "QT Version: " + QString(qVersion()) ); + addOutput( "System", "Kernel: " + K3b::kernelVersion() ); + + // devices in the logfile + for( QPtrListIterator<K3bDevice::Device> it( k3bcore->deviceManager()->allDevices() ); *it; ++it ) { + K3bDevice::Device* dev = *it; + addOutput( "Devices", + QString( "%1 (%2, %3) [%5] [%6] [%7]" ) + .arg( dev->vendor() + " " + dev->description() + " " + dev->version() ) + .arg( dev->blockDeviceName() ) + .arg( dev->genericDevice() ) + .arg( K3bDevice::deviceTypeString( dev->type() ) ) + .arg( K3bDevice::mediaTypeString( dev->supportedProfiles() ) ) + .arg( K3bDevice::writingModeString( dev->writingModes() ) ) ); + } +} + + +void K3bDebuggingOutputDialog::slotUser1() +{ + QString filename = KFileDialog::getSaveFileName(); + if( !filename.isEmpty() ) { + QFile f( filename ); + if( !f.exists() || KMessageBox::warningContinueCancel( this, + i18n("Do you want to overwrite %1?").arg(filename), + i18n("File Exists"), i18n("Overwrite") ) + == KMessageBox::Continue ) { + + if( f.open( IO_WriteOnly ) ) { + QTextStream t( &f ); + t << debugView->text(); + } + else { + KMessageBox::error( this, i18n("Could not open file %1").arg(filename) ); + } + } + } +} + + +void K3bDebuggingOutputDialog::slotUser2() +{ + QApplication::clipboard()->setText( debugView->text(), QClipboard::Clipboard ); +} + +#include "k3bdebuggingoutputdialog.moc" diff --git a/src/k3bdebuggingoutputdialog.h b/src/k3bdebuggingoutputdialog.h new file mode 100644 index 0000000..0e74b71 --- /dev/null +++ b/src/k3bdebuggingoutputdialog.h @@ -0,0 +1,46 @@ +/* + * + * $Id: k3bdebuggingoutputdialog.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_DEBUGGING_OUTPUT_DIALOG_H_ +#define _K3B_DEBUGGING_OUTPUT_DIALOG_H_ + +#include <kdialogbase.h> +#include <qmap.h> + +class QTextEdit; + +class K3bDebuggingOutputDialog : public KDialogBase +{ + Q_OBJECT + + public: + K3bDebuggingOutputDialog( QWidget* parent ); + + public slots: + void setOutput( const QMap<QString, QStringList>& ); + void addOutput( const QString&, const QString& ); + void clear(); + + private: + void slotUser1(); + void slotUser2(); + + QTextEdit* debugView; + QMap<QString, int> m_paragraphMap; +}; + + + +#endif diff --git a/src/k3bdebuggingoutputfile.cpp b/src/k3bdebuggingoutputfile.cpp new file mode 100644 index 0000000..2f99e96 --- /dev/null +++ b/src/k3bdebuggingoutputfile.cpp @@ -0,0 +1,75 @@ +/* + * + * $Id: k3bdebuggingoutputfile.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bdebuggingoutputfile.h" + +#include <k3bdevicemanager.h> +#include <k3bdevice.h> +#include <k3bcore.h> +#include <k3bversion.h> +#include <k3bdeviceglobals.h> +#include <k3bglobals.h> + +#include <kstandarddirs.h> +#include <kglobalsettings.h> +#include <kapplication.h> + +#include <qtextstream.h> + + +K3bDebuggingOutputFile::K3bDebuggingOutputFile() + : QFile( locateLocal( "appdata", "lastlog.log", true ) ) +{ +} + + +bool K3bDebuggingOutputFile::open() +{ + if( !QFile::open( IO_WriteOnly ) ) + return false; + + addOutput( "System", "K3b Version: " + k3bcore->version() ); + addOutput( "System", "KDE Version: " + QString(KDE::versionString()) ); + addOutput( "System", "QT Version: " + QString(qVersion()) ); + addOutput( "System", "Kernel: " + K3b::kernelVersion() ); + + // devices in the logfile + for( QPtrListIterator<K3bDevice::Device> it( k3bcore->deviceManager()->allDevices() ); *it; ++it ) { + K3bDevice::Device* dev = *it; + addOutput( "Devices", + QString( "%1 (%2, %3) [%5] [%6] [%7]" ) + .arg( dev->vendor() + " " + dev->description() + " " + dev->version() ) + .arg( dev->blockDeviceName() ) + .arg( dev->genericDevice() ) + .arg( K3bDevice::deviceTypeString( dev->type() ) ) + .arg( K3bDevice::mediaTypeString( dev->supportedProfiles() ) ) + .arg( K3bDevice::writingModeString( dev->writingModes() ) ) ); + } + + return true; +} + + +void K3bDebuggingOutputFile::addOutput( const QString& app, const QString& msg ) +{ + if( !isOpen() ) + open(); + + QTextStream s( this ); + s << "[" << app << "] " << msg << endl; + flush(); +} + +#include "k3bdebuggingoutputfile.moc" diff --git a/src/k3bdebuggingoutputfile.h b/src/k3bdebuggingoutputfile.h new file mode 100644 index 0000000..c0af0e5 --- /dev/null +++ b/src/k3bdebuggingoutputfile.h @@ -0,0 +1,39 @@ +/* + * + * $Id: k3bdebuggingoutputfile.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_DEBUGGING_OUTPUT_FILE_H_ +#define _K3B_DEBUGGING_OUTPUT_FILE_H_ + +#include <qfile.h> +#include <qobject.h> + +class K3bDebuggingOutputFile : public QObject, public QFile +{ + Q_OBJECT + + public: + K3bDebuggingOutputFile(); + + /** + * Open the default output file and write some system information. + */ + bool open(); + + public slots: + void addOutput( const QString&, const QString& ); +}; + + +#endif diff --git a/src/k3bdiroperator.cpp b/src/k3bdiroperator.cpp new file mode 100644 index 0000000..12c6ba4 --- /dev/null +++ b/src/k3bdiroperator.cpp @@ -0,0 +1,159 @@ + +/* + * + * $Id: k3bdiroperator.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bdiroperator.h" + +#include <k3bapplication.h> +#include <k3b.h> +#include <k3bcore.h> + +#include <kcombiview.h> +#include <kfilepreview.h> +#include <kaction.h> +#include <kbookmarkmenu.h> +#include <kstandarddirs.h> +#include <kpopupmenu.h> + +#include <qdir.h> + + +K3bDirOperator::K3bDirOperator(const KURL& url, QWidget* parent, const char* name ) + : KDirOperator( url, parent, name ) +{ + setViewConfig( k3bcore->config(), "file view" ); + setMode( KFile::Files ); + + // disable the del-key since we still have a focus problem and users keep + // deleting files when they want to remove project entries + KAction* aDelete = actionCollection()->action("delete"); + if( aDelete ) + aDelete->setShortcut( 0 ); + + // add the bookmark stuff + KBookmarkManager* bmMan = KBookmarkManager::managerForFile( locateLocal( "data", "k3b/bookmarks.xml" ), false ); + bmMan->setEditorOptions( i18n("K3b Bookmarks"), false ); + bmMan->setUpdate( true ); + bmMan->setShowNSBookmarks( false ); + + m_bmPopup = new KActionMenu( i18n("Bookmarks"), "bookmark", this, "bookmarks" ); + m_bmMenu = new KBookmarkMenu( bmMan, this, m_bmPopup->popupMenu(), actionCollection(), true ); + + (void)new KAction( i18n("&Add to Project"), SHIFT+Key_Return, + this, SLOT(slotAddFilesToProject()), + actionCollection(), "add_file_to_project"); +} + + +K3bDirOperator::~K3bDirOperator() +{ + delete m_bmMenu; +} + + +void K3bDirOperator::readConfig( KConfig* cfg, const QString& group ) +{ + QString oldGroup = cfg->group(); + cfg->setGroup( group ); + + KDirOperator::readConfig( cfg, group ); + setView( KFile::Default ); + + // + // There seems to be a bug in the KDELibs which makes setURL crash on + // some systems when used with a non-existing url + // + QString lastUrl = cfg->readPathEntry( "last url", QDir::home().absPath() ); + while( !QFile::exists(lastUrl) ) { + QString urlUp = lastUrl.section( '/', 0, -2 ); + if( urlUp == lastUrl ) + lastUrl = QDir::home().absPath(); + else + lastUrl = urlUp; + } + + setURL( KURL::fromPathOrURL(lastUrl), true ); + + cfg->setGroup( oldGroup ); + + emit urlEntered( url() ); +} + + +void K3bDirOperator::writeConfig( KConfig* cfg, const QString& group ) +{ + QString oldGroup = cfg->group(); + cfg->setGroup( group ); + + KDirOperator::writeConfig( cfg, group ); + cfg->writePathEntry( "last url", url().path() ); + + cfg->setGroup( oldGroup ); +} + + +void K3bDirOperator::openBookmarkURL( const QString& url ) +{ + setURL( KURL::fromPathOrURL( url ), true ); +} + + +QString K3bDirOperator::currentTitle() const +{ + return url().path(-1); +} + + +QString K3bDirOperator::currentURL() const +{ + return url().path(-1); +} + + +void K3bDirOperator::activatedMenu( const KFileItem*, const QPoint& pos ) +{ + // both from KDirOperator + setupMenu(); + updateSelectionDependentActions(); + + // insert our own actions + KActionMenu* dirOpMenu = (KActionMenu*)actionCollection()->action("popupMenu"); + dirOpMenu->insert( new KActionSeparator( actionCollection() ) ); + dirOpMenu->insert( m_bmPopup ); + + dirOpMenu->insert( actionCollection()->action("add_file_to_project"), 0 ); + dirOpMenu->insert( new KActionSeparator( actionCollection() ), 1 ); + + bool hasSelection = view() && view()->selectedItems() && + !view()->selectedItems()->isEmpty(); + actionCollection()->action("add_file_to_project")->setEnabled( hasSelection && k3bappcore->k3bMainWindow()->activeView() != 0 ); + + dirOpMenu->popup( pos ); +} + + +void K3bDirOperator::slotAddFilesToProject() +{ + KURL::List files; + for( QPtrListIterator<KFileItem> it( *(selectedItems()) ); it.current(); ++it ) { + files.append( it.current()->url() ); + } + if( !files.isEmpty() ) + k3bappcore->k3bMainWindow()->addUrls( files ); +} + +#include "k3bdiroperator.moc" + diff --git a/src/k3bdiroperator.h b/src/k3bdiroperator.h new file mode 100644 index 0000000..b231a8d --- /dev/null +++ b/src/k3bdiroperator.h @@ -0,0 +1,82 @@ +/* + * + * $Id: k3bdiroperator.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BDIROPERATOR_H +#define K3BDIROPERATOR_H + +#include <kdiroperator.h> +#include <kbookmarkmanager.h> + +class QIconViewItem; +class QListViewItem; +class KBookmarkMenu; +class KActionMenu; + + + +/** + *@author Sebastian Trueg + */ +class K3bDirOperator : public KDirOperator, public KBookmarkOwner +{ + Q_OBJECT + + public: + K3bDirOperator( const KURL& urlName = KURL(), QWidget* parent = 0, const char* name = 0 ); + ~K3bDirOperator(); + + /** + * reimplemented from KDirOperator + */ + void readConfig( KConfig* cfg, const QString& group ); + + /** + * reimplemented from KDirOperator + */ + void writeConfig( KConfig* cfg, const QString& group ); + + /** + * reimplemented from KBookmarkOwner + */ + void openBookmarkURL( const QString& url ); + + /** + * reimplemented from KBookmarkOwner + */ + QString currentTitle() const; + + /** + * reimplemented from KBookmarkOwner + */ + QString currentURL() const; + + KActionMenu* bookmarkMenu() const { return m_bmPopup; } + + public slots: + void slotAddFilesToProject(); + + protected slots: + /** + * reimplemented from KDirOperator + */ + void activatedMenu( const KFileItem*, const QPoint& ); + + private: + KBookmarkMenu* m_bmMenu; + KActionMenu* m_bmPopup; +}; + +#endif diff --git a/src/k3bdirview.cpp b/src/k3bdirview.cpp new file mode 100644 index 0000000..d711300 --- /dev/null +++ b/src/k3bdirview.cpp @@ -0,0 +1,367 @@ +/* + * + * $Id: k3bdirview.cpp 627621 2007-01-27 12:31:44Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include <config.h> + +#include "k3bdirview.h" +#include "k3bapplication.h" +#include "k3b.h" + +#include "rip/k3baudiocdview.h" +#include "rip/k3bvideocdview.h" +#ifdef HAVE_LIBDVDREAD +#include "rip/videodvd/k3bvideodvdrippingview.h" +#endif +#include "k3bfileview.h" +#include "k3bfiletreeview.h" +#include "k3bappdevicemanager.h" +#include "k3bdiskinfoview.h" +#include <k3bdevicehandler.h> +#include <k3bdevice.h> +#include <k3bthememanager.h> +#include <k3bmediacache.h> +#include <k3bexternalbinmanager.h> +#include <k3bpassivepopup.h> + +#include <unistd.h> +// QT-includes +#include <qdir.h> +#include <qlistview.h> +#include <qstring.h> +#include <qfile.h> +#include <qfileinfo.h> +#include <qpixmap.h> +#include <qstringlist.h> +#include <qstrlist.h> +#include <qheader.h> +#include <qsplitter.h> +#include <qpushbutton.h> +#include <qlayout.h> +#include <qiconset.h> +#include <qvaluelist.h> +#include <qlabel.h> +#include <qwidgetstack.h> +#include <qscrollview.h> +#include <qpainter.h> +#include <qsimplerichtext.h> + +// KDE-includes +#include <kmimetype.h> +#include <kcursor.h> +#include <kfiledetailview.h> +#include <ktoolbar.h> +#include <kiconloader.h> +#include <kurl.h> +#include <klocale.h> +#include <kstandarddirs.h> +#include <kio/file.h> +#include <kio/global.h> +#include <krun.h> +#include <kprocess.h> +#include <kio/job.h> +#include <kcombobox.h> +#include <kfiletreeview.h> +#include <kdialog.h> +#include <kmessagebox.h> +#include <kstdaction.h> +#include <kconfig.h> +#include <kaction.h> +#include <kinputdialog.h> + + + +class K3bDirView::Private +{ +public: + bool contextMediaInfoRequested; +}; + + + +K3bDirView::K3bDirView(K3bFileTreeView* treeView, QWidget *parent, const char *name ) + : QVBox(parent, name), + m_fileTreeView(treeView), + m_bViewDiskInfo(false) +{ + d = new Private; + d->contextMediaInfoRequested = false; + + if( !m_fileTreeView ) { + m_mainSplitter = new QSplitter( this ); + m_fileTreeView = new K3bFileTreeView( m_mainSplitter ); + m_viewStack = new QWidgetStack( m_mainSplitter ); + } + else { + m_viewStack = new QWidgetStack( this ); + m_mainSplitter = 0; + } + + m_fileTreeView->header()->hide(); + + m_fileView = new K3bFileView(m_viewStack, "fileView"); + m_cdView = new K3bAudioCdView(m_viewStack, "cdview"); + m_videoView = new K3bVideoCdView(m_viewStack, "videoview"); + m_infoView = new K3bDiskInfoView(m_viewStack, "infoView"); +#ifdef HAVE_LIBDVDREAD + m_movieView = new K3bVideoDVDRippingView(m_viewStack, "movieview"); +#endif + + m_viewStack->raiseWidget( m_fileView ); + + m_fileTreeView->addDefaultBranches(); + m_fileTreeView->addCdDeviceBranches( k3bcore->deviceManager() ); + m_fileTreeView->setCurrentDevice( k3bappcore->appDeviceManager()->currentDevice() ); + + m_fileView->setAutoUpdate( true ); // in case we look at the mounted path + + if( m_mainSplitter ) { + // split + QValueList<int> sizes = m_mainSplitter->sizes(); + int all = sizes[0] + sizes[1]; + sizes[1] = all*2/3; + sizes[0] = all - sizes[1]; + m_mainSplitter->setSizes( sizes ); + } + + connect( m_fileTreeView, SIGNAL(urlExecuted(const KURL&)), + this, SLOT(slotDirActivated(const KURL&)) ); + connect( m_fileTreeView, SIGNAL(deviceExecuted(K3bDevice::Device*)), + this, SLOT(showDevice(K3bDevice::Device*)) ); + connect( m_fileTreeView, SIGNAL(deviceExecuted(K3bDevice::Device*)), + this, SIGNAL(deviceSelected(K3bDevice::Device*)) ); + connect( m_fileTreeView, SIGNAL(contextMenu(K3bDevice::Device*, const QPoint&)), + this, SLOT(slotFileTreeContextMenu(K3bDevice::Device*, const QPoint&)) ); + + connect( m_fileView, SIGNAL(urlEntered(const KURL&)), m_fileTreeView, SLOT(followUrl(const KURL&)) ); + connect( m_fileView, SIGNAL(urlEntered(const KURL&)), this, SIGNAL(urlEntered(const KURL&)) ); + + connect( k3bappcore->appDeviceManager(), SIGNAL(mountFinished(const QString&)), + this, SLOT(slotMountFinished(const QString&)) ); + connect( k3bappcore->appDeviceManager(), SIGNAL(unmountFinished(bool)), + this, SLOT(slotUnmountFinished(bool)) ); + connect( k3bappcore->appDeviceManager(), SIGNAL(detectingDiskInfo(K3bDevice::Device*)), + this, SLOT(slotDetectingDiskInfo(K3bDevice::Device*)) ); +} + +K3bDirView::~K3bDirView() +{ + delete d; +} + + +void K3bDirView::showUrl( const KURL& url ) +{ + slotDirActivated( url ); +} + + +void K3bDirView::showDevice( K3bDevice::Device* dev ) +{ + d->contextMediaInfoRequested = true; + m_fileTreeView->setSelectedDevice( dev ); + showMediumInfo( k3bappcore->mediaCache()->medium( dev ) ); +} + + +void K3bDirView::slotDetectingDiskInfo( K3bDevice::Device* dev ) +{ + d->contextMediaInfoRequested = false; + m_fileTreeView->setSelectedDevice( dev ); + showMediumInfo( k3bappcore->mediaCache()->medium( dev ) ); +} + + +void K3bDirView::showMediumInfo( const K3bMedium& medium ) +{ + if( !d->contextMediaInfoRequested || + medium.diskInfo().diskState() == K3bDevice::STATE_EMPTY || + medium.diskInfo().diskState() == K3bDevice::STATE_NO_MEDIA ) { + + // show cd info + m_viewStack->raiseWidget( m_infoView ); + m_infoView->reload( medium ); + return; + } + +#ifdef HAVE_LIBDVDREAD + else if( medium.content() & K3bMedium::CONTENT_VIDEO_DVD ) { + KMessageBox::ButtonCode r = KMessageBox::Yes; + if( KMessageBox::shouldBeShownYesNo( "videodvdripping", r ) ) { + r = (KMessageBox::ButtonCode) + KMessageBox::questionYesNoCancel( this, + i18n("<p>You have selected the K3b Video DVD ripping tool." + "<p>It is intended to <em>rip single titles</em> from a video DVD " + "into a compressed format such as XviD. Menu structures are completely ignored." + "<p>If you intend to copy the plain Video DVD vob files from the DVD " + "(including decryption) for further processing with another application, " + "please use the following link to access the Video DVD file structure: " + "<a href=\"videodvd:/\">videodvd:/</a>" + "<p>If you intend to make a copy of the entire Video DVD including all menus " + "and extras it is recommended to use the K3b DVD Copy tool."), + i18n("Video DVD ripping"), + i18n("Continue"), + i18n("Open DVD Copy Dialog"), + "videodvdripping", + KMessageBox::AllowLink ); + } + else { // if we do not show the dialog we always continue with the ripping. Everything else would be confusing + r = KMessageBox::Yes; + } + + if( r == KMessageBox::Cancel ) { + // m_viewStack->raiseWidget( m_fileView ); + } + else if( r == KMessageBox::No ) { + m_viewStack->raiseWidget( m_fileView ); + static_cast<K3bMainWindow*>( kapp->mainWidget() )->slotDvdCopy(); + } + else { + m_movieView->reload( medium ); + m_viewStack->raiseWidget( m_movieView ); + } + + return; + } +#endif + + else if( medium.content() & K3bMedium::CONTENT_DATA ) { + bool mount = true; + if( medium.content() & K3bMedium::CONTENT_VIDEO_CD ) { + if( !k3bcore ->externalBinManager() ->foundBin( "vcdxrip" ) ) { + KMessageBox::sorry( this, + i18n("K3b uses vcdxrip from the vcdimager package to rip Video CDs. " + "Please make sure it is installed.") ); + } + else { + if( KMessageBox::questionYesNo( this, + i18n("Found %1. Do you want K3b to mount the data part " + "or show all the tracks?").arg( i18n("Video CD") ), + i18n("Video CD"), + i18n("Mount CD"), + i18n("Show Video Tracks") ) == KMessageBox::No ) { + mount = false; + m_viewStack->raiseWidget( m_videoView ); + m_videoView->reload( medium ); + } + } + } + else if( medium.content() & K3bMedium::CONTENT_AUDIO ) { + if( KMessageBox::questionYesNo( this, + i18n("Found %1. Do you want K3b to mount the data part " + "or show all the tracks?").arg( i18n("Audio CD") ), + i18n("Audio CD"), + i18n("Mount CD"), + i18n("Show Audio Tracks") ) == KMessageBox::No ) { + mount = false; + m_viewStack->raiseWidget( m_cdView ); + m_cdView->reload( medium ); + } + } + + if( mount ) + k3bappcore->appDeviceManager()->mountDisk( medium.device() ); + } + + else if( medium.content() & K3bMedium::CONTENT_AUDIO ) { + m_viewStack->raiseWidget( m_cdView ); + m_cdView->reload( medium ); + } + + else { + // show cd info + m_viewStack->raiseWidget( m_infoView ); + m_infoView->reload( medium ); + } + + d->contextMediaInfoRequested = false; +} + + +void K3bDirView::slotMountFinished( const QString& mp ) +{ + if( !mp.isEmpty() ) { + slotDirActivated( mp ); + m_fileView->reload(); // HACK to get the contents shown... FIXME + } + else { + m_viewStack->raiseWidget( m_fileView ); + K3bPassivePopup::showPopup( i18n("<p>K3b was unable to mount medium <b>%1</b> in device <em>%2 - %3</em>") + .arg( k3bappcore->mediaCache()->medium( k3bappcore->appDeviceManager()->currentDevice() ).shortString() ) + .arg( k3bappcore->appDeviceManager()->currentDevice()->vendor() ) + .arg( k3bappcore->appDeviceManager()->currentDevice()->description() ), + i18n("Mount Failed"), + K3bPassivePopup::Warning ); + } +} + + +void K3bDirView::slotUnmountFinished( bool success ) +{ + if( success ) { + // TODO: check if the fileview is still displaying a folder from the medium + } + else { + K3bPassivePopup::showPopup( i18n("<p>K3b was unable to unmount medium <b>%1</b> in device <em>%2 - %3</em>") + .arg( k3bappcore->mediaCache()->medium( k3bappcore->appDeviceManager()->currentDevice() ).shortString() ) + .arg( k3bappcore->appDeviceManager()->currentDevice()->vendor() ) + .arg( k3bappcore->appDeviceManager()->currentDevice()->description() ), + i18n("Unmount Failed"), + K3bPassivePopup::Warning ); + } +} + + +void K3bDirView::slotFileTreeContextMenu( K3bDevice::Device* /*dev*/, const QPoint& p ) +{ + KAction* a = k3bappcore->appDeviceManager()->actionCollection()->action( "device_popup" ); + if( KActionMenu* m = dynamic_cast<KActionMenu*>(a) ) + m->popup( p ); +} + + +void K3bDirView::slotDirActivated( const QString& url ) +{ +// m_urlCombo->insertItem( url, 0 ); + slotDirActivated( KURL::fromPathOrURL(url) ); +} + + +void K3bDirView::slotDirActivated( const KURL& url ) +{ + m_fileView->setUrl(url, true); +// m_urlCombo->setEditText( url.path() ); + + m_viewStack->raiseWidget( m_fileView ); +} + + +void K3bDirView::home() +{ + slotDirActivated( QDir::homeDirPath() ); +} + + +void K3bDirView::saveConfig( KConfig* c ) +{ + m_fileView->saveConfig(c); +} + + +void K3bDirView::readConfig( KConfig* c ) +{ + m_fileView->readConfig(c); +} + +#include "k3bdirview.moc" diff --git a/src/k3bdirview.h b/src/k3bdirview.h new file mode 100644 index 0000000..7d4cdf0 --- /dev/null +++ b/src/k3bdirview.h @@ -0,0 +1,100 @@ +/* + * + * $Id: k3bdirview.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BDIRVIEW_H +#define K3BDIRVIEW_H + +#include <qvbox.h> + +#include <k3bmedium.h> + +class QSplitter; +class KURL; +class K3bAudioCdView; +class K3bVideoCdView; +class K3bFileView; +class K3bVideoDVDRippingView; +class KComboBox; +class K3bFileTreeView; +class QWidgetStack; +class K3bDiskInfoView; +class QScrollView; +class QLabel; +class KConfig; +class K3bDeviceBranch; + +namespace K3bDevice { + class Device; + class DiskInfo; +} + +namespace KIO { + class Job; +} + + +/** + *@author Sebastian Trueg + */ +class K3bDirView : public QVBox +{ + Q_OBJECT + + public: + K3bDirView(K3bFileTreeView* tree, QWidget *parent=0, const char *name=0); + ~K3bDirView(); + + public slots: + void saveConfig( KConfig* c ); + void readConfig( KConfig* c ); + void showUrl( const KURL& ); + void showDevice( K3bDevice::Device* ); + + protected slots: + void slotDirActivated( const KURL& ); + void slotDirActivated( const QString& ); + void slotMountFinished( const QString& ); + void slotUnmountFinished( bool ); + void showMediumInfo( const K3bMedium& ); + void slotDetectingDiskInfo( K3bDevice::Device* dev ); + void home(); + void slotFileTreeContextMenu( K3bDevice::Device* dev, const QPoint& p ); + + signals: + void urlEntered( const KURL& ); + void deviceSelected( K3bDevice::Device* ); + + private: + QWidgetStack* m_viewStack; + QScrollView* m_scroll; + + K3bAudioCdView* m_cdView; + K3bVideoCdView* m_videoView; + K3bVideoDVDRippingView* m_movieView; + K3bFileView* m_fileView; + K3bDiskInfoView* m_infoView; + + KComboBox* m_urlCombo; + QSplitter* m_mainSplitter; + K3bFileTreeView* m_fileTreeView; + + bool m_bViewDiskInfo; + + class Private; + Private* d; +}; + +#endif diff --git a/src/k3bdiskinfoview.cpp b/src/k3bdiskinfoview.cpp new file mode 100644 index 0000000..4a1208f --- /dev/null +++ b/src/k3bdiskinfoview.cpp @@ -0,0 +1,500 @@ +/* + * + * $Id: k3bdiskinfoview.cpp 643214 2007-03-16 15:25:24Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include <config.h> + + +#include "k3bdiskinfoview.h" + +#include <k3bdiskinfo.h> +#include <k3bcdtext.h> +#include <k3bdeviceglobals.h> +#include <k3bglobals.h> +#include <k3bstdguiitems.h> +#include <k3blistview.h> +#include <k3biso9660.h> + +#include <qlabel.h> +#include <qlayout.h> +#include <qfont.h> +#include <qcolor.h> +#include <qheader.h> +#include <qstring.h> +#include <qpainter.h> +#include <qpalette.h> +#include <qpixmap.h> +#include <qregion.h> +#include <qframe.h> + +#include <kdialog.h> +#include <klocale.h> +#include <klistview.h> +#include <kiconloader.h> +#include <kstandarddirs.h> +#include <kdebug.h> +#include <kio/global.h> + + +// FIXME: use K3bListViewItem instead +class K3bDiskInfoView::HeaderViewItem : public KListViewItem +{ +public: + HeaderViewItem( QListView* parent ) + : KListViewItem( parent ) {} + HeaderViewItem( QListViewItem* parent ) + : KListViewItem( parent ) {} + HeaderViewItem( QListView* parent, QListViewItem* after ) + : KListViewItem( parent, after ) {} + HeaderViewItem( QListViewItem* parent, QListViewItem* after ) + : KListViewItem( parent, after ) {} + HeaderViewItem( QListView* parent, const QString& t1 ) + : KListViewItem( parent, t1 ) {} + HeaderViewItem( QListViewItem* parent, const QString& t1 ) + : KListViewItem( parent, t1 ) {} + HeaderViewItem( QListView* parent, QListViewItem* after, const QString& t1 ) + : KListViewItem( parent, after, t1 ) {} + HeaderViewItem( QListViewItem* parent, QListViewItem* after, const QString& t1 ) + : KListViewItem( parent, after, t1 ) {} + + void paintCell( QPainter* p, const QColorGroup & cg, int column, int width, int align ) + { + QFont f ( p->font() ); + f.setBold( true ); + p->setFont( f ); + KListViewItem::paintCell( p, cg, column, width, align ); + } +}; + + +class K3bDiskInfoView::TwoColumnViewItem : public KListViewItem +{ +public: + TwoColumnViewItem( QListView* parent ) + : KListViewItem( parent ) {} + TwoColumnViewItem( QListViewItem* parent ) + : KListViewItem( parent ) {} + TwoColumnViewItem( QListView* parent, QListViewItem* after ) + : KListViewItem( parent, after ) {} + TwoColumnViewItem( QListViewItem* parent, QListViewItem* after ) + : KListViewItem( parent, after ) {} + TwoColumnViewItem( QListView* parent, const QString& t1 ) + : KListViewItem( parent, t1 ) {} + TwoColumnViewItem( QListViewItem* parent, const QString& t1 ) + : KListViewItem( parent, t1 ) {} + TwoColumnViewItem( QListView* parent, QListViewItem* after, const QString& t1 ) + : KListViewItem( parent, after, t1 ) {} + TwoColumnViewItem( QListViewItem* parent, QListViewItem* after, const QString& t1 ) + : KListViewItem( parent, after, t1 ) {} + + void paintCell( QPainter* p, const QColorGroup & cg, int column, int width, int align ) + { + + if( column == 1 ) { + int newWidth = width; + + int i = 2; + for( ; i < listView()->columns(); ++i ) { + newWidth += listView()->columnWidth( i ); + } + + // TODO: find a way to get the TRUE new width after resizing + + // QRect r = p->clipRegion().boundingRect(); + // r.setWidth( newWidth ); + // p->setClipRect( r ); + p->setClipping( false ); + + KListViewItem::paintCell( p, cg, column, newWidth, align ); + } else if( column == 0 ) + KListViewItem::paintCell( p, cg, column, width, align ); + } +}; + + + +K3bDiskInfoView::K3bDiskInfoView( QWidget* parent, const char* name ) + : K3bMediaContentsView( true, + K3bMedium::CONTENT_ALL, + K3bDevice::MEDIA_ALL|K3bDevice::MEDIA_UNKNOWN, + K3bDevice::STATE_EMPTY|K3bDevice::STATE_INCOMPLETE|K3bDevice::STATE_COMPLETE|K3bDevice::STATE_UNKNOWN, + parent, name ) +{ + m_infoView = new KListView( this ); + setMainWidget( m_infoView ); + + m_infoView->setSorting( -1 ); + m_infoView->setAllColumnsShowFocus( true ); + m_infoView->setSelectionMode( QListView::NoSelection ); + m_infoView->setResizeMode( KListView::AllColumns ); + m_infoView->setAlternateBackground( QColor() ); + + m_infoView->addColumn( "1" ); + m_infoView->addColumn( "2" ); + m_infoView->addColumn( "3" ); + m_infoView->addColumn( "4" ); +#ifdef K3B_DEBUG + m_infoView->addColumn( "index0" ); +#endif + + m_infoView->header()->hide(); + + // do not automatically reload the disk info + // setAutoReload( false ); +} + + +K3bDiskInfoView::~K3bDiskInfoView() +{} + + +void K3bDiskInfoView::reloadMedium() +{ + m_infoView->clear(); + + setTitle( medium().shortString( true ) ); + + if( medium().diskInfo().diskState() == K3bDevice::STATE_NO_MEDIA ) { + (void)new QListViewItem( m_infoView, i18n("No medium present") ); + setRightPixmap( K3bTheme::MEDIA_NONE ); + } + else { + if( medium().diskInfo().empty() ) { + setRightPixmap( K3bTheme::MEDIA_EMPTY ); + } + else { + switch( medium().toc().contentType() ) { + case K3bDevice::AUDIO: + setRightPixmap( K3bTheme::MEDIA_AUDIO ); + break; + case K3bDevice::DATA: { + if( medium().content() & K3bMedium::CONTENT_VIDEO_DVD ) { + setRightPixmap( K3bTheme::MEDIA_VIDEO ); + } + else { + setRightPixmap( K3bTheme::MEDIA_DATA ); + } + break; + } + case K3bDevice::MIXED: + setRightPixmap( K3bTheme::MEDIA_MIXED ); + break; + default: + setTitle( i18n("Unknown Disk Type") ); + setRightPixmap( K3bTheme::MEDIA_NONE ); + } + } + + createMediaInfoItems( medium() ); + + + // iso9660 info + // ///////////////////////////////////////////////////////////////////////////////////// + if( medium().content() & K3bMedium::CONTENT_DATA ) { + (void)new KListViewItem( m_infoView, m_infoView->lastChild() ); // empty spacer item + createIso9660InfoItems( medium().iso9660Descriptor() ); + } + + // tracks + // ///////////////////////////////////////////////////////////////////////////////////// + if( !medium().toc().isEmpty() ) { + + if( m_infoView->childCount() ) + (void)new KListViewItem( m_infoView, m_infoView->lastChild() ); // empty spacer item + + KListViewItem* trackHeaderItem = new HeaderViewItem( m_infoView, m_infoView->lastChild(), i18n("Tracks") ); + + // create header item + KListViewItem* item = new KListViewItem( trackHeaderItem, + i18n("Type"), + i18n("Attributes"), + i18n("First-Last Sector"), + i18n("Length") ); + +#ifdef K3B_DEBUG + item->setText( 4, "Index0" ); +#endif + + int lastSession = 0; + + // if we have multiple sessions we create a header item for every session + KListViewItem* trackItem = 0; + if( medium().diskInfo().numSessions() > 1 && medium().toc()[0].session() > 0 ) { + trackItem = new HeaderViewItem( trackHeaderItem, item, i18n("Session %1").arg(1) ); + lastSession = 1; + } + else + trackItem = trackHeaderItem; + + // create items for the tracks + K3bDevice::Toc::const_iterator it; + int index = 1; + for( it = medium().toc().begin(); it != medium().toc().end(); ++it ) { + const K3bTrack& track = *it; + + if( medium().diskInfo().numSessions() > 1 && track.session() != lastSession ) { + lastSession = track.session(); + trackItem->setOpen(true); + trackItem = new HeaderViewItem( trackHeaderItem, + m_infoView->lastItem()->parent(), + i18n("Session %1").arg(lastSession) ); + } + + item = new KListViewItem( trackItem, item ); + QString text; + if( track.type() == K3bTrack::AUDIO ) { + item->setPixmap( 0, SmallIcon( "sound" ) ); + text = i18n("Audio"); + } else { + item->setPixmap( 0, SmallIcon( "tar" ) ); + if( track.mode() == K3bTrack::MODE1 ) + text = i18n("Data/Mode1"); + else if( track.mode() == K3bTrack::MODE2 ) + text = i18n("Data/Mode2"); + else if( track.mode() == K3bTrack::XA_FORM1 ) + text = i18n("Data/Mode2 XA Form1"); + else if( track.mode() == K3bTrack::XA_FORM2 ) + text = i18n("Data/Mode2 XA Form2"); + else + text = i18n("Data"); + } + item->setText( 0, i18n("%1 (%2)").arg( QString::number(index).rightJustify( 2, ' ' )).arg(text) ); + item->setText( 1, QString( "%1/%2" ) + .arg( track.copyPermitted() ? i18n("copy") : i18n("no copy") ) + .arg( track.type() == K3bTrack::AUDIO + ? ( track.preEmphasis() ? i18n("preemp") : i18n("no preemp") ) + : ( track.recordedIncremental() ? i18n("incremental") : i18n("uninterrupted") ) ) ); + item->setText( 2, + QString("%1 - %2") + .arg(track.firstSector().lba()) + .arg(track.lastSector().lba()) ); + item->setText( 3, QString::number( track.length().lba() ) + " (" + track.length().toString() + ")" ); + +#ifdef K3B_DEBUG + if( track.type() == K3bTrack::AUDIO ) + item->setText( 4, QString( "%1 (%2)" ).arg(track.index0().toString()).arg(track.index0().lba()) ); +#endif + ++index; + } + + trackItem->setOpen(true); + trackHeaderItem->setOpen( true ); + } + + + // CD-TEXT + // ///////////////////////////////////////////////////////////////////////////////////// + if( !medium().cdText().isEmpty() ) { + medium().cdText().debug(); + if( m_infoView->childCount() ) + (void)new KListViewItem( m_infoView, m_infoView->lastChild() ); // empty spacer item + + KListViewItem* cdTextHeaderItem = new HeaderViewItem( m_infoView, + m_infoView->lastChild(), + i18n("CD-TEXT (excerpt)") ); + + // create header item + KListViewItem* item = new KListViewItem( cdTextHeaderItem, + i18n("Performer"), + i18n("Title"), + i18n("Songwriter"), + i18n("Composer") ); + item = new KListViewItem( cdTextHeaderItem, item ); + item->setText( 0, i18n("CD:") + " " + + medium().cdText().performer() ); + item->setText( 1, medium().cdText().title() ); + item->setText( 2, medium().cdText().songwriter() ); + item->setText( 3, medium().cdText().composer() ); + + int index = 1; + for( unsigned int i = 0; i < medium().cdText().count(); ++i ) { + item = new KListViewItem( cdTextHeaderItem, item ); + item->setText( 0, QString::number(index).rightJustify( 2, ' ' ) + " " + + medium().cdText().at(i).performer() ); + item->setText( 1, medium().cdText().at(i).title() ); + item->setText( 2, medium().cdText().at(i).songwriter() ); + item->setText( 3, medium().cdText().at(i).composer() ); + ++index; + } + + cdTextHeaderItem->setOpen( true ); + } + } +} + + +void K3bDiskInfoView::createMediaInfoItems( const K3bMedium& medium ) +{ + const K3bDevice::DiskInfo& info = medium.diskInfo(); + + KListViewItem* atipItem = new HeaderViewItem( m_infoView, m_infoView->lastItem(), i18n("Medium") ); + QString typeStr; + if( info.mediaType() != K3bDevice::MEDIA_UNKNOWN ) + typeStr = K3bDevice::mediaTypeString( info.mediaType() ); + else + typeStr = i18n("Unknown (probably CD-ROM)"); + + KListViewItem* atipChild = new KListViewItem( atipItem, i18n("Type:"), typeStr ); + + if( info.isDvdMedia() ) + atipChild = new KListViewItem( atipItem, atipChild, + i18n("Media ID:"), + !info.mediaId().isEmpty() ? QString::fromLatin1( info.mediaId() ) : i18n("unknown") ); + + + atipChild = new KListViewItem( atipItem, atipChild, + i18n("Capacity:"), + i18n("%1 min").arg(info.capacity().toString()), + KIO::convertSize(info.capacity().mode1Bytes()) ); + + if( !info.empty() ) + atipChild = new KListViewItem( atipItem, atipChild, + i18n("Used Capacity:"), + i18n("%1 min").arg(info.size().toString()), + KIO::convertSize(info.size().mode1Bytes()) ); + + if( info.appendable() ) + atipChild = new KListViewItem( atipItem, atipChild, + i18n("Remaining:"), + i18n("%1 min").arg( info.remainingSize().toString() ), + KIO::convertSize(info.remainingSize().mode1Bytes()) ); + + atipChild = new KListViewItem( atipItem, atipChild, + i18n("Rewritable:"), + info.rewritable() ? i18n("yes") : i18n("no") ); + + atipChild = new KListViewItem( atipItem, atipChild, + i18n("Appendable:"), + info.appendable() ? i18n("yes") : i18n("no") ); + + atipChild = new KListViewItem( atipItem, atipChild, + i18n("Empty:"), + info.empty() ? i18n("yes") : i18n("no") ); + + if( info.isDvdMedia() ) + atipChild = new KListViewItem( atipItem, atipChild, + i18n("Layers:"), + QString::number( info.numLayers() ) ); + + if( info.mediaType() == K3bDevice::MEDIA_DVD_PLUS_RW ) { + atipChild = new KListViewItem( atipItem, atipChild, + i18n("Background Format:") ); + switch( info.bgFormatState() ) { + case K3bDevice::BG_FORMAT_NONE: + atipChild->setText( 1, i18n("not formatted") ); + break; + case K3bDevice::BG_FORMAT_INCOMPLETE: + atipChild->setText( 1, i18n("incomplete") ); + break; + case K3bDevice::BG_FORMAT_IN_PROGRESS: + atipChild->setText( 1, i18n("in progress") ); + break; + case K3bDevice::BG_FORMAT_COMPLETE: + atipChild->setText( 1, i18n("complete") ); + break; + } + } + + atipChild = new KListViewItem( atipItem, atipChild, + i18n("Sessions:"), + QString::number( info.numSessions() ) ); + + if( info.mediaType() & K3bDevice::MEDIA_WRITABLE ) { + atipChild = new KListViewItem( atipItem, atipChild, + i18n("Supported writing speeds:") ); + QString s; + if( medium.writingSpeeds().isEmpty() ) + s = "-"; + else + for( QValueList<int>::const_iterator it = medium.writingSpeeds().begin(); + it != medium.writingSpeeds().end(); ++it ) { + if( !s.isEmpty() ) { + s.append( "\n" ); + atipChild->setMultiLinesEnabled( true ); + } + + if( info.isDvdMedia() ) + s.append( QString().sprintf( "%.1fx (%d KB/s)", (double)*it / 1385.0, *it ) ); + else + s.append( QString( "%1x (%2 KB/s)" ).arg( *it/175 ).arg( *it ) ); + } + + atipChild->setText( 1, s ); + } + + atipItem->setOpen( true ); +} + + +void K3bDiskInfoView::createIso9660InfoItems( const K3bIso9660SimplePrimaryDescriptor& iso ) +{ + KListViewItem* iso9660Item = new HeaderViewItem( m_infoView, m_infoView->lastChild(), + i18n("ISO9660 Filesystem Info") ); + KListViewItem* iso9660Child = 0; + + iso9660Child = new KListViewItem( iso9660Item, iso9660Child, + i18n("System Id:"), + iso.systemId.isEmpty() + ? QString("-") + : iso.systemId ); + iso9660Child = new KListViewItem( iso9660Item, iso9660Child, + i18n("Volume Id:"), + iso.volumeId.isEmpty() + ? QString("-") + : iso.volumeId ); + iso9660Child = new KListViewItem( iso9660Item, iso9660Child, + i18n("Volume Set Id:"), + iso.volumeSetId.isEmpty() + ? QString("-") + : iso.volumeSetId ); + iso9660Child = new KListViewItem( iso9660Item, iso9660Child, + i18n("Publisher Id:"), + iso.publisherId.isEmpty() + ? QString("-") + : iso.publisherId ); + iso9660Child = new KListViewItem( iso9660Item, iso9660Child, + i18n("Preparer Id:"), + iso.preparerId.isEmpty() + ? QString("-") + : iso.preparerId ); + iso9660Child = new KListViewItem( iso9660Item, iso9660Child, + i18n("Application Id:"), + iso.applicationId.isEmpty() + ? QString("-") + : iso.applicationId ); +// iso9660Child = new KListViewItem( iso9660Item, iso9660Child, +// i18n("Volume Size:"), +// QString( "%1 (%2*%3)" ) +// .arg(iso.logicalBlockSize +// *iso.volumeSpaceSize) +// .arg(iso.logicalBlockSize) +// .arg(iso.volumeSpaceSize), +// KIO::convertSize(iso.logicalBlockSize +// *iso.volumeSpaceSize) ); + + iso9660Item->setOpen( true ); +} + + +void K3bDiskInfoView::enableInteraction( bool enable ) +{ + QListViewItemIterator it( m_infoView ); + while( it.current() ) { + it.current()->setEnabled( enable ); + ++it; + } +} + +#include "k3bdiskinfoview.moc" + diff --git a/src/k3bdiskinfoview.h b/src/k3bdiskinfoview.h new file mode 100644 index 0000000..7c817a7 --- /dev/null +++ b/src/k3bdiskinfoview.h @@ -0,0 +1,56 @@ +/* + * + * $Id: k3bdiskinfoview.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + + +#ifndef K3BDISKINFOVIEW_H +#define K3BDISKINFOVIEW_H + +#include "k3bmediacontentsview.h" +#include "k3bmedium.h" + +class QLabel; +class KListView; +class K3bIso9660; + +namespace K3bDevice { + class DiskInfoDetector; + class DiskInfo; +} + +class K3bDiskInfoView : public K3bMediaContentsView +{ + Q_OBJECT + + public: + K3bDiskInfoView( QWidget* parent = 0, const char* name = 0 ); + ~K3bDiskInfoView(); + + void enableInteraction( bool enable ); + + private: + void reloadMedium(); + + void createMediaInfoItems( const K3bMedium& ); + void createIso9660InfoItems( const K3bIso9660SimplePrimaryDescriptor& ); + + KListView* m_infoView; + + class HeaderViewItem; + class TwoColumnViewItem; +}; + + +#endif diff --git a/src/k3bemptydiscwaiter.cpp b/src/k3bemptydiscwaiter.cpp new file mode 100644 index 0000000..7e11198 --- /dev/null +++ b/src/k3bemptydiscwaiter.cpp @@ -0,0 +1,761 @@ +/* + * + * $Id: k3bemptydiscwaiter.cpp 642801 2007-03-15 12:39:04Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bemptydiscwaiter.h" +#include "k3bmediacache.h" +#include "k3bapplication.h" +#include <k3bdevice.h> +#include <k3bdeviceglobals.h> +#include <k3bdevicehandler.h> +#include <k3bglobals.h> +#include <k3bcore.h> +#include <k3biso9660.h> +#include "k3bblankingjob.h" +#include <k3bbusywidget.h> +#include <k3bprogressdialog.h> +#include <k3bdvdformattingjob.h> + +#include <qtimer.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qtooltip.h> +#include <qpushbutton.h> +#include <qapplication.h> +#include <qeventloop.h> +#include <qfont.h> + +#include <klocale.h> +#include <kconfig.h> +#include <kiconloader.h> +#include <kmessagebox.h> +#include <kactivelabel.h> +#include <knotifyclient.h> + + +class K3bEmptyDiscWaiter::Private +{ +public: + Private() + : erasingInfoDialog(0) { + dialogVisible = false; + inLoop = false; + mediumChanged = 0; + blockMediaChange = false; + } + + K3bDevice::Device* device; + + int wantedMediaType; + int wantedMediaState; + + QString wantedMediaTypeString; + + int result; + int dialogVisible; + bool inLoop; + + bool blockMediaChange; + int mediumChanged; + + bool forced; + bool canceled; + + bool waitingDone; + + QLabel* labelRequest; + QLabel* labelFoundMedia; + QLabel* pixLabel; + + K3bProgressDialog* erasingInfoDialog; +}; + + + +K3bEmptyDiscWaiter::K3bEmptyDiscWaiter( K3bDevice::Device* device, QWidget* parent, const char* name ) + : KDialogBase( KDialogBase::Plain, i18n("Waiting for Disk"), + KDialogBase::Cancel|KDialogBase::User1|KDialogBase::User2|KDialogBase::User3, + KDialogBase::User3, parent, name, true, true, i18n("Force"), i18n("Eject"), i18n("Load") ) +{ + d = new Private(); + d->device = device; + + // setup the gui + // ----------------------------- + d->labelRequest = new QLabel( plainPage() ); + d->labelRequest->setAlignment( Qt::AlignLeft | Qt::AlignVCenter ); + d->labelFoundMedia = new QLabel( plainPage() ); + d->pixLabel = new QLabel( plainPage() ); + d->pixLabel->setAlignment( Qt::AlignHCenter | Qt::AlignTop ); + + QFont f( d->labelFoundMedia->font() ); + f.setBold(true); + d->labelFoundMedia->setFont( f ); + + QGridLayout* grid = new QGridLayout( plainPage() ); + grid->setMargin( marginHint() ); + grid->setSpacing( spacingHint() ); + + grid->addMultiCellWidget( d->pixLabel, 0, 2, 0, 0 ); + grid->addColSpacing( 1, 20 ); + grid->addWidget( new QLabel( i18n("Found media:"), plainPage() ), 0, 2 ); + grid->addWidget( d->labelFoundMedia, 0, 3 ); + grid->addMultiCellWidget( d->labelRequest, 1, 1, 2, 3 ); + grid->setRowStretch( 2, 1 ); + grid->setColStretch( 3, 1 ); + // ----------------------------- + + connect( k3bappcore->mediaCache(), SIGNAL(mediumChanged(K3bDevice::Device*)), + this, SLOT(slotMediumChanged(K3bDevice::Device*)) ); + + QToolTip::add( actionButton(KDialogBase::User1), + i18n("Force K3b to continue if it seems not to detect your empty CD/DVD.") ); +} + + +K3bEmptyDiscWaiter::~K3bEmptyDiscWaiter() +{ + delete d; +} + + +int K3bEmptyDiscWaiter::waitForDisc( int mediaState, int mediaType, const QString& message ) +{ + if ( d->inLoop ) { + kdError() << "(K3bEmptyDiscWaiter) Recursive call detected." << endl; + return -1; + } + + d->wantedMediaState = mediaState; + d->wantedMediaType = mediaType; + d->dialogVisible = false; + d->forced = false; + d->canceled = false; + d->waitingDone = false; + d->blockMediaChange = false; + d->mediumChanged = 0; + + // + // We do not cover every case here but just the ones that really make sense + // + if( (d->wantedMediaType & K3bDevice::MEDIA_WRITABLE_DVD) && + (d->wantedMediaType & K3bDevice::MEDIA_WRITABLE_CD) ) + d->wantedMediaTypeString = i18n("CD-R(W) or DVD%1R(W)").arg(""); + else if( d->wantedMediaType & K3bDevice::MEDIA_WRITABLE_DVD_SL ) + d->wantedMediaTypeString = i18n("DVD%1R(W)").arg(""); + else if( d->wantedMediaType & K3bDevice::MEDIA_WRITABLE_DVD_DL ) + d->wantedMediaTypeString = i18n("Double Layer DVD%1R").arg(""); + else + d->wantedMediaTypeString = i18n("CD-R(W)"); + + if( message.isEmpty() ) { + if( (d->wantedMediaState & K3bDevice::STATE_COMPLETE) && (d->wantedMediaState & K3bDevice::STATE_INCOMPLETE) ) + d->labelRequest->setText( i18n("Please insert a complete or appendable %4 medium " + "into drive<p><b>%1 %2 (%3)</b>.") + .arg(d->device->vendor()) + .arg(d->device->description()) + .arg(d->device->devicename()) + .arg( d->wantedMediaTypeString ) ); + else if( d->wantedMediaState & K3bDevice::STATE_COMPLETE ) + d->labelRequest->setText( i18n("Please insert a complete %4 medium " + "into drive<p><b>%1 %2 (%3)</b>.") + .arg(d->device->vendor()) + .arg(d->device->description()) + .arg(d->device->devicename()) + .arg( d->wantedMediaTypeString ) ); + else if( (d->wantedMediaState & K3bDevice::STATE_INCOMPLETE) && (d->wantedMediaState & K3bDevice::STATE_EMPTY) ) + d->labelRequest->setText( i18n("Please insert an empty or appendable %4 medium " + "into drive<p><b>%1 %2 (%3)</b>.") + .arg(d->device->vendor()) + .arg(d->device->description()) + .arg(d->device->devicename()) + .arg( d->wantedMediaTypeString ) ); + else if( d->wantedMediaState & K3bDevice::STATE_INCOMPLETE ) + d->labelRequest->setText( i18n("Please insert an appendable %4 medium " + "into drive<p><b>%1 %2 (%3)</b>.") + .arg(d->device->vendor()) + .arg(d->device->description()) + .arg(d->device->devicename()) + .arg( d->wantedMediaTypeString ) ); + else if( d->wantedMediaState & K3bDevice::STATE_EMPTY ) + d->labelRequest->setText( i18n("Please insert an empty %4 medium " + "into drive<p><b>%1 %2 (%3)</b>.") + .arg(d->device->vendor()) + .arg(d->device->description()) + .arg(d->device->devicename()) + .arg( d->wantedMediaTypeString ) ); + else // fallback case (this should not happen in K3b) + d->labelRequest->setText( i18n("Please insert a suitable medium " + "into drive<p><b>%1 %2 (%3)</b>.") + .arg(d->device->vendor()) + .arg(d->device->description()) + .arg(d->device->devicename()) ); + + } + else + d->labelRequest->setText( message ); + + if( d->wantedMediaType & K3bDevice::MEDIA_WRITABLE_DVD ) + d->pixLabel->setPixmap( KGlobal::instance()->iconLoader()->loadIcon( "dvd_unmount", + KIcon::NoGroup, KIcon::SizeMedium ) ); + else + d->pixLabel->setPixmap( KGlobal::instance()->iconLoader()->loadIcon( "cdwriter_unmount", + KIcon::NoGroup, KIcon::SizeMedium ) ); + + adjustSize(); + + slotMediumChanged( d->device ); + + // + // in case we already found a medium and thus the dialog is not shown entering + // the loop only causes problems (since there is no dialog yet the user could + // not have forced or canceled yet + // + if( !d->waitingDone ) { + d->inLoop = true; + QApplication::eventLoop()->enterLoop(); + } + + return d->result; +} + + +int K3bEmptyDiscWaiter::exec() +{ + return waitForDisc(); +} + + +void K3bEmptyDiscWaiter::slotMediumChanged( K3bDevice::Device* dev ) +{ + kdDebug() << "(K3bEmptyDiscWaiter) slotMediumChanged() " << endl; + if( d->forced || d->canceled || d->device != dev ) + return; + + // + // This slot may open dialogs which enter a new event loop and that + // may result in another call to this slot if a medium changes while + // a dialog is open + // + if( d->blockMediaChange ) { + d->mediumChanged++; + return; + } + + d->blockMediaChange = true; + + KConfig* c = k3bcore->config(); + bool formatWithoutAsking = KConfigGroup( k3bcore->config(), "General Options" ).readBoolEntry( "auto rewritable erasing", false ); + + K3bMedium medium = k3bappcore->mediaCache()->medium( dev ); + + d->labelFoundMedia->setText( medium.shortString( false ) ); + + if( medium.diskInfo().diskState() == K3bDevice::STATE_NO_MEDIA ) { + continueWaiting(); + d->blockMediaChange = false; + return; + } + +// QString mediaState; +// if( medium.diskInfo().diskState() == K3bDevice::STATE_COMPLETE ) +// mediaState = i18n("complete"); +// else if( medium.diskInfo().diskState() == K3bDevice::STATE_INCOMPLETE ) +// mediaState = i18n("appendable"); +// else if( medium.diskInfo().diskState() == K3bDevice::STATE_EMPTY ) +// mediaState = i18n("empty"); + +// if( !mediaState.isEmpty() ) +// mediaState = " (" + mediaState +")"; + + + // ///////////////////////////////////////////////////////////// + // + // DVD+RW handling + // + // ///////////////////////////////////////////////////////////// + + // DVD+RW: if empty we need to preformat. Although growisofs does it before writing doing it here + // allows better control and a progress bar. If it's not empty we should check if there is + // already a filesystem on the media. + if( (d->wantedMediaType & K3bDevice::MEDIA_DVD_PLUS_RW) && + (medium.diskInfo().mediaType() & K3bDevice::MEDIA_DVD_PLUS_RW) ) { + + kdDebug() << "(K3bEmptyDiscWaiter) ------ found DVD+RW as wanted." << endl; + + if( medium.diskInfo().diskState() == K3bDevice::STATE_EMPTY ) { + if( d->wantedMediaState & K3bDevice::STATE_EMPTY ) { + // special case for the formatting job which wants to preformat on it's own! + if( d->wantedMediaState & K3bDevice::STATE_COMPLETE && + d->wantedMediaState & K3bDevice::STATE_EMPTY ) { + kdDebug() << "(K3bEmptyDiscWaiter) special case: DVD+RW for the formatting job." << endl; + finishWaiting( K3bDevice::MEDIA_DVD_PLUS_RW ); + } + else { + // empty - preformat without asking + prepareErasingDialog(); + + K3bDvdFormattingJob job( this ); + job.setDevice( d->device ); + job.setQuickFormat( true ); + job.setForce( false ); + job.setForceNoEject( true ); + + d->erasingInfoDialog->setText( i18n("Preformatting DVD+RW") ); + connect( &job, SIGNAL(finished(bool)), this, SLOT(slotErasingFinished(bool)) ); + connect( &job, SIGNAL(percent(int)), d->erasingInfoDialog, SLOT(setProgress(int)) ); + connect( d->erasingInfoDialog, SIGNAL(cancelClicked()), &job, SLOT(cancel()) ); + job.start( medium.diskInfo() ); + d->erasingInfoDialog->exec( true ); + } + } + else { + kdDebug() << "(K3bEmptyDiscWaiter) starting devicehandler: empty DVD+RW where a non-empty was requested." << endl; + continueWaiting(); + } + } + else { + // + // We have a DVD+RW medium which is already preformatted + // + if( d->wantedMediaState == K3bDevice::STATE_EMPTY ) { + // check if the media contains a filesystem + K3bIso9660 isoF( d->device ); + bool hasIso = isoF.open(); + + if( formatWithoutAsking || + !hasIso || + KMessageBox::warningContinueCancel( parentWidgetToUse(), + i18n("Found %1 media in %2 - %3. " + "Should it be overwritten?") + .arg("DVD+RW") + .arg(d->device->vendor()) + .arg(d->device->description()), + i18n("Found %1").arg("DVD+RW"),i18n("Overwrite") ) == KMessageBox::Continue ) { + finishWaiting( K3bDevice::MEDIA_DVD_PLUS_RW ); + } + else { + kdDebug() << "(K3bEmptyDiscWaiter) starting devicehandler: no DVD+RW overwrite" << endl; + K3b::unmount( d->device ); + K3bDevice::eject( d->device ); + continueWaiting(); + } + } + + // + // We want a DVD+RW not nessessarily empty. No problem, just use this one. Becasue incomplete and complete + // are handled the same everywhere (isofs is grown). + // + else { + finishWaiting( K3bDevice::MEDIA_DVD_PLUS_RW ); + } + } + } // --- DVD+RW -------- + + + // ///////////////////////////////////////////////////////////// + // + // DVD-RW handling + // + // ///////////////////////////////////////////////////////////// + + // + // DVD-RW in sequential mode can be empty. DVD-RW in restricted overwrite mode is always complete. + // + else if( (d->wantedMediaType & (K3bDevice::MEDIA_DVD_RW| + K3bDevice::MEDIA_DVD_RW_SEQ| + K3bDevice::MEDIA_DVD_RW_OVWR) ) && + (medium.diskInfo().mediaType() & (K3bDevice::MEDIA_DVD_RW| + K3bDevice::MEDIA_DVD_RW_SEQ| + K3bDevice::MEDIA_DVD_RW_OVWR) ) ) { + + kdDebug() << "(K3bEmptyDiscWaiter) ------ found DVD-R(W) as wanted." << endl; + + // we format in the following cases: + // seq. incr. and not empty and empty requested + // seq. incr. and restr. overwri. reqested + // restr. ovw. and seq. incr. requested + + // we have exactly what was requested + if( (d->wantedMediaType & medium.diskInfo().mediaType()) && + (d->wantedMediaState & medium.diskInfo().diskState()) ) { + finishWaiting( medium.diskInfo().mediaType() ); + } + + // DVD-RW in restr. overwrite may just be overwritten + else if( (medium.diskInfo().mediaType() & K3bDevice::MEDIA_DVD_RW_OVWR) && + (d->wantedMediaType & K3bDevice::MEDIA_DVD_RW_OVWR) ) { + if( d->wantedMediaState == K3bDevice::STATE_EMPTY ) { + + kdDebug() << "(K3bEmptyDiscWaiter) ------ DVD-RW restricted overwrite." << endl; + + // check if the media contains a filesystem + K3bIso9660 isoF( d->device ); + bool hasIso = isoF.open(); + + if( formatWithoutAsking || + !hasIso || + KMessageBox::warningContinueCancel( parentWidgetToUse(), + i18n("Found %1 media in %2 - %3. " + "Should it be overwritten?") + .arg(K3bDevice::mediaTypeString(medium.diskInfo().mediaType())) + .arg(d->device->vendor()) + .arg(d->device->description()), + i18n("Found %1").arg("DVD-RW"),i18n("Overwrite") ) == KMessageBox::Continue ) { + finishWaiting( K3bDevice::MEDIA_DVD_RW_OVWR ); + } + else { + kdDebug() << "(K3bEmptyDiscWaiter) starting devicehandler: no DVD-RW overwrite." << endl; + K3b::unmount( d->device ); + K3bDevice::eject( d->device ); + continueWaiting(); + } + } + + else if( !(d->wantedMediaState & K3bDevice::STATE_EMPTY ) ) { + // check if the media contains a filesystem + K3bIso9660 isoF( d->device ); + bool hasIso = isoF.open(); + + if( hasIso ) { + finishWaiting( K3bDevice::MEDIA_DVD_RW_OVWR ); + } + else { + kdDebug() << "(K3bEmptyDiscWaiter) starting devicehandler: empty DVD-RW where a non-empty was requested." << endl; + continueWaiting(); + } + } + + // + // We want a DVD-RW overwrite not nessessarily empty. No problem, just use this one. Becasue incomplete and complete + // are handled the same everywhere (isofs is grown). + // + else { + finishWaiting( K3bDevice::MEDIA_DVD_RW_OVWR ); + } + } + + // formatting + else if( ( (d->wantedMediaType & K3bDevice::MEDIA_DVD_RW_OVWR) && + (medium.diskInfo().mediaType() & K3bDevice::MEDIA_DVD_RW_SEQ) && + !(d->wantedMediaType & K3bDevice::MEDIA_DVD_RW_SEQ) ) || + + ( (d->wantedMediaType & K3bDevice::MEDIA_DVD_RW_SEQ) && + (medium.diskInfo().mediaType() & K3bDevice::MEDIA_DVD_RW_OVWR) && + !(d->wantedMediaType & K3bDevice::MEDIA_DVD_RW_OVWR) ) || + + ( (d->wantedMediaType & K3bDevice::MEDIA_DVD_RW_SEQ) && + (medium.diskInfo().mediaType() & K3bDevice::MEDIA_DVD_RW_SEQ) && + (d->wantedMediaState & K3bDevice::STATE_EMPTY) && + (medium.diskInfo().diskState() != K3bDevice::STATE_EMPTY) ) ) { + + kdDebug() << "(K3bEmptyDiscWaiter) ------ DVD-RW needs to be formated." << endl; + + if( formatWithoutAsking || + KMessageBox::warningContinueCancel( parentWidgetToUse(), + i18n("Found %1 media in %2 - %3. " + "Should it be formatted?") + .arg( K3bDevice::mediaTypeString(medium.diskInfo().mediaType()) ) + .arg(d->device->vendor()) + .arg(d->device->description()), + i18n("Found %1").arg("DVD-RW"), i18n("Format") ) == KMessageBox::Continue ) { + + kdDebug() << "(K3bEmptyDiscWaiter) ------ formatting DVD-RW." << endl; + + prepareErasingDialog(); + + K3bDvdFormattingJob job( this ); + job.setDevice( d->device ); + // we prefere the current mode of the media if no special mode has been requested + job.setMode( ( (d->wantedMediaType & K3bDevice::MEDIA_DVD_RW_SEQ) && + (d->wantedMediaType & K3bDevice::MEDIA_DVD_RW_OVWR) ) + ? ( medium.diskInfo().mediaType() == K3bDevice::MEDIA_DVD_RW_OVWR + ? K3b::WRITING_MODE_RES_OVWR + : K3b::WRITING_MODE_INCR_SEQ ) + : ( (d->wantedMediaType & K3bDevice::MEDIA_DVD_RW_SEQ) + ? K3b::WRITING_MODE_INCR_SEQ + : K3b::WRITING_MODE_RES_OVWR ) ); + job.setQuickFormat( true ); + job.setForce( false ); + job.setForceNoEject(true); + + d->erasingInfoDialog->setText( i18n("Formatting DVD-RW") ); + connect( &job, SIGNAL(finished(bool)), this, SLOT(slotErasingFinished(bool)) ); + connect( &job, SIGNAL(percent(int)), d->erasingInfoDialog, SLOT(setProgress(int)) ); + connect( d->erasingInfoDialog, SIGNAL(cancelClicked()), &job, SLOT(cancel()) ); + job.start( medium.diskInfo() ); + d->erasingInfoDialog->exec( true ); + } + else { + kdDebug() << "(K3bEmptyDiscWaiter) starting devicehandler: no DVD-RW formatting." << endl; + K3b::unmount( d->device ); + K3bDevice::eject( d->device ); + continueWaiting(); + } + } + else { + kdDebug() << "(K3bEmptyDiscWaiter) ------ nothing useful found." << endl; + continueWaiting(); + } + } // --- DVD-RW ------ + + + // ///////////////////////////////////////////////////////////// + // + // CD handling (and DVD-R and DVD+R) + // + // ///////////////////////////////////////////////////////////// + + // we have exactly what was requested + else if( (d->wantedMediaType & medium.diskInfo().mediaType()) && + (d->wantedMediaState & medium.diskInfo().diskState()) ) + finishWaiting( medium.diskInfo().mediaType() ); + + else if( (medium.diskInfo().mediaType() != K3bDevice::MEDIA_UNKNOWN) && + (d->wantedMediaType & medium.diskInfo().mediaType()) && + (d->wantedMediaState & medium.diskInfo().diskState()) ) + finishWaiting( medium.diskInfo().mediaType() ); + + // this is for CD drives that are not able to determine the state of a disk + else if( medium.diskInfo().diskState() == K3bDevice::STATE_UNKNOWN && + medium.diskInfo().mediaType() == K3bDevice::MEDIA_CD_ROM && + d->wantedMediaType & K3bDevice::MEDIA_CD_ROM ) + finishWaiting( medium.diskInfo().mediaType() ); + + // format CD-RW + else if( (d->wantedMediaType & medium.diskInfo().mediaType()) && + (d->wantedMediaState & K3bDevice::STATE_EMPTY) && + medium.diskInfo().rewritable() ) { + + if( formatWithoutAsking || + KMessageBox::questionYesNo( parentWidgetToUse(), + i18n("Found rewritable media in %1 - %2. " + "Should it be erased?").arg(d->device->vendor()).arg(d->device->description()), + i18n("Found Rewritable Disk"), + KGuiItem(i18n("&Erase"), "cdrwblank"), + KGuiItem(i18n("E&ject")) ) == KMessageBox::Yes ) { + + + prepareErasingDialog(); + + // start a k3bblankingjob + d->erasingInfoDialog->setText( i18n("Erasing CD-RW") ); + + // the user may be using cdrdao for erasing as cdrecord does not work + int erasingApp = K3b::DEFAULT; + if( KConfigGroup( c, "General Options" ).readBoolEntry( "Manual writing app selection", false ) ) { + erasingApp = K3b::writingAppFromString( KConfigGroup( c, "CDRW Erasing" ).readEntry( "writing_app" ) ); + } + + K3bBlankingJob job( this ); + job.setDevice( d->device ); + job.setMode( K3bBlankingJob::Fast ); + job.setForce(true); + job.setForceNoEject(true); + job.setSpeed( 0 ); // Auto + job.setWritingApp( erasingApp ); + connect( &job, SIGNAL(finished(bool)), this, SLOT(slotErasingFinished(bool)) ); + connect( d->erasingInfoDialog, SIGNAL(cancelClicked()), &job, SLOT(cancel()) ); + job.start(); + d->erasingInfoDialog->exec( false ); + } + else { + kdDebug() << "(K3bEmptyDiscWaiter) starting devicehandler: no CD-RW overwrite." << endl; + K3b::unmount( d->device ); + K3bDevice::eject( d->device ); + continueWaiting(); + } + } + else { + kdDebug() << "(K3bEmptyDiscWaiter) ------ nothing useful found." << endl; + continueWaiting(); + } + + // handle queued medium changes + d->blockMediaChange = false; + if( d->mediumChanged > 0 ) { + d->mediumChanged--; + slotMediumChanged( dev ); + } +} + + +void K3bEmptyDiscWaiter::showDialog() +{ + // we need to show the dialog if not done already + if( !d->dialogVisible ) { + + KNotifyClient::event( 0, "WaitingForMedium", i18n("Waiting for Medium") ); + + d->dialogVisible = true; + clearWFlags( WDestructiveClose ); + setWFlags( WShowModal ); + setResult( 0 ); + show(); + } +} + + +void K3bEmptyDiscWaiter::continueWaiting() +{ + showDialog(); +} + + +void K3bEmptyDiscWaiter::slotCancel() +{ + kdDebug() << "(K3bEmptyDiscWaiter) slotCancel() " << endl; + d->canceled = true; + finishWaiting( CANCELED ); +} + + +void K3bEmptyDiscWaiter::slotUser1() +{ + d->forced = true; + finishWaiting( DISK_READY ); +} + + +void K3bEmptyDiscWaiter::slotUser2() +{ + K3b::unmount( d->device ); + K3bDevice::eject( d->device ); +} + + +void K3bEmptyDiscWaiter::slotUser3() +{ + K3bDevice::load( d->device ); +} + + +void K3bEmptyDiscWaiter::finishWaiting( int code ) +{ + kdDebug() << "(K3bEmptyDiscWaiter) finishWaiting() " << endl; + + d->waitingDone = true; + d->result = code; + + if( d->dialogVisible ) + hide(); + + if( d->inLoop ) { + d->inLoop = false; + kdDebug() << "(K3bEmptyDiscWaiter) exitLoop " << endl; + QApplication::eventLoop()->exitLoop(); + } +} + + +void K3bEmptyDiscWaiter::slotErasingFinished( bool success ) +{ + if( success ) { + connect( K3bDevice::reload( d->device ), + SIGNAL(finished(K3bDevice::DeviceHandler*)), + this, + SLOT(slotReloadingAfterErasingFinished(K3bDevice::DeviceHandler*)) ); + } + else { + K3bDevice::eject( d->device ); + KMessageBox::error( d->erasingInfoDialog, i18n("Erasing failed.") ); + d->erasingInfoDialog->hide(); // close the dialog thus ending it's event loop -> back to slotMediumChanged + } +} + + +void K3bEmptyDiscWaiter::slotReloadingAfterErasingFinished( K3bDevice::DeviceHandler* ) +{ + // close the dialog thus ending it's event loop -> back to slotMediumChanged + d->erasingInfoDialog->hide(); +} + + +int K3bEmptyDiscWaiter::wait( K3bDevice::Device* device, bool appendable, int mediaType, QWidget* parent ) +{ + K3bEmptyDiscWaiter d( device, parent ? parent : qApp->activeWindow() ); + int mediaState = K3bDevice::STATE_EMPTY; + if( appendable ) mediaState |= K3bDevice::STATE_INCOMPLETE; + return d.waitForDisc( mediaState, mediaType ); +} + + +int K3bEmptyDiscWaiter::wait( K3bDevice::Device* device, + int mediaState, + int mediaType, + const QString& message, + QWidget* parent ) +{ + K3bEmptyDiscWaiter d( device, parent ? parent : qApp->activeWindow() ); + return d.waitForDisc( mediaState, mediaType, message ); +} + + +void K3bEmptyDiscWaiter::prepareErasingDialog() +{ + // we hide the emptydiskwaiter so the info dialog needs to have the same parent + if( !d->erasingInfoDialog ) + d->erasingInfoDialog = new K3bProgressDialog( QString::null, parentWidget() ); + + // + // hide the dialog + // + if( d->dialogVisible ) { + hide(); + d->dialogVisible = false; + } +} + + +QWidget* K3bEmptyDiscWaiter::parentWidgetToUse() +{ + // we might also show dialogs if the discwaiter widget is not visible yet + if( d->dialogVisible ) + return this; + else + return parentWidget(); +} + + +int K3bEmptyDiscWaiter::waitForMedia( K3bDevice::Device* device, + int mediaState, + int mediaType, + const QString& message ) +{ + // this is only needed for the formatting + return wait( device, mediaState, mediaType, message, d->erasingInfoDialog ); +} + + +bool K3bEmptyDiscWaiter::questionYesNo( const QString& text, + const QString& caption, + const QString& yesText, + const QString& noText ) +{ + return ( KMessageBox::questionYesNo( parentWidgetToUse(), + text, + caption, + yesText.isEmpty() ? KStdGuiItem::yes() : KGuiItem(yesText), + noText.isEmpty() ? KStdGuiItem::no() : KGuiItem(noText) ) == KMessageBox::Yes ); +} + + +void K3bEmptyDiscWaiter::blockingInformation( const QString& text, + const QString& caption ) +{ + KMessageBox::information( this, text, caption ); +} + +#include "k3bemptydiscwaiter.moc" diff --git a/src/k3bemptydiscwaiter.h b/src/k3bemptydiscwaiter.h new file mode 100644 index 0000000..ce3bced --- /dev/null +++ b/src/k3bemptydiscwaiter.h @@ -0,0 +1,139 @@ +/* + * + * $Id: k3bemptydiscwaiter.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BEMPTYDISCWAITER_H +#define K3BEMPTYDISCWAITER_H + +#include <kdialogbase.h> +#include <k3bjobhandler.h> + +#include <k3bdiskinfo.h> + +namespace K3bDevice { + class Device; + class DeviceHandler; +} + + +/** + * Tests for an empty cd in a given device. + * + * Use the static wait methods. + * + * @author Sebastian Trueg + */ +class K3bEmptyDiscWaiter : public KDialogBase, public K3bJobHandler +{ + Q_OBJECT + + public: + ~K3bEmptyDiscWaiter(); + + /** + * This should be replaced by the mediaType that was found or -1 for forced. + * MEDIA_NONE if canceled. + */ + enum returnValue { DISK_READY = 0, + CANCELED = -1 }; + + /** + * the same as waitForEmptyDisc( false ); + */ + int exec(); + + /** + * @reimplemented from K3bJobHandler + * \internal do not use! + */ + int waitForMedia( K3bDevice::Device*, + int mediaState = K3bDevice::STATE_EMPTY, + int mediaType = K3bDevice::MEDIA_WRITABLE_CD, + const QString& message = QString::null ); + + /** + * @reimplemented from K3bJobHandler + */ + bool questionYesNo( const QString& text, + const QString& caption = QString::null, + const QString& yesText = QString::null, + const QString& noText = QString::null ); + + /** + * reimplemented from K3bJobHandler + */ + void blockingInformation( const QString& text, + const QString& caption = QString::null ); + + /** + * This only openes a dialog if the first check failed. + */ + static int wait( K3bDevice::Device* device, + bool appendable = false, + int mediaType = K3bDevice::MEDIA_WRITABLE_CD, + QWidget* parent = 0 ); + + /** + * Starts the emptydiskwaiter. + * + * \param mediaState a bitwise combination of the K3bDevice::State enum + * \param mediaType a bitwise combination of the K3bDevice::MediaType enum + * \return the found MediaType on success, 0 if forced and -1 if canceled + */ + static int wait( K3bDevice::Device*, + int mediaState, + int mediaType = K3bDevice::MEDIA_WRITABLE_CD, + const QString& message = QString::null, + QWidget* parent = 0 ); + + protected slots: + void slotCancel(); + void slotUser1(); + void slotUser2(); + void slotUser3(); + void slotMediumChanged( K3bDevice::Device* ); + void showDialog(); + void continueWaiting(); + void slotErasingFinished( bool ); + void slotReloadingAfterErasingFinished( K3bDevice::DeviceHandler* ); + + protected: + /** + * Use the static wait methods. + */ + explicit K3bEmptyDiscWaiter( K3bDevice::Device* device, QWidget* parent = 0, const char* name = 0 ); + + int waitForDisc( int mediaState = K3bDevice::STATE_EMPTY, + int mediaType = K3bDevice::MEDIA_WRITABLE_CD, + const QString& message = QString::null ); + + + /** + * Nobody closes this dialog but itself! + */ + void closeEvent( QCloseEvent* ) {} + + private: + void finishWaiting( int ); + void prepareErasingDialog(); + + QWidget* parentWidgetToUse(); + + class Private; + Private* d; +}; + + +#endif diff --git a/src/k3bfiletreecombobox.cpp b/src/k3bfiletreecombobox.cpp new file mode 100644 index 0000000..ce9b6b7 --- /dev/null +++ b/src/k3bfiletreecombobox.cpp @@ -0,0 +1,393 @@ +/* + * + * $Id: k3bfiletreecombobox.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bfiletreecombobox.h" +#include "k3bfiletreeview.h" + +#include <k3bdevicemanager.h> +#include <k3bdevice.h> +#include <k3bcore.h> +#include <k3bglobals.h> + +#include <qrect.h> +#include <qapplication.h> +#include <qstyle.h> +#include <qlistbox.h> +#include <qheader.h> +#include <qevent.h> +#include <qpainter.h> +#include <qpalette.h> +#include <qdrawutil.h> +#include <qdir.h> + +#include <kdebug.h> +#include <kiconloader.h> +#include <kurlcompletion.h> +#include <kuser.h> + + +class K3bFileTreeComboBox::Private +{ +public: + Private() { + poppedUp = false; + ignoreNextMouseClick = false; + } + bool poppedUp; + bool ignoreNextMouseClick; // used when the view was hidden with the arrow button + + KURLCompletion* urlCompletion; +}; + + +K3bFileTreeComboBox::K3bFileTreeComboBox( QWidget* parent, const char* name ) + : KComboBox( true, parent, name ) +{ + d = new Private; + + d->urlCompletion = new KURLCompletion(); + setCompletionObject( d->urlCompletion ); + + m_fileTreeView = new K3bFileTreeView( this ); + m_fileTreeView->hide(); + m_fileTreeView->reparent( this, WType_Popup, QPoint(0,0), false ); + m_fileTreeView->header()->hide(); + m_fileTreeView->installEventFilter(this); + + m_fileTreeView->addDefaultBranches(); + m_fileTreeView->addCdDeviceBranches( k3bcore->deviceManager() ); + + // HACK! Why the hell is QComboBox that closed??? + listBox()->insertItem( "HACK" ); + + connect( m_fileTreeView, SIGNAL(deviceExecuted(K3bDevice::Device*)), + this, SLOT(slotDeviceExecuted(K3bDevice::Device*)) ); + connect( m_fileTreeView, SIGNAL(urlExecuted(const KURL&)), + this, SLOT(slotUrlExecuted(const KURL&)) ); + + connect( lineEdit(), SIGNAL(returnPressed()), + this, SLOT(slotGoUrl()) ); + + // TODO: subclass KURLCompletition to support the dev:/ stuff and block any non-local urls +} + + +K3bFileTreeComboBox::~K3bFileTreeComboBox() +{ + delete d->urlCompletion; + delete d; +} + + +void K3bFileTreeComboBox::slotDeviceExecuted( K3bDevice::Device* dev ) +{ + setDevice( dev ); + popdown(); + emit deviceExecuted( dev ); +} + + +void K3bFileTreeComboBox::slotUrlExecuted( const KURL& url ) +{ + setUrl( url ); + emit urlExecuted( url ); +} + + +void K3bFileTreeComboBox::setUrl( const KURL& url ) +{ + setEditText( SmallIcon("folder"), K3b::convertToLocalUrl(url).path() ); + popdown(); +} + + +void K3bFileTreeComboBox::setDevice( K3bDevice::Device* dev ) +{ + setEditText( SmallIcon("cdrom_unmount"), dev->vendor() + " " + dev->description() + " (" + dev->blockDeviceName() + ")" ); +} + + +void K3bFileTreeComboBox::setEditText( const QPixmap& pix, const QString& t ) +{ + // QComboBox::changeItem() doesn't honor the pixmap when + // using an editable combobox, so we just remove and insert + + setUpdatesEnabled( false ); + lineEdit()->setUpdatesEnabled( false ); + + removeItem(0); + insertItem( pix, t, 0 ); + lineEdit()->setText( t ); + + setUpdatesEnabled( true ); + lineEdit()->setUpdatesEnabled( true ); + update(); +} + + +void K3bFileTreeComboBox::setCurrentItem( int ) +{ + // the current item is always 0 due to the ugly but quite smart HACK ;) +} + + +void K3bFileTreeComboBox::setCurrentText( const QString& ) +{ +} + + +void K3bFileTreeComboBox::popup() +{ + // code mainly from qcombobox.cpp + + m_fileTreeView->triggerUpdate(); + int w = QMAX( m_fileTreeView->sizeHint().width(), width() ); + int h = m_fileTreeView->sizeHint().height(); + QRect screen = QApplication::desktop()->availableGeometry( this ); + int sx = screen.x(); // screen pos + int sy = screen.y(); + int sw = screen.width(); // screen width + int sh = screen.height(); // screen height + QPoint pos = mapToGlobal( QPoint(0,height()) ); + // ## Similar code is in QPopupMenu + int x = pos.x(); + int y = pos.y(); + + // the complete widget must be visible + if ( x + w > sx + sw ) + x = sx+sw - w; + if ( x < sx ) + x = sx; + if (y + h > sy+sh && y - h - height() >= 0 ) + y = y - h - height(); + + QRect rect = + style().querySubControlMetrics( QStyle::CC_ComboBox, this, + QStyle::SC_ComboBoxListBoxPopup, + QStyleOption( x, y, w, h ) ); + // work around older styles that don't implement the combobox + // listbox popup subcontrol + if ( rect.isNull() ) + rect.setRect( x, y, w, h ); + + m_fileTreeView->setGeometry( rect ); + m_fileTreeView->raise(); + + // TODO: somehow set the current item + + m_fileTreeView->show(); + d->poppedUp = true; + d->ignoreNextMouseClick = false; +} + + +void K3bFileTreeComboBox::popdown() +{ + m_fileTreeView->hide(); + d->poppedUp = false; + repaint(); // repaint the arrow +} + + +void K3bFileTreeComboBox::slotGoUrl() +{ + QString p = currentText(); + + // check for a media url or a device string + if( K3bDevice::Device* dev = K3b::urlToDevice( p ) ) { + emit deviceExecuted( dev ); + return; + } + + // check for our own internal format + else if( p.contains("/dev/") ) { + int pos1 = p.findRev('('); + int pos2 = p.findRev(')'); + QString devStr = p.mid( pos1+1, pos2-pos1-1 ); + if( K3bDevice::Device* dev = k3bcore->deviceManager()->findDevice( devStr ) ) { + emit deviceExecuted( dev ); + return; + } + } + + // no device -> select url + + // + // Properly replace home dirs. + // a single ~ will be replaced with the current user's home dir + // while for example "~ftp" will be replaced by the home dir of user + // ftp + // + // TODO: move this to k3bglobals + + // to expand another user's home dir we need a tilde followed by a user name + static QRegExp someUsersHomeDir( "\\~([^/]+)" ); + int pos = 0; + while( ( pos = someUsersHomeDir.search( p, pos ) ) != -1 ) { + KUser user( someUsersHomeDir.cap(1) ); + if( user.isValid() ) + p.replace( pos, someUsersHomeDir.cap(1).length() + 1, user.homeDir() ); + else + ++pos; // skip this ~ + } + + // now replace the unmatched tildes with our home dir + p.replace( "~", K3b::prepareDir( QDir::homeDirPath() ) ); + + + lineEdit()->setText( p ); + KURL url; + url.setPath( p ); + emit urlExecuted( url ); +} + + +bool K3bFileTreeComboBox::eventFilter( QObject* o, QEvent* e ) +{ + if( dynamic_cast<K3bFileTreeView*>(o) == m_fileTreeView ) { + if( e->type() == QEvent::DragLeave ) { + // the user dragged a dir from the filetree + // now + popdown(); + return true; + } + else if( e->type() == QEvent::KeyPress ) { + QKeyEvent *k = (QKeyEvent *)e; + if( k->key() == Qt::Key_Escape ) { + popdown(); + return true; + } + } + else if( e->type() == QEvent::MouseButtonPress ) { + QMouseEvent* me = (QMouseEvent*)e; + if ( !m_fileTreeView->rect().contains( me->pos() ) ) { + QRect arrowRect = style().querySubControlMetrics( QStyle::CC_ComboBox, this, + QStyle::SC_ComboBoxArrow); + arrowRect = QStyle::visualRect(arrowRect, this); + + // Correction for motif style, where arrow is smaller + // and thus has a rect that doesn't fit the button. + arrowRect.setHeight( QMAX( height() - (2 * arrowRect.y()), arrowRect.height() ) ); + + if ( arrowRect.contains( mapFromGlobal(me->globalPos()) ) ) { + d->ignoreNextMouseClick = true; // in the case we hit the arrow button + } + popdown(); + } + return false; // we need this in the listview + } + + return false; + } + else + return KComboBox::eventFilter(o, e); +} + + +void K3bFileTreeComboBox::mousePressEvent( QMouseEvent* e ) +{ + // mainly from qcombobox.cpp + + if ( e->button() != LeftButton ) + return; + if ( d->ignoreNextMouseClick ) { + d->ignoreNextMouseClick = FALSE; + return; + } + + QRect arrowRect = style().querySubControlMetrics( QStyle::CC_ComboBox, this, + QStyle::SC_ComboBoxArrow); + arrowRect = QStyle::visualRect(arrowRect, this); + + // Correction for motif style, where arrow is smaller + // and thus has a rect that doesn't fit the button. + arrowRect.setHeight( QMAX( height() - (2 * arrowRect.y()), arrowRect.height() ) ); + + if ( arrowRect.contains( e->pos() ) ) { + popup(); + repaint( FALSE ); + } +} + + +void K3bFileTreeComboBox::keyPressEvent( QKeyEvent* e ) +{ + if( e->key() == Qt::Key_Escape ) { + popdown(); + } + KComboBox::keyPressEvent(e); +} + + +void K3bFileTreeComboBox::paintEvent( QPaintEvent* ) +{ + // a lot of code from qcombobox.cpp + + // we only need this since there is no way to change the status of the arrow-button + + QPainter p( this ); + const QColorGroup & g = colorGroup(); + p.setPen(g.text()); + + QStyle::SFlags flags = QStyle::Style_Default; + if (isEnabled()) + flags |= QStyle::Style_Enabled; + if (hasFocus()) + flags |= QStyle::Style_HasFocus; + + if ( width() < 5 || height() < 5 ) { + qDrawShadePanel( &p, rect(), g, FALSE, 2, + &g.brush( QColorGroup::Button ) ); + return; + } + + // bool reverse = QApplication::reverseLayout(); + + style().drawComplexControl( QStyle::CC_ComboBox, &p, this, rect(), g, + flags, QStyle::SC_All, + (d->poppedUp ? + QStyle::SC_ComboBoxArrow : + QStyle::SC_None )); + + QRect re = style().querySubControlMetrics( QStyle::CC_ComboBox, this, + QStyle::SC_ComboBoxEditField ); + re = QStyle::visualRect(re, this); + p.setClipRect( re ); + +// QListBoxItem * item = listBox()->item( 0 ); +// if ( item ) { +// // we calculate the QListBoxTexts height (ignoring strut) +// int itemh = d->listBox()->fontMetrics().lineSpacing() + 2; +// p.translate( re.x(), re.y() + (re.height() - itemh)/2 ); +// item->paint( &p ); +// } +// } else if ( d->listBox() && d->listBox()->item( 0 ) ) { + p.setClipping( FALSE ); + QListBoxItem * item = listBox()->item( 0 ); + const QPixmap *pix = item->pixmap(); + if ( pix ) { + p.fillRect( re.x(), re.y(), pix->width() + 4, re.height(), + colorGroup().brush( QColorGroup::Base ) ); + p.drawPixmap( re.x() + 2, re.y() + + ( re.height() - pix->height() ) / 2, *pix ); + } +// } + p.setClipping( FALSE ); +} + + +#include "k3bfiletreecombobox.moc" + diff --git a/src/k3bfiletreecombobox.h b/src/k3bfiletreecombobox.h new file mode 100644 index 0000000..50bc683 --- /dev/null +++ b/src/k3bfiletreecombobox.h @@ -0,0 +1,72 @@ +/* + * + * $Id: k3bfiletreecombobox.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_FILETREE_COMBOBOX_H_ +#define _K3B_FILETREE_COMBOBOX_H_ + +#include <kcombobox.h> + +class K3bFileTreeView; +class QEvent; +class QKeyEvent; +class QMouseEvent; +class QPaintEvent; + +namespace K3bDevice { + class Device; +} + +class K3bFileTreeComboBox : public KComboBox +{ + Q_OBJECT + + public: + K3bFileTreeComboBox( QWidget* parent = 0, const char* name = 0 ); + ~K3bFileTreeComboBox(); + + void popup(); + void popdown(); + + void setCurrentItem( int ); + void setCurrentText( const QString& ); + + public slots: + void setDevice( K3bDevice::Device* ); + void setUrl( const KURL& url ); + void slotGoUrl(); + + signals: + void urlExecuted( const KURL& url ); + void deviceExecuted( K3bDevice::Device* dev ); + + private slots: + void slotDeviceExecuted( K3bDevice::Device* ); + void slotUrlExecuted( const KURL& url ); + + protected: + bool eventFilter( QObject*, QEvent* ); + void keyPressEvent( QKeyEvent* ); + void mousePressEvent( QMouseEvent* ); + void paintEvent( QPaintEvent* ); + + private: + void setEditText( const QPixmap& pix, const QString& t ); + + class Private; + Private* d; + K3bFileTreeView* m_fileTreeView; +}; + +#endif diff --git a/src/k3bfiletreeview.cpp b/src/k3bfiletreeview.cpp new file mode 100644 index 0000000..36c86c3 --- /dev/null +++ b/src/k3bfiletreeview.cpp @@ -0,0 +1,728 @@ +/* + * + * $Id: k3bfiletreeview.cpp 657858 2007-04-25 08:25:11Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bfiletreeview.h" +#include "k3bappdevicemanager.h" +#include "k3bapplication.h" +#include "k3bmediacache.h" +#include "k3btooltip.h" +#include "k3bthememanager.h" + +#include <k3bdevice.h> +#include <k3bdiskinfo.h> +#include <k3bglobals.h> + +#include <kiconloader.h> +#include <klocale.h> +#include <kurl.h> +#include <kstandarddirs.h> +#include <kaction.h> +#include <kio/global.h> +#include <kfileitem.h> +#include <kapplication.h> +#include <kglobalsettings.h> + +#include <qdir.h> +#include <qevent.h> +#include <qdragobject.h> +#include <qcursor.h> +#include <qnamespace.h> +#include <qmap.h> +#include <qptrdict.h> +#include <qpainter.h> +#include <qfont.h> +#include <qstyle.h> +#include <qlabel.h> +#include <qlayout.h> + + +K3bDeviceBranch::K3bDeviceBranch( KFileTreeView* view, K3bDevice::Device* dev, KFileTreeViewItem* item ) + : KFileTreeBranch( view, + KURL( "media:/" + dev->blockDeviceName() ), + QString("%1 - %2").arg(dev->vendor()).arg(dev->description()), + ( dev->burner() + ? SmallIcon("cdwriter_unmount") + : SmallIcon("cdrom_unmount") ), + false, + item == 0 + ? new K3bDeviceBranchViewItem( view, dev, this ) + : item ), + m_device( dev ), + m_showBlockDeviceName( false ) +{ + setAutoUpdate(true); + root()->setExpandable(false); + updateLabel(); + + connect( k3bappcore->mediaCache(), SIGNAL(mediumChanged(K3bDevice::Device*)), + this, SLOT(slotMediumChanged(K3bDevice::Device*)) ); +} + + +bool K3bDeviceBranch::populate( const KURL& url, KFileTreeViewItem *currItem ) +{ + // FIXME: we somehow need to "unpopulate" once the medium is unmounted + + // make sure we do not try to populate in case we are not mounted + if( K3b::isMounted( m_device ) ) { + bool b = KFileTreeBranch::populate( url, currItem ); + populateFinished( currItem ); + return b; + } + else + populateFinished( currItem ); + + return true; +} + + +void K3bDeviceBranch::setCurrent( bool c ) +{ + static_cast<K3bDeviceBranchViewItem*>( root() )->setCurrent( c ); +} + + +void K3bDeviceBranch::updateLabel() +{ + if( m_showBlockDeviceName ) + setName( QString("%1 %2 (%3)") + .arg(m_device->vendor()) + .arg(m_device->description()) + .arg(m_device->blockDeviceName()) ); + else + setName( QString("%1 %2") + .arg(m_device->vendor()) + .arg(m_device->description()) ); + + if( k3bappcore->mediaCache() ) { + root()->setMultiLinesEnabled( true ); + root()->setText( 0, name() + "\n" + k3bappcore->mediaCache()->mediumString( m_device ) ); + static_cast<K3bFileTreeView*>( root()->listView() )->updateMinimumWidth(); + } + else { + root()->setMultiLinesEnabled( false ); + root()->setText( 0, name() ); + } +} + + +void K3bDeviceBranch::slotMediumChanged( K3bDevice::Device* dev ) +{ + if( dev == m_device ) + updateLabel(); +} + + +void K3bDeviceBranch::showBlockDeviceName( bool b ) +{ + m_showBlockDeviceName = b; + updateLabel(); +} + + +K3bFileTreeBranch::K3bFileTreeBranch( KFileTreeView* view, + const KURL& url, + const QString& name, + const QPixmap& pix, + bool showHidden, + KFileTreeViewItem* item ) + : KFileTreeBranch( view, url, name, pix, showHidden, + item == 0 + ? new K3bFileTreeViewItem( view, + new KFileItem( url, "inode/directory", + S_IFDIR ), + this ) + : item ) +{ +} + + + +K3bDeviceBranchViewItem::K3bDeviceBranchViewItem( KFileTreeViewItem* parent, + K3bDevice::Device* dev, + K3bDeviceBranch* branch ) + : KFileTreeViewItem( parent, + new KFileItem( KURL( "media:/" + dev->blockDeviceName() ), + "inode/directory", + S_IFDIR ), + branch ), + m_bCurrent( false ), + m_device( dev ) +{ +} + + +K3bDeviceBranchViewItem::K3bDeviceBranchViewItem( KFileTreeView* parent, + K3bDevice::Device* dev, + K3bDeviceBranch* branch ) + : KFileTreeViewItem( parent, + new KFileItem( KURL( "media:/" + dev->blockDeviceName() ), + "inode/directory", + S_IFDIR ), + branch ), + m_bCurrent( false ), + m_device( dev ) +{ +} + + +void K3bDeviceBranchViewItem::setCurrent( bool c ) +{ + m_bCurrent = c; + repaint(); +} + + +void K3bDeviceBranchViewItem::paintCell( QPainter* p, const QColorGroup& cg, int /* col */, int width, int align ) +{ + p->save(); + + int xpos = 1; + int ypos = 1; + QFontMetrics fm( p->fontMetrics() ); + + if( isSelected() ) { + p->fillRect( 0, 0, width, height(), + cg.brush( QColorGroup::Highlight ) ); + p->setPen( cg.highlightedText() ); + } + else { + p->fillRect( 0, 0, width, height(), cg.base() ); + p->setPen( cg.text() ); + } + + if( pixmap(0) ) { + p->drawPixmap( xpos, ypos, *pixmap(0) ); + xpos += pixmap(0)->width() + 5; + } + + if( m_bCurrent ) { + QFont f( listView()->font() ); + f.setBold( true ); + p->setFont( f ); + } + + ypos += fm.ascent(); + QString line1 = text(0).left( text(0).find('\n') ); + p->drawText( xpos, ypos, line1 ); + + QFont f( listView()->font() ); + f.setItalic( true ); + f.setBold( false ); + f.setPointSize( f.pointSize() - 2 ); + p->setFont( f ); + + ypos += p->fontMetrics().height() + 1; + QString line2 = text(0).mid( text(0).find('\n')+1 ); + p->drawText( xpos - p->fontMetrics().leftBearing( line2[0] ), ypos, line2 ); + + + // from QListViewItem + if( isOpen() && childCount() ) { + int textheight = fm.size( align, text(0) ).height() + 2 * listView()->itemMargin(); + textheight = QMAX( textheight, QApplication::globalStrut().height() ); + if ( textheight % 2 > 0 ) + textheight++; + if ( textheight < height() ) { + int w = listView()->treeStepSize() / 2; + listView()->style().drawComplexControl( QStyle::CC_ListView, p, listView(), + QRect( 0, textheight, w + 1, height() - textheight + 1 ), cg, + QStyle::Style_Enabled, + QStyle::SC_ListViewExpand, + (uint)QStyle::SC_All, QStyleOption( this ) ); + } + } + + p->restore(); +} + + +int K3bDeviceBranchViewItem::widthHint() const +{ + QFont f( listView()->font() ); + if ( m_bCurrent ) { + f.setBold( true ); + } + int w = QFontMetrics(f).width( text(0).left( text(0).find('\n') ) ); + + f.setItalic( true ); + f.setBold( false ); + f.setPointSize( f.pointSize() - 2 ); + w = QMAX( w, QFontMetrics(f).width( text(0).mid( text(0).find('\n')+1 ) ) ); + + w++; // see paintCell + + if( pixmap(0) ) + w += pixmap(0)->width() + 5; + + return w; +} + + +QString K3bDeviceBranchViewItem::key( int column, bool ascending ) const +{ + return "0" + KFileTreeViewItem::key( column, ascending ); +} + + + +K3bFileTreeViewItem::K3bFileTreeViewItem( KFileTreeViewItem* parent, KFileItem* item, KFileTreeBranch* branch ) + : KFileTreeViewItem( parent, item, branch ) +{ +} + + +K3bFileTreeViewItem::K3bFileTreeViewItem( KFileTreeView* parent, KFileItem* item, KFileTreeBranch* branch ) + : KFileTreeViewItem( parent, item, branch ) +{ +} + + +QString K3bFileTreeViewItem::key( int column, bool ascending ) const +{ + return "1" + KFileTreeViewItem::key( column, ascending ); +} + + +class K3bDeviceTreeToolTip : public K3bToolTip +{ +public: + K3bDeviceTreeToolTip( QWidget* parent, K3bFileTreeView* lv ); + + void maybeTip( const QPoint &pos ); + +private: + K3bFileTreeView* m_view; +}; + + +K3bDeviceTreeToolTip::K3bDeviceTreeToolTip( QWidget* parent, K3bFileTreeView* lv ) + : K3bToolTip( parent ), + m_view( lv ) +{ + setTipTimeout( 500 ); +} + + +void K3bDeviceTreeToolTip::maybeTip( const QPoint& pos ) +{ + if( !parentWidget() || !m_view ) + return; + + K3bDeviceBranchViewItem* item = dynamic_cast<K3bDeviceBranchViewItem*>( m_view->itemAt( pos ) ); + if( !item ) + return; + + K3bDevice::Device* dev = static_cast<K3bDeviceBranch*>( item->branch() )->device(); + + QFrame* tooltip = new QFrame( parentWidget() ); + tooltip->setFrameStyle( QFrame::Panel | QFrame::Raised ); + tooltip->setFrameShape( QFrame::StyledPanel ); + QGridLayout* lay = new QGridLayout( tooltip, 2, 2, tooltip->frameWidth()*2 /*margin*/, 6 /*spacing*/ ); + + QString text = k3bappcore->mediaCache()->medium( dev ).longString(); + int detailsStart = text.find( "<p>", 3 ); + QString details = text.mid( detailsStart ); + text.truncate( detailsStart ); + + QLabel* label = new QLabel( text, tooltip ); + label->setMargin( 9 ); + lay->addMultiCellWidget( label, 0, 0, 0, 1 ); + label = new QLabel( details, tooltip ); + label->setMargin( 9 ); + label->setAlignment( Qt::Vertical ); + lay->addMultiCellWidget( label, 1, 2, 0, 0 ); + label = new QLabel( tooltip ); + lay->addWidget( label, 2, 1 ); + lay->setColStretch( 0, 1 ); + + if( K3bTheme* theme = k3bappcore->themeManager()->currentTheme() ) { + tooltip->setPaletteBackgroundColor( theme->backgroundColor() ); + tooltip->setPaletteForegroundColor( theme->foregroundColor() ); + K3bTheme::PixmapType pm; + int c = k3bappcore->mediaCache()->medium( dev ).content(); + if( c & (K3bMedium::CONTENT_VIDEO_CD|K3bMedium::CONTENT_VIDEO_DVD) ) + pm = K3bTheme::MEDIA_VIDEO; + else if( c & K3bMedium::CONTENT_AUDIO && + c & K3bMedium::CONTENT_DATA ) + pm = K3bTheme::MEDIA_MIXED; + else if( c & K3bMedium::CONTENT_AUDIO ) + pm = K3bTheme::MEDIA_AUDIO; + else if( c & K3bMedium::CONTENT_DATA ) + pm = K3bTheme::MEDIA_DATA; + else { + K3bDevice::DiskInfo di = k3bappcore->mediaCache()->diskInfo( dev ); + if( di.diskState() == K3bDevice::STATE_EMPTY ) + pm = K3bTheme::MEDIA_EMPTY; + else + pm = K3bTheme::MEDIA_NONE; + } + label->setPixmap( theme->pixmap( pm ) ); + } + + // the tooltip will take care of deleting the widget + tip( m_view->itemRect( item ), tooltip ); +} + + + +class K3bFileTreeView::Private +{ +public: + Private() + : deviceManager(0), + currentDeviceBranch(0) { + } + + QPtrDict<K3bDeviceBranch> deviceBranchDict; + QMap<KFileTreeBranch*, K3bDevice::Device*> branchDeviceMap; + + K3bDevice::DeviceManager* deviceManager; + K3bDeviceBranch* currentDeviceBranch; + + K3bDeviceTreeToolTip* toolTip; +}; + +K3bFileTreeView::K3bFileTreeView( QWidget *parent, const char *name ) + : KFileTreeView( parent, name ) +{ + d = new Private(); + + d->toolTip = new K3bDeviceTreeToolTip( viewport(), this ); + + addColumn( i18n("Directories") ); + setDragEnabled( true ); + setAlternateBackground( QColor() ); + setFullWidth(true); + // setRootIsDecorated(true); + setSorting(0); + + m_dirOnlyMode = true; + m_menuEnabled = false; + + connect( this, SIGNAL(executed(QListViewItem*)), this, SLOT(slotItemExecuted(QListViewItem*)) ); + connect( this, SIGNAL(returnPressed(QListViewItem*)), this, SLOT(slotItemExecuted(QListViewItem*)) ); + connect( this, SIGNAL(contextMenu(KListView*, QListViewItem* , const QPoint& )), + this, SLOT(slotContextMenu(KListView*, QListViewItem* , const QPoint& )) ); + + // we always simulate the single click + slotSettingsChangedK3b(KApplication::SETTINGS_MOUSE); + if( kapp ) + connect( kapp, SIGNAL(settingsChanged(int)), SLOT(slotSettingsChangedK3b(int)) ); + + initActions(); +} + + +K3bFileTreeView::~K3bFileTreeView() +{ + delete d; +} + + +void K3bFileTreeView::clear() +{ + KFileTreeView::clear(); + if( d->deviceManager ) + d->deviceManager->disconnect( this ); + d->deviceManager = 0; +} + + +void K3bFileTreeView::initActions() +{ +// m_actionCollection = new KActionCollection( this ); + +// m_devicePopupMenu = new KActionMenu( m_actionCollection, "device_popup_menu" ); +// m_urlPopupMenu = new KActionMenu( m_actionCollection, "url_popup_menu" ); + +// KAction* actionDiskInfo = new KAction( i18n("&Disk Info"), "info", 0, this, SLOT(slotShowDiskInfo()), +// m_actionCollection, "disk_info"); +// KAction* actionUnmount = new KAction( i18n("&Unmount"), "cdrom_unmount", 0, this, SLOT(slotUnmountDisk()), +// m_actionCollection, "disk_unmount"); +// KAction* actionEject = new KAction( i18n("&Eject"), "", 0, this, SLOT(slotEjectDisk()), +// m_actionCollection, "disk_eject"); + +// m_devicePopupMenu->insert( actionDiskInfo ); +// m_devicePopupMenu->insert( new KActionSeparator( this ) ); +// m_devicePopupMenu->insert( actionUnmount ); +// m_devicePopupMenu->insert( actionEject ); + +} + + +void K3bFileTreeView::addDefaultBranches() +{ + KURL home = KURL::fromPathOrURL( QDir::homeDirPath() ); + KURL root = KURL( "file:/" ); + + KFileTreeBranch* treeBranch = addBranch( new K3bFileTreeBranch( this, root, i18n("Root"), SmallIcon("folder_red") ) ); + treeBranch = addBranch( new K3bFileTreeBranch( this, home, i18n("Home"), SmallIcon("folder_home") ) ); + treeBranch->setOpen( true ); +} + + +void K3bFileTreeView::addCdDeviceBranches( K3bDevice::DeviceManager* dm ) +{ + kdDebug() << "(K3bFileTreeView::addCdDeviceBranches)" << endl; + + // remove all previous added device branches + for( QMap<KFileTreeBranch*, K3bDevice::Device*>::Iterator it = d->branchDeviceMap.begin(); + it != d->branchDeviceMap.end(); ++it ) { + removeBranch( it.key() ); + } + + // clear the maps + d->branchDeviceMap.clear(); + d->deviceBranchDict.clear(); + + for( QPtrListIterator<K3bDevice::Device> it( dm->allDevices() ); *it; ++it ) + addDeviceBranch( *it ); + + if( dm != d->deviceManager ) { + if( d->deviceManager ) + d->deviceManager->disconnect( this ); + d->deviceManager = dm; + + // make sure we get changes to the config + connect( dm, SIGNAL(changed(K3bDevice::DeviceManager*)), + this, SLOT(addCdDeviceBranches(K3bDevice::DeviceManager*)) ); + + if( K3bAppDeviceManager* appDevM = dynamic_cast<K3bAppDeviceManager*>( dm ) ) + connect( appDevM, SIGNAL(currentDeviceChanged(K3bDevice::Device*)), + this, SLOT(setCurrentDevice(K3bDevice::Device*)) ); + } + + K3bDevice::Device* currentDevice = k3bappcore->appDeviceManager()->currentDevice(); + if ( !currentDevice && !k3bappcore->appDeviceManager()->allDevices().isEmpty() ) { + k3bappcore->appDeviceManager()->setCurrentDevice( k3bappcore->appDeviceManager()->allDevices().getFirst() ); + } + + d->currentDeviceBranch = d->deviceBranchDict[currentDevice]; + if( d->currentDeviceBranch ) { + d->currentDeviceBranch->setCurrent( true ); + } + + kdDebug() << "(K3bFileTreeView::addCdDeviceBranches) done" << endl; +} + + +void K3bFileTreeView::addDeviceBranch( K3bDevice::Device* dev ) +{ + K3bDeviceBranch* newBranch = new K3bDeviceBranch( this, dev ); + addBranch( newBranch ); + + // search for an equal device + int equalCnt = 0; + K3bDeviceBranch* equalBranch = 0; + for( QMap<KFileTreeBranch*, K3bDevice::Device*>::Iterator it = d->branchDeviceMap.begin(); + it != d->branchDeviceMap.end(); ++it ) { + K3bDevice::Device* itDev = it.data(); + K3bDeviceBranch* itBranch = (K3bDeviceBranch*)it.key(); + if( itDev->vendor() == dev->vendor() && + itDev->description() == dev->description() ) { + ++equalCnt; + equalBranch = itBranch; + } + } + + // if there is at least one equal device add the block device name + // if there is more than one equal device they have been updated after + // adding the last one so there is no need to update more than two + if( equalCnt > 0 ) { + kdDebug() << "(K3bFileTreeView) equal branch" << endl; + newBranch->showBlockDeviceName(true); + equalBranch->showBlockDeviceName(true); + } + + // add to maps + d->branchDeviceMap.insert( newBranch, dev ); + d->deviceBranchDict.insert( (void*)dev, newBranch ); + + updateMinimumWidth(); +} + + +KFileTreeBranch* K3bFileTreeView::addBranch( KFileTreeBranch* branch ) +{ + KFileTreeBranch* newBranch = KFileTreeView::addBranch( branch ); + newBranch->setChildRecurse( false ); + setDirOnlyMode( newBranch, m_dirOnlyMode ); + + return newBranch; +} + + +KFileTreeBranch* K3bFileTreeView::addBranch( const KURL& url, const QString& name, const QPixmap& pix, bool showHidden ) +{ + KFileTreeBranch* newBranch = KFileTreeView::addBranch( url, name, pix, showHidden ); + newBranch->setChildRecurse( false ); + setDirOnlyMode( newBranch, m_dirOnlyMode ); + + return newBranch; +} + + +void K3bFileTreeView::slotItemExecuted( QListViewItem* item ) +{ + KFileTreeViewItem* treeItem = static_cast<KFileTreeViewItem*>(item); + if( d->branchDeviceMap.contains( treeItem->branch() ) && + treeItem == treeItem->branch()->root() ) { + K3bDevice::Device* dev = d->branchDeviceMap[treeItem->branch()]; + k3bappcore->appDeviceManager()->setCurrentDevice( dev ); + emit deviceExecuted( dev ); + } + else + emit urlExecuted( treeItem->url() ); +} + + +void K3bFileTreeView::setTreeDirOnlyMode( bool b ) +{ + m_dirOnlyMode = b; +} + + +void K3bFileTreeView::followUrl( const KURL& url ) +{ + // TODO: first try the current branch + KFileTreeBranchIterator it( branches() ); + for( ; *it; ++it ) { + if( !d->branchDeviceMap.contains( *it ) ) + if( KFileTreeViewItem* item = (*it)->findTVIByURL( url ) ) { + setCurrentItem( item ); + setSelected(item, true); + ensureItemVisible( item ); + return; + } + } +} + + +void K3bFileTreeView::slotContextMenu( KListView*, QListViewItem* item, const QPoint& p ) +{ + KFileTreeViewItem* treeItem = dynamic_cast<KFileTreeViewItem*>(item); + if( treeItem ) { + K3bDevice::Device* device = 0; + QMap<KFileTreeBranch*, K3bDevice::Device*>::iterator devIt = + d->branchDeviceMap.find( treeItem->branch() ); + if( devIt != d->branchDeviceMap.end() ) + device = devIt.data(); + + setCurrentItem( treeItem ); + setSelected( treeItem, true); + + if( device ) { + k3bappcore->appDeviceManager()->setCurrentDevice( device ); + emit contextMenu( device, p ); + } + else + emit contextMenu( treeItem->url(), p ); + } + else + kdWarning() << "(K3bFileTreeView) found viewItem that is no KFileTreeViewItem!" << endl; +} + + +K3bDevice::Device* K3bFileTreeView::selectedDevice() const +{ + KFileTreeViewItem* treeItem = dynamic_cast<KFileTreeViewItem*>(selectedItem()); + if( treeItem ) { + if( d->branchDeviceMap.contains( treeItem->branch() ) ) + return d->branchDeviceMap[treeItem->branch()]; + } + return 0; +} + + +KURL K3bFileTreeView::selectedUrl() const +{ + KFileTreeViewItem* treeItem = dynamic_cast<KFileTreeViewItem*>(selectedItem()); + if( treeItem ) { + if( !d->branchDeviceMap.contains( treeItem->branch() ) ) + return treeItem->url(); + } + return KURL(); +} + + +void K3bFileTreeView::setCurrentDevice( K3bDevice::Device* dev ) +{ + if( d->currentDeviceBranch ) + d->currentDeviceBranch->setCurrent( false ); + + if( dev ) { + if ( ( d->currentDeviceBranch = branch( dev ) ) ) + d->currentDeviceBranch->setCurrent( true ); + } + + updateMinimumWidth(); +} + + +void K3bFileTreeView::setSelectedDevice( K3bDevice::Device* dev ) +{ + setCurrentDevice( dev ); + K3bDeviceBranch* b = branch( dev ); + setCurrentItem( b->root() ); + setSelected( b->root(), true ); +} + + +K3bDeviceBranch* K3bFileTreeView::branch( K3bDevice::Device* dev ) +{ + return d->deviceBranchDict.find( (void*)dev ); +} + + +void K3bFileTreeView::slotSettingsChangedK3b(int category) +{ + // we force single click like konqueror does. This really should be done in KFileTreeView + + if( category == KApplication::SETTINGS_MOUSE ) { + disconnect(this, SIGNAL(mouseButtonClicked(int, QListViewItem*, const QPoint &, int)), + this, SLOT(slotMouseButtonClickedK3b(int, QListViewItem*, const QPoint &, int))); + + if( !KGlobalSettings::singleClick() ) + connect(this, SIGNAL(mouseButtonClicked(int, QListViewItem*, const QPoint &, int)), + this, SLOT(slotMouseButtonClickedK3b(int, QListViewItem*, const QPoint &, int))); + } +} + + +void K3bFileTreeView::slotMouseButtonClickedK3b( int btn, QListViewItem *item, const QPoint &pos, int c ) +{ + if( (btn == LeftButton) && item ) + emitExecute(item, pos, c); +} + + +void K3bFileTreeView::updateMinimumWidth() +{ + // + // only handle the device branches, we don't care about the folders. + // + int w = 0; + for( QMap<KFileTreeBranch*, K3bDevice::Device*>::Iterator it = d->branchDeviceMap.begin(); + it != d->branchDeviceMap.end(); ++it ) { + w = QMAX( w, static_cast<K3bDeviceBranchViewItem*>( it.key()->root() )->widthHint() ); + } + + // width of the items + scrollbar width + the frame + a little eyecandy spacing + setMinimumWidth( w + verticalScrollBar()->sizeHint().width() + 2*frameWidth() + 2 ); +} + +#include "k3bfiletreeview.moc" diff --git a/src/k3bfiletreeview.h b/src/k3bfiletreeview.h new file mode 100644 index 0000000..31a25c4 --- /dev/null +++ b/src/k3bfiletreeview.h @@ -0,0 +1,199 @@ +/* + * + * $Id: k3bfiletreeview.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BFILETREEVIEW_H +#define K3BFILETREEVIEW_H + + +#include <kfiletreeview.h> + +class KFileTreeBranch; +class KActionCollection; +class KActionMenu; +class QPoint; +class QDropEvent; +class QDragEnterEvent; + +namespace K3bDevice { + class Device; + class DeviceManager; +} + +namespace KIO { + class Job; +} + + +class K3bDeviceBranch : public KFileTreeBranch +{ + Q_OBJECT + + public: + K3bDeviceBranch( KFileTreeView*, K3bDevice::Device* dev, KFileTreeViewItem* item = 0 ); + + K3bDevice::Device* device() const { return m_device; } + + /** + * Adds or removes the blockdevicename from the branch name + */ + void showBlockDeviceName( bool b ); + + public slots: + void setCurrent( bool ); + + bool populate( const KURL& url, KFileTreeViewItem *currItem ); + + private slots: + void slotMediumChanged( K3bDevice::Device* ); + + private: + void updateLabel(); + + K3bDevice::Device* m_device; + bool m_showBlockDeviceName; +}; + + +class K3bFileTreeBranch : public KFileTreeBranch +{ + public: + K3bFileTreeBranch( KFileTreeView*, + const KURL& url, + const QString& name, + const QPixmap& pix, + bool showHidden = false, + KFileTreeViewItem* item = 0 ); +}; + + +class K3bDeviceBranchViewItem : public KFileTreeViewItem +{ + public: + K3bDeviceBranchViewItem( KFileTreeViewItem*, K3bDevice::Device*, K3bDeviceBranch* ); + K3bDeviceBranchViewItem( KFileTreeView*, K3bDevice::Device*, K3bDeviceBranch* ); + + QString key( int column, bool ascending ) const; + + void setCurrent( bool ); + + void paintCell( QPainter* p, const QColorGroup& cg, int col, int width, int align ); + + int widthHint() const; + + private: + bool m_bCurrent; + + K3bDevice::Device* m_device; +}; + + +class K3bFileTreeViewItem : public KFileTreeViewItem +{ + public: + K3bFileTreeViewItem( KFileTreeViewItem*, KFileItem*, KFileTreeBranch* ); + K3bFileTreeViewItem( KFileTreeView *, KFileItem*, KFileTreeBranch* ); + + QString key( int column, bool ascending ) const; +}; + + +/** + *@author Sebastian Trueg + */ +class K3bFileTreeView : public KFileTreeView +{ + Q_OBJECT + + public: + K3bFileTreeView( QWidget *parent = 0, const char *name = 0 ); + ~K3bFileTreeView(); + + + virtual KFileTreeBranch* addBranch( KFileTreeBranch* ); + virtual KFileTreeBranch* addBranch( const KURL& url, const QString& name, const QPixmap& , bool showHidden = false ); + + K3bDeviceBranch* branch( K3bDevice::Device* dev ); + + /** + * returns 0 if no device is selected + */ + K3bDevice::Device* selectedDevice() const; + + /** + * returnes an empty url if no url is selected + */ + KURL selectedUrl() const; + + public slots: + /** + * adds home and root dir branch + */ + void addDefaultBranches(); + void addCdDeviceBranches( K3bDevice::DeviceManager* ); + void addDeviceBranch( K3bDevice::Device* dev ); + + /** + * Make dev the current device. This does not mean that the device entry + * will be highlighted but marked otherwise since this means that it is the + * current device in the application and not the treeview. + */ + void setCurrentDevice( K3bDevice::Device* dev ); + + /** + * his will highlight the device and also make it the current device. + */ + void setSelectedDevice( K3bDevice::Device* dev ); + + void followUrl( const KURL& url ); + void setTreeDirOnlyMode( bool b ); + void enablePopupMenu( bool b ) { m_menuEnabled = b; } + + /** + * @reimplemented + */ + virtual void clear(); + + void updateMinimumWidth(); + + signals: + void urlExecuted( const KURL& url ); + void deviceExecuted( K3bDevice::Device* dev ); + + /** only gets emitted if the menu is disabled */ + void contextMenu( K3bDevice::Device*, const QPoint& ); + /** only gets emitted if the menu is disabled */ + void contextMenu( const KURL& url, const QPoint& ); + + private slots: + void slotItemExecuted( QListViewItem* item ); + void slotContextMenu( KListView*, QListViewItem*, const QPoint& ); + void slotSettingsChangedK3b(int category); + void slotMouseButtonClickedK3b( int btn, QListViewItem *item, const QPoint &pos, int c ); + + private: + void initActions(); + + class Private; + Private* d; + + bool m_dirOnlyMode; + KActionCollection* m_actionCollection; + KActionMenu* m_devicePopupMenu; + KActionMenu* m_urlPopupMenu; + bool m_menuEnabled; +}; + +#endif diff --git a/src/k3bfileview.cpp b/src/k3bfileview.cpp new file mode 100644 index 0000000..04ce435 --- /dev/null +++ b/src/k3bfileview.cpp @@ -0,0 +1,183 @@ +/* + * + * $Id: k3bfileview.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bfileview.h" +#include "k3b.h" +#include "k3bdiroperator.h" +#include "k3btoolbox.h" +#include "k3bapplication.h" + +#include <qwidget.h> +#include <qdragobject.h> +#include <qlayout.h> +#include <qdir.h> +#include <qvbox.h> +#include <qlabel.h> +#include <qtoolbutton.h> + +#include <kfiledetailview.h> +#include <klistview.h> +#include <kaction.h> +#include <ktoolbar.h> +#include <ktoolbarbutton.h> +#include <kurl.h> +#include <kurldrag.h> +#include <kfilefiltercombo.h> +#include <klocale.h> +#include <kfileitem.h> +#include <kmessagebox.h> +#include <kdirlister.h> +#include <kprogress.h> + + +K3bFileView::K3bFileView(QWidget *parent, const char *name ) + : K3bContentsView( false, parent, name) +{ + setupGUI(); +} + + +K3bFileView::~K3bFileView() +{ +} + + +KActionCollection* K3bFileView::actionCollection() const +{ + return m_dirOp->actionCollection(); +} + + +void K3bFileView::setupGUI() +{ + QVBoxLayout* layout = new QVBoxLayout( this ); + // layout->setAutoAdd( true ); + + m_dirOp = new K3bDirOperator( KURL::fromPathOrURL(QDir::home().absPath()), this ); + m_toolBox = new K3bToolBox( this ); + + layout->addWidget( m_toolBox ); + layout->addWidget( m_dirOp ); + layout->setStretchFactor( m_dirOp, 1 ); + + // setup actions + KAction* actionHome = m_dirOp->actionCollection()->action("home"); + KAction* actionBack = m_dirOp->actionCollection()->action("back"); + KAction* actionUp = m_dirOp->actionCollection()->action("up"); + KAction* actionReload = m_dirOp->actionCollection()->action("reload"); + + m_toolBox->addButton( actionUp ); + m_toolBox->addButton( actionBack ); + m_toolBox->addButton( actionHome ); + m_toolBox->addButton( actionReload ); + m_toolBox->addSpacing(); + m_toolBox->addButton( m_dirOp->actionCollection()->action("short view") ); + m_toolBox->addButton( m_dirOp->actionCollection()->action("detailed view") ); + m_toolBox->addSpacing(); + m_toolBox->addButton( m_dirOp->bookmarkMenu() ); + m_toolBox->addSpacing(); + + // create filter selection combobox + m_toolBox->addSpacing(); + m_toolBox->addLabel( i18n("Filter:") ); + m_toolBox->addSpacing(); + m_filterWidget = new KFileFilterCombo( m_toolBox, "filterwidget" ); + m_toolBox->addWidget( m_filterWidget ); + m_toolBox->addStretch(); + m_toolBox->addWidget( m_dirOp->progressBar() ); + + m_filterWidget->setEditable( true ); + QString filter = i18n("*|All Files"); + filter += "\n" + i18n("audio/x-mp3 audio/x-wav application/x-ogg |Sound Files"); + filter += "\n" + i18n("audio/x-wav |Wave Sound Files"); + filter += "\n" + i18n("audio/x-mp3 |MP3 Sound Files"); + filter += "\n" + i18n("application/x-ogg |Ogg Vorbis Sound Files"); + filter += "\n" + i18n("video/mpeg |MPEG Video Files"); + m_filterWidget->setFilter(filter); + + connect( m_filterWidget, SIGNAL(filterChanged()), SLOT(slotFilterChanged()) ); + + connect( m_dirOp, SIGNAL(fileHighlighted(const KFileItem*)), this, SLOT(slotFileHighlighted(const KFileItem*)) ); + connect( m_dirOp, SIGNAL(urlEntered(const KURL&)), this, SIGNAL(urlEntered(const KURL&)) ); + connect( m_dirOp, SIGNAL(fileSelected(const KFileItem*)), m_dirOp, SLOT(slotAddFilesToProject()) ); + + slotFileHighlighted(0); +} + +void K3bFileView::setDir( const QString& dir ) +{ + KURL url; + url.setPath(dir); + setUrl( url ); +} + + +void K3bFileView::setUrl(const KURL& url, bool forward) +{ + m_dirOp->setURL( url, forward ); +} + +KURL K3bFileView::url() +{ + return m_dirOp->url(); +} + +void K3bFileView::setAutoUpdate( bool b ) +{ + m_dirOp->dirLister()->setAutoUpdate( b ); +} + +void K3bFileView::slotFileHighlighted( const KFileItem* ) +{ +} + + +void K3bFileView::slotFilterChanged() +{ + QString filter = m_filterWidget->currentFilter(); + m_dirOp->clearFilter(); + + if( filter.find( '/' ) > -1 ) { + QStringList types = QStringList::split( " ", filter ); + types.prepend( "inode/directory" ); + m_dirOp->setMimeFilter( types ); + } + else + m_dirOp->setNameFilter( filter ); + + m_dirOp->rereadDir(); + // emit filterChanged( filter ); +} + + +void K3bFileView::reload() +{ + m_dirOp->actionCollection()->action("reload")->activate(); +} + + +void K3bFileView::saveConfig( KConfig* c ) +{ + m_dirOp->writeConfig( c, "file view" ); +} + + +void K3bFileView::readConfig( KConfig* c ) +{ + m_dirOp->readConfig( c, "file view" ); +} + +#include "k3bfileview.moc" diff --git a/src/k3bfileview.h b/src/k3bfileview.h new file mode 100644 index 0000000..f89d3b8 --- /dev/null +++ b/src/k3bfileview.h @@ -0,0 +1,74 @@ +/* + * + * $Id: k3bfileview.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BFILEVIEW_H +#define K3BFILEVIEW_H + + +#include "k3bcontentsview.h" + + +class K3bDirOperator; +class QDragObject; +class KURL; +class KFileFilterCombo; +class KFileItem; +class KActionCollection; +class KConfig; +class K3bToolBox; + + +/** + *@author Sebastian Trueg + */ +class K3bFileView : public K3bContentsView +{ + Q_OBJECT + + public: + K3bFileView(QWidget *parent=0, const char *name=0); + ~K3bFileView(); + + void setUrl( const KURL &url, bool forward = true ); + KURL url(); + + KActionCollection* actionCollection() const; + + void reload(); + + signals: + void urlEntered( const KURL& url ); + + public slots: + void setDir( const QString& ); + void saveConfig( KConfig* c ); + void readConfig( KConfig* c ); + void setAutoUpdate( bool ); + + private: + K3bToolBox* m_toolBox; + K3bDirOperator* m_dirOp; + KFileFilterCombo* m_filterWidget; + + void setupGUI(); + + private slots: + void slotFilterChanged(); + void slotFileHighlighted( const KFileItem* item ); +}; + + +#endif diff --git a/src/k3bfirstrun.cpp b/src/k3bfirstrun.cpp new file mode 100644 index 0000000..23a285a --- /dev/null +++ b/src/k3bfirstrun.cpp @@ -0,0 +1,84 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bfirstrun.h" +#include "k3b.h" +#include "k3bservicemenuinstaller.h" +#include <k3bcore.h> + +#include <klocale.h> +#include <kiconloader.h> +#include <kconfig.h> + +#include <qlayout.h> +#include <qlabel.h> + + +void K3bFirstRun::run( QWidget* parent ) +{ + if( !k3bcore->config()->readBoolEntry( "First run", true ) ) + return; + + k3bcore->config()->writeEntry( "First run", false ); + + // for now the first run dialog only asks for + // the konqui integration. So in case it is + // already installed there is no need to show the + // dialog. + K3bServiceInstaller si; + if( si.allInstalled() ) + return; + + K3bFirstRun dlg( parent ); + if( dlg.exec() == QDialog::Accepted ) + si.install( parent ); +} + + +K3bFirstRun::K3bFirstRun( QWidget* parent ) + : KDialogBase( Plain, + i18n("First Run"), + Ok|Cancel, + Ok, + parent, + 0, + true, + true ) +{ + setButtonOK( i18n("Enable Konqueror integration") ); + setButtonCancel( i18n("No Konqueror integration") ); + + QFrame* plain = plainPage(); + QLabel* label = new QLabel( i18n("<p>K3b can integrate itself into Konqueror. This integration " + "allows to start K3b from the context menu in the file manager." + "<p><em>The Konqueror integration can always be disabled and " + "enabled again from the K3b settings.</em>"), plain ); + QLabel* pixLabel = new QLabel( plain ); + pixLabel->setPixmap( DesktopIcon( "konqueror" ) ); + + QHBoxLayout* lay = new QHBoxLayout( plain ); + lay->setMargin( 0 ); + lay->setSpacing( spacingHint() ); + lay->addWidget( pixLabel ); + lay->addWidget( label ); + lay->setStretchFactor( label, 1 ); +} + + +K3bFirstRun::~K3bFirstRun() +{ +} + +#include "k3bfirstrun.moc" diff --git a/src/k3bfirstrun.h b/src/k3bfirstrun.h new file mode 100644 index 0000000..d59c931 --- /dev/null +++ b/src/k3bfirstrun.h @@ -0,0 +1,34 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_FIRST_RUN_H_ +#define _K3B_FIRST_RUN_H_ + +#include <kdialogbase.h> + + +class K3bFirstRun : public KDialogBase +{ + Q_OBJECT + + public: + static void run( QWidget* parent = 0 ); + + private: + K3bFirstRun( QWidget* parent ); + ~K3bFirstRun(); +}; + +#endif diff --git a/src/k3bflatbutton.cpp b/src/k3bflatbutton.cpp new file mode 100644 index 0000000..808de32 --- /dev/null +++ b/src/k3bflatbutton.cpp @@ -0,0 +1,203 @@ +/* + * + * $Id: k3bflatbutton.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bflatbutton.h" +#include "k3bthememanager.h" +#include "k3bapplication.h" + +#include <kaction.h> +#include <kiconloader.h> +#include <kglobal.h> + +#include <qpainter.h> +#include <qtooltip.h> +#include <qfontmetrics.h> +#include <qpixmap.h> + + +K3bFlatButton::K3bFlatButton( QWidget *parent, const char *name ) + : QFrame( parent, name/*, WNoAutoErase*/ ), + m_pressed(false) +{ + init(); +} + + +K3bFlatButton::K3bFlatButton( const QString& text, QWidget *parent, const char *name ) + : QFrame( parent, name/*, WNoAutoErase*/ ), + m_pressed(false) +{ + init(); + setText( text ); +} + + +K3bFlatButton::K3bFlatButton( KAction* a, QWidget *parent, const char *name ) + : QFrame( parent, name/*, WNoAutoErase*/ ), + m_pressed(false) +{ + init(); + + setText( a->text() ); + QToolTip::add( this, a->toolTip() ); + setPixmap( KGlobal::iconLoader()->loadIcon( a->icon(), KIcon::NoGroup, 32 ) ); + connect( this, SIGNAL(clicked()), a, SLOT(activate()) ); +} + + +K3bFlatButton::~K3bFlatButton() {} + + +void K3bFlatButton::init() +{ + setHover(false); + setMargin(5); + setFrameStyle( QFrame::Box|QFrame::Plain ); + + connect( k3bappcore->themeManager(), SIGNAL(themeChanged()), this, SLOT(slotThemeChanged()) ); + connect( kapp, SIGNAL(appearanceChanged()), this, SLOT(slotThemeChanged()) ); + slotThemeChanged(); +} + + +void K3bFlatButton::setText( const QString& s ) +{ + m_text = s; + m_text.remove( '&' ); + + update(); +} + + +void K3bFlatButton::setPixmap( const QPixmap& p ) +{ + m_pixmap = p; + update(); +} + + +void K3bFlatButton::enterEvent( QEvent* ) +{ + setHover(true); +} + + +void K3bFlatButton::leaveEvent( QEvent* ) +{ + setHover(false); +} + + +void K3bFlatButton::mousePressEvent( QMouseEvent* e ) +{ + if( e->button() == QMouseEvent::LeftButton ) { + emit pressed(); + m_pressed = true; + } + else + e->ignore(); +} + + +void K3bFlatButton::mouseReleaseEvent( QMouseEvent* e ) +{ + if( e->button() == QMouseEvent::LeftButton ) { + if( m_pressed ) + emit clicked(); + m_pressed = false; + } + else + e->ignore(); +} + + +void K3bFlatButton::setHover( bool b ) +{ + if( b ) { + setPaletteBackgroundColor( m_foreColor ); + setPaletteForegroundColor( m_backColor ); + } else { + setPaletteBackgroundColor( m_backColor ); + setPaletteForegroundColor( m_foreColor ); + } + + m_hover = b; + + update(); +} + + +QSize K3bFlatButton::sizeHint() const +{ + // height: pixmap + 5 spacing + font height + frame width + // width: max( pixmap, text) + frame width + return QSize( QMAX( m_pixmap.width(), fontMetrics().width( m_text ) ) + frameWidth()*2, + m_pixmap.height() + fontMetrics().height() + 5 + frameWidth()*2 ); +} + + +void K3bFlatButton::drawContents( QPainter* p ) +{ + QRect rect = contentsRect(); + +// if( m_hover ) +// p->fillRect( rect, m_foreColor ); +// else if( parentWidget() ) { +// QRect r( mapToParent( QPoint(lineWidth(), lineWidth()) ), +// mapToParent( QPoint(width()-2*lineWidth(), height()-2*lineWidth() )) ); + +// parentWidget()->repaint( r ); +// } + + p->save(); + + QRect textRect = fontMetrics().boundingRect( m_text ); + int textX = QMAX( 0, ( rect.width() - textRect.width() ) / 2 ); + int textY = textRect.height(); + + if( !m_pixmap.isNull() ) { + p->translate( rect.left(), rect.top() ); + textX = QMAX( textX, (m_pixmap.width() - textRect.width()) / 2 ); + textY += 5 + m_pixmap.height(); + + int pixX = QMAX( QMAX( 0, (textRect.width() - m_pixmap.width()) / 2 ), + ( rect.width() - m_pixmap.width() ) / 2 ); + p->drawPixmap( pixX, 0, m_pixmap ); + p->drawText( textX, textY, m_text ); + } + else + p->drawText( rect, Qt::AlignCenter, m_text ); + + p->restore(); +} + + +void K3bFlatButton::setColors( const QColor& fore, const QColor& back ) +{ + m_foreColor = fore; + m_backColor = back; + + setHover( m_hover ); +} + + +void K3bFlatButton::slotThemeChanged() +{ + if( K3bTheme* theme = k3bappcore->themeManager()->currentTheme() ) { + setColors( theme->foregroundColor(), theme->backgroundColor() ); + } +} + +#include "k3bflatbutton.moc" diff --git a/src/k3bflatbutton.h b/src/k3bflatbutton.h new file mode 100644 index 0000000..a3dc97e --- /dev/null +++ b/src/k3bflatbutton.h @@ -0,0 +1,77 @@ +/* + * + * $Id: k3bflatbutton.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef FLATBUTTON_H +#define FLATBUTTON_H + +#include <qframe.h> +#include <qcolor.h> +#include <qpixmap.h> + +class QEvent; +class QMouseEvent; +class QPainter; +class KAction; + + +/** +@author Sebastian Trueg +*/ +class K3bFlatButton : public QFrame +{ + Q_OBJECT + + public: + K3bFlatButton( QWidget *parent = 0, const char *name = 0 ); + K3bFlatButton( const QString& text, QWidget *parent = 0, const char *name = 0 ); + K3bFlatButton( KAction*, QWidget *parent = 0, const char *name = 0 ); + + ~K3bFlatButton(); + + QSize sizeHint() const; + + public slots: + void setColors( const QColor& fore, const QColor& back ); + void setText( const QString& ); + void setPixmap( const QPixmap& ); + + signals: + void pressed(); + void clicked(); + + private slots: + void slotThemeChanged(); + + private: + void init(); + + void mousePressEvent(QMouseEvent* e); + void mouseReleaseEvent(QMouseEvent* e); + void enterEvent( QEvent* ); + void leaveEvent( QEvent* ); + void drawContents( QPainter* ); + + void setHover( bool ); + + bool m_pressed; + QColor m_backColor; + QColor m_foreColor; + QString m_text; + QPixmap m_pixmap; + + bool m_hover; +}; + +#endif diff --git a/src/k3binteractiondialog.cpp b/src/k3binteractiondialog.cpp new file mode 100644 index 0000000..4784c7f --- /dev/null +++ b/src/k3binteractiondialog.cpp @@ -0,0 +1,662 @@ +/* + * + * $Id$ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3binteractiondialog.h" +#include "k3btitlelabel.h" +#include "kcutlabel.h" +#include "k3bstdguiitems.h" +#include "k3bpushbutton.h" +#include "k3bthemedheader.h" +#include "k3bthememanager.h" +#include <k3bapplication.h> +#include <k3btoolbutton.h> +#include <k3bmultichoicedialog.h> + +#include <qlabel.h> +#include <qtoolbutton.h> +#include <qlayout.h> +#include <qtooltip.h> +#include <qwhatsthis.h> +#include <qstring.h> +#include <qpoint.h> +#include <qfont.h> +#include <qpopupmenu.h> +#include <qeventloop.h> +#include <qapplication.h> +#include <qtimer.h> + +#include <klocale.h> +#include <kdebug.h> +#include <kstandarddirs.h> +#include <kstdguiitem.h> +#include <kpushbutton.h> +#include <kconfig.h> +#include <kiconloader.h> +#include <kglobalsettings.h> +#include <kdeversion.h> + + +K3bInteractionDialog::K3bInteractionDialog( QWidget* parent, + const char* name, + const QString& title, + const QString& subTitle, + int buttonMask, + int defaultButton, + const QString& configGroup, + bool modal, + WFlags fl ) + : KDialog( parent, name, modal, fl ), + m_mainWidget(0), + m_defaultButton(defaultButton), + m_configGroup(configGroup), + m_exitLoopOnHide(true), + m_inLoop(false), + m_inToggleMode(false), + m_delayedInit(false) +{ + installEventFilter( this ); + + mainGrid = new QGridLayout( this ); + mainGrid->setSpacing( spacingHint() ); + mainGrid->setMargin( marginHint() ); + + // header + // --------------------------------------------------------------------------------------------------- + m_dialogHeader = new K3bThemedHeader( this ); + mainGrid->addMultiCellWidget( m_dialogHeader, 0, 0, 0, 2 ); + + + // settings buttons + // --------------------------------------------------------------------------------------------------- + if( !m_configGroup.isEmpty() ) { + QHBoxLayout* layout2 = new QHBoxLayout( 0, 0, spacingHint(), "layout2"); + m_buttonLoadSettings = new K3bToolButton( /*i18n("User Defaults"), */this ); + ((K3bToolButton*)m_buttonLoadSettings)->setIconSet( SmallIconSet( "revert" ) ); + QPopupMenu* userDefaultsPopup = new QPopupMenu( m_buttonLoadSettings ); + userDefaultsPopup->insertItem( i18n("Load default settings"), this, SLOT(slotLoadK3bDefaults()) ); + userDefaultsPopup->insertItem( i18n("Load saved settings"), this, SLOT(slotLoadUserDefaults()) ); + userDefaultsPopup->insertItem( i18n("Load last used settings"), this, SLOT(slotLoadLastSettings()) ); + ((QToolButton*)m_buttonLoadSettings)->setPopup( userDefaultsPopup ); + ((K3bToolButton*)m_buttonLoadSettings)->setInstantMenu( true ); + layout2->addWidget( m_buttonLoadSettings ); + + m_buttonSaveSettings = new QToolButton( /*i18n("Save User Defaults"), */this, "m_buttonSaveSettings" ); + ((QToolButton*)m_buttonSaveSettings)->setIconSet( SmallIconSet( "filesave" ) ); + layout2->addWidget( m_buttonSaveSettings ); + + mainGrid->addLayout( layout2, 2, 0 ); + } + + QSpacerItem* spacer = new QSpacerItem( 10, 10, QSizePolicy::Expanding, QSizePolicy::Minimum ); + mainGrid->addItem( spacer, 2, 1 ); + + + // action buttons + // --------------------------------------------------------------------------------------------------- + QHBoxLayout* layout5 = new QHBoxLayout( 0, 0, spacingHint(), "layout5"); + + if( buttonMask & START_BUTTON ) { + KGuiItem startItem = KStdGuiItem::ok(); + m_buttonStart = new KPushButton( startItem, this, "m_buttonStart" ); + // refine the button text + setButtonText( START_BUTTON, + i18n("Start"), + i18n("Start the task") ); + QFont fnt( m_buttonStart->font() ); + fnt.setBold(true); + m_buttonStart->setFont( fnt ); + } + else + m_buttonStart = 0; + + if( buttonMask & SAVE_BUTTON ) { + m_buttonSave = new KPushButton( KStdGuiItem::save(), this, "m_buttonSave" ); + } + else + m_buttonSave = 0; + + if( buttonMask & CANCEL_BUTTON ) { + m_buttonCancel = new KPushButton( KConfigGroup( k3bcore->config(), "General Options" ) + .readBoolEntry( "keep action dialogs open", false ) + ? KStdGuiItem::close() + : KStdGuiItem::cancel(), + this, + "m_buttonCancel" ); + } + else + m_buttonCancel = 0; + + // we only handle some of the possible settings since + // our buttons are always to the right of the dialog + int btl = 0; +#if KDE_IS_VERSION(3,3,0) + btl = KGlobalSettings::buttonLayout(); +#endif + switch( btl ) { + case 0: // KDE default + default: + if ( m_buttonStart ) + layout5->addWidget( m_buttonStart ); + if ( m_buttonSave ) + layout5->addWidget( m_buttonSave ); + if ( m_buttonCancel ) + layout5->addWidget( m_buttonCancel ); + break; + + case 1: // something different + if ( m_buttonCancel ) + layout5->addWidget( m_buttonCancel ); + if ( m_buttonSave ) + layout5->addWidget( m_buttonSave ); + if ( m_buttonStart ) + layout5->addWidget( m_buttonStart ); + break; + + case 2: // GTK-Style + if ( m_buttonSave ) + layout5->addWidget( m_buttonSave ); + if ( m_buttonCancel ) + layout5->addWidget( m_buttonCancel ); + if ( m_buttonStart ) + layout5->addWidget( m_buttonStart ); + break; + } + + mainGrid->addLayout( layout5, 2, 2 ); + + mainGrid->setRowStretch( 1, 1 ); + + setTitle( title, subTitle ); + + initConnections(); + initToolTipsAndWhatsThis(); + + setDefaultButton( START_BUTTON ); +} + +K3bInteractionDialog::~K3bInteractionDialog() +{ +} + + +void K3bInteractionDialog::show() +{ + KDialog::show(); + if( KPushButton* b = getButton( m_defaultButton ) ) + b->setFocus(); +} + + +QSize K3bInteractionDialog::sizeHint() const +{ + QSize s = KDialog::sizeHint(); + // I want the dialogs to look good. + // That means their height should never outgrow their width + if( s.height() > s.width() ) + s.setWidth( s.height() ); + + return s; +} + + +void K3bInteractionDialog::initConnections() +{ + if( m_buttonStart ) { + connect( m_buttonStart, SIGNAL(clicked()), + this, SLOT(slotStartClickedInternal()) ); + } + if( m_buttonSave ) { +// connect( m_buttonSave, SIGNAL(clicked()), +// this, SLOT(slotSaveLastSettings()) ); + connect( m_buttonSave, SIGNAL(clicked()), + this, SLOT(slotSaveClicked()) ); + } + if( m_buttonCancel ) + connect( m_buttonCancel, SIGNAL(clicked()), + this, SLOT(slotCancelClicked()) ); + + if( !m_configGroup.isEmpty() ) { + connect( m_buttonSaveSettings, SIGNAL(clicked()), + this, SLOT(slotSaveUserDefaults()) ); + } +} + + +void K3bInteractionDialog::initToolTipsAndWhatsThis() +{ + if( !m_configGroup.isEmpty() ) { + // ToolTips + // ------------------------------------------------------------------------- + QToolTip::add( m_buttonLoadSettings, i18n("Load default or saved settings") ); + QToolTip::add( m_buttonSaveSettings, i18n("Save current settings to reuse them later") ); + + // What's This info + // ------------------------------------------------------------------------- + QWhatsThis::add( m_buttonLoadSettings, i18n("<p>Load a set of settings either from the default K3b settings, " + "settings saved before, or the last used ones.") ); + QWhatsThis::add( m_buttonSaveSettings, i18n("<p>Saves the current settings of the action dialog." + "<p>These settings can be loaded with the <em>Load saved settings</em> " + "button." + "<p><b>The K3b defaults are not overwritten by this.</b>") ); + } +} + + +void K3bInteractionDialog::setTitle( const QString& title, const QString& subTitle ) +{ + m_dialogHeader->setTitle( title, subTitle ); + + setCaption( title ); +} + + +void K3bInteractionDialog::setMainWidget( QWidget* w ) +{ + w->reparent( this, QPoint(0,0) ); + mainGrid->addMultiCellWidget( w, 1, 1, 0, 2 ); + m_mainWidget = w; +} + +QWidget* K3bInteractionDialog::mainWidget() +{ + if( !m_mainWidget ) { + setMainWidget( new QWidget( this ) ); + } + return m_mainWidget; +} + +void K3bInteractionDialog::slotLoadK3bDefaults() +{ + loadK3bDefaults(); +} + +void K3bInteractionDialog::slotLoadUserDefaults() +{ + KConfigGroup c( k3bcore->config(), m_configGroup ); + loadUserDefaults( &c ); +} + +void K3bInteractionDialog::slotSaveUserDefaults() +{ + KConfigGroup c( k3bcore->config(), m_configGroup ); + saveUserDefaults( &c ); +} + + +void K3bInteractionDialog::slotLoadLastSettings() +{ + KConfigGroup c( k3bcore->config(), "last used " + m_configGroup ); + loadUserDefaults( &c ); +} + + +void K3bInteractionDialog::saveLastSettings() +{ + KConfigGroup c( k3bcore->config(), "last used " + m_configGroup ); + saveUserDefaults( &c ); +} + + +void K3bInteractionDialog::slotStartClickedInternal() +{ + saveLastSettings(); + + KConfigGroup c( k3bcore->config(), "General Options" ); + if( !c.readNumEntry( "action dialog startup settings", 0 ) ) { + // first time saving last used settings + switch( K3bMultiChoiceDialog::choose( i18n("Action Dialog Settings"), + i18n("<p>K3b handles three sets of settings in action dialogs: " + "the defaults, the saved settings, and the last used settings. " + "Please choose which of these sets should be loaded if an action " + "dialog is opened again." + "<p><em>Be aware that this choice can always be changed from the K3b " + "configuration dialog.</em>"), + QMessageBox::Question, + this, + 0, + 3, + i18n("Default Settings"), + i18n("Saved Settings"), + i18n("Last Used Settings") ) ) { + case 1: + c.writeEntry( "action dialog startup settings", LOAD_K3B_DEFAULTS ); + break; + case 2: + c.writeEntry( "action dialog startup settings", LOAD_SAVED_SETTINGS ); + break; + case 3: + c.writeEntry( "action dialog startup settings", LOAD_LAST_SETTINGS ); + break; + } + } + + slotStartClicked(); +} + + +void K3bInteractionDialog::slotStartClicked() +{ + emit started(); +} + +void K3bInteractionDialog::slotCancelClicked() +{ + emit canceled(); + close( false ); +} + +void K3bInteractionDialog::slotSaveClicked() +{ + emit saved(); +} + + +void K3bInteractionDialog::setDefaultButton( int button ) +{ + m_defaultButton = button; + + // reset all other default buttons + if( KPushButton* b = getButton( START_BUTTON ) ) + b->setDefault( true ); + if( KPushButton* b = getButton( SAVE_BUTTON ) ) + b->setDefault( true ); + if( KPushButton* b = getButton( CANCEL_BUTTON ) ) + b->setDefault( true ); + + // set the selected default + if( KPushButton* b = getButton( button ) ) + b->setDefault( true ); +} + + +bool K3bInteractionDialog::eventFilter( QObject* o, QEvent* ev ) +{ + if( dynamic_cast<K3bInteractionDialog*>(o) == this && + ev->type() == QEvent::KeyPress ) { + + QKeyEvent* kev = dynamic_cast<QKeyEvent*>(ev); + + switch ( kev->key() ) { + case Key_Enter: + case Key_Return: + // if the process finished this closes the dialog + if( m_defaultButton == START_BUTTON ) { + if( m_buttonStart->isEnabled() ) + slotStartClickedInternal(); + } + else if( m_defaultButton == CANCEL_BUTTON ) { + if( m_buttonCancel->isEnabled() ) + slotCancelClicked(); + } + else if( m_defaultButton == SAVE_BUTTON ) { + if( m_buttonSave->isEnabled() ) + slotSaveClicked(); + } + return true; + + case Key_Escape: + // simulate button clicks + if( m_buttonCancel ) { + if( m_buttonCancel->isEnabled() ) + slotCancelClicked(); + } + return true; + } + } + + return KDialog::eventFilter( o, ev ); +} + + +KPushButton* K3bInteractionDialog::getButton( int button ) +{ + switch( button ) { + case START_BUTTON: + return m_buttonStart; + case SAVE_BUTTON: + return m_buttonSave; + case CANCEL_BUTTON: + return m_buttonCancel; + default: + return 0; + } +} + + +void K3bInteractionDialog::setButtonGui( int button, + const KGuiItem& item ) +{ + if( KPushButton* b = getButton( button ) ) + b->setGuiItem( item ); +} + + +void K3bInteractionDialog::setButtonText( int button, + const QString& text, + const QString& tooltip, + const QString& whatsthis ) +{ + if( KPushButton* b = getButton( button ) ) { + b->setText( text ); + QToolTip::remove( b ); + QWhatsThis::remove( b ); + QToolTip::add( b, tooltip ); + QWhatsThis::add( b, whatsthis ); + } +} + + +void K3bInteractionDialog::setButtonEnabled( int button, bool enabled ) +{ + if( KPushButton* b = getButton( button ) ) { + b->setEnabled( enabled ); + // make sure the correct button is selected as default again + setDefaultButton( m_defaultButton ); + } +} + + +void K3bInteractionDialog::setButtonShown( int button, bool shown ) +{ + if( KPushButton* b = getButton( button ) ) { + b->setShown( shown ); + // make sure the correct button is selected as default again + setDefaultButton( m_defaultButton ); + } +} + + +void K3bInteractionDialog::setStartButtonText( const QString& text, + const QString& tooltip, + const QString& whatsthis ) +{ + if( m_buttonStart ) { + m_buttonStart->setText( text ); + QToolTip::remove( m_buttonStart ); + QWhatsThis::remove( m_buttonStart ); + QToolTip::add( m_buttonStart, tooltip ); + QWhatsThis::add( m_buttonStart, whatsthis ); + } +} + + +void K3bInteractionDialog::setCancelButtonText( const QString& text, + const QString& tooltip, + const QString& whatsthis ) +{ + if( m_buttonCancel ) { + m_buttonCancel->setText( text ); + QToolTip::remove( m_buttonCancel ); + QWhatsThis::remove( m_buttonCancel ); + QToolTip::add( m_buttonCancel, tooltip ); + QWhatsThis::add( m_buttonCancel, whatsthis ); + } +} + + +void K3bInteractionDialog::setSaveButtonText( const QString& text, + const QString& tooltip, + const QString& whatsthis ) +{ + if( m_buttonSave ) { + m_buttonSave->setText( text ); + QToolTip::remove( m_buttonSave ); + QWhatsThis::remove( m_buttonSave ); + QToolTip::add( m_buttonSave, tooltip ); + QWhatsThis::add( m_buttonSave, whatsthis ); + } +} + + +void K3bInteractionDialog::saveUserDefaults( KConfigBase* ) +{ +} + + +void K3bInteractionDialog::loadUserDefaults( KConfigBase* ) +{ +} + + +void K3bInteractionDialog::loadK3bDefaults() +{ +} + + +void K3bInteractionDialog::loadStartupSettings() +{ + KConfigGroup c( k3bcore->config(), "General Options" ); + + // earlier K3b versions loaded the saved settings + // so that is what we do as a default + int i = c.readNumEntry( "action dialog startup settings", LOAD_SAVED_SETTINGS ); + switch( i ) { + case LOAD_K3B_DEFAULTS: + slotLoadK3bDefaults(); + break; + case LOAD_SAVED_SETTINGS: + slotLoadUserDefaults(); + break; + case LOAD_LAST_SETTINGS: + slotLoadLastSettings(); + break; + } +} + + +int K3bInteractionDialog::exec() +{ + return exec( true ); +} + + +int K3bInteractionDialog::exec( bool returnOnHide ) +{ + m_exitLoopOnHide = returnOnHide; + + // the following code is mainly taken from QDialog::exec + + if( m_inLoop ) { + kdError() << "(K3bInteractionDialog::exec) Recursive call detected." << endl; + return -1; + } + + bool destructiveClose = testWFlags( WDestructiveClose ); + clearWFlags( WDestructiveClose ); + + bool wasShowModal = testWFlags( WShowModal ); + setWFlags( WShowModal ); + setResult( 0 ); + + loadStartupSettings(); + show(); + if( m_delayedInit ) + QTimer::singleShot( 0, this, SLOT(slotDelayedInit()) ); + else + init(); + + m_inLoop = true; + QApplication::eventLoop()->enterLoop(); + + if( !wasShowModal ) + clearWFlags( WShowModal ); + + int res = result(); + + if( destructiveClose ) + delete this; + + return res; +} + + +void K3bInteractionDialog::hide() +{ + if( isHidden() ) + return; + + KDialog::hide(); + + if( m_inLoop && m_exitLoopOnHide ) { + m_inLoop = false; + QApplication::eventLoop()->exitLoop(); + } +} + + +bool K3bInteractionDialog::close( bool alsoDelete ) +{ + if( m_inLoop && !m_exitLoopOnHide ) { + m_inLoop = false; + QApplication::eventLoop()->exitLoop(); + } + + return KDialog::close( alsoDelete ); +} + + +void K3bInteractionDialog::done( int r ) +{ + if( m_inLoop && !m_exitLoopOnHide ) { + m_inLoop = false; + QApplication::eventLoop()->exitLoop(); + } + + return KDialog::done( r ); +} + + +void K3bInteractionDialog::slotToggleAll() +{ + if( !m_inToggleMode ) { + m_inToggleMode = true; + toggleAll(); + m_inToggleMode = false; + } +} + + +void K3bInteractionDialog::toggleAll() +{ +} + + +void K3bInteractionDialog::slotDelayedInit() +{ + init(); +} + +#include "k3binteractiondialog.moc" diff --git a/src/k3binteractiondialog.h b/src/k3binteractiondialog.h new file mode 100644 index 0000000..2bdb426 --- /dev/null +++ b/src/k3binteractiondialog.h @@ -0,0 +1,279 @@ +/* + * + * $Id: k3binteractiondialog.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_INTERACTION_DIALOG_H_ +#define _K3B_INTERACTION_DIALOG_H_ + +#include <kdialog.h> + + +class QGridLayout; +class QLabel; +class KPushButton; +class QButton; +class K3bThemedHeader; +class KConfigBase; +class KGuiItem; + + +/** + * This is the base dialog for all the dialogs in K3b that start + * some job. Use setMainWidget to set the contents or let mainWidget() + * create an empty plain page. + * The default implementations of the slots just emit the + * corresponding signals. + */ +class K3bInteractionDialog : public KDialog +{ + Q_OBJECT + + public: + /** + * The constructor. + * loadUserDefaults will be called automatically when the dialog is showing. + * + * @param title the text to be displayed in the K3b header (not the widget frame) + * @param subTitle additional text that will be displayed after the title in smaller size + * @param buttonMask combination of Buttons + * @param defaultButton may also be null to deactivate the feature + * @param configgroup The config group used for the loadUserDefaults and saveUserDefaults methods + */ + K3bInteractionDialog( QWidget* parent = 0, + const char* name = 0, + const QString& title = QString::null, + const QString& subTitle = QString::null, + int buttonMask = START_BUTTON|CANCEL_BUTTON, + int defaultButton = START_BUTTON, + const QString& configgroup = QString::null, + bool modal = true, + WFlags fl = 0 ); + virtual ~K3bInteractionDialog(); + + void setMainWidget( QWidget* w ); + void setTitle( const QString& title, const QString& subTitle = QString::null ); + void setDefaultButton( int b ); + + /** + * Reimplemented for internal reasons. The API does not change. + */ + int exec(); + + /** + * @param returnOnHide if false the dialog can be hidden and shown without being closed. + * one needs to call close() to actually close the dialog. + */ + int exec( bool returnOnHide ); + + /** + * reimplemented to allow initialization after the dialog has been opened. + */ + void show(); + + /** + * Reimplemented for internal reasons. The API does not change. + */ + void hide(); + + /** + * Reimplemented for internal reasons. The API does not change. + */ + bool close( bool alsoDelete ); + + inline bool close() { return close( false ); } + + /** + * If no mainWidget has been set a plain page will be created. + */ + QWidget* mainWidget(); + + enum Buttons { + START_BUTTON = 1, + SAVE_BUTTON = 2, + CANCEL_BUTTON = 4 + }; + + QSize sizeHint() const; + + const QString& configGroup() const { return m_configGroup; } + + /** + * K3b's dialogs use this method to determine if it is safe to hide when starting + * some action. Take for example the copy dialog which starts a copy job with a progress + * dialog. Both the job and the progress dialog are deleted by the copy dialog after the + * progress dialog has been closed. If the copy dialog would hide itself before starting + * the job and exitLoopOnHide() would return true the hiding would result in the exec call + * of the copy dialog to return. And what would that mean for the code after the hide() + * statement (deleting of the job and so on). + * + * \return true in case this dialog will not exit it's private event loop + * in case it is hidden. + * + * \see exec(bool) + */ + bool exitLoopOnHide() const { return m_exitLoopOnHide; } + + enum StartUpSettings { + LOAD_K3B_DEFAULTS = 1, + LOAD_SAVED_SETTINGS = 2, + LOAD_LAST_SETTINGS = 3 + }; + + signals: + void started(); + void canceled(); + void saved(); + + public slots: + /** + * \deprecated use setButtonText + */ + void setStartButtonText( const QString& text, + const QString& tooltip = QString::null, + const QString& whatsthis = QString::null ); + /** + * \deprecated use setButtonText + */ + void setCancelButtonText( const QString& text, + const QString& tooltip = QString::null, + const QString& whatsthis = QString::null ); + /** + * \deprecated use setButtonText + */ + void setSaveButtonText( const QString& text, + const QString& tooltip = QString::null, + const QString& whatsthis = QString::null ); + + void setButtonGui( int button, + const KGuiItem& ); + + void setButtonText( int button, + const QString& text, + const QString& tooltip = QString::null, + const QString& whatsthis = QString::null ); + + void setButtonEnabled( int button, bool enabled ); + void setButtonShown( int button, bool enabled ); + + /** + * If set true the init() method will be called via a QTimer to ensure event + * handling be done before (default: false). + */ + void setDelayedInitialization( bool b ) { m_delayedInit = b; } + + protected slots: + // FIXME: replace these with protected methods which are called from private slots. + virtual void slotStartClicked(); + + /** + * The default implementation emits the canceled() signal + * and calls close() + */ + virtual void slotCancelClicked(); + virtual void slotSaveClicked(); + + /** + * This slot will call the toggleAll() method protecting from infinite loops + * caused by one element influencing another element which in turn influences + * the first. + * + * Connect this slot to GUI elements (like Checkboxes) that change + * the state of the whole dialog. + */ + void slotToggleAll(); + + protected: + /** + * Reimplement this method in case you are using slotToggleAll() + */ + virtual void toggleAll(); + + /** + * Reimplement this to support the save/load user default buttons. + * @p config is already set to the correct group. + * + * The save/load buttons are only activated if the config group is + * set in the constructor. + */ + virtual void saveUserDefaults( KConfigBase* config ); + + /** + * Reimplement this to support the save/load user default buttons. + * @p config is already set to the correct group. + * + * The save/load buttons are only activated if the config group is + * set in the constructor. + */ + virtual void loadUserDefaults( KConfigBase* config ); + + /** + * Reimplement this to support the "k3b defaults" button. + * set all GUI options to reasonable defaults. + */ + virtual void loadK3bDefaults(); + + /** + * This is called after the dialog has been shown. + * Use this for initialization that should happen + * when the user already sees the dialog. + */ + virtual void init() {} + + /** + * reimplemented from QDialog + */ + virtual bool eventFilter( QObject*, QEvent* ); + + protected slots: + /** + * Reimplemented for internal reasons. The API does not change. + */ + virtual void done( int ); + + private slots: + void slotLoadK3bDefaults(); + void slotLoadUserDefaults(); + void slotSaveUserDefaults(); + void slotLoadLastSettings(); + void slotStartClickedInternal(); + void slotDelayedInit(); + + private: + void initConnections(); + void initToolTipsAndWhatsThis(); + void saveLastSettings(); + void loadStartupSettings(); + + KPushButton* getButton( int ); + + K3bThemedHeader* m_dialogHeader; + KPushButton* m_buttonStart; + KPushButton* m_buttonSave; + KPushButton* m_buttonCancel; + QWidget* m_mainWidget; + + QButton* m_buttonLoadSettings; + QButton* m_buttonSaveSettings; + + QGridLayout* mainGrid; + int m_defaultButton; + QString m_configGroup; + + bool m_exitLoopOnHide; + bool m_inLoop; + bool m_inToggleMode; + bool m_delayedInit; +}; + +#endif diff --git a/src/k3binterface.cpp b/src/k3binterface.cpp new file mode 100644 index 0000000..c95e598 --- /dev/null +++ b/src/k3binterface.cpp @@ -0,0 +1,192 @@ +/* + * + * $Id: k3binterface.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3binterface.h" +#include "k3bprojectinterface.h" +#include "k3bprojectmanager.h" +#include "k3bapplication.h" +#include "k3bdoc.h" +#include "k3bview.h" +#include "k3bcore.h" +#include "k3b.h" + +#include <k3bglobals.h> + +#include <dcopclient.h> +#include <qptrlist.h> +#include <qtimer.h> + + + +K3bInterface::K3bInterface() + : DCOPObject( "K3bInterface" ), + m_main( 0 ) +{ +} + +DCOPRef K3bInterface::createDataCDProject() +{ + return DCOPRef( kapp->dcopClient()->appId(), + k3bappcore->projectManager()->dcopInterface( k3bappcore->projectManager()->createProject( K3bDoc::DATA ) )->objId() ); +} + +DCOPRef K3bInterface::createAudioCDProject() +{ + return DCOPRef( kapp->dcopClient()->appId(), + k3bappcore->projectManager()->dcopInterface( k3bappcore->projectManager()->createProject( K3bDoc::AUDIO ) )->objId() ); +} + +DCOPRef K3bInterface::createMixedCDProject() +{ + return DCOPRef( kapp->dcopClient()->appId(), + k3bappcore->projectManager()->dcopInterface( k3bappcore->projectManager()->createProject( K3bDoc::MIXED ) )->objId() ); +} + +DCOPRef K3bInterface::createVideoCDProject() +{ + return DCOPRef( kapp->dcopClient()->appId(), + k3bappcore->projectManager()->dcopInterface( k3bappcore->projectManager()->createProject( K3bDoc::VCD ) )->objId() ); +} + +DCOPRef K3bInterface::createMovixCDProject() +{ + return DCOPRef( kapp->dcopClient()->appId(), + k3bappcore->projectManager()->dcopInterface( k3bappcore->projectManager()->createProject( K3bDoc::MOVIX ) )->objId() ); +} + +DCOPRef K3bInterface::createDataDVDProject() +{ + return DCOPRef( kapp->dcopClient()->appId(), + k3bappcore->projectManager()->dcopInterface( k3bappcore->projectManager()->createProject( K3bDoc::DVD ) )->objId() ); +} + +DCOPRef K3bInterface::createVideoDVDProject() +{ + return DCOPRef( kapp->dcopClient()->appId(), + k3bappcore->projectManager()->dcopInterface( k3bappcore->projectManager()->createProject( K3bDoc::VIDEODVD ) )->objId() ); +} + +DCOPRef K3bInterface::createMovixDVDProject() +{ + return DCOPRef( kapp->dcopClient()->appId(), + k3bappcore->projectManager()->dcopInterface( k3bappcore->projectManager()->createProject( K3bDoc::MOVIX_DVD ) )->objId() ); +} + +DCOPRef K3bInterface::currentProject() +{ + K3bView* view = m_main->activeView(); + if( view ) + return DCOPRef( kapp->dcopClient()->appId(), + k3bappcore->projectManager()->dcopInterface( view->doc() )->objId() ); + else + return DCOPRef(); +} + +DCOPRef K3bInterface::openProject( const KURL& url ) +{ + K3bDoc* doc = k3bappcore->projectManager()->openProject( url ); + if( doc ) + return DCOPRef( kapp->dcopClient()->appId(), + k3bappcore->projectManager()->dcopInterface( doc )->objId() ); + else + return DCOPRef(); +} + +QValueList<DCOPRef> K3bInterface::projects() +{ + QValueList<DCOPRef> lst; + const QPtrList<K3bDoc>& docs = k3bappcore->projectManager()->projects(); + for( QPtrListIterator<K3bDoc> it( docs ); it.current(); ++it ) + lst.append( DCOPRef( kapp->dcopClient()->appId(), k3bappcore->projectManager()->dcopInterface( it.current() )->objId() ) ); + + return lst; +} + +void K3bInterface::addUrls( const KURL::List& urls ) +{ + m_main->addUrls( urls ); +} + +void K3bInterface::addUrl( const KURL& url ) +{ + KURL::List l; + l.append(url); + addUrls( l ); +} + + +void K3bInterface::copyCd( const KURL& dev ) +{ + m_main->cdCopy( K3b::urlToDevice( dev ) ); +} + + +void K3bInterface::copyDvd( const KURL& dev ) +{ + m_main->dvdCopy( K3b::urlToDevice( dev ) ); +} + + +void K3bInterface::copyCd() +{ + // HACK since we want this method to return immediately + QTimer::singleShot( 0, m_main, SLOT(slotCdCopy()) ); +} + + +void K3bInterface::copyDvd() +{ + // HACK since we want this method to return immediately + QTimer::singleShot( 0, m_main, SLOT(slotDvdCopy()) ); +} + + +void K3bInterface::eraseCdrw() +{ + // HACK since we want this method to return immediately + QTimer::singleShot( 0, m_main, SLOT(slotBlankCdrw()) ); +} + + +void K3bInterface::formatDvd() +{ + // HACK since we want this method to return immediately + QTimer::singleShot( 0, m_main, SLOT(slotFormatDvd()) ); +} + + +void K3bInterface::burnCdImage( const KURL& url ) +{ + m_main->slotWriteCdImage( url ); +} + + +void K3bInterface::burnDvdImage( const KURL& url ) +{ + m_main->slotWriteDvdIsoImage( url ); +} + + +bool K3bInterface::blocked() const +{ + return k3bcore->jobsRunning(); +} + + +void K3bInterface::cddaRip( const KURL& dev ) +{ + m_main->cddaRip( K3b::urlToDevice( dev ) ); +} diff --git a/src/k3binterface.h b/src/k3binterface.h new file mode 100644 index 0000000..b54e2ef --- /dev/null +++ b/src/k3binterface.h @@ -0,0 +1,102 @@ +/* + * + * $Id: k3binterface.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_INTERFACE_H_ +#define _K3B_INTERFACE_H_ + +#include <dcopobject.h> +#include <dcopref.h> +#include <qvaluelist.h> + +#include <kurl.h> + +class K3bMainWindow; +namespace K3bDevice { + class Device; +} + + +class K3bInterface : public DCOPObject +{ + K_DCOP + + public: + K3bInterface(); + + void setMainWindow( K3bMainWindow* mw ) { m_main = mw; } + + k_dcop: + /** + * returns a DCOPRef to a K3bProjectInterface + */ + DCOPRef createDataCDProject(); + DCOPRef createAudioCDProject(); + DCOPRef createMixedCDProject(); + DCOPRef createVideoCDProject(); + DCOPRef createMovixCDProject(); + DCOPRef createDataDVDProject(); + DCOPRef createVideoDVDProject(); + DCOPRef createMovixDVDProject(); + + /** + * Returns a reference to the currently active project. + * This is useful to do things like: + * + * <pre>k3b --audiocd</pre> + * and then use dcop on the newly created project via: + * <pre>dcop $(dcop k3b K3bInterface currentProject) something</pre> + */ + DCOPRef currentProject(); + + DCOPRef openProject( const KURL& url ); + + QValueList<DCOPRef> projects(); + + void copyCd(); + void copyDvd(); + void copyCd( const KURL& dev ); + void copyDvd( const KURL& dev ); + void eraseCdrw(); + void formatDvd(); + void burnCdImage( const KURL& url ); + void burnDvdImage( const KURL& url ); + + /** + * Open the audio ripping window for the specified device. + */ + void cddaRip( const KURL& dev ); + + /** + * Add URLs to the current active project. + * If no project is open a new Audio or Data CD + * project will be created depending on the type + * of the first file. + */ + void addUrls( const KURL::List& urls ); + void addUrl( const KURL& url ); + + /** + * @return true if currently some job is running. + */ + bool blocked() const; + + private: + K3bMainWindow* m_main; + + K3bDevice::Device* m_lastDevice; +}; + +#endif diff --git a/src/k3bjobinterface.cpp b/src/k3bjobinterface.cpp new file mode 100644 index 0000000..60e4436 --- /dev/null +++ b/src/k3bjobinterface.cpp @@ -0,0 +1,190 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bjobinterface.h" + +#include <k3bjob.h> + +#include <qcstring.h> +#include <qdatastream.h> + + +K3bJobInterface::K3bJobInterface( QObject* parent ) + : QObject( parent ), + DCOPObject( "K3bJobInterface" ), + m_job( 0 ) +{ +} + + +void K3bJobInterface::setJob( K3bJob* job ) +{ + if( m_job ) + m_job->disconnect( this ); + + m_job = job; + m_lastProgress = m_lastSubProgress = 0; + + if( m_job ) { + connect( m_job, SIGNAL(newTask(const QString&)), this, SLOT(slotNewTask(const QString&)) ); + connect( m_job, SIGNAL(newSubTask(const QString&)), this, SLOT(slotNewSubTask(const QString&)) ); + connect( m_job, SIGNAL(infoMessage(const QString&, int)), this, SLOT(slotInfoMessage(const QString&, int)) ); + connect( m_job, SIGNAL(finished(bool)), this, SLOT(slotFinished(bool)) ); + connect( m_job, SIGNAL(started()), this, SLOT(slotStarted()) ); + connect( m_job, SIGNAL(canceled()), this, SLOT(slotCanceled()) ); + connect( m_job, SIGNAL(percent(int)), this, SLOT(slotProgress(int)) ); + connect( m_job, SIGNAL(subPercent(int)), this, SLOT(slotSubProgress(int)) ); + connect( m_job, SIGNAL(nextTrack(int, int)), this, SLOT(slotNextTrack(int, int)) ); + + if( m_job->inherits( "K3bBurnJob" ) ) { + connect( m_job, SIGNAL(bufferStatus(int)), this, SLOT(slotBuffer(int)) ); + connect( m_job, SIGNAL(deviceBuffer(int)), this, SLOT(slotDeviceBuffer(int)) ); + } + + connect( m_job, SIGNAL(destroyed()), this, SLOT(slotDestroyed()) ); + } +} + + +bool K3bJobInterface::jobRunning() const +{ + return ( m_job && m_job->active() ); +} + + +QString K3bJobInterface::jobDescription() const +{ + if( m_job ) + return m_job->jobDescription(); + else + return QString::null; +} + + +QString K3bJobInterface::jobDetails() const +{ + if( m_job ) + return m_job->jobDetails(); + else + return QString::null; +} + + +void K3bJobInterface::slotStarted() +{ + m_lastProgress = m_lastSubProgress = 0; + emitDCOPSignal( "started()", QByteArray() ); +} + + +void K3bJobInterface::slotCanceled() +{ + emitDCOPSignal( "canceled()", QByteArray() ); +} + + +void K3bJobInterface::slotFinished( bool success ) +{ + QByteArray params; + QDataStream stream(params, IO_WriteOnly); + stream << success; + emitDCOPSignal( "finished(bool)", params ); +} + + +void K3bJobInterface::slotInfoMessage( const QString& message, int type ) +{ + QByteArray params; + QDataStream stream(params, IO_WriteOnly); + stream << message << type; + emitDCOPSignal( "infoMessage(QString)", params ); +} + + +void K3bJobInterface::slotProgress( int val ) +{ + if( m_lastProgress != val ) { + m_lastProgress = val; + QByteArray params; + QDataStream stream(params, IO_WriteOnly); + stream << val; + emitDCOPSignal( "progress(int)", params ); + } +} + + +void K3bJobInterface::slotSubProgress( int val ) +{ + if( m_lastSubProgress != val ) { + m_lastSubProgress = val; + QByteArray params; + QDataStream stream(params, IO_WriteOnly); + stream << val; + emitDCOPSignal( "subProgress(int)", params ); + } +} + + +void K3bJobInterface::slotNewTask( const QString& task ) +{ + QByteArray params; + QDataStream stream(params, IO_WriteOnly); + stream << task; + emitDCOPSignal( "newTask(QString)", params ); +} + + +void K3bJobInterface::slotNewSubTask( const QString& task ) +{ + QByteArray params; + QDataStream stream(params, IO_WriteOnly); + stream << task; + emitDCOPSignal( "newSubTask(QString)", params ); +} + + +void K3bJobInterface::slotBuffer( int val ) +{ + QByteArray params; + QDataStream stream(params, IO_WriteOnly); + stream << val; + emitDCOPSignal( "buffer(int)", params ); +} + + +void K3bJobInterface::slotDeviceBuffer( int val ) +{ + QByteArray params; + QDataStream stream(params, IO_WriteOnly); + stream << val; + emitDCOPSignal( "deviceBuffer(int)", params ); +} + + +void K3bJobInterface::slotNextTrack( int track, int numTracks ) +{ + QByteArray params; + QDataStream stream(params, IO_WriteOnly); + stream << track << numTracks; + emitDCOPSignal( "nextTrack(int,int)", params ); +} + + +void K3bJobInterface::slotDestroyed() +{ + m_job = 0; +} + +#include "k3bjobinterface.moc" diff --git a/src/k3bjobinterface.h b/src/k3bjobinterface.h new file mode 100644 index 0000000..0d27ac2 --- /dev/null +++ b/src/k3bjobinterface.h @@ -0,0 +1,82 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_JOB_INTERFACE_H_ +#define _K3B_JOB_INTERFACE_H_ + +#include <qobject.h> +#include <dcopobject.h> + +class K3bJob; + + +/** + * A DCOP interface for K3b's currently running job. + * + * This may be used for example in a karamba theme with a non-volitile + * DCOP connection. + */ +class K3bJobInterface : public QObject, public DCOPObject +{ + Q_OBJECT + K_DCOP + + public: + K3bJobInterface( QObject* parent ); + + void setJob( K3bJob* ); + + k_dcop: + bool jobRunning() const; + + QString jobDescription() const; + QString jobDetails() const; + + k_dcop_signals: + void started(); + void canceled(); + void finished( bool ); + void infoMessage( const QString&, int ); + void progress( int ); + void subProgress( int ); + void newTask( const QString& ); + void newSubTask( const QString& ); + void buffer( int ); + void deviceBuffer( int ); + void nextTrack( int track, int numTracks ); + + private slots: + void slotStarted(); + void slotCanceled(); + void slotFinished( bool ); + void slotInfoMessage( const QString&, int ); + void slotProgress( int ); + void slotSubProgress( int ); + void slotNewTask( const QString& ); + void slotNewSubTask( const QString& ); + void slotBuffer( int ); + void slotDeviceBuffer( int ); + void slotNextTrack( int track, int numTracks ); + + void slotDestroyed(); + + private: + K3bJob* m_job; + + int m_lastProgress; + int m_lastSubProgress; +}; + +#endif diff --git a/src/k3bjobprogressdialog.cpp b/src/k3bjobprogressdialog.cpp new file mode 100644 index 0000000..351f1d9 --- /dev/null +++ b/src/k3bjobprogressdialog.cpp @@ -0,0 +1,696 @@ +/* + * + * $Id$ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bjobprogressdialog.h" +#include "k3bapplication.h" +#include "k3bemptydiscwaiter.h" +#include "k3bjobprogressosd.h" +#include "k3bdebuggingoutputdialog.h" +#include "k3bapplication.h" +#include "k3bjobinterface.h" +#include "k3bthemedlabel.h" +#include <k3bjob.h> +#include <kcutlabel.h> +#include <k3bdevice.h> +#include <k3bdevicemanager.h> +#include <k3bdeviceglobals.h> +#include <k3bglobals.h> +#include <k3bstdguiitems.h> +#include <k3bversion.h> +#include <k3bthememanager.h> + +#include <qgroupbox.h> +#include <qlabel.h> +#include <qpushbutton.h> +#include <qlayout.h> +#include <qvariant.h> +#include <qtooltip.h> +#include <qwhatsthis.h> +#include <qdatetime.h> +#include <qstring.h> +#include <qhbox.h> +#include <qheader.h> +#include <qscrollbar.h> +#include <qpoint.h> +#include <qfontmetrics.h> +#include <qtimer.h> +#include <qfont.h> +#include <qeventloop.h> +#include <qfile.h> +#include <qapplication.h> + +#include <kprogress.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <klistview.h> +#include <kiconloader.h> +#include <kconfig.h> +#include <kdebug.h> +#include <kglobal.h> +#include <knotifyclient.h> +#include <kstandarddirs.h> +#include <kapplication.h> +#include <kmainwindow.h> +#include <kstdguiitem.h> +#include <kpushbutton.h> + + + + +class K3bJobProgressDialog::Private +{ +public: + int lastProgress; +}; + + + +K3bJobProgressDialog::K3bJobProgressDialog( QWidget* parent, + const char* name, + bool showSubProgress, + bool modal, WFlags fl ) + : KDialog( parent, name, modal, fl ), + in_loop(false), + m_osd(0) +{ + d = new Private; + + setupGUI(); + setupConnections(); + + if( !showSubProgress ) { + m_progressSubPercent->hide(); + } + + m_job = 0; + m_timer = new QTimer( this ); + + connect( m_timer, SIGNAL(timeout()), this, SLOT(slotUpdateTime()) ); +} + + +/* + * Destroys the object and frees any allocated resources + */ +K3bJobProgressDialog::~K3bJobProgressDialog() +{ + delete d; + delete m_osd; +} + + +void K3bJobProgressDialog::setupGUI() +{ + QVBoxLayout* mainLayout = new QVBoxLayout( this, 11, 6, "mainLayout"); + + + // header + // ------------------------------------------------------------------------------------------ + QFrame* headerFrame = new QFrame( this, "headerFrame" ); + headerFrame->setFrameShape( QFrame::StyledPanel ); + headerFrame->setFrameShadow( QFrame::Sunken ); + headerFrame->setLineWidth( 1 ); + headerFrame->setMargin( 1 ); + QHBoxLayout* headerLayout = new QHBoxLayout( headerFrame ); + headerLayout->setMargin( 2 ); // to make sure the frame gets displayed + headerLayout->setSpacing( 0 ); + m_pixLabel = new K3bThemedLabel( headerFrame ); + headerLayout->addWidget( m_pixLabel ); + + QFrame* frame4 = new QFrame( headerFrame, "frame4" ); + frame4->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)5, (QSizePolicy::SizeType)5, 1, 0, frame4->sizePolicy().hasHeightForWidth() ) ); + frame4->setFrameShape( QFrame::NoFrame ); + frame4->setFrameShadow( QFrame::Raised ); + QVBoxLayout* frame4Layout = new QVBoxLayout( frame4, 6, 3, "frame4Layout"); + + m_labelJob = new K3bThemedLabel( frame4 ); + m_labelJob->setMinimumVisibleText( 40 ); + QFont m_labelJob_font( m_labelJob->font() ); + m_labelJob_font.setPointSize( m_labelJob_font.pointSize() + 2 ); + m_labelJob_font.setBold( true ); + m_labelJob->setFont( m_labelJob_font ); + m_labelJob->setAlignment( int( QLabel::AlignVCenter | QLabel::AlignRight ) ); + frame4Layout->addWidget( m_labelJob ); + + m_labelJobDetails = new K3bThemedLabel( frame4 ); + m_labelJobDetails->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)5, (QSizePolicy::SizeType)5, 0, 1, m_labelJobDetails->sizePolicy().hasHeightForWidth() ) ); + m_labelJobDetails->setAlignment( int( QLabel::AlignVCenter | QLabel::AlignRight ) ); + frame4Layout->addWidget( m_labelJobDetails ); + headerLayout->addWidget( frame4 ); + + mainLayout->addWidget( headerFrame ); + // ------------------------------------------------------------------------------------------ + + + m_viewInfo = new KListView( this, "m_viewInfo" ); + m_viewInfo->addColumn( "" ); + m_viewInfo->addColumn( i18n( "Message" ) ); + m_viewInfo->setFullWidth( true ); + m_viewInfo->header()->hide(); + m_viewInfo->setSorting(-1); + mainLayout->addWidget( m_viewInfo ); + + + // progress header + // ------------------------------------------------------------------------------------------ + QFrame* progressHeaderFrame = new QFrame( this, "progressHeaderFrame" ); + progressHeaderFrame->setFrameShape( QFrame::StyledPanel ); + progressHeaderFrame->setFrameShadow( QFrame::Sunken ); + progressHeaderFrame->setLineWidth( 1 ); + progressHeaderFrame->setMargin( 1 ); + + QHBoxLayout* progressHeaderLayout = new QHBoxLayout( progressHeaderFrame ); + progressHeaderLayout->setMargin( 2 ); + progressHeaderLayout->setSpacing( 0 ); + + QFrame* frame5 = new QFrame( progressHeaderFrame, "frame5" ); + frame5->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)5, (QSizePolicy::SizeType)5, 1, 0, frame5->sizePolicy().hasHeightForWidth() ) ); + frame5->setFrameShape( QFrame::NoFrame ); + frame5->setFrameShadow( QFrame::Raised ); + QVBoxLayout* frame5Layout = new QVBoxLayout( frame5, 6, 3, "frame5Layout"); + + m_labelTask = new K3bThemedLabel( frame5 ); + QFont m_labelTask_font( m_labelTask->font() ); + m_labelTask_font.setPointSize( m_labelTask_font.pointSize() + 2 ); + m_labelTask_font.setBold( true ); + m_labelTask->setFont( m_labelTask_font ); + frame5Layout->addWidget( m_labelTask ); + + m_labelElapsedTime = new K3bThemedLabel( frame5 ); + m_labelElapsedTime->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)5, (QSizePolicy::SizeType)5, 0, 1, m_labelElapsedTime->sizePolicy().hasHeightForWidth() ) ); + frame5Layout->addWidget( m_labelElapsedTime ); + progressHeaderLayout->addWidget( frame5 ); + + progressHeaderLayout->addWidget( new K3bThemedLabel( K3bTheme::PROGRESS_RIGHT, progressHeaderFrame ) ); + mainLayout->addWidget( progressHeaderFrame ); + // ------------------------------------------------------------------------------------------ + + QHBoxLayout* layout3 = new QHBoxLayout( 0, 0, 6, "layout3"); + + m_labelSubTask = new KCutLabel( this, "m_labelSubTask" ); + layout3->addWidget( m_labelSubTask ); + + m_labelSubProcessedSize = new QLabel( this, "m_labelSubProcessedSize" ); + m_labelSubProcessedSize->setAlignment( int( QLabel::AlignVCenter | QLabel::AlignRight ) ); + layout3->addWidget( m_labelSubProcessedSize ); + mainLayout->addLayout( layout3 ); + + m_progressSubPercent = new KProgress( this, "m_progressSubPercent" ); + mainLayout->addWidget( m_progressSubPercent ); + + QHBoxLayout* layout4 = new QHBoxLayout( 0, 0, 6, "layout4"); + + QLabel* textLabel5 = new QLabel( i18n("Overall progress:"), this, "textLabel5" ); + layout4->addWidget( textLabel5 ); + + m_labelProcessedSize = new QLabel( this, "m_labelProcessedSize" ); + m_labelProcessedSize->setAlignment( int( QLabel::AlignVCenter | QLabel::AlignRight ) ); + layout4->addWidget( m_labelProcessedSize ); + mainLayout->addLayout( layout4 ); + + m_progressPercent = new KProgress( this, "m_progressPercent" ); + mainLayout->addWidget( m_progressPercent ); + + m_frameExtraInfo = new QFrame( this, "m_frameExtraInfo" ); + m_frameExtraInfo->setFrameShape( QFrame::NoFrame ); + m_frameExtraInfo->setFrameShadow( QFrame::Raised ); + m_frameExtraInfoLayout = new QGridLayout( m_frameExtraInfo ); + m_frameExtraInfoLayout->setMargin(0); + m_frameExtraInfoLayout->setSpacing( spacingHint() ); + mainLayout->addWidget( m_frameExtraInfo ); + + QFrame* line2 = new QFrame( this, "line2" ); + line2->setFrameShape( QFrame::HLine ); + line2->setFrameShadow( QFrame::Sunken ); + mainLayout->addWidget( line2 ); + + QHBoxLayout* layout5 = new QHBoxLayout( 0, 0, 6, "layout5"); + QSpacerItem* spacer = new QSpacerItem( 10, 10, QSizePolicy::Expanding, QSizePolicy::Minimum ); + layout5->addItem( spacer ); + + m_buttonCancel = new KPushButton( KStdGuiItem::cancel(), this, "m_buttonCancel" ); + layout5->addWidget( m_buttonCancel ); + m_buttonClose = new KPushButton( KStdGuiItem::close(), this ); + layout5->addWidget( m_buttonClose ); + m_buttonShowDebug = new QPushButton( i18n("Show Debugging Output"), this ); + layout5->addWidget( m_buttonShowDebug ); + + mainLayout->addLayout( layout5 ); + + m_pixLabel->setThemePixmap( K3bTheme::PROGRESS_WORKING ); + + slotThemeChanged(); + + connect( k3bappcore->themeManager(), SIGNAL(themeChanged()), + this, SLOT(slotThemeChanged()) ); + connect( kapp, SIGNAL(appearanceChanged()), + this, SLOT(slotThemeChanged()) ); +} + + +void K3bJobProgressDialog::show() +{ + if( KConfigGroup( k3bcore->config(), "General Options" ).readBoolEntry( "hide main window while writing", false ) ) + if( QWidget* w = kapp->mainWidget() ) + w->hide(); + + if( m_osd ) { + m_osd->readSettings( k3bcore->config() ); + m_osd->show(); + } + + KDialog::show(); +} + + +void K3bJobProgressDialog::setExtraInfo( QWidget *extra ) +{ + extra->reparent( m_frameExtraInfo, QPoint(0,0) ); + m_frameExtraInfoLayout->addWidget( extra, 0, 0 ); +} + + +void K3bJobProgressDialog::closeEvent( QCloseEvent* e ) +{ + if( m_buttonClose->isVisible() ) { + KDialog::closeEvent( e ); + if( QWidget* w = kapp->mainWidget() ) + w->show(); + + if( !m_plainCaption.isEmpty() ) + if( KMainWindow* w = dynamic_cast<KMainWindow*>(kapp->mainWidget()) ) + w->setPlainCaption( m_plainCaption ); + + if( m_osd ) { + m_osd->hide(); + m_osd->saveSettings( kapp->config() ); + } + } + else + e->ignore(); +} + + +void K3bJobProgressDialog::setupConnections() +{ + connect( m_buttonCancel, SIGNAL(clicked()), this, SLOT(slotCancelButtonPressed()) ); + connect( m_buttonClose, SIGNAL(clicked()), this, SLOT(close()) ); + connect( m_buttonShowDebug, SIGNAL(clicked()), this, SLOT(slotShowDebuggingOutput()) ); +} + + +void K3bJobProgressDialog::slotProcessedSize( int processed, int size ) +{ + m_labelProcessedSize->setText( i18n("%1 of %2 MB").arg( processed ).arg( size ) ); +} + + +void K3bJobProgressDialog::slotProcessedSubSize( int processedTrackSize, int trackSize ) +{ + m_labelSubProcessedSize->setText( i18n("%1 of %2 MB").arg(processedTrackSize).arg(trackSize) ); +} + + +void K3bJobProgressDialog::slotInfoMessage( const QString& infoString, int type ) +{ + QListViewItem* currentInfoItem = new QListViewItem( m_viewInfo, m_viewInfo->lastItem(), QString::null, infoString ); + currentInfoItem->setSelectable( false ); + + // set the icon + switch( type ) { + case K3bJob::ERROR: + currentInfoItem->setPixmap( 0, SmallIcon( "stop" ) ); + break; + case K3bJob::WARNING: + currentInfoItem->setPixmap( 0, SmallIcon( "yellowinfo" ) ); + break; + case K3bJob::SUCCESS: + currentInfoItem->setPixmap( 0, SmallIcon( "ok" ) ); + break; + case K3bJob::INFO: + default: + currentInfoItem->setPixmap( 0, SmallIcon( "info" ) ); + } + + // This should scroll down (hopefully!) + m_viewInfo->ensureItemVisible( currentInfoItem ); +} + + +void K3bJobProgressDialog::slotFinished( bool success ) +{ + kdDebug() << "(K3bJobProgressDialog) received finished signal!" << endl; + + m_logFile.close(); + + if( success ) { + m_pixLabel->setThemePixmap( K3bTheme::PROGRESS_SUCCESS ); + + m_labelTask->setText( i18n("Success.") ); + m_labelTask->setPaletteForegroundColor( Qt::darkGreen ); + m_labelSubTask->setText( QString::null ); + + m_progressPercent->setValue(100); + m_progressSubPercent->setValue(100); + slotProgress(100); + + // one last time update to be sure no remaining time is displayed anymore + slotUpdateTime(); + + if( m_osd ) + m_osd->setText( i18n("Success.") ); + + KNotifyClient::event( 0, "SuccessfullyFinished", i18n("Successfully finished.") ); + } + else { + m_pixLabel->setThemePixmap( K3bTheme::PROGRESS_FAIL ); + + m_labelTask->setPaletteForegroundColor( Qt::red ); + + if( m_bCanceled ) { + m_labelTask->setText( i18n("Canceled.") ); + if( m_osd ) + m_osd->setText( i18n("Canceled.") ); + } + else { + m_labelTask->setText( i18n("Error.") ); + if( m_osd ) + m_osd->setText( i18n("Error.") ); + } + + KNotifyClient::event( 0, "FinishedWithError", i18n("Finished with errors") ); + } + + m_buttonCancel->hide(); + m_buttonShowDebug->show(); + m_buttonClose->show(); + m_timer->stop(); +} + + +void K3bJobProgressDialog::slotCanceled() +{ + m_bCanceled = true; +} + + +void K3bJobProgressDialog::setJob( K3bJob* job ) +{ + m_bCanceled = false; + + // clear everything + m_buttonClose->hide(); + m_buttonShowDebug->hide(); + m_buttonCancel->show(); + m_buttonCancel->setEnabled(true); + m_viewInfo->clear(); + m_progressPercent->setValue(0); + m_progressSubPercent->setValue(0); + m_labelTask->setText(""); + m_labelSubTask->setText(""); + m_labelProcessedSize->setText(""); + m_labelSubProcessedSize->setText(""); + m_labelTask->setPaletteForegroundColor( k3bappcore->themeManager()->currentTheme()->foregroundColor() ); + m_debugOutputMap.clear(); + + // disconnect from the former job + if( m_job ) + disconnect( m_job ); + m_job = job; + + if( job ) { + + // connect to all the shit + connect( job, SIGNAL(infoMessage(const QString&,int)), this, SLOT(slotInfoMessage(const QString&,int)) ); + + connect( job, SIGNAL(percent(int)), m_progressPercent, SLOT(setValue(int)) ); + connect( job, SIGNAL(percent(int)), this, SLOT(slotProgress(int)) ); + connect( job, SIGNAL(subPercent(int)), m_progressSubPercent, SLOT(setValue(int)) ); + + connect( job, SIGNAL(processedSubSize(int, int)), this, SLOT(slotProcessedSubSize(int, int)) ); + connect( job, SIGNAL(processedSize(int, int)), this, SLOT(slotProcessedSize(int, int)) ); + + connect( job, SIGNAL(newTask(const QString&)), this, SLOT(slotNewTask(const QString&)) ); + connect( job, SIGNAL(newSubTask(const QString&)), this, SLOT(slotNewSubTask(const QString&)) ); + connect( job, SIGNAL(started()), this, SLOT(slotStarted()) ); + connect( job, SIGNAL(finished(bool)), this, SLOT(slotFinished(bool)) ); + connect( job, SIGNAL(canceled()), this, SLOT(slotCanceled()) ); + + connect( job, SIGNAL(debuggingOutput(const QString&, const QString&)), + this, SLOT(slotDebuggingOutput(const QString&, const QString&)) ); + + m_labelJob->setText( m_job->jobDescription() ); + m_labelJobDetails->setText( m_job->jobDetails() ); + + setCaption( m_job->jobDescription() ); + + if( KConfigGroup( k3bcore->config(), "General Options" ).readBoolEntry( "Show progress OSD", true ) ) { + if( !m_osd ) + m_osd = new K3bJobProgressOSD( this, "progressosd" ); + } + else + delete m_osd; + + if( m_osd ) { + m_osd->setText( job->jobDescription() ); + // FIXME: use a setJob method and let the osd also change the text color to red/green + // connect( job, SIGNAL(newTask(const QString&)), m_osd, SLOT(setText(const QString&)) ); + connect( job, SIGNAL(percent(int)), m_osd, SLOT(setProgress(int)) ); + } + } +} + + +void K3bJobProgressDialog::slotCancelButtonPressed() +{ + if( m_job ) + if( KMessageBox::questionYesNo( this, i18n("Do you really want to cancel?"), i18n("Cancel Confirmation") ) == KMessageBox::Yes ) { + if( m_job ) { + m_job->cancel(); + m_buttonCancel->setDisabled(true); // do not cancel twice + } + } +} + + +void K3bJobProgressDialog::slotNewSubTask(const QString& name) +{ + m_labelSubTask->setText(name); + m_labelSubProcessedSize->setText(""); + m_progressSubPercent->setValue(0); +} + +void K3bJobProgressDialog::slotNewTask(const QString& name) +{ + m_labelTask->setText( name ); +} + + +void K3bJobProgressDialog::slotStarted() +{ + d->lastProgress = 0; + m_timer->start( 1000 ); + m_startTime = QTime::currentTime(); + if( KMainWindow* w = dynamic_cast<KMainWindow*>(kapp->mainWidget()) ) + m_plainCaption = w->caption(); + + m_logFile.open(); +} + + +void K3bJobProgressDialog::slotUpdateTime() +{ + int elapsed = m_startTime.secsTo( QTime::currentTime() ); + + QString s = i18n("Elapsed time: %1 h").arg( QTime().addSecs(elapsed).toString() ); + if( d->lastProgress > 0 && d->lastProgress < 100 ) { + int rem = m_startTime.secsTo( m_lastProgressUpdateTime ) * (100-d->lastProgress) / d->lastProgress; + s += " / " + i18n("Remaining: %1 h").arg( QTime().addSecs(rem).toString() ); + } + + m_labelElapsedTime->setText( s ); +} + + +void K3bJobProgressDialog::slotDebuggingOutput( const QString& type, const QString& output ) +{ + m_debugOutputMap[type].append(output); + m_logFile.addOutput( type, output ); +} + + +void K3bJobProgressDialog::slotShowDebuggingOutput() +{ + K3bDebuggingOutputDialog debugWidget( this ); + debugWidget.setOutput( m_debugOutputMap ); + debugWidget.exec(); +} + + +void K3bJobProgressDialog::slotProgress( int percent ) +{ + if( percent > d->lastProgress ) { + d->lastProgress = percent; + m_lastProgressUpdateTime = QTime::currentTime(); + if( KMainWindow* w = dynamic_cast<KMainWindow*>(kapp->mainWidget()) ) { + w->setPlainCaption( QString( "(%1%) %2" ).arg(percent).arg(m_plainCaption) ); + } + + setCaption( QString( "(%1%) %2" ).arg(percent).arg(m_job->jobDescription()) ); + } +} + + +void K3bJobProgressDialog::keyPressEvent( QKeyEvent *e ) +{ + e->accept(); + + switch ( e->key() ) { + case Key_Enter: + case Key_Return: + // if the process finished this closes the dialog + if( m_buttonClose->isVisible() ) + close(); + break; + case Key_Escape: + // simulate button clicks + if( m_buttonCancel->isVisible() && m_buttonCancel->isEnabled() ) + slotCancelButtonPressed(); + else if( !m_buttonCancel->isVisible() ) + close(); + break; + default: + // nothing + break; + } +} + + +QSize K3bJobProgressDialog::sizeHint() const +{ + QSize s = layout()->totalSizeHint(); + if( s.width() < s.height() ) + s.setWidth( s.height() ); + return s; +} + + +int K3bJobProgressDialog::startJob( K3bJob* job ) +{ + if( job ) { + setJob( job ); + k3bappcore->jobInterface()->setJob( job ); + } + else if( !m_job ) { + kdError() << "(K3bJobProgressDialog) null job!" << endl; + return -1; + } + + // the following code is mainly taken from QDialog::exec + + if ( in_loop ) { + kdError() << "(K3bJobProgressDialog::startJob) Recursive call detected." << endl; + return -1; + } + + bool destructiveClose = testWFlags( WDestructiveClose ); + clearWFlags( WDestructiveClose ); + + bool wasShowModal = testWFlags( WShowModal ); + setWFlags( WShowModal ); + setResult( 0 ); + + show(); + + // start the job after showing the dialog + m_job->start(); + + in_loop = true; + QApplication::eventLoop()->enterLoop(); + + if ( !wasShowModal ) + clearWFlags( WShowModal ); + + int res = result(); + + if ( destructiveClose ) + delete this; + + return res; +} + + +void K3bJobProgressDialog::hide() +{ + // we need to reimplement this since + // QDialog does not know if we are in a loop from startJob + + if ( isHidden() ) + return; + + KDialog::hide(); + + if ( in_loop ) { + in_loop = FALSE; + QApplication::eventLoop()->exitLoop(); + } +} + + +int K3bJobProgressDialog::waitForMedia( K3bDevice::Device* device, + int mediaState, + int mediaType, + const QString& message ) +{ + return K3bEmptyDiscWaiter::wait( device, mediaState, mediaType, message, this ); +} + + +bool K3bJobProgressDialog::questionYesNo( const QString& text, + const QString& caption, + const QString& yesText, + const QString& noText ) +{ + return ( KMessageBox::questionYesNo( this, + text, + caption, + yesText.isEmpty() ? KStdGuiItem::yes() : KGuiItem(yesText), + noText.isEmpty() ? KStdGuiItem::no() : KGuiItem(noText) ) == KMessageBox::Yes ); +} + + +void K3bJobProgressDialog::blockingInformation( const QString& text, + const QString& caption ) +{ + KMessageBox::information( this, text, caption ); +} + + +void K3bJobProgressDialog::slotThemeChanged() +{ + if( K3bTheme* theme = k3bappcore->themeManager()->currentTheme() ) { + static_cast<QWidget*>(child( "frame4" ))->setPaletteBackgroundColor( theme->backgroundColor() ); + static_cast<QWidget*>(child( "frame4" ))->setPaletteForegroundColor( theme->backgroundColor() ); + static_cast<QWidget*>(child( "frame5" ))->setPaletteBackgroundColor( theme->backgroundColor() ); + static_cast<QWidget*>(child( "frame5" ))->setPaletteForegroundColor( theme->backgroundColor() ); + static_cast<QWidget*>(child( "progressHeaderFrame" ))->setPaletteBackgroundColor( theme->backgroundColor() ); + static_cast<QWidget*>(child( "progressHeaderFrame" ))->setPaletteForegroundColor( theme->backgroundColor() ); + static_cast<QWidget*>(child( "headerFrame" ))->setPaletteBackgroundColor( theme->backgroundColor() ); + static_cast<QWidget*>(child( "headerFrame" ))->setPaletteForegroundColor( theme->backgroundColor() ); + } +} + +#include "k3bjobprogressdialog.moc" diff --git a/src/k3bjobprogressdialog.h b/src/k3bjobprogressdialog.h new file mode 100644 index 0000000..5bc1af2 --- /dev/null +++ b/src/k3bjobprogressdialog.h @@ -0,0 +1,173 @@ +/* + * + * $Id: k3bjobprogressdialog.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_JOB_PROGRESSDIALOG_H_ +#define _K3B_JOB_PROGRESSDIALOG_H_ + +#include <kdialog.h> + +#include "k3bdebuggingoutputfile.h" + +#include <k3bjobhandler.h> + +#include <qdatetime.h> +#include <qfile.h> + +class QVBoxLayout; +class QHBoxLayout; +class QGridLayout; +class KListView; +class QFrame; +class QGroupBox; +class QLabel; +class QListViewItem; +class KProgress; +class QPushButton; +class QTimer; +class K3bJob; +class KCutLabel; +class QCloseEvent; +class QGridLayout; +class QKeyEvent; +class K3bJobProgressOSD; +class K3bThemedLabel; + + +class K3bJobProgressDialog : public KDialog, public K3bJobHandler +{ + Q_OBJECT + + public: + K3bJobProgressDialog( QWidget* parent = 0, + const char* name = 0, + bool showSubProgress = true, + bool modal = FALSE, + WFlags fl = 0 ); + virtual ~K3bJobProgressDialog(); + + virtual void setJob( K3bJob* job ); + void setExtraInfo( QWidget *extra ); + + /** + * reimplemented for internal reasons + */ + void show(); + + /** + * reimplemented for internal reasons + */ + void hide(); + + /** + * This will show the dialog and then start the given job or + * if job == 0 the job set with setJob + * Use instead of exec() + */ + int startJob( K3bJob* job = 0 ); + + QSize sizeHint() const; + + /** + * @reimplemented from K3bJobHandler + */ + int waitForMedia( K3bDevice::Device*, + int mediaState = K3bDevice::STATE_EMPTY, + int mediaType = K3bDevice::MEDIA_WRITABLE_CD, + const QString& message = QString::null ); + + /** + * @reimplemented from K3bJobHandler + */ + bool questionYesNo( const QString& text, + const QString& caption = QString::null, + const QString& yesText = QString::null, + const QString& noText = QString::null ); + + /** + * reimplemented from K3bJobHandler + */ + void blockingInformation( const QString& text, + const QString& caption = QString::null ); + + protected slots: + virtual void slotProcessedSize( int processed, int size ); + virtual void slotProcessedSubSize( int processed, int size ); + virtual void slotInfoMessage( const QString& infoString, int type ); + virtual void slotDebuggingOutput( const QString&, const QString& ); + virtual void slotNewSubTask(const QString& name); + virtual void slotNewTask(const QString& name); + virtual void slotFinished(bool); + virtual void slotCanceled(); + virtual void slotStarted(); + + + void slotCancelButtonPressed(); + void slotUpdateTime(); + void slotShowDebuggingOutput(); + + void slotProgress( int ); + + virtual void slotThemeChanged(); + + protected: + void closeEvent( QCloseEvent* ); + void keyPressEvent( QKeyEvent* e ); + + void setupGUI(); + void setupConnections(); + + K3bThemedLabel* m_labelJob; + K3bThemedLabel* m_labelJobDetails; + KListView* m_viewInfo; + K3bThemedLabel* m_labelTask; + K3bThemedLabel* m_labelElapsedTime; + KCutLabel* m_labelSubTask; + QLabel* m_labelSubProcessedSize; + KProgress* m_progressSubPercent; + QLabel* m_labelProcessedSize; + KProgress* m_progressPercent; + QFrame* m_frameExtraInfo; + QPushButton* m_buttonCancel; + QPushButton* m_buttonClose; + QPushButton* m_buttonShowDebug; + K3bThemedLabel* m_pixLabel; + + QGridLayout* m_frameExtraInfoLayout; + + private: + class Private; + Private* d; + + K3bJob* m_job; + QTimer* m_timer; + QTime m_startTime; + QTime m_lastProgressUpdateTime; + + K3bDebuggingOutputFile m_logFile; + + QMap<QString, QStringList> m_debugOutputMap; + + bool m_bCanceled; + + QString m_plainCaption; + + bool in_loop; + + K3bJobProgressOSD* m_osd; +}; + + +#endif diff --git a/src/k3bjobprogressosd.cpp b/src/k3bjobprogressosd.cpp new file mode 100644 index 0000000..0797c3a --- /dev/null +++ b/src/k3bjobprogressosd.cpp @@ -0,0 +1,303 @@ +/* + * + * $Id: k3bjobprogressosd.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bjobprogressosd.h" + +#include <k3bthememanager.h> +#include <k3bapplication.h> + +#include <kwin.h> +#include <kiconloader.h> +#include <kdebug.h> +#include <kcursor.h> +#include <kconfig.h> +#include <klocale.h> +#include <kpopupmenu.h> + +#include <qpixmap.h> +#include <qpainter.h> +#include <qapplication.h> + +#include <X11/Xlib.h> + + +K3bJobProgressOSD::K3bJobProgressOSD( QWidget* parent, const char* name ) + : QWidget( parent, name, WType_TopLevel | WNoAutoErase | WStyle_Customize | WX11BypassWM | WStyle_StaysOnTop ), + m_dirty(true), + m_progress(0), + m_dragging(false), + m_screen(0), + m_position(s_outerMargin, s_outerMargin) +{ + setFocusPolicy( NoFocus ); + setBackgroundMode( NoBackground ); + + // dummy size + resize( 20, 20 ); + + // make sure we are always visible + KWin::setOnAllDesktops( winId(), true ); + + connect( k3bappcore->themeManager(), SIGNAL(themeChanged()), + this, SLOT(refresh()) ); + connect( kapp, SIGNAL(appearanceChanged()), + this, SLOT(refresh()) ); +} + + +K3bJobProgressOSD::~K3bJobProgressOSD() +{ +} + + +void K3bJobProgressOSD::show() +{ + // start with 0 progress + setProgress(0); + + if( m_dirty ) + renderOSD(); + + QWidget::show(); +} + + +void K3bJobProgressOSD::setText( const QString& text ) +{ + if( m_text != text ) { + m_text = text; + refresh(); + } +} + + +void K3bJobProgressOSD::setProgress( int p ) +{ + if( m_progress != p ) { + m_progress = p; + refresh(); + } +} + + +void K3bJobProgressOSD::setPosition( const QPoint& p ) +{ + m_position = p; + reposition(); +} + + +void K3bJobProgressOSD::refresh() +{ + if( isVisible() ) + renderOSD(); + else + m_dirty = true; +} + + +void K3bJobProgressOSD::renderOSD() +{ + // ---------------------------------------- + // | Copying CD | + // | K3B ========== 40% | + // | | + // ---------------------------------------- + + // calculate needed size + if( K3bTheme* theme = k3bappcore->themeManager()->currentTheme() ) { + QPixmap icon = KGlobal::iconLoader()->loadIcon( "k3b", KIcon::NoGroup, 32 ); + int margin = 10; + int textWidth = fontMetrics().width( m_text ); + + // do not change the size every time the text changes, just in case we are too small + QSize newSize( QMAX( QMAX( 2*margin + icon.width() + margin + textWidth, 100 ), width() ), + QMAX( 2*margin + icon.height(), 2*margin + fontMetrics().height()*2 ) ); + + m_osdBuffer.resize( newSize ); + QPainter p( &m_osdBuffer ); + + p.setPen( theme->foregroundColor() ); + + // draw the background and the frame + QRect thisRect( 0, 0, newSize.width(), newSize.height() ); + p.fillRect( thisRect, theme->backgroundColor() ); + p.drawRect( thisRect ); + + // draw the k3b icon + p.drawPixmap( margin, (newSize.height()-icon.height())/2, icon ); + + // draw the text + QSize textSize = fontMetrics().size( 0, m_text ); + int textX = 2*margin + icon.width(); + int textY = margin + fontMetrics().ascent(); + p.drawText( textX, textY, m_text ); + + // draw the progress + textY += fontMetrics().descent() + 4; + QRect progressRect( textX, textY, newSize.width()-textX-margin, newSize.height()-textY-margin ); + p.drawRect( progressRect ); + progressRect.setWidth( m_progress > 0 ? m_progress*progressRect.width()/100 : 0 ); + p.fillRect( progressRect, theme->foregroundColor() ); + + // reposition the osd + reposition( newSize ); + + m_dirty = false; + + update(); + } +} + + +void K3bJobProgressOSD::setScreen( int screen ) +{ + const int n = QApplication::desktop()->numScreens(); + m_screen = (screen >= n) ? n-1 : screen; + reposition(); +} + + +void K3bJobProgressOSD::reposition( QSize newSize ) +{ + if( !newSize.isValid() ) + newSize = size(); + + QPoint newPos = m_position; + const QRect& screen = QApplication::desktop()->screenGeometry( m_screen ); + + // now to properly resize if put into one of the corners we interpret the position + // depending on the quadrant + int midH = screen.width()/2; + int midV = screen.height()/2; + if( newPos.x() > midH ) + newPos.rx() -= newSize.width(); + if( newPos.y() > midV ) + newPos.ry() -= newSize.height(); + + newPos = fixupPosition( newPos ); + + // correct for screen position + newPos += screen.topLeft(); + + // ensure we are painted before we move + if( isVisible() ) + paintEvent( 0 ); + + // fancy X11 move+resize, reduces visual artifacts + XMoveResizeWindow( x11Display(), winId(), newPos.x(), newPos.y(), newSize.width(), newSize.height() ); +} + + +void K3bJobProgressOSD::paintEvent( QPaintEvent* ) +{ + bitBlt( this, 0, 0, &m_osdBuffer ); +} + + +void K3bJobProgressOSD::mousePressEvent( QMouseEvent* e ) +{ + m_dragOffset = e->pos(); + + if( e->button() == LeftButton && !m_dragging ) { + grabMouse( KCursor::sizeAllCursor() ); + m_dragging = true; + } + else if( e->button() == RightButton ) { + KPopupMenu m; + if( m.insertItem( i18n("Hide OSD") ) == m.exec( e->globalPos() ) ) + hide(); + } +} + + +void K3bJobProgressOSD::mouseReleaseEvent( QMouseEvent* ) +{ + if( m_dragging ) { + m_dragging = false; + releaseMouse(); + } +} + + +void K3bJobProgressOSD::mouseMoveEvent( QMouseEvent* e ) +{ + if( m_dragging && this == mouseGrabber() ) { + + // check if the osd has been dragged out of the current screen + int currentScreen = QApplication::desktop()->screenNumber( e->globalPos() ); + if( currentScreen != -1 ) + m_screen = currentScreen; + + const QRect& screen = QApplication::desktop()->screenGeometry( m_screen ); + + // make sure the position is valid + m_position = fixupPosition( e->globalPos() - m_dragOffset - screen.topLeft() ); + + // move us to the new position + move( m_position ); + + // fix the position + int midH = screen.width()/2; + int midV = screen.height()/2; + if( m_position.x() + width() > midH ) + m_position.rx() += width(); + if( m_position.y() + height() > midV ) + m_position.ry() += height(); + } +} + + +QPoint K3bJobProgressOSD::fixupPosition( const QPoint& pp ) +{ + QPoint p(pp); + const QRect& screen = QApplication::desktop()->screenGeometry( m_screen ); + int maxY = screen.height() - height() - s_outerMargin; + int maxX = screen.width() - width() - s_outerMargin; + + if( p.y() < s_outerMargin ) + p.ry() = s_outerMargin; + else if( p.y() > maxY ) + p.ry() = maxY; + + if( p.x() < s_outerMargin ) + p.rx() = s_outerMargin; + else if( p.x() > maxX ) + p.rx() = screen.width() - s_outerMargin - width(); + + p += screen.topLeft(); + + return p; +} + + +void K3bJobProgressOSD::readSettings( KConfigBase* c ) +{ + KConfigGroup grp( c, "OSD Position" ); + + setPosition( grp.readPointEntry( "Position", 0 ) ); + setScreen( grp.readNumEntry( "Screen", 0 ) ); +} + + +void K3bJobProgressOSD::saveSettings( KConfigBase* c ) +{ + KConfigGroup grp( c, "OSD Position" ); + + grp.writeEntry( "Position", m_position ); + grp.writeEntry( "Screen", m_screen ); +} + +#include "k3bjobprogressosd.moc" diff --git a/src/k3bjobprogressosd.h b/src/k3bjobprogressosd.h new file mode 100644 index 0000000..1bb9221 --- /dev/null +++ b/src/k3bjobprogressosd.h @@ -0,0 +1,88 @@ +/* + * + * $Id: k3bjobprogressosd.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_JOB_PROGRESS_OSD_H_ +#define _K3B_JOB_PROGRESS_OSD_H_ + +#include <qwidget.h> +#include <qpixmap.h> + +class QPaintEvent; +class QMouseEvent; +class KConfigBase; + +/** + * An OSD displaying a text and a progress bar. + * + * Insprired by Amarok's OSD (I also took a bit of their code. :) + */ +class K3bJobProgressOSD : public QWidget +{ + Q_OBJECT + + public: + K3bJobProgressOSD( QWidget* parent = 0, const char* name = 0 ); + ~K3bJobProgressOSD(); + + int screen() const { return m_screen; } + const QPoint& position() const { return m_position; } + + void readSettings( KConfigBase* ); + void saveSettings( KConfigBase* ); + + public slots: + void setScreen( int ); + void setText( const QString& ); + void setProgress( int ); + + /** + * The position refers to one of the corners of the widget + * regarding on the value of the x and y coordinate. + * If for example the x coordinate is bigger than half the screen + * width it refers to the left edge of the widget. + */ + void setPosition( const QPoint& ); + + void show(); + + protected: + void paintEvent( QPaintEvent* ); + void mousePressEvent( QMouseEvent* ); + void mouseReleaseEvent( QMouseEvent* ); + void mouseMoveEvent( QMouseEvent* ); + void renderOSD(); + void reposition( QSize size = QSize() ); + + protected slots: + void refresh(); + + private: + /** + * Ensure that the position is inside m_screen + */ + QPoint fixupPosition( const QPoint& p ); + static const int s_outerMargin = 15; + + QPixmap m_osdBuffer; + bool m_dirty; + QString m_text; + int m_progress; + bool m_dragging; + QPoint m_dragOffset; + int m_screen; + QPoint m_position; +}; + +#endif diff --git a/src/k3blsofwrapper.cpp b/src/k3blsofwrapper.cpp new file mode 100644 index 0000000..56d5d5b --- /dev/null +++ b/src/k3blsofwrapper.cpp @@ -0,0 +1,108 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3blsofwrapper.h" + +#include <k3bdevice.h> +#include <k3bprocess.h> +#include <k3bglobals.h> + +#include <qfile.h> +#include <qfileinfo.h> + +#include <sys/types.h> +#include <unistd.h> + +static K3bLsofWrapper::Process createProcess( const QString& name, int pid ) +{ + K3bLsofWrapper::Process p; + p.name = name; + p.pid = pid; + return p; +} + + +class K3bLsofWrapper::Private +{ +public: + QValueList<Process> apps; + QString lsofBin; +}; + + +K3bLsofWrapper::K3bLsofWrapper() +{ + d = new Private; +} + + +K3bLsofWrapper::~K3bLsofWrapper() +{ + delete d; +} + + +bool K3bLsofWrapper::checkDevice( K3bDevice::Device* dev ) +{ + d->apps.clear(); + + if( !findLsofExecutable() ) + return false; + + // run lsof + KProcess p; + K3bProcessOutputCollector out( &p ); + + // + // We use the following output form: + // p<PID> + // c<COMMAND_NAME> + // + p << d->lsofBin << "-Fpc" << dev->blockDeviceName(); + + if( !p.start( KProcess::Block, KProcess::Stdout ) ) + return false; + + // + // now process its output + QStringList l = QStringList::split( "\n", out.output() ); + for( QStringList::iterator it = l.begin(); it != l.end(); ++it ) { + int pid = (*it).mid(1).toInt(); + QString app = (*(++it)).mid(1); + + kdDebug() << "(K3bLsofWrapper) matched: app: " << app << " pid: " << pid << endl; + + // we don't care about ourselves using the device ;) + if( pid != (int)::getpid() ) + d->apps.append( createProcess( app, pid ) ); + } + + return true; +} + + +const QValueList<K3bLsofWrapper::Process>& K3bLsofWrapper::usingApplications() const +{ + return d->apps; +} + + +bool K3bLsofWrapper::findLsofExecutable() +{ + if( d->lsofBin.isEmpty() ) + d->lsofBin = K3b::findExe( "lsof" ); + + return !d->lsofBin.isEmpty(); +} diff --git a/src/k3blsofwrapper.h b/src/k3blsofwrapper.h new file mode 100644 index 0000000..8ab11dc --- /dev/null +++ b/src/k3blsofwrapper.h @@ -0,0 +1,60 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_LSOF_WRAPPER_H_ +#define _K3B_LSOF_WRAPPER_H_ + +#include <qvaluelist.h> + +namespace K3bDevice { + class Device; +} + + +class K3bLsofWrapper +{ + public: + K3bLsofWrapper(); + ~K3bLsofWrapper(); + + /** + * Checks which processes currently have an open file descriptor + * to the device. + * + * \return true if lsof was successfully called. + */ + bool checkDevice( K3bDevice::Device* ); + + struct Process { + QString name; + int pid; + }; + + /** + * \return A list of all applications that had an open + * handle on the device used in the last successful call + * to checkDevice. + */ + const QValueList<Process>& usingApplications() const; + + private: + bool findLsofExecutable(); + + class Private; + Private* d; +}; + +#endif + diff --git a/src/k3blsofwrapperdialog.cpp b/src/k3blsofwrapperdialog.cpp new file mode 100644 index 0000000..e081e38 --- /dev/null +++ b/src/k3blsofwrapperdialog.cpp @@ -0,0 +1,127 @@ +/* + * + * $Id: k3bapplication.cpp 567271 2006-07-28 13:19:18Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3blsofwrapperdialog.h" +#include "k3blsofwrapper.h" +#include <k3brichtextlabel.h> + +#include <k3bdevice.h> + +#include <kdebug.h> +#include <klocale.h> +#include <kmessagebox.h> + +#include <qpushbutton.h> + +#include <sys/types.h> +#include <signal.h> + + +static QString joinProcessNames( const QValueList<K3bLsofWrapper::Process>& apps ) +{ + QStringList l; + for( QValueList<K3bLsofWrapper::Process>::const_iterator it = apps.begin(); + it != apps.end(); ++it ) + l.append( (*it).name ); + return l.join( ", " ); +} + + +K3bLsofWrapperDialog::K3bLsofWrapperDialog( QWidget* parent ) + : KDialogBase( KDialogBase::Swallow, + i18n("Device in use"), + Close|User1|User2, + Close, + parent, + 0, + true, + true, + KGuiItem( i18n("Quit the other applications") ), + KGuiItem( i18n("Check again") ) ) +{ + setButtonText( Close, i18n("Continue") ); + + m_label = new K3bRichTextLabel( this ); + setMainWidget( m_label ); + + connect( this, SIGNAL(user1Clicked()), SLOT(slotQuitOtherApps()) ); + connect( this, SIGNAL(user2Clicked()), SLOT(slotCheckDevice()) ); +} + + +K3bLsofWrapperDialog::~K3bLsofWrapperDialog() +{ +} + + +bool K3bLsofWrapperDialog::slotCheckDevice() +{ + K3bLsofWrapper lsof; + if( lsof.checkDevice( m_device ) ) { + const QValueList<K3bLsofWrapper::Process>& apps = lsof.usingApplications(); + if( apps.count() > 0 ) { + m_label->setText( i18n("<p>Device <b>'%1'</b> is already in use by other applications " + "(<em>%2</em>)." + "<p>It is highly recommended to quit those before continuing. " + "Otherwise K3b might not be able to fully access the device." + "<p><em>Hint: Sometimes shutting down an application does not " + "happen instantly. In that case you might have to use the '%3' " + "button.") + .arg( m_device->vendor() + " - " + m_device->description() ) + .arg( joinProcessNames(apps) ) + .arg( actionButton( User2 )->text() ) ); + return true; + } + } + + // once no apps are running we can close the dialog + close(); + + return false; +} + + +void K3bLsofWrapperDialog::slotQuitOtherApps() +{ + K3bLsofWrapper lsof; + if( lsof.checkDevice( m_device ) ) { + const QValueList<K3bLsofWrapper::Process>& apps = lsof.usingApplications(); + if( apps.count() > 0 ) { + if( KMessageBox::warningYesNo( this, + i18n("<p>Do you really want K3b to kill the following processes: <em>") + + joinProcessNames(apps) ) == KMessageBox::Yes ) { + for( QValueList<K3bLsofWrapper::Process>::const_iterator it = apps.begin(); + it != apps.end(); ++it ) + ::kill( (*it).pid, SIGTERM ); + } + else + return; + } + } + + // after quitting the other applications recheck for running ones + slotCheckDevice(); +} + + +void K3bLsofWrapperDialog::checkDevice( K3bDevice::Device* dev, QWidget* parent ) +{ + K3bLsofWrapperDialog dlg( parent ); + dlg.m_device = dev; + if( dlg.slotCheckDevice() ) + dlg.exec(); +} + +#include "k3blsofwrapperdialog.moc" diff --git a/src/k3blsofwrapperdialog.h b/src/k3blsofwrapperdialog.h new file mode 100644 index 0000000..e00da0b --- /dev/null +++ b/src/k3blsofwrapperdialog.h @@ -0,0 +1,53 @@ +/* + * + * $Id: k3bapplication.cpp 567271 2006-07-28 13:19:18Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_LSOF_WRAPPER_DIALOG_H_ +#define _K3B_LSOF_WRAPPER_DIALOG_H_ + +#include <kdialogbase.h> + +class K3bRichTextLabel; +namespace K3bDevice { + class Device; +} + +class K3bLsofWrapperDialog : public KDialogBase +{ + Q_OBJECT + + public: + ~K3bLsofWrapperDialog(); + + /** + * Check if other applications are currently using the device and if so + * warn the user and provide a quick solution to shut down these other + * applications. + * + * If the device is not in use this method simply returns. + */ + static void checkDevice( K3bDevice::Device* dev, QWidget* parent = 0 ); + + private slots: + bool slotCheckDevice(); + void slotQuitOtherApps(); + + private: + K3bLsofWrapperDialog( QWidget* parent ); + + K3bDevice::Device* m_device; + K3bRichTextLabel* m_label; +}; + +#endif diff --git a/src/k3bmediacache.cpp b/src/k3bmediacache.cpp new file mode 100644 index 0000000..fa9f51b --- /dev/null +++ b/src/k3bmediacache.cpp @@ -0,0 +1,373 @@ +/* + * + * $Id: sourceheader 380067 2005-01-19 13:03:46Z trueg $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bmediacache.h" +#include "k3bmedium.h" + +#include <k3bdevicemanager.h> +#include <k3bdeviceglobals.h> +#include <k3bscsicommand.h> +#include <k3bcore.h> + +#include <kdebug.h> +#include <kapplication.h> +#include <klocale.h> + +#include <qthread.h> +#include <qmutex.h> +#include <qevent.h> + + +// //////////////////////////////////////////////////////////////////////////////// +// MEDIA CACHE SUPPORT CLASSES +// //////////////////////////////////////////////////////////////////////////////// + +class K3bMediaCache::MediaChangeEvent : public QCustomEvent +{ +public: + static const int EventCode; + + MediaChangeEvent( K3bDevice::Device* dev ) + : QCustomEvent( EventCode ), + m_device( dev ) {} + + K3bDevice::Device* device() const { return m_device; } + +private: + K3bDevice::Device* m_device; +}; + +const int K3bMediaCache::MediaChangeEvent::EventCode = QEvent::User + 22; + + +class K3bMediaCache::DeviceEntry +{ +public: + DeviceEntry( K3bMediaCache* cache, K3bDevice::Device* dev ); + ~DeviceEntry(); + + K3bMedium medium; + + int blockedId; + + QMutex mutex; + + K3bMediaCache::PollThread* thread; + + K3bMediaCache* cache; + + void clear() { + medium.reset(); + } +}; + + +class K3bMediaCache::PollThread : public QThread +{ +public: + PollThread( K3bMediaCache::DeviceEntry* de ) + : m_deviceEntry( de ) {} + +protected: + void run(); + +private: + K3bMediaCache::DeviceEntry* m_deviceEntry; +}; + + + + +// //////////////////////////////////////////////////////////////////////////////// +// MEDIA CACHE SUPPORT CLASSES IMPL +// //////////////////////////////////////////////////////////////////////////////// + + +K3bMediaCache::DeviceEntry::DeviceEntry( K3bMediaCache* c, K3bDevice::Device* dev ) + : medium(dev), + blockedId(0), + cache(c) +{ + thread = new K3bMediaCache::PollThread( this ); +} + + +K3bMediaCache::DeviceEntry::~DeviceEntry() +{ + delete thread; +} + + +void K3bMediaCache::PollThread::run() +{ + while( m_deviceEntry->blockedId == 0 ) { + bool unitReady = m_deviceEntry->medium.device()->testUnitReady(); + bool mediumCached = ( m_deviceEntry->medium.diskInfo().diskState() != K3bDevice::STATE_NO_MEDIA ); + + // + // we only get the other information in case the disk state changed or if we have + // no info at all (FIXME: there are drives around that are not able to provide a proper + // disk state) + // + if( m_deviceEntry->medium.diskInfo().diskState() == K3bDevice::STATE_UNKNOWN || + unitReady != mediumCached ) { + + // + // The medium has changed. We need to update the information. + // + K3bMedium m( m_deviceEntry->medium.device() ); + m.update(); + + // block the info since it is not valid anymore + m_deviceEntry->mutex.lock(); + + // m_deviceEntry->medium.update(); + m_deviceEntry->medium = m; + + // + // inform the media cache about the media change + // + if( m_deviceEntry->blockedId == 0 ) + QApplication::postEvent( m_deviceEntry->cache, + new K3bMediaCache::MediaChangeEvent( m_deviceEntry->medium.device() ) ); + + // the information is valid. let the info go. + m_deviceEntry->mutex.unlock(); + } + + if( m_deviceEntry->blockedId == 0 ) + QThread::sleep( 2 ); + } +} + + + + + +// //////////////////////////////////////////////////////////////////////////////// +// MEDIA CACHE IMPL +// //////////////////////////////////////////////////////////////////////////////// + + +K3bMediaCache::K3bMediaCache( QObject* parent ) + : QObject( parent ) +{ +} + + +K3bMediaCache::~K3bMediaCache() +{ + clearDeviceList(); +} + + +int K3bMediaCache::blockDevice( K3bDevice::Device* dev ) +{ + DeviceEntry* e = findDeviceEntry( dev ); + if( e ) { + if( e->blockedId ) + return -1; + else { + // block the information + e->mutex.lock(); + + // create (hopefully) unique id + e->blockedId = KApplication::random(); + + // let the info go + e->mutex.unlock(); + + // wait for the thread to stop + e->thread->wait(); + + return e->blockedId; + } + } + else + return -1; +} + + +bool K3bMediaCache::unblockDevice( K3bDevice::Device* dev, int id ) +{ + DeviceEntry* e = findDeviceEntry( dev ); + if( e && e->blockedId && e->blockedId == id ) { + e->blockedId = 0; + + // for security reasons we emit no medium signal at this point + // otherwise a job might resuse the old medium information + e->medium = K3bMedium( dev ); + emit mediumChanged( dev ); + + // restart the poll thread + e->thread->start(); + + return true; + } + else + return false; +} + + +bool K3bMediaCache::isBlocked( K3bDevice::Device* dev ) +{ + if( DeviceEntry* e = findDeviceEntry( dev ) ) + return ( e->blockedId != 0 ); + else + return false; +} + + +K3bMedium K3bMediaCache::medium( K3bDevice::Device* dev ) +{ + if( DeviceEntry* e = findDeviceEntry( dev ) ) { + e->mutex.lock(); + K3bMedium m = e->medium; + e->mutex.unlock(); + return m; + } + else + return K3bMedium(); +} + + +K3bDevice::DiskInfo K3bMediaCache::diskInfo( K3bDevice::Device* dev ) +{ + if( DeviceEntry* e = findDeviceEntry( dev ) ) { + e->mutex.lock(); + K3bDevice::DiskInfo di = e->medium.diskInfo(); + e->mutex.unlock(); + return di; + } + else + return K3bDevice::DiskInfo(); +} + + +K3bDevice::Toc K3bMediaCache::toc( K3bDevice::Device* dev ) +{ + if( DeviceEntry* e = findDeviceEntry( dev ) ) { + e->mutex.lock(); + K3bDevice::Toc toc = e->medium.toc(); + e->mutex.unlock(); + return toc; + } + else + return K3bDevice::Toc(); +} + + +K3bDevice::CdText K3bMediaCache::cdText( K3bDevice::Device* dev ) +{ + if( DeviceEntry* e = findDeviceEntry( dev ) ) { + e->mutex.lock(); + K3bDevice::CdText cdt = e->medium.cdText(); + e->mutex.unlock(); + return cdt; + } + else + return K3bDevice::CdText(); +} + + +QValueList<int> K3bMediaCache::writingSpeeds( K3bDevice::Device* dev ) +{ + if( DeviceEntry* e = findDeviceEntry( dev ) ) { + e->mutex.lock(); + QValueList<int> ws = e->medium.writingSpeeds(); + e->mutex.unlock(); + return ws; + } + else + return QValueList<int>(); +} + + +QString K3bMediaCache::mediumString( K3bDevice::Device* device, bool useContent ) +{ + if( DeviceEntry* e = findDeviceEntry( device ) ) { + return e->medium.shortString( useContent ); + } + else + return QString::null; +} + + +void K3bMediaCache::clearDeviceList() +{ + kdDebug() << k_funcinfo << endl; + + // make all the threads stop + for( QMap<K3bDevice::Device*, DeviceEntry*>::iterator it = m_deviceMap.begin(); + it != m_deviceMap.end(); ++it ) { + it.data()->blockedId = 1; + } + + // and remove them + for( QMap<K3bDevice::Device*, DeviceEntry*>::iterator it = m_deviceMap.begin(); + it != m_deviceMap.end(); ++it ) { + kdDebug() << k_funcinfo << " waiting for info thread " << it.key()->blockDeviceName() << " to finish" << endl; + it.data()->thread->wait(); + delete it.data(); + } + + m_deviceMap.clear(); +} + + +void K3bMediaCache::buildDeviceList( K3bDevice::DeviceManager* dm ) +{ + // remember blocked ids + QMap<K3bDevice::Device*, int> blockedIds; + for( QMap<K3bDevice::Device*, DeviceEntry*>::iterator it = m_deviceMap.begin(); + it != m_deviceMap.end(); ++it ) + blockedIds.insert( it.key(), it.data()->blockedId ); + + clearDeviceList(); + + const QPtrList<K3bDevice::Device>& devices = dm->allDevices(); + for( QPtrListIterator<K3bDevice::Device> it( devices ); *it; ++it ) { + m_deviceMap.insert( *it, new DeviceEntry( this, *it ) ); + QMap<K3bDevice::Device*, int>::const_iterator bi_it = blockedIds.find( *it ); + if( bi_it != blockedIds.end() ) + m_deviceMap[*it]->blockedId = bi_it.data(); + } + + // start all the polling threads + for( QMap<K3bDevice::Device*, DeviceEntry*>::iterator it = m_deviceMap.begin(); + it != m_deviceMap.end(); ++it ) { + if( !it.data()->blockedId ) + it.data()->thread->start(); + } +} + + +K3bMediaCache::DeviceEntry* K3bMediaCache::findDeviceEntry( K3bDevice::Device* dev ) +{ + QMap<K3bDevice::Device*, DeviceEntry*>::iterator it = m_deviceMap.find( dev ); + if( it != m_deviceMap.end() ) + return it.data(); + else + return 0; +} + + +void K3bMediaCache::customEvent( QCustomEvent* e ) +{ + if( e->type() == MediaChangeEvent::EventCode ) + emit mediumChanged( static_cast<MediaChangeEvent*>( e )->device() ); +} + +#include "k3bmediacache.moc" diff --git a/src/k3bmediacache.h b/src/k3bmediacache.h new file mode 100644 index 0000000..dd0dd0d --- /dev/null +++ b/src/k3bmediacache.h @@ -0,0 +1,148 @@ +/* + * + * $Id: sourceheader 380067 2005-01-19 13:03:46Z trueg $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_MEDIA_CACHE_H_ +#define _K3B_MEDIA_CACHE_H_ + +#include <qobject.h> + +#include <qvaluelist.h> + +#include <k3bdevice.h> +#include <k3btoc.h> +#include <k3bcdtext.h> +#include <k3bdiskinfo.h> + +#include "k3bmedium.h" + +namespace K3bDevice { + class DeviceManager; +} + +class QCustomEvent; + + +/** + * The Media Cache does know the status of all devices at all times + * (except for blocked devices). + * + * It should be used to get information about media and device status + * instead of the libk3bdevice methods for faster access. + * + * The Media Cache polls for new information every 2 seconds on all devices + * (except for blocked ones) and emits signals in case a device status changed + * (for example a media was inserted or removed). + * + * To start the media caching call buildDeviceList(). + */ +class K3bMediaCache : public QObject +{ + Q_OBJECT + + public: + K3bMediaCache( QObject* parent = 0 ); + ~K3bMediaCache(); + + /** + * block a device so it will not be polled. This is used + * to disable polling on devices that are currently in use + * for burning. + * + * \return A unique id to be used to unblock the device or -1 if the device + * is already blocked. + */ + int blockDevice( K3bDevice::Device* dev ); + + /** + * Unblock a device that has been blocked with block() before. + * + * \param id The id returned by the previous call to block(). This makes + * sure only the one who did the block may unblock the device. + * + * \return true if dev has been blocked with id before. false otherwise. + */ + bool unblockDevice( K3bDevice::Device* dev, int id ); + + bool isBlocked( K3bDevice::Device* dev ); + + /** + * Read cached medium information. + */ + K3bMedium medium( K3bDevice::Device* dev ); + + /** + * Read cached disk information. + */ + K3bDevice::DiskInfo diskInfo( K3bDevice::Device* ); + + /** + * Read cached Table of contents. + */ + K3bDevice::Toc toc( K3bDevice::Device* ); + + /** + * Read cached CD text from an Audio CD. + */ + K3bDevice::CdText cdText( K3bDevice::Device* ); + + /** + * Read cached supported writing speeds. + */ + QValueList<int> writingSpeeds( K3bDevice::Device* ); + + /** + * \see K3bMedium::shortString() + */ + QString mediumString( K3bDevice::Device* device, bool useContent = true ); + + signals: + /** + * Signal emitted whenever a medium changes. That means when a new medium is inserted + * or an old one is removed. + * + * This signal will also be emitted when a previously blocked device becomes unblocked. + * + * Be aware though that the Media Cache will silently ignore removed devices. That means + * once should also listen to K3bDevice::DeviceManager::changed() in case a USB drive or + * something similar is removed. + */ + void mediumChanged( K3bDevice::Device* dev ); + + public slots: + /** + * Build the device list and start the polling. + * It might make sense to connect this to K3bDevice::DeviceManager::changed() + */ + void buildDeviceList( K3bDevice::DeviceManager* ); + + /** + * Clear the device list and stop all the polling. + * This is also done in the destructor. + */ + void clearDeviceList(); + + private: + class PollThread; + class DeviceEntry; + class MediaChangeEvent; + + QMap<K3bDevice::Device*, DeviceEntry*> m_deviceMap; + + DeviceEntry* findDeviceEntry( K3bDevice::Device* ); + void customEvent( QCustomEvent* ); +}; + +#endif diff --git a/src/k3bmediacontentsview.cpp b/src/k3bmediacontentsview.cpp new file mode 100644 index 0000000..4f42595 --- /dev/null +++ b/src/k3bmediacontentsview.cpp @@ -0,0 +1,166 @@ +/* + * + * $Id: k3bmediacontentsview.cpp 627519 2007-01-26 22:37:51Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bmediacontentsview.h" + +#include <k3bmediacache.h> +#include <k3bapplication.h> + +#include <qlabel.h> +#include <qlayout.h> +#include <qpixmap.h> +#include <qwidgetstack.h> + + +class K3bMediaContentsView::Private +{ +public: + K3bMedium medium; + int supportedMediumContent; + int supportedMediumTypes; + int supportedMediumStates; + + bool autoReload; +}; + + +K3bMediaContentsView::K3bMediaContentsView( bool withHeader, + int mediumContent, + int mediumTypes, + int mediumState, + QWidget* parent, + const char* name ) + : K3bContentsView( withHeader, parent, name ) +{ + d = new Private; + d->supportedMediumContent = mediumContent; + d->supportedMediumTypes = mediumTypes; + d->supportedMediumStates = mediumState; + d->autoReload = true; + + connect( k3bappcore->mediaCache(), SIGNAL(mediumChanged(K3bDevice::Device*)), + this, SLOT(slotMediumChanged(K3bDevice::Device*)) ); +} + + +K3bMediaContentsView::~K3bMediaContentsView() +{ + delete d; +} + + +void K3bMediaContentsView::setAutoReload( bool b ) +{ + d->autoReload = b; +} + + +int K3bMediaContentsView::supportedMediumContent() const +{ + return d->supportedMediumContent; +} + + +int K3bMediaContentsView::supportedMediumTypes() const +{ + return d->supportedMediumTypes; +} + + +int K3bMediaContentsView::supportedMediumStates() const +{ + return d->supportedMediumStates; +} + + +const K3bMedium& K3bMediaContentsView::medium() const +{ + return d->medium; +} + + +K3bDevice::Device* K3bMediaContentsView::device() const +{ + return medium().device(); +} + + +void K3bMediaContentsView::setMedium( const K3bMedium& m ) +{ + d->medium = m; +} + + +void K3bMediaContentsView::reload( K3bDevice::Device* dev ) +{ + reload( k3bappcore->mediaCache()->medium( dev ) ); +} + + +void K3bMediaContentsView::reload( const K3bMedium& m ) +{ + setMedium( m ); + reload(); +} + + +void K3bMediaContentsView::reload() +{ + enableInteraction( true ); + reloadMedium(); +} + + +void K3bMediaContentsView::enableInteraction( bool enable ) +{ + mainWidget()->setEnabled( enable ); +} + + +void K3bMediaContentsView::slotMediumChanged( K3bDevice::Device* dev ) +{ + // FIXME: derive a K3bContentsStack from QWidgetStack and let it set an active flag + // to replace this hack + if( QWidgetStack* stack = dynamic_cast<QWidgetStack*>( parentWidget() ) ) + if( stack->visibleWidget() != this ) + return; + + if( !d->autoReload /*|| !isActive()*/ ) + return; + + if( dev == device() ) { + K3bMedium m = k3bappcore->mediaCache()->medium( dev ); + + // no need to reload if the medium did not change (this is even + // important since K3b blocks the devices in action and after + // the release they are signalled as changed) + if( m == medium() ) { + kdDebug() << k_funcinfo << " medium did not change" << endl; + enableInteraction( true ); + } + else if( m.content() & supportedMediumContent() && + m.diskInfo().mediaType() & supportedMediumTypes() && + m.diskInfo().diskState() & supportedMediumStates() ) { + kdDebug() << k_funcinfo << " new supported medium found" << endl; + reload( m ); + } + else { + kdDebug() << k_funcinfo << " unsupported medium found" << endl; + enableInteraction( false ); + } + } +} + +#include "k3bmediacontentsview.moc" diff --git a/src/k3bmediacontentsview.h b/src/k3bmediacontentsview.h new file mode 100644 index 0000000..7e60838 --- /dev/null +++ b/src/k3bmediacontentsview.h @@ -0,0 +1,116 @@ +/* + * + * $Id: k3bmediacontentsview.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_MEDIUM_CONTENTS_VIEW_H_ +#define _K3B_MEDIUM_CONTENTS_VIEW_H_ + +#include "k3bcontentsview.h" +#include <k3bthememanager.h> +#include <k3bmedium.h> + +class K3bThemedHeader; + + +/** + * Abstract class from which all cd views must be derived. The contents view automatically handles medium changes for + * the selected device and reloads the contents if a new usable medium is inserted or disables the controls if the + * medium is just ejected. For this to work the proper content types have to be set. + * + * TODO: how about giving this one a KActionCollection so it can handle the toolbar automatically + */ +class K3bMediaContentsView : public K3bContentsView +{ + Q_OBJECT + + public: + virtual ~K3bMediaContentsView(); + + const K3bMedium& medium() const; + + /** + * Equals medium().device() + */ + K3bDevice::Device* device() const; + + /** + * \return A bitwise or of K3bMedium::ContentType which + * represents the content types that can be displayed by this + * medium view. + */ + int supportedMediumContent() const; + int supportedMediumTypes() const; + int supportedMediumStates() const; + + public slots: + /** + * Does some internal stuff and calls reloadMedium. + * Normally there is no need to call this manually. + */ + void reload(); + + /** + * Has the same effect as reload( k3bappcore->mediaCache()->medium( dev ) ); + */ + void reload( K3bDevice::Device* dev ); + + /** + * Has the same effect as setMedium( m ), reload() + */ + void reload( const K3bMedium& m ); + + /** + * Enable or disable auto reloading when a new medium is inserted. + * If enabled (the default) the view will be reloaded if a new usable + * (as determined by the supportedXXX methods) medium has been inserted + * into the current device. + */ + void setAutoReload( bool b ); + + /** + * Enable or disable the controls of this view. + * The default implementation simply disables the whole window + */ + virtual void enableInteraction( bool enable ); + + protected: + K3bMediaContentsView( bool withHeader, + int mediumContent, + int mediumTypes, + int mediumState, + QWidget* parent = 0, + const char* name = 0 ); + + /** + * Changes the medium without reloading the contents. + * Do not use, use reload( const K3bMedium& ) instead. + */ + void setMedium( const K3bMedium& ); + + /** + * Called by reload. Reimplement to actually display + * the contents of the medium. + */ + virtual void reloadMedium() = 0; + + private slots: + void slotMediumChanged( K3bDevice::Device* ); + + private: + class Private; + Private* d; +}; + +#endif diff --git a/src/k3bmediaselectioncombobox.cpp b/src/k3bmediaselectioncombobox.cpp new file mode 100644 index 0000000..df51566 --- /dev/null +++ b/src/k3bmediaselectioncombobox.cpp @@ -0,0 +1,505 @@ +/* + * + * $Id: sourceheader 380067 2005-01-19 13:03:46Z trueg $ + * Copyright (C) 2005-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bmediaselectioncombobox.h" +#include "k3bapplication.h" +#include "k3bmediacache.h" + +#include <k3bdevice.h> +#include <k3bdevicemanager.h> +#include <k3bdeviceglobals.h> +#include <k3bdiskinfo.h> +#include <k3btoc.h> +#include <k3bcdtext.h> + +#include <kdebug.h> +#include <klocale.h> + +#include <qfont.h> +#include <qmap.h> +#include <qvaluevector.h> +#include <qtooltip.h> +#include <qlistbox.h> + + +class K3bMediaSelectionComboBox::ToolTip : public QToolTip +{ +public: + ToolTip( K3bMediaSelectionComboBox* box ); + + void maybeTip( const QPoint &pos ); + +private: + K3bMediaSelectionComboBox* m_box; +}; + + +K3bMediaSelectionComboBox::ToolTip::ToolTip( K3bMediaSelectionComboBox* box ) + : QToolTip( box->listBox()->viewport() ), + m_box( box ) +{ +} + +void K3bMediaSelectionComboBox::ToolTip::maybeTip( const QPoint& pos ) +{ + if( !parentWidget() || !m_box ) + return; + + QListBoxItem* item = m_box->listBox()->itemAt( pos ); + if( !item ) + return; + + int index = m_box->listBox()->index( item ); + + if( K3bDevice::Device* dev = m_box->deviceAt( index ) ) { + tip( m_box->listBox()->itemRect( item ), + m_box->mediumToolTip( k3bappcore->mediaCache()->medium( dev ) ) ); + } +} + + + + + +class K3bMediaSelectionComboBox::Private +{ +public: + Private() + : ignoreDevice( 0 ) { + } + + QMap<K3bDevice::Device*, int> deviceIndexMap; + QValueVector<K3bDevice::Device*> devices; + + K3bDevice::Device* ignoreDevice; + + // medium strings for every entry + QMap<QString, int> mediaStringMap; + + int wantedMediumType; + int wantedMediumState; + int wantedMediumContent; + + QFont font; +}; + + +K3bMediaSelectionComboBox::K3bMediaSelectionComboBox( QWidget* parent ) + : KComboBox( false, parent ) +{ + d = new Private(); + + // set defaults + d->wantedMediumType = K3bDevice::MEDIA_WRITABLE_CD; + d->wantedMediumState = K3bDevice::STATE_EMPTY; + d->wantedMediumContent = K3bMedium::CONTENT_ALL; + + d->font = font(); + + connect( this, SIGNAL(activated(int)), + this, SLOT(slotActivated(int)) ); + connect( k3bcore->deviceManager(), SIGNAL(changed(K3bDevice::DeviceManager*)), + this, SLOT(slotDeviceManagerChanged(K3bDevice::DeviceManager*)) ); + connect( k3bappcore->mediaCache(), SIGNAL(mediumChanged(K3bDevice::Device*)), + this, SLOT(slotMediumChanged(K3bDevice::Device*)) ); + connect( this, SIGNAL(selectionChanged(K3bDevice::Device*)), + this, SLOT(slotUpdateToolTip(K3bDevice::Device*)) ); + + updateMedia(); + + // initialize the tooltip for the dropdown box + (void)new ToolTip( this ); +} + + +K3bMediaSelectionComboBox::~K3bMediaSelectionComboBox() +{ + delete d; +} + + +void K3bMediaSelectionComboBox::setIgnoreDevice( K3bDevice::Device* dev ) +{ + d->ignoreDevice = dev; + updateMedia(); +} + + +K3bDevice::Device* K3bMediaSelectionComboBox::selectedDevice() const +{ + if( d->devices.count() > 0 ) + return d->devices[currentItem()]; + else + return 0; +} + + +QValueList<K3bDevice::Device*> K3bMediaSelectionComboBox::allDevices() const +{ + QValueList<K3bDevice::Device*> l; + for( unsigned int i = 0; i < d->devices.count(); ++i ) + l.append( d->devices[i] ); + return l; +} + + +void K3bMediaSelectionComboBox::setSelectedDevice( K3bDevice::Device* dev ) +{ + if( dev && d->deviceIndexMap.contains( dev ) ) { + setCurrentItem( d->deviceIndexMap[dev] ); + emit selectionChanged( dev ); + } +} + + +void K3bMediaSelectionComboBox::setWantedMediumType( int type ) +{ + if( type != 0 && type != d->wantedMediumType) { + d->wantedMediumType = type; + updateMedia(); + } +} + + +void K3bMediaSelectionComboBox::setWantedMediumState( int state ) +{ + if( state != 0 && state != d->wantedMediumState ) { + d->wantedMediumState = state; + updateMedia(); + } +} + + +void K3bMediaSelectionComboBox::setWantedMediumContent( int content ) +{ + if( content != d->wantedMediumContent ) { + d->wantedMediumContent = content; + updateMedia(); + } +} + + +int K3bMediaSelectionComboBox::wantedMediumType() const +{ + return d->wantedMediumType; +} + + +int K3bMediaSelectionComboBox::wantedMediumState() const +{ + return d->wantedMediumState; +} + + +int K3bMediaSelectionComboBox::wantedMediumContent() const +{ + return d->wantedMediumContent; +} + + +void K3bMediaSelectionComboBox::slotActivated( int i ) +{ + if( d->devices.count() > 0 ) + emit selectionChanged( d->devices[i] ); +} + + +void K3bMediaSelectionComboBox::slotMediumChanged( K3bDevice::Device* dev ) +{ + updateMedium( dev ); +} + + +void K3bMediaSelectionComboBox::clear() +{ + d->deviceIndexMap.clear(); + d->mediaStringMap.clear(); + d->devices.clear(); + KComboBox::clear(); +} + + +void K3bMediaSelectionComboBox::showNoMediumMessage() +{ + // make it italic + QFont f( d->font ); + f.setItalic( true ); + setFont( f ); + + insertItem( noMediumMessage() ); +} + + +void K3bMediaSelectionComboBox::updateMedia() +{ + // reset font + setFont( d->font ); + + // remember set of devices + QValueVector<K3bDevice::Device*> oldDevices = d->devices; + + // remember last selected medium + K3bDevice::Device* selected = selectedDevice(); + + clear(); + + // + // We need to only check a selection of the available devices based on the + // wanted media type. + // + + // no ROM media -> we most likely want only CD/DVD writers + bool rwOnly = !( wantedMediumType() & (K3bDevice::MEDIA_CD_ROM|K3bDevice::MEDIA_DVD_ROM) ); + bool dvdOnly = !( wantedMediumType() & (K3bDevice::MEDIA_CD_ROM|K3bDevice::MEDIA_WRITABLE_CD) ); + + QPtrList<K3bDevice::Device> devices = k3bcore->deviceManager()->allDevices(); + if( dvdOnly ) { + if( rwOnly ) + devices = k3bcore->deviceManager()->dvdWriter(); + else + devices = k3bcore->deviceManager()->dvdReader(); + } + else if( rwOnly ) + devices = k3bcore->deviceManager()->cdWriter(); + else + devices = k3bcore->deviceManager()->cdReader(); + + for( QPtrListIterator<K3bDevice::Device> it( devices ); *it; ++it ) { + if ( d->ignoreDevice == *it ) { + continue; + } + + K3bMedium medium = k3bappcore->mediaCache()->medium( *it ); + + if( showMedium( medium ) ) { + addMedium( *it ); + } + } + + // + // Now in case no usable medium was found show the user a little message + // + if( d->devices.isEmpty() ) { + showNoMediumMessage(); + if( selected != 0 ) { + // inform that we have no medium at all + emit selectionChanged( 0 ); + } + } + else if( selected && d->deviceIndexMap.contains( selected ) ) { + setCurrentItem( d->deviceIndexMap[selected] ); + } + else { + emit selectionChanged( selectedDevice() ); + } + + // did the selection of devices change + if( !(d->devices == oldDevices) ) { + emit newMedia(); + for( unsigned int i = 0; i < d->devices.count(); ++i ) { + unsigned int j = 0; + for( j = 0; j < oldDevices.count(); ++j ) { + if( oldDevices[j] == d->devices[i] ) + break; + } + if( j == oldDevices.count() ) { + // prefere a newly inserted medium over the previously selected + setSelectedDevice( d->devices[i] ); + emit newMedium( d->devices[i] ); + } + } + } +} + + +void K3bMediaSelectionComboBox::updateMedium( K3bDevice::Device* ) +{ + // for now we simply rebuild the whole list + updateMedia(); +} + + +void K3bMediaSelectionComboBox::addMedium( K3bDevice::Device* dev ) +{ + // + // In case we only want an empty medium (this might happen in case the + // the medium is rewritable) we do not care about the contents but tell + // the user that the medium is rewritable. + // Otherwise we show the contents type since this might also be used + // for source selection. + // + QString s = mediumString( k3bappcore->mediaCache()->medium( dev ) ); + + // + // Now let's see if this string is already contained in the list + // and if so add the device name to both + // + if( d->mediaStringMap.contains( s ) ) { + // + // insert the modified string + // + insertItem( s + QString(" (%1 - %2)").arg(dev->vendor()).arg(dev->description()) ); + + // + // change the already existing string if we did not already do so + // (which happens if more than 2 entries have the same medium string) + // + int prevIndex = d->mediaStringMap[s]; + if( prevIndex >= 0 ) + changeItem( text(prevIndex) + QString(" (%1 - %2)").arg(d->devices[prevIndex]->vendor()).arg(d->devices[prevIndex]->description()), + prevIndex ); + + // + // mark the string as already changed + // + d->mediaStringMap[s] = -1; + } + else { + // + // insert the plain medium string + // + insertItem( s ); + d->mediaStringMap[s] = count()-1; + } + + // + // update the helper structures + // + d->deviceIndexMap[dev] = count()-1; + d->devices.append( dev ); +} + + +void K3bMediaSelectionComboBox::slotDeviceManagerChanged( K3bDevice::DeviceManager* ) +{ + updateMedia(); +} + + +K3bDevice::Device* K3bMediaSelectionComboBox::deviceAt( unsigned int index ) +{ + if( index < d->devices.count() ) + return d->devices[index]; + else + return 0; +} + + +bool K3bMediaSelectionComboBox::showMedium( const K3bMedium& m ) const +{ + // + // also use if wantedMediumState empty and medium rewritable + // because we can always format/erase/overwrite it + // + // DVD+RW and DVD-RW restr. ovwr. are never reported as appendable + // + return( m.diskInfo().mediaType() & d->wantedMediumType && + m.content() & d->wantedMediumContent && + ( m.diskInfo().diskState() & d->wantedMediumState + || + ( d->wantedMediumState & K3bDevice::STATE_EMPTY && + m.diskInfo().rewritable() ) + || + ( d->wantedMediumState & K3bDevice::STATE_INCOMPLETE && + !m.diskInfo().empty() && + m.diskInfo().mediaType() & (K3bDevice::MEDIA_DVD_PLUS_RW|K3bDevice::MEDIA_DVD_RW_OVWR) ) ) + ); +} + + +QString K3bMediaSelectionComboBox::mediumString( const K3bMedium& medium ) const +{ + return medium.shortString( d->wantedMediumState != K3bDevice::STATE_EMPTY ); +} + + +QString K3bMediaSelectionComboBox::mediumToolTip( const K3bMedium& m ) const +{ + return m.longString(); +} + + +QString K3bMediaSelectionComboBox::noMediumMessage() const +{ + QString stateString; + if( d->wantedMediumContent == K3bMedium::CONTENT_ALL ) { + if( d->wantedMediumState == K3bDevice::STATE_EMPTY ) + stateString = i18n("an empty %1 medium"); + else if( d->wantedMediumState == K3bDevice::STATE_INCOMPLETE ) + stateString = i18n("an appendable %1 medium"); + else if( d->wantedMediumState == K3bDevice::STATE_COMPLETE ) + stateString = i18n("a complete %1 medium"); + else if( d->wantedMediumState & (K3bDevice::STATE_EMPTY|K3bDevice::STATE_INCOMPLETE) && + !(d->wantedMediumState & K3bDevice::STATE_COMPLETE) ) + stateString = i18n("an empty or appendable %1 medium"); + else if( d->wantedMediumState & (K3bDevice::STATE_COMPLETE|K3bDevice::STATE_INCOMPLETE) ) + stateString = i18n("a complete or appendable %1 medium"); + else + stateString = i18n("a %1 medium"); + } + else { + // + // we only handle the combinations that make sense here + // + if( d->wantedMediumContent & K3bMedium::CONTENT_VIDEO_CD || + d->wantedMediumContent & K3bMedium::CONTENT_VIDEO_DVD ) + stateString = i18n("a Video %1 medium"); + else if( d->wantedMediumContent & K3bMedium::CONTENT_AUDIO && + d->wantedMediumContent & K3bMedium::CONTENT_DATA ) + stateString = i18n("a Mixed Mode %1 medium"); + else if( d->wantedMediumContent & K3bMedium::CONTENT_AUDIO ) + stateString = i18n("an Audio %1 medium"); + else if( d->wantedMediumContent & K3bMedium::CONTENT_DATA ) + stateString = i18n("a Data %1 medium"); + else + stateString = i18n("an empty %1 medium"); + } + + // this is basically the same as in K3bEmptyDiskWaiter + // FIXME: include things like only rewritable dvd or cd since we will probably need that + QString mediumString; + if( d->wantedMediumType == (K3bDevice::MEDIA_CD_ALL|K3bDevice::MEDIA_DVD_ALL) ) + mediumString = i18n("CD or DVD"); + else if( d->wantedMediumType == K3bDevice::MEDIA_CD_ALL ) + mediumString = i18n("CD"); + else if( d->wantedMediumType == K3bDevice::MEDIA_DVD_ALL ) + mediumString = i18n("DVD"); + else if( (d->wantedMediumType & K3bDevice::MEDIA_WRITABLE_DVD) && + (d->wantedMediumType & K3bDevice::MEDIA_WRITABLE_CD) ) + mediumString = i18n("CD-R(W) or DVD%1R(W)").arg(""); + else if( d->wantedMediumType & K3bDevice::MEDIA_WRITABLE_DVD_SL ) + mediumString = i18n("DVD%1R(W)").arg(""); + else if( d->wantedMediumType & K3bDevice::MEDIA_WRITABLE_DVD_DL ) + mediumString = i18n("Double Layer DVD%1R").arg(""); + else if( d->wantedMediumType & K3bDevice::MEDIA_WRITABLE_CD ) + mediumString = i18n("CD-R(W)"); + else if( d->wantedMediumType & K3bDevice::MEDIA_DVD_ROM ) + mediumString = i18n("DVD-ROM"); + else + mediumString = i18n("CD-ROM"); + + return i18n("Please insert %1...").arg( stateString.arg( mediumString ) ); +} + + +void K3bMediaSelectionComboBox::slotUpdateToolTip( K3bDevice::Device* dev ) +{ + // update the tooltip for the combobox (the tooltip for the dropdown box is created in the constructor) + QToolTip::remove( this ); + if( dev ) + QToolTip::add( this, mediumToolTip( k3bappcore->mediaCache()->medium( dev ) ) ); +} + +#include "k3bmediaselectioncombobox.moc" diff --git a/src/k3bmediaselectioncombobox.h b/src/k3bmediaselectioncombobox.h new file mode 100644 index 0000000..8a592c9 --- /dev/null +++ b/src/k3bmediaselectioncombobox.h @@ -0,0 +1,136 @@ +/* + * + * $Id: sourceheader 380067 2005-01-19 13:03:46Z trueg $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_MEDIA_SELECTION_COMBOBOX_H_ +#define _K3B_MEDIA_SELECTION_COMBOBOX_H_ + +#include <kcombobox.h> + +#include "k3bmedium.h" + +namespace K3bDevice { + class Device; + class DeviceManager; +} + +/** + * Combo box which allows to select a media (in comparison + * to the K3bDeviceComboBox which allows to select a device. + * + * This class uses the K3bMediaCache to update it's status. + */ +class K3bMediaSelectionComboBox : public KComboBox +{ + Q_OBJECT + + public: + K3bMediaSelectionComboBox( QWidget* parent ); + virtual ~K3bMediaSelectionComboBox(); + + /** + * Although the widget allows selection of media this + * results in a device being selected. + */ + K3bDevice::Device* selectedDevice() const; + + QValueList<K3bDevice::Device*> allDevices() const; + + int wantedMediumType() const; + int wantedMediumState() const; + int wantedMediumContent() const; + + signals: + /** + * Be aware that his signal will also be emitted in case + * no medium is available with a null pointer. + */ + void selectionChanged( K3bDevice::Device* ); + + /** + * This signal is emitted if the selection of media changed. + * This includes a change due to changing the wanted medium state. + */ + void newMedia(); + + void newMedium( K3bDevice::Device* dev ); + + public slots: + /** + * Only works in case the device actually contains a usable medium. + * Otherwise the currently selected medium stays selected. + */ + void setSelectedDevice( K3bDevice::Device* ); + + /** + * Set the wanted medium type. Defaults to writable CD. + * + * \param type a bitwise combination of the K3bDevice::MediaType enum + */ + void setWantedMediumType( int type ); + + /** + * Set the wanted medium state. Defaults to empty media. + * + * \param state a bitwise combination of the K3bDevice::State enum + */ + void setWantedMediumState( int state ); + + /** + * Set the wanted medium content type. The default is K3bMedium::CONTENT_ALL (i.e. ignore media + * content) + * Be aware that 0 maps to K3bMedium::CONTENT_NONE, i.e. empty media. + * + * \param content A bitwise or of K3bMedium::MediumContent + */ + void setWantedMediumContent( int content ); + + /** + * Set the device to ignore. This device will not be checked for + * wanted media. This is many useful for media copy. + * + * \param dev The device to ignore or 0 to not ignore any device. + */ + void setIgnoreDevice( K3bDevice::Device* dev ); + + private slots: + void slotMediumChanged( K3bDevice::Device* ); + void slotDeviceManagerChanged( K3bDevice::DeviceManager* ); + void slotActivated( int i ); + void slotUpdateToolTip( K3bDevice::Device* ); + + protected: + void updateMedia(); + virtual bool showMedium( const K3bMedium& ) const; + virtual QString mediumString( const K3bMedium& ) const; + virtual QString mediumToolTip( const K3bMedium& ) const; + virtual QString noMediumMessage() const; + + private: + void updateMedium( K3bDevice::Device* ); + void addMedium( K3bDevice::Device* ); + void showNoMediumMessage(); + void clear(); + + // usedby the tooltip + K3bDevice::Device* deviceAt( unsigned int index ); + + class ToolTip; + friend class ToolTip; + + class Private; + Private* d; +}; + +#endif diff --git a/src/k3bmediaselectiondialog.cpp b/src/k3bmediaselectiondialog.cpp new file mode 100644 index 0000000..3607297 --- /dev/null +++ b/src/k3bmediaselectiondialog.cpp @@ -0,0 +1,127 @@ +/* + * + * $Id: sourceheader 380067 2005-01-19 13:03:46Z trueg $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bmediaselectiondialog.h" +#include "k3bmediaselectioncombobox.h" +#include "k3bmediacache.h" +#include "k3bapplication.h" + +#include <klocale.h> + +#include <qlayout.h> +#include <qlabel.h> + + +K3bMediaSelectionDialog::K3bMediaSelectionDialog( QWidget* parent, + const QString& title, + const QString& text, + bool modal ) + : KDialogBase( KDialogBase::Plain, + title.isEmpty() ? i18n("Medium Selection") : title, + Ok|Cancel, + Ok, + parent, + 0, + modal ) +{ + QGridLayout* lay = new QGridLayout( plainPage() ); + + QLabel* label = new QLabel( text.isEmpty() ? i18n("Please select a medium:") : text, plainPage() ); + m_combo = new K3bMediaSelectionComboBox( plainPage() ); + + // lay->setMargin( marginHint() ); + lay->setSpacing( spacingHint() ); + lay->addWidget( label, 0, 0 ); + lay->addWidget( m_combo, 1, 0 ); + lay->setRowStretch( 2, 1 ); + + connect( m_combo, SIGNAL(selectionChanged(K3bDevice::Device*)), + this, SLOT(slotSelectionChanged(K3bDevice::Device*)) ); + + slotSelectionChanged( m_combo->selectedDevice() ); +} + + +K3bMediaSelectionDialog::~K3bMediaSelectionDialog() +{ +} + + +void K3bMediaSelectionDialog::setWantedMediumType( int type ) +{ + m_combo->setWantedMediumType( type ); +} + + +void K3bMediaSelectionDialog::setWantedMediumState( int state ) +{ + m_combo->setWantedMediumState( state ); +} + + +void K3bMediaSelectionDialog::setWantedMediumContent( int content ) +{ + m_combo->setWantedMediumContent( content ); +} + + +K3bDevice::Device* K3bMediaSelectionDialog::selectedDevice() const +{ + return m_combo->selectedDevice(); +} + + +void K3bMediaSelectionDialog::slotSelectionChanged( K3bDevice::Device* dev ) +{ + enableButtonOK( dev != 0 ); +} + + +K3bDevice::Device* K3bMediaSelectionDialog::selectMedium( int type, int state, int content, + QWidget* parent, + const QString& title, const QString& text, + bool* canceled ) +{ + K3bMediaSelectionDialog dlg( parent, title, text ); + dlg.setWantedMediumType( type ); + dlg.setWantedMediumState( state ); + dlg.setWantedMediumContent( content ); + + // even if no usable medium is inserted the combobox shows the "insert one" message + // so it's not sufficient to check for just one entry to check if there only is a + // single useable medium + if( ( dlg.selectedDevice() && dlg.m_combo->count() == 1 ) + || dlg.exec() == Accepted ) { + if( canceled ) + *canceled = false; + return dlg.selectedDevice(); + } + else { + if( canceled ) + *canceled = true; + return 0; + } +} + + +K3bDevice::Device* K3bMediaSelectionDialog::selectMedium( int type, int state, + QWidget* parent, + const QString& title, const QString& text, + bool* canceled ) +{ + return selectMedium( type, state, K3bMedium::CONTENT_ALL, parent, title, text, canceled ); +} + +#include "k3bmediaselectiondialog.moc" diff --git a/src/k3bmediaselectiondialog.h b/src/k3bmediaselectiondialog.h new file mode 100644 index 0000000..317767d --- /dev/null +++ b/src/k3bmediaselectiondialog.h @@ -0,0 +1,87 @@ +/* + * + * $Id: sourceheader 380067 2005-01-19 13:03:46Z trueg $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_MEDIA_SELECTION_DIALOG_H_ +#define _K3B_MEDIA_SELECTION_DIALOG_H_ + +#include <kdialogbase.h> +#include <k3bmedium.h> + +class K3bMediaSelectionComboBox; +namespace K3bDevice { + class Device; +} + +class K3bMediaSelectionDialog : public KDialogBase +{ + Q_OBJECT + + public: + /** + * Do not use the constructor. Use the static method instead. + */ + K3bMediaSelectionDialog( QWidget* parent = 0, + const QString& title = QString::null, + const QString& text = QString::null, + bool modal = false ); + ~K3bMediaSelectionDialog(); + + /** + * \see K3bMediaSelectionComboBox::setWantedMediumType() + */ + void setWantedMediumType( int type ); + + /** + * \see K3bMediaSelectionComboBox::setWantedMediumState() + */ + void setWantedMediumState( int state ); + + /** + * \see K3bMediaSelectionComboBox::setWantedMediumContent() + */ + void setWantedMediumContent( int state ); + + /** + * Although the dialog is used to select a medium the result is the + * device containing that medium. + */ + K3bDevice::Device* selectedDevice() const; + + /** + * \deprecated + * + * Select a medium. + * If only one medium of the wanted type is found the method returns immideately + * without showing the dialog. + */ + static K3bDevice::Device* selectMedium( int type, int state, QWidget* parent = 0, + const QString& title = QString::null, + const QString& text = QString::null, + bool* canceled = 0 ); + + static K3bDevice::Device* selectMedium( int type, int state, int content = K3bMedium::CONTENT_ALL, + QWidget* parent = 0, + const QString& title = QString::null, + const QString& text = QString::null, + bool* canceled = 0 ); + + private slots: + void slotSelectionChanged( K3bDevice::Device* ); + + private: + K3bMediaSelectionComboBox* m_combo; +}; + +#endif diff --git a/src/k3bmedium.cpp b/src/k3bmedium.cpp new file mode 100644 index 0000000..18d6257 --- /dev/null +++ b/src/k3bmedium.cpp @@ -0,0 +1,463 @@ + +/* + * + * $Id: sourceheader 380067 2005-01-19 13:03:46Z trueg $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include <config.h> + +#include "k3bmedium.h" + +#include <k3bdeviceglobals.h> +#include <k3bglobals.h> +#include <k3biso9660.h> +#include <k3biso9660backend.h> + +#include <klocale.h> +#include <kio/global.h> + +/** + * Internal class used by K3bMedium + */ +class K3bMedium::Data : public KShared +{ +public: + Data(); + + K3bDevice::Device* device; + K3bDevice::DiskInfo diskInfo; + K3bDevice::Toc toc; + K3bDevice::CdText cdText; + QValueList<int> writingSpeeds; + K3bIso9660SimplePrimaryDescriptor isoDesc; + int content; +}; + + + +K3bMedium::Data::Data() + : device( 0 ), + content( K3bMedium::CONTENT_NONE ) +{ +} + + +K3bMedium::K3bMedium() +{ + d = new Data; +} + + + +K3bMedium::K3bMedium( const K3bMedium& other ) +{ + d = other.d; +} + + +K3bMedium::K3bMedium( K3bDevice::Device* dev ) +{ + d = new Data; + d->device = dev; +} + + +K3bMedium::~K3bMedium() +{ +} + + +K3bMedium& K3bMedium::operator=( const K3bMedium& other ) +{ + if( this != &other ) + d = other.d; + return *this; +} + + +void K3bMedium::detach() +{ + if( d.count() > 1 ) + d = new Data( *d ); +} + + +void K3bMedium::setDevice( K3bDevice::Device* dev ) +{ + if( d->device != dev ) { + reset(); + d->device = dev; + } +} + +K3bDevice::Device* K3bMedium::device() const +{ + return d->device; +} + + +const K3bDevice::DiskInfo& K3bMedium::diskInfo() const +{ + return d->diskInfo; +} + + +const K3bDevice::Toc& K3bMedium::toc() const +{ + return d->toc; +} + + +const K3bDevice::CdText& K3bMedium::cdText() const +{ + return d->cdText; +} + + +const QValueList<int>& K3bMedium::writingSpeeds() const +{ + return d->writingSpeeds; +} + + +int K3bMedium::content() const +{ + return d->content; +} + + +const K3bIso9660SimplePrimaryDescriptor& K3bMedium::iso9660Descriptor() const +{ + return d->isoDesc; +} + + +void K3bMedium::reset() +{ + detach(); + + d->diskInfo = K3bDevice::DiskInfo(); + d->toc.clear(); + d->cdText.clear(); + d->writingSpeeds.clear(); + d->content = CONTENT_NONE; + + // clear the desc + d->isoDesc = K3bIso9660SimplePrimaryDescriptor(); +} + + +void K3bMedium::update() +{ + if( d->device ) { + reset(); + + d->diskInfo = d->device->diskInfo(); + + if( d->diskInfo.diskState() != K3bDevice::STATE_NO_MEDIA ) { + kdDebug() << "(K3bMedium) found medium:" << endl + << "=====================================================" << endl; + d->diskInfo.debug(); + kdDebug() << "=====================================================" << endl; + } + + if( diskInfo().diskState() == K3bDevice::STATE_COMPLETE || + diskInfo().diskState() == K3bDevice::STATE_INCOMPLETE ) { + d->toc = d->device->readToc(); + if( d->toc.contentType() == K3bDevice::AUDIO || + d->toc.contentType() == K3bDevice::MIXED ) + d->cdText = d->device->readCdText(); + } + + if( diskInfo().mediaType() & K3bDevice::MEDIA_WRITABLE ) { + d->writingSpeeds = d->device->determineSupportedWriteSpeeds(); + } + + analyseContent(); + } +} + + +void K3bMedium::analyseContent() +{ + // set basic content types + switch( toc().contentType() ) { + case K3bDevice::AUDIO: + d->content = CONTENT_AUDIO; + break; + case K3bDevice::DATA: + case K3bDevice::DVD: + d->content = CONTENT_DATA; + break; + case K3bDevice::MIXED: + d->content = CONTENT_AUDIO|CONTENT_DATA; + break; + default: + d->content = CONTENT_NONE; + } + + // analyze filesystem + if( d->content & CONTENT_DATA ) { + //kdDebug() << "(K3bMedium) Checking file system." << endl; + + unsigned long startSec = 0; + + if( diskInfo().numSessions() > 1 ) { + // We use the last data track + // this way we get the latest session on a ms cd + K3bDevice::Toc::const_iterator it = toc().end(); + --it; // this is valid since there is at least one data track + while( it != toc().begin() && (*it).type() != K3bDevice::Track::DATA ) + --it; + startSec = (*it).firstSector().lba(); + } + else { + // use first data track + K3bDevice::Toc::const_iterator it = toc().begin(); + while( it != toc().end() && (*it).type() != K3bDevice::Track::DATA ) + ++it; + startSec = (*it).firstSector().lba(); + } + + //kdDebug() << "(K3bMedium) Checking file system at " << startSec << endl; + + // force the backend since we don't need decryption + // which just slows down the whole process + K3bIso9660 iso( new K3bIso9660DeviceBackend( d->device ) ); + iso.setStartSector( startSec ); + iso.setPlainIso9660( true ); + if( iso.open() ) { + d->isoDesc = iso.primaryDescriptor(); + kdDebug() << "(K3bMedium) found volume id from start sector " << startSec + << ": '" << d->isoDesc.volumeId << "'" << endl; + + if( diskInfo().isDvdMedia() ) { + // Every VideoDVD needs to have a VIDEO_TS.IFO file + if( iso.firstIsoDirEntry()->entry( "VIDEO_TS/VIDEO_TS.IFO" ) != 0 ) + d->content |= CONTENT_VIDEO_DVD; + } + else { + kdDebug() << "(K3bMedium) checking for VCD." << endl; + + // check for VCD + const K3bIso9660Entry* vcdEntry = iso.firstIsoDirEntry()->entry( "VCD/INFO.VCD" ); + const K3bIso9660Entry* svcdEntry = iso.firstIsoDirEntry()->entry( "SVCD/INFO.SVD" ); + const K3bIso9660File* vcdInfoFile = 0; + if( vcdEntry ) { + kdDebug() << "(K3bMedium) found vcd entry." << endl; + if( vcdEntry->isFile() ) + vcdInfoFile = static_cast<const K3bIso9660File*>(vcdEntry); + } + if( svcdEntry && !vcdInfoFile ) { + kdDebug() << "(K3bMedium) found svcd entry." << endl; + if( svcdEntry->isFile() ) + vcdInfoFile = static_cast<const K3bIso9660File*>(svcdEntry); + } + + if( vcdInfoFile ) { + char buffer[8]; + + if ( vcdInfoFile->read( 0, buffer, 8 ) == 8 && + ( !qstrncmp( buffer, "VIDEO_CD", 8 ) || + !qstrncmp( buffer, "SUPERVCD", 8 ) || + !qstrncmp( buffer, "HQ-VCD ", 8 ) ) ) + d->content |= CONTENT_VIDEO_CD; + } + } + } // opened iso9660 + } +} + + +QString K3bMedium::shortString( bool useContent ) const +{ + QString mediaTypeString = K3bDevice::mediaTypeString( diskInfo().mediaType(), true ); + + if( diskInfo().diskState() == K3bDevice::STATE_UNKNOWN ) { + return i18n("No medium information"); + } + + else if( diskInfo().diskState() == K3bDevice::STATE_NO_MEDIA ) { + return i18n("No medium present"); + } + + else if( diskInfo().diskState() == K3bDevice::STATE_EMPTY ) { + return i18n("Empty %1 medium").arg( mediaTypeString ); + } + + else { + if( useContent ) { + // AUDIO + MIXED + if( toc().contentType() == K3bDevice::AUDIO || + toc().contentType() == K3bDevice::MIXED ) { + if( !cdText().performer().isEmpty() || !cdText().title().isEmpty() ) { + return QString("%1 - %2 (%3)") + .arg( cdText().performer() ) + .arg( cdText().title() ) + .arg( toc().contentType() == K3bDevice::AUDIO ? i18n("Audio CD") : i18n("Mixed CD") ); + } + else if( toc().contentType() == K3bDevice::AUDIO ) { + return i18n("Audio CD"); + } + else { + return i18n("%1 (Mixed CD)").arg( beautifiedVolumeId() ); + } + } + + // DATA CD and DVD + else if( !volumeId().isEmpty() ) { + if( content() & CONTENT_VIDEO_DVD ) { + return QString("%1 (%2)").arg( beautifiedVolumeId() ).arg( i18n("Video DVD") ); + } + else if( content() & CONTENT_VIDEO_CD ) { + return QString("%1 (%2)").arg( beautifiedVolumeId() ).arg( i18n("Video CD") ); + } + else if( diskInfo().diskState() == K3bDevice::STATE_INCOMPLETE ) { + return i18n("%1 (Appendable Data %2)").arg( beautifiedVolumeId(), mediaTypeString ); + } + else { + return i18n("%1 (Complete Data %2)").arg( beautifiedVolumeId(), mediaTypeString ); + } + } + else { + if( diskInfo().diskState() == K3bDevice::STATE_INCOMPLETE ) { + return i18n("Appendable Data %1").arg( mediaTypeString ); + } + else { + return i18n("Complete Data %1").arg( mediaTypeString ); + } + } + } + + // without content + else { + if( diskInfo().diskState() == K3bDevice::STATE_INCOMPLETE ) { + return i18n("Appendable %1 medium").arg( mediaTypeString ); + } + else { + return i18n("Complete %1 medium").arg( mediaTypeString ); + } + } + } +} + + +QString K3bMedium::longString() const +{ + QString s = QString("<p><nobr><b>%1 %2</b> (%3)</nobr>" + "<p>") + .arg( d->device->vendor() ) + .arg( d->device->description() ) + .arg( d->device->blockDeviceName() ) + + shortString( true ); + + if( diskInfo().diskState() == K3bDevice::STATE_COMPLETE || + diskInfo().diskState() == K3bDevice::STATE_INCOMPLETE ) { + s += "<br>" + i18n("%1 in %n track", "%1 in %n tracks", toc().count() ) + .arg( KIO::convertSize(diskInfo().size().mode1Bytes() ) ); + if( diskInfo().numSessions() > 1 ) + s += i18n(" and %n session", " and %n sessions", diskInfo().numSessions() ); + } + + if( diskInfo().diskState() == K3bDevice::STATE_EMPTY || + diskInfo().diskState() == K3bDevice::STATE_INCOMPLETE ) + s += "<br>" + i18n("Free space: %1") + .arg( KIO::convertSize( diskInfo().remainingSize().mode1Bytes() ) ); + + if( !diskInfo().empty() && diskInfo().rewritable() ) + s += "<br>" + i18n("Capacity: %1") + .arg( KIO::convertSize( diskInfo().capacity().mode1Bytes() ) ); + + return s; +} + + +const QString& K3bMedium::volumeId() const +{ + return iso9660Descriptor().volumeId; +} + + +QString K3bMedium::beautifiedVolumeId() const +{ + const QString& oldId = volumeId(); + QString newId; + + bool newWord = true; + for( unsigned int i = 0; i < oldId.length(); ++i ) { + QChar c = oldId[i]; + // + // first let's handle the cases where we do not change + // the id anyway + // + // In case the id already contains spaces or lower case chars + // it is likely that it already looks good and does ignore + // the restricted iso9660 charset (like almost every project + // created with K3b) + // + if( c.isLetter() && c.lower() == c ) + return oldId; + else if( c.isSpace() ) + return oldId; + + // replace underscore with space + else if( c.unicode() == 95 ) { + newId.append( ' ' ); + newWord = true; + } + + // from here on only upper case chars and numbers and stuff + else if( c.isLetter() ) { + if( newWord ) { + newId.append( c ); + newWord = false; + } + else { + newId.append( c.lower() ); + } + } + else { + newId.append( c ); + } + } + + return newId; +} + + +bool K3bMedium::operator==( const K3bMedium& other ) +{ + if( this->d == other.d ) + return true; + + return( this->device() == other.device() && + this->diskInfo() == other.diskInfo() && + this->toc() == other.toc() && + this->cdText() == other.cdText() && + this->content() == other.content() && + this->iso9660Descriptor() == other.iso9660Descriptor() ); +} + + +bool K3bMedium::operator!=( const K3bMedium& other ) +{ + if( this->d == other.d ) + return false; + + return( this->device() != other.device() || + this->diskInfo() != other.diskInfo() || + this->toc() != other.toc() || + this->cdText() != other.cdText() || + this->content() != other.content() || + this->iso9660Descriptor() != other.iso9660Descriptor() ); +} diff --git a/src/k3bmedium.h b/src/k3bmedium.h new file mode 100644 index 0000000..22b8c00 --- /dev/null +++ b/src/k3bmedium.h @@ -0,0 +1,134 @@ +/* + * + * $Id: sourceheader 380067 2005-01-19 13:03:46Z trueg $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_MEDIUM_H_ +#define _K3B_MEDIUM_H_ + +#include <k3bdiskinfo.h> +#include <k3btoc.h> +#include <k3bcdtext.h> +#include <k3bdevice.h> +#include <k3biso9660.h> + +#include <ksharedptr.h> + + +/** + * K3bMedium represents a medium in K3b. + * + * It is implicetely shared, thus copying is very fast. + */ +class K3bMedium +{ + public: + K3bMedium(); + K3bMedium( const K3bMedium& ); + K3bMedium( K3bDevice::Device* dev ); + ~K3bMedium(); + + K3bMedium& operator=( const K3bMedium& ); + + void setDevice( K3bDevice::Device* dev ); + + /** + * Resets everything to default values except the device. + * This means empty toc, cd text, no writing speeds, and a diskinfo + * with state UNKNOWN. + */ + void reset(); + + /** + * Updates the medium information if the device is not null. + * Do not use this in the GUI thread since it uses blocking + * K3bdevice methods. + */ + void update(); + + K3bDevice::Device* device() const; + const K3bDevice::DiskInfo& diskInfo() const; + const K3bDevice::Toc& toc() const; + const K3bDevice::CdText& cdText() const; + + /** + * The writing speeds the device supports with the inserted medium. + * With older devices this list might even be empty for writable + * media. In that case refer to K3bDevice::Device::maxWriteSpeed + * combined with a manual speed selection. + */ + const QValueList<int>& writingSpeeds() const; + const QString& volumeId() const; + + /** + * This method tries to make a volume identificator witch uses a reduced character set + * look more beautiful by, for example, replacing '_' with a space or replacing all upper + * case words. + * + * Volume ids already containing spaces or lower case characters are left unchanged. + */ + QString beautifiedVolumeId() const; + + /** + * Content type. May be combined by a binary OR. + */ + enum MediumContent { + CONTENT_NONE = 0x1, + CONTENT_AUDIO = 0x2, + CONTENT_DATA = 0x4, + CONTENT_VIDEO_CD = 0x8, + CONTENT_VIDEO_DVD = 0x10, + CONTENT_ALL = 0xFF + }; + + /** + * \return a bitwise combination of MediumContent. + * A VideoCD for example may have the following content: + * CONTENT_AUDIO|CONTENT_DATA|CONTENT_VIDEO_CD + */ + int content() const; + + /** + * \return The volume descriptor from the ISO9660 filesystem. + */ + const K3bIso9660SimplePrimaryDescriptor& iso9660Descriptor() const; + + /** + * \return A short one-liner string representing the medium. + * This string may be used for labels or selection boxes. + * \param useContent if true the content of the CD/DVD will be used, otherwise + * the string will simply be something like "empty DVD-R medium". + */ + QString shortString( bool useContent = true ) const; + + /** + * \return A HTML formatted string decribing this medium. This includes the device, the + * medium type, the contents type, and some detail information like the number of + * tracks. + * This string may be used for tooltips or short descriptions. + */ + QString longString() const; + + bool operator==( const K3bMedium& other ); + bool operator!=( const K3bMedium& other ); + + private: + void analyseContent(); + + void detach(); + + class Data; + KSharedPtr<Data> d; +}; + +#endif diff --git a/src/k3bminibutton.cpp b/src/k3bminibutton.cpp new file mode 100644 index 0000000..0d0a1db --- /dev/null +++ b/src/k3bminibutton.cpp @@ -0,0 +1,77 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * K3bMiniButton is based on KDockButton_Private + * Copyright (C) 2000 Max Judin <novaprint@mtu-net.ru> + * Copyright (C) 2002,2003 Joseph Wenninger <jowenn@kde.org> + * Copyright (C) 2005 Dominik Haumann <dhdev@gmx.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bminibutton.h" + +#include <qpainter.h> + + +K3bMiniButton::K3bMiniButton( QWidget *parent, const char * name ) + :QPushButton( parent, name ), + m_mouseOver( false ) +{ + setFocusPolicy( NoFocus ); +} + +K3bMiniButton::~K3bMiniButton() +{ +} + + +void K3bMiniButton::drawButton( QPainter* p ) +{ + p->fillRect( 0,0, width(), height(), QBrush(colorGroup().brush(QColorGroup::Background)) ); + p->drawPixmap( (width() - pixmap()->width()) / 2, (height() - pixmap()->height()) / 2, *pixmap() ); + if( m_mouseOver && !isDown() ){ + p->setPen( white ); + p->moveTo( 0, height() - 1 ); + p->lineTo( 0, 0 ); + p->lineTo( width() - 1, 0 ); + + p->setPen( colorGroup().dark() ); + p->lineTo( width() - 1, height() - 1 ); + p->lineTo( 0, height() - 1 ); + } + if( isOn() || isDown() ){ + p->setPen( colorGroup().dark() ); + p->moveTo( 0, height() - 1 ); + p->lineTo( 0, 0 ); + p->lineTo( width() - 1, 0 ); + + p->setPen( white ); + p->lineTo( width() - 1, height() - 1 ); + p->lineTo( 0, height() - 1 ); + } +} + +void K3bMiniButton::enterEvent( QEvent * ) +{ + m_mouseOver = true; + repaint(); +} + + +void K3bMiniButton::leaveEvent( QEvent * ) +{ + m_mouseOver = false; + repaint(); +} + +#include "k3bminibutton.moc" diff --git a/src/k3bminibutton.h b/src/k3bminibutton.h new file mode 100644 index 0000000..b3d38a0 --- /dev/null +++ b/src/k3bminibutton.h @@ -0,0 +1,51 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * K3bMiniButton is based on KDockButton_Private + * Copyright (C) 2000 Max Judin <novaprint@mtu-net.ru> + * Copyright (C) 2002,2003 Joseph Wenninger <jowenn@kde.org> + * Copyright (C) 2005 Dominik Haumann <dhdev@gmx.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_MINI_BUTTON_H_ +#define _K3B_MINI_BUTTON_H_ + +#include <qpushbutton.h> + +class QPainter; +class QEvent; + + +/** + * K3bMiniButton is a minimalistic button mainly used + * to show a pixmap. + */ +class K3bMiniButton : public QPushButton +{ + Q_OBJECT + + public: + K3bMiniButton( QWidget *parent=0, const char *name=0 ); + virtual ~K3bMiniButton(); + + protected: + virtual void drawButton( QPainter * ); + virtual void enterEvent( QEvent * ); + virtual void leaveEvent( QEvent * ); + + private: + bool m_mouseOver; +}; + +#endif diff --git a/src/k3bmixedprojectinterface.cpp b/src/k3bmixedprojectinterface.cpp new file mode 100644 index 0000000..3b5004e --- /dev/null +++ b/src/k3bmixedprojectinterface.cpp @@ -0,0 +1,46 @@ +/* + * + * $Id: k3bmixedprojectinterface.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bmixedprojectinterface.h" +#include "k3bdataprojectinterface.h" +#include "k3baudioprojectinterface.h" + +#include <kapplication.h> +#include <dcopclient.h> + +#include <k3bmixeddoc.h> +#include <k3bdatadoc.h> +#include <k3baudiodoc.h> + + +K3bMixedProjectInterface::K3bMixedProjectInterface( K3bMixedDoc* doc, const char* name ) + : K3bProjectInterface( doc, name ), + m_mixedDoc( doc ) +{ + m_dataInterface = new K3bDataProjectInterface( doc->dataDoc(), objId() + "-datapart" ); + m_audioInterface = new K3bAudioProjectInterface( doc->audioDoc(), objId() + "-audiopart" ); +} + + +DCOPRef K3bMixedProjectInterface::dataPart() const +{ + return DCOPRef( kapp->dcopClient()->appId(), m_dataInterface->objId() ); +} + + +DCOPRef K3bMixedProjectInterface::audioPart() const +{ + return DCOPRef( kapp->dcopClient()->appId(), m_audioInterface->objId() ); +} diff --git a/src/k3bmixedprojectinterface.h b/src/k3bmixedprojectinterface.h new file mode 100644 index 0000000..21892d1 --- /dev/null +++ b/src/k3bmixedprojectinterface.h @@ -0,0 +1,47 @@ +/* + * + * $Id: k3bmixedprojectinterface.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_MIXED_PROJECT_INTERFACE_H_ +#define _K3B_MIXED_PROJECT_INTERFACE_H_ + +#include "k3bprojectinterface.h" + +#include <dcopref.h> + +class K3bMixedDoc; +class K3bDataProjectInterface; +class K3bAudioProjectInterface; + + +class K3bMixedProjectInterface : public K3bProjectInterface +{ + K_DCOP + + public: + K3bMixedProjectInterface( K3bMixedDoc*, const char* name = 0 ); + + k_dcop: + DCOPRef dataPart() const; + DCOPRef audioPart() const; + + private: + K3bMixedDoc* m_mixedDoc; + + K3bDataProjectInterface* m_dataInterface; + K3bAudioProjectInterface* m_audioInterface; +}; + +#endif diff --git a/src/k3bmusicbrainz.cpp b/src/k3bmusicbrainz.cpp new file mode 100644 index 0000000..f0415af --- /dev/null +++ b/src/k3bmusicbrainz.cpp @@ -0,0 +1,103 @@ +/* + * + * $Id: k3bmusicbrainz.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include <config.h> + +#ifdef HAVE_MUSICBRAINZ + +#include "k3bmusicbrainz.h" + +#include <musicbrainz/mb_c.h> + +#include <kprotocolmanager.h> +#include <kurl.h> +#include <kdebug.h> + + +class K3bMusicBrainz::Private +{ +public: + musicbrainz_t mb; + + QStringList titles; + QStringList artists; +}; + + +K3bMusicBrainz::K3bMusicBrainz() +{ + d = new Private; + d->mb = mb_New(); + mb_UseUTF8( d->mb, 1 ); +} + + +K3bMusicBrainz::~K3bMusicBrainz() +{ + mb_Delete( d->mb ); + delete d; +} + + +int K3bMusicBrainz::query( const QCString& trm ) +{ + d->titles.clear(); + d->artists.clear(); + + if( KProtocolManager::useProxy() ) { + KURL proxy = KProtocolManager::proxyFor("http"); + mb_SetProxy( d->mb, const_cast<char*>(proxy.host().latin1()), short(proxy.port()) ); + } + + char* args[2]; + args[0] = trm.data(); + args[1] = 0; + + if( mb_QueryWithArgs( d->mb, (char*)MBQ_TrackInfoFromTRMId, (char**)args ) ) { + + unsigned int i = 1; + while( mb_Select(d->mb, (char*)MBS_Rewind) && mb_Select1( d->mb, (char*)MBS_SelectTrack, i ) ) { + QCString data(256); + mb_GetResultData( d->mb, (char*)MBE_TrackGetArtistName, data.data(), 256 ); + d->artists.append( QString::fromUtf8( data ).stripWhiteSpace() ); + mb_GetResultData( d->mb, (char*)MBE_TrackGetTrackName, data.data(), 256 ); + d->titles.append( QString::fromUtf8( data ).stripWhiteSpace() ); + + ++i; + } + + return i-1; + } + else { + char buffer[256]; + mb_GetQueryError( d->mb, buffer, 256 ); + kdDebug() << "(K3bMusicBrainz) query error: " << buffer << endl; + return 0; + } +} + + +const QString& K3bMusicBrainz::title( unsigned int i ) const +{ + return d->titles[i]; +} + + +const QString& K3bMusicBrainz::artist( unsigned int i ) const +{ + return d->artists[i]; +} + +#endif diff --git a/src/k3bmusicbrainz.h b/src/k3bmusicbrainz.h new file mode 100644 index 0000000..6cf5d06 --- /dev/null +++ b/src/k3bmusicbrainz.h @@ -0,0 +1,54 @@ +/* + * + * $Id: k3bmusicbrainz.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_MUSICBRAINZ_H_ +#define _K3B_MUSICBRAINZ_H_ + +#include <config.h> + +#ifdef HAVE_MUSICBRAINZ + +#include <qcstring.h> +#include <qstring.h> + + +/** + * A wrapper class around libmusicbrainz. Use in combination with K3bTRM. + * + * Tries to determine the artist and title related to a trm. + */ +class K3bMusicBrainz +{ + public: + K3bMusicBrainz(); + ~K3bMusicBrainz(); + + /** + * \return number of found results. + */ + int query( const QCString& trm ); + + const QString& title( unsigned int i = 0 ) const; + const QString& artist( unsigned int i = 0 ) const; + + private: + class Private; + Private* d; +}; + + +#endif + +#endif diff --git a/src/k3bpassivepopup.cpp b/src/k3bpassivepopup.cpp new file mode 100644 index 0000000..d1865cf --- /dev/null +++ b/src/k3bpassivepopup.cpp @@ -0,0 +1,280 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bpassivepopup.h" +#include "k3bwidgetshoweffect.h" +#include "k3btimeoutwidget.h" +#include "k3bminibutton.h" + +#include "k3bthememanager.h" +#include <k3bapplication.h> + +#include <kapplication.h> +#include <klocale.h> +#include <kiconloader.h> +#include <kguiitem.h> +#include <kpushbutton.h> +#include <kactivelabel.h> + +#include <qtimer.h> +#include <qlayout.h> +#include <qlabel.h> +#include <qmainwindow.h> +#include <qmessagebox.h> +#include <qstyle.h> +#include <qtooltip.h> +#include <qfont.h> + + +static const char* const sticky_xpm[] = { + "5 5 2 1", + "# c black", + ". c None", + "#####", + "#...#", + "#...#", + "#...#", + "#####" +}; + +static QPixmap themedMessageBoxIcon( K3bPassivePopup::MessageType mt ) +{ + QString icon_name; + QMessageBox::Icon qIcon; + + switch( mt ) { + case K3bPassivePopup::Information: + qIcon = QMessageBox::Information; + icon_name = "messagebox_info"; + break; + case K3bPassivePopup::Warning: + qIcon = QMessageBox::Warning; + icon_name = "messagebox_warning"; + break; + case K3bPassivePopup::Error: + qIcon = QMessageBox::Critical; + icon_name = "messagebox_critical"; + break; + default: + return QPixmap(); + break; + } + + QPixmap ret = KApplication::kApplication()->iconLoader()->loadIcon(icon_name, KIcon::NoGroup, KIcon::SizeMedium, KIcon::DefaultState, 0, true); + + if( ret.isNull() ) + return QMessageBox::standardIcon( qIcon ); + else + return ret; +} + + +class K3bPassivePopup::Private +{ +public: + int timeout; + int showEffect; + + K3bTimeoutWidget* timeoutWidget; + QLabel* titleLabel; + KActiveLabel* messageLabel; + QLabel* pixmapLabel; + K3bMiniButton* closeButton; + K3bMiniButton* stickyButton; +}; + + +K3bPassivePopup::K3bPassivePopup( QWidget* parent ) + : QFrame( parent ) +{ + d = new Private; + d->timeout = 6000; + d->showEffect = 0; + + setFrameStyle( QFrame::StyledPanel | QFrame::Raised ); + // setWFlags( Qt::WX11BypassWM ); + + QVBoxLayout* mainLay = new QVBoxLayout( this ); + mainLay->setMargin( frameWidth() ); + mainLay->setSpacing( 0 ); + + QGridLayout* grid = new QGridLayout; + grid->setMargin( 9 ); + grid->setSpacing( 6 ); + + d->titleLabel = new QLabel( this ); + d->titleLabel->setMargin( 5 ); + d->titleLabel->setAlignment( Qt::AlignCenter ); + QFont fnt( d->titleLabel->font() ); + fnt.setBold( true ); + d->titleLabel->setFont( fnt ); + + d->messageLabel = new KActiveLabel( this ); + + d->pixmapLabel = new QLabel( this ); + d->pixmapLabel->setAlignment( Qt::AlignTop ); + + d->timeoutWidget = new K3bTimeoutWidget( this ); + connect( d->timeoutWidget, SIGNAL(timeout()), this, SLOT(slotClose()) ); + + d->closeButton = new K3bMiniButton( d->titleLabel ); + d->closeButton->setPixmap( style().stylePixmap( QStyle::SP_TitleBarCloseButton, this ) ); + d->closeButton->setFixedSize( d->closeButton->pixmap()->width(), d->closeButton->pixmap()->height() ); + QToolTip::add( d->closeButton, i18n("Close") ); + connect( d->closeButton, SIGNAL(clicked()), this, SLOT(slotClose()) ); + + d->stickyButton = new K3bMiniButton( d->titleLabel ); + d->stickyButton->setToggleButton( true ); + d->stickyButton->setPixmap( const_cast< const char** >( sticky_xpm ) ); + d->stickyButton->setFixedSize( d->closeButton->pixmap()->width(), d->closeButton->pixmap()->height() ); + QToolTip::add( d->stickyButton, i18n("Keep Open") ); + connect( d->stickyButton, SIGNAL(toggled(bool)), this, SLOT(slotSticky(bool)) ); + + grid->addWidget( d->pixmapLabel, 0, 0 ); + grid->addWidget( d->messageLabel, 0, 1 ); + grid->addWidget( d->timeoutWidget, 0, 2 ); + grid->setColStretch( 1, 1 ); + + mainLay->addWidget( d->titleLabel ); + mainLay->addLayout( grid, 1 ); + + QHBoxLayout* titleLay = new QHBoxLayout( d->titleLabel ); + titleLay->setMargin( d->titleLabel->margin() ); + titleLay->setSpacing( 2 ); + titleLay->addStretch(); + titleLay->addWidget( d->stickyButton ); + titleLay->addWidget( d->closeButton ); + + if( K3bTheme* theme = k3bappcore->themeManager()->currentTheme() ) { + d->titleLabel->setPaletteBackgroundColor( theme->backgroundColor() ); + d->titleLabel->setPaletteForegroundColor( theme->foregroundColor() ); + } + + setTitle( QString::null ); + setMessageType( Information ); +} + + +K3bPassivePopup::~K3bPassivePopup() +{ + delete d; +} + + +void K3bPassivePopup::setShowCloseButton( bool b ) +{ + d->closeButton->setShown( b ); + adjustSize(); +} + + +void K3bPassivePopup::setShowCountdown( bool b ) +{ + d->timeoutWidget->setShown( b ); + d->stickyButton->setShown( b ); +} + + +void K3bPassivePopup::setMessage( const QString& m ) +{ + d->messageLabel->setText( "<qt>" + m ); + adjustSize(); +} + + +void K3bPassivePopup::setTitle( const QString& t ) +{ + d->titleLabel->setText( t ); + // d->titleLabel->setShown( !t.isEmpty() ); + adjustSize(); +} + + +void K3bPassivePopup::setTimeout( int msecs ) +{ + d->timeout = msecs; +} + + +void K3bPassivePopup::setMessageType( MessageType m ) +{ + d->pixmapLabel->setPixmap( themedMessageBoxIcon( m ) ); + adjustSize(); +} + + +void K3bPassivePopup::slideIn() +{ + d->showEffect = K3bWidgetShowEffect::Slide; + connect( K3bWidgetShowEffect::showWidget( this, (K3bWidgetShowEffect::Effect)d->showEffect ), SIGNAL(widgetShown(QWidget*)), + this, SLOT(slotShown()) ); +} + + +void K3bPassivePopup::slotShown() +{ + if( d->timeoutWidget->isVisible() ) { + d->timeoutWidget->setTimeout( d->timeout ); + d->timeoutWidget->start(); + } + else + QTimer::singleShot( d->timeout, this, SLOT(slotClose()) ); +} + + +void K3bPassivePopup::slotHidden() +{ + deleteLater(); +} + + +void K3bPassivePopup::slotClose() +{ + if( d->showEffect != 0 ) { + connect( K3bWidgetShowEffect::hideWidget( this, (K3bWidgetShowEffect::Effect)d->showEffect ), SIGNAL(widgetHidden(QWidget*)), + this, SLOT(slotHidden()) ); + } + else + deleteLater(); +} + + +void K3bPassivePopup::slotSticky( bool b ) +{ + if( b ) { + d->timeoutWidget->pause(); + } + else { + d->timeoutWidget->resume(); + } +} + + +void K3bPassivePopup::showPopup( const QString& message, + const QString& title, + MessageType messageType, + bool countdown, + bool button ) +{ + K3bPassivePopup* pop = new K3bPassivePopup( static_cast<QMainWindow*>(qApp->mainWidget())->centralWidget() ); + pop->setMessage( message ); + pop->setTitle( title ); + pop->setMessageType( messageType ); + pop->setShowCloseButton( button ); + pop->setShowCountdown( countdown ); + pop->slideIn(); +} + +#include "k3bpassivepopup.moc" diff --git a/src/k3bpassivepopup.h b/src/k3bpassivepopup.h new file mode 100644 index 0000000..e567d7e --- /dev/null +++ b/src/k3bpassivepopup.h @@ -0,0 +1,76 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_PASSIVE_POPUP_H_ +#define _K3B_PASSIVE_POPUP_H_ + +#include <qframe.h> + +class K3bTimeoutWidget; +class KActiveLabel; +class KPushButton; +class QLabel; + + +/** + * A message box which is closed using a timer or a close button + * It will delete itself once it has been closed. + */ +class K3bPassivePopup : public QFrame +{ + Q_OBJECT + + public: + K3bPassivePopup( QWidget* parent ); + ~K3bPassivePopup(); + + enum MessageType { + Information, + Warning, + Error + }; + + /** + * This will show the popup using K3bWidgetShowEffect::Slide and close it the + * same way. + */ + void slideIn(); + + static void showPopup( const QString& message, + const QString& title = QString::null, + MessageType messageType = Information, + bool countdown = true, + bool button = true ); + + public slots: + void setShowCloseButton( bool b ); + void setShowCountdown( bool b ); + void setMessage( const QString& m ); + void setTitle( const QString& t ); + void setTimeout( int msecs ); + void setMessageType( MessageType m ); + + private slots: + void slotShown(); + void slotHidden(); + void slotClose(); + void slotSticky( bool ); + + private: + class Private; + Private* d; +}; + +#endif diff --git a/src/k3bprojectinterface.cpp b/src/k3bprojectinterface.cpp new file mode 100644 index 0000000..46968fd --- /dev/null +++ b/src/k3bprojectinterface.cpp @@ -0,0 +1,138 @@ +/* + * + * $Id: k3bprojectinterface.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bprojectinterface.h" +#include "k3bburnprogressdialog.h" +#include <k3bdoc.h> +#include <k3bview.h> +#include <k3bmsf.h> +#include <k3bcore.h> +#include <k3bdevicemanager.h> +#include <k3bjob.h> + +#include <qtimer.h> + + +//static +QCString K3bProjectInterface::newIfaceName() +{ + static int s_docIFNumber = 0; + QCString name; + name.setNum( s_docIFNumber++ ); + name.prepend("K3bProject-"); + return name; +} + + +K3bProjectInterface::K3bProjectInterface( K3bDoc* doc, const char* name ) + : DCOPObject( name ? QCString(name) : newIfaceName() ), + m_doc( doc ) +{ +} + + +K3bProjectInterface::~K3bProjectInterface() +{ +} + +void K3bProjectInterface::addUrls( const QStringList& urls ) +{ + m_doc->addUrls( KURL::List(urls) ); +} + +void K3bProjectInterface::addUrl( const QString& url ) +{ + m_doc->addUrl( KURL(url) ); +} + +void K3bProjectInterface::burn() +{ + // we want to return this method immediately + QTimer::singleShot( 0, m_doc->view(), SLOT(slotBurn()) ); +} + + +bool K3bProjectInterface::directBurn() +{ + if( m_doc->burner() ) { + K3bJobProgressDialog* dlg = 0; + if( m_doc->onlyCreateImages() ) + dlg = new K3bJobProgressDialog( m_doc->view() ); + else + dlg = new K3bBurnProgressDialog( m_doc->view() ); + + K3bJob* job = m_doc->newBurnJob( dlg ); + + dlg->startJob( job ); + + delete job; + delete dlg; + + return true; + } + else + return false; +} + + +void K3bProjectInterface::setBurnDevice( const QString& name ) +{ + if( K3bDevice::Device* dev = k3bcore->deviceManager()->findDevice( name ) ) + m_doc->setBurner( dev ); +} + + +int K3bProjectInterface::length() const +{ + return m_doc->length().lba(); +} + + +KIO::filesize_t K3bProjectInterface::size() const +{ + return m_doc->size(); +} + + +const QString& K3bProjectInterface::imagePath() const +{ + return m_doc->tempDir(); +} + + +QString K3bProjectInterface::projectType() const +{ + switch( m_doc->type() ) { + case K3bDoc::AUDIO: + return "audiocd"; + case K3bDoc::DATA: + return "datacd"; + case K3bDoc::MIXED: + return "mixedcd"; + case K3bDoc::VCD: + return "videocd"; + case K3bDoc::MOVIX: + return "emovixcd"; + case K3bDoc::MOVIX_DVD: + return "emovixdvd"; + case K3bDoc::DVD: + return "datadvd"; + case K3bDoc::VIDEODVD: + return "videodvd"; + default: + return "unknown"; + } +} diff --git a/src/k3bprojectinterface.h b/src/k3bprojectinterface.h new file mode 100644 index 0000000..8deb848 --- /dev/null +++ b/src/k3bprojectinterface.h @@ -0,0 +1,91 @@ +/* + * + * $Id: k3bprojectinterface.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_PROJECT_INTERFACE_H_ +#define _K3B_PROJECT_INTERFACE_H_ + +#include <dcopobject.h> +#include <kio/global.h> +#include <qstringlist.h> + +class K3bDoc; + +/** + * Base class for all project interfaces + */ +class K3bProjectInterface : public DCOPObject +{ + K_DCOP + + public: + K3bProjectInterface( K3bDoc*, const char* name = 0 ); + virtual ~K3bProjectInterface(); + + // Generate a name for this interface. Automatically used if name=0 is + // passed to the constructor + static QCString newIfaceName(); + + k_dcop: + virtual void addUrls( const QStringList& urls ); + virtual void addUrl( const QString& url ); + + /** + * Opens the burn dialog + */ + virtual void burn(); + + /** + * Starts the burning immedeately + * \return true if the burning could be started. Be aware that the return + * value does not say anything about the success of the burning + * process. + */ + virtual bool directBurn(); + + virtual void setBurnDevice( const QString& blockdevicename ); + + /** + * \return the length of the project in blocks (frames). + */ + virtual int length() const; + + /** + * \return size of the project in bytes. + */ + virtual KIO::filesize_t size() const; + + virtual const QString& imagePath() const; + + /** + * \return A string representation of the project type. One of: + * \li "datacd" - Data CD + * \li "audiocd" - Audio CD + * \li "mixedcd" - Mixed Mode CD + * \li "videocd" - Video + * \li "emovixcd" - eMovix CD + * \li "datadvd" - Data DVD + * \li "videodvd" - Video DVD + * \li "emovixdvd" - eMovix DVD + * + * Be aware that this is not the same as K3bDoc::documentType for historical reasons. + */ + virtual QString projectType() const; + + private: + K3bDoc* m_doc; +}; + +#endif diff --git a/src/k3bprojectmanager.cpp b/src/k3bprojectmanager.cpp new file mode 100644 index 0000000..0c6d65f --- /dev/null +++ b/src/k3bprojectmanager.cpp @@ -0,0 +1,653 @@ +/* + * + * $Id$ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bprojectmanager.h" + +#include "k3bprojectinterface.h" +#include "k3bdataprojectinterface.h" +#include "k3baudioprojectinterface.h" +#include "k3bmixedprojectinterface.h" +#include "kostore/koStore.h" +#include "kostore/koStoreDevice.h" +#include "k3bapplication.h" +#include "k3binteractiondialog.h" + +#include <k3baudiodoc.h> +#include <k3baudiodatasourceiterator.h> +#include <k3baudiocdtracksource.h> +#include <k3bdatadoc.h> +#include <k3bdvddoc.h> +#include <k3bvideodvddoc.h> +#include <k3bmixeddoc.h> +#include <k3bvcddoc.h> +#include <k3bmovixdoc.h> +#include <k3bmovixdvddoc.h> +#include <k3bglobals.h> +#include <k3bisooptions.h> +#include <k3bdevicemanager.h> + +#include <qptrlist.h> +#include <qmap.h> +#include <qtextstream.h> +#include <qdom.h> +#include <qfile.h> +#include <qapplication.h> +#include <qcursor.h> + +#include <kurl.h> +#include <kdebug.h> +#include <kconfig.h> +#include <kio/netaccess.h> +#include <klocale.h> +#include <kmessagebox.h> + + +class K3bProjectManager::Private +{ +public: + QPtrList<K3bDoc> projects; + K3bDoc* activeProject; + QMap<K3bDoc*, K3bProjectInterface*> projectInterfaceMap; + + int audioUntitledCount; + int dataUntitledCount; + int mixedUntitledCount; + int vcdUntitledCount; + int movixUntitledCount; + int movixDvdUntitledCount; + int dvdUntitledCount; + int videoDvdUntitledCount; +}; + + + + +K3bProjectManager::K3bProjectManager( QObject* parent, const char* name ) + : QObject( parent, name ) +{ + d = new Private(); + d->activeProject = 0; + + d->audioUntitledCount = 0; + d->dataUntitledCount = 0; + d->mixedUntitledCount = 0; + d->vcdUntitledCount = 0; + d->movixUntitledCount = 0; + d->movixDvdUntitledCount = 0; + d->dvdUntitledCount = 0; + d->videoDvdUntitledCount = 0; +} + +K3bProjectManager::~K3bProjectManager() +{ + delete d; +} + + +const QPtrList<K3bDoc>& K3bProjectManager::projects() const +{ + return d->projects; +} + + +void K3bProjectManager::addProject( K3bDoc* doc ) +{ + if( !d->projects.containsRef( doc ) ) { + kdDebug() << "(K3bProjectManager) adding doc " << doc->URL().path() << endl; + + d->projects.append(doc); + + connect( doc, SIGNAL(changed(K3bDoc*)), + this, SLOT(slotProjectChanged(K3bDoc*)) ); + + emit newProject( doc ); + } +} + + +void K3bProjectManager::removeProject( K3bDoc* doc ) +{ + // + // QPtrList.findRef seems to be buggy. Everytime we search for the + // first added item it is not found! + // + for( QPtrListIterator<K3bDoc> it( d->projects ); + it.current(); ++it ) { + if( it.current() == doc ) { + + // remove the DCOP interface + QMap<K3bDoc*, K3bProjectInterface*>::iterator it = d->projectInterfaceMap.find( doc ); + if( it != d->projectInterfaceMap.end() ) { + // delete the interface + delete it.data(); + d->projectInterfaceMap.remove( it ); + } + + d->projects.removeRef(doc); + emit closingProject(doc); + + return; + } + } + kdDebug() << "(K3bProjectManager) unable to find doc: " << doc->URL().path() << endl; +} + + +K3bDoc* K3bProjectManager::findByUrl( const KURL& url ) +{ + for( QPtrListIterator<K3bDoc> it( d->projects ); + it.current(); ++it ) { + K3bDoc* doc = it.current(); + if( doc->URL() == url ) + return doc; + } + return 0; +} + + +bool K3bProjectManager::isEmpty() const +{ + return d->projects.isEmpty(); +} + + +void K3bProjectManager::setActive( K3bDoc* doc ) +{ + if( !doc ) { + d->activeProject = 0L; + emit activeProjectChanged( 0L ); + return; + } + + // + // QPtrList.findRef seems to be buggy. Everytime we search for the + // first added item it is not found! + // + for( QPtrListIterator<K3bDoc> it( d->projects ); + it.current(); ++it ) { + if( it.current() == doc ) { + d->activeProject = doc; + emit activeProjectChanged(doc); + } + } +} + + +K3bDoc* K3bProjectManager::activeProject() const +{ + return d->activeProject; +} + + +K3bDoc* K3bProjectManager::createEmptyProject( K3bDoc::DocType type ) +{ + K3bDoc* doc = 0; + QString fileName; + + switch( type ) { + case K3bDoc::AUDIO: { + doc = new K3bAudioDoc( this ); + fileName = i18n("AudioCD%1").arg(d->audioUntitledCount++); + break; + } + + case K3bDoc::DATA: { + doc = new K3bDataDoc( this ); + fileName = i18n("DataCD%1").arg(d->dataUntitledCount++); + break; + } + + case K3bDoc::MIXED: { + doc = new K3bMixedDoc( this ); + fileName=i18n("MixedCD%1").arg(d->mixedUntitledCount++); + break; + } + + case K3bDoc::VCD: { + doc = new K3bVcdDoc( this ); + fileName=i18n("VideoCD%1").arg(d->vcdUntitledCount++); + break; + } + + case K3bDoc::MOVIX: { + doc = new K3bMovixDoc( this ); + fileName=i18n("eMovixCD%1").arg(d->movixUntitledCount++); + break; + } + + case K3bDoc::MOVIX_DVD: { + doc = new K3bMovixDvdDoc( this ); + fileName=i18n("eMovixDVD%1").arg(d->movixDvdUntitledCount++); + break; + } + + case K3bDoc::DVD: { + doc = new K3bDvdDoc( this ); + fileName = i18n("DataDVD%1").arg(d->dvdUntitledCount++); + break; + } + + case K3bDoc::VIDEODVD: { + doc = new K3bVideoDvdDoc( this ); + fileName = i18n("VideoDVD%1").arg(d->videoDvdUntitledCount++); + break; + } + } + + KURL url; + url.setFileName(fileName); + doc->setURL(url); + + doc->newDocument(); + + loadDefaults( doc ); + + return doc; +} + + +K3bDoc* K3bProjectManager::createProject( K3bDoc::DocType type ) +{ + K3bDoc* doc = createEmptyProject( type ); + + // create the dcop interface + dcopInterface( doc ); + + addProject( doc ); + + return doc; +} + + +void K3bProjectManager::loadDefaults( K3bDoc* doc ) +{ + KConfig* c = kapp->config(); + + QString oldGroup = c->group(); + + QString cg = "default " + doc->typeString() + " settings"; + + // earlier K3b versions loaded the saved settings + // so that is what we do as a default + int i = KConfigGroup( c, "General Options" ).readNumEntry( "action dialog startup settings", + K3bInteractionDialog::LOAD_SAVED_SETTINGS ); + if( i == K3bInteractionDialog::LOAD_K3B_DEFAULTS ) + return; // the default k3b settings are the ones everyone starts with + else if( i == K3bInteractionDialog::LOAD_LAST_SETTINGS ) + cg = "last used " + cg; + + c->setGroup( cg ); + + QString mode = c->readEntry( "writing_mode" ); + if ( mode == "dao" ) + doc->setWritingMode( K3b::DAO ); + else if( mode == "tao" ) + doc->setWritingMode( K3b::TAO ); + else if( mode == "raw" ) + doc->setWritingMode( K3b::RAW ); + else + doc->setWritingMode( K3b::WRITING_MODE_AUTO ); + + doc->setDummy( c->readBoolEntry( "simulate", false ) ); + doc->setOnTheFly( c->readBoolEntry( "on_the_fly", true ) ); + doc->setRemoveImages( c->readBoolEntry( "remove_image", true ) ); + doc->setOnlyCreateImages( c->readBoolEntry( "only_create_image", false ) ); + doc->setBurner( k3bcore->deviceManager()->findDevice( c->readEntry( "writer_device" ) ) ); + // Default = 0 (Auto) + doc->setSpeed( c->readNumEntry( "writing_speed", 0 ) ); + doc->setWritingApp( K3b::writingAppFromString( c->readEntry( "writing_app" ) ) ); + + + switch( doc->type() ) { + case K3bDoc::AUDIO: { + K3bAudioDoc* audioDoc = static_cast<K3bAudioDoc*>(doc); + + audioDoc->writeCdText( c->readBoolEntry( "cd_text", true ) ); + audioDoc->setHideFirstTrack( c->readBoolEntry( "hide_first_track", false ) ); + audioDoc->setNormalize( c->readBoolEntry( "normalize", false ) ); + audioDoc->setAudioRippingParanoiaMode( c->readNumEntry( "paranoia mode", 0 ) ); + audioDoc->setAudioRippingRetries( c->readNumEntry( "read retries", 128 ) ); + audioDoc->setAudioRippingIgnoreReadErrors( c->readBoolEntry( "ignore read errors", false ) ); + + break; + } + + case K3bDoc::MOVIX: + case K3bDoc::MOVIX_DVD: { + K3bMovixDoc* movixDoc = static_cast<K3bMovixDoc*>(doc); + + movixDoc->setSubtitleFontset( c->readEntry("subtitle_fontset") ); + + movixDoc->setLoopPlaylist( c->readNumEntry("loop", 1 ) ); + movixDoc->setAdditionalMPlayerOptions( c->readEntry( "additional_mplayer_options" ) ); + movixDoc->setUnwantedMPlayerOptions( c->readEntry( "unwanted_mplayer_options" ) ); + + movixDoc->setBootMessageLanguage( c->readEntry("boot_message_language") ); + + movixDoc->setDefaultBootLabel( c->readEntry( "default_boot_label" ) ); + + movixDoc->setShutdown( c->readBoolEntry( "shutdown", false) ); + movixDoc->setReboot( c->readBoolEntry( "reboot", false ) ); + movixDoc->setEjectDisk( c->readBoolEntry( "eject", false ) ); + movixDoc->setRandomPlay( c->readBoolEntry( "random_play", false ) ); + movixDoc->setNoDma( c->readBoolEntry( "no_dma", false ) ); + // fallthrough + } + + case K3bDoc::DATA: + case K3bDoc::DVD: { + K3bDataDoc* dataDoc = static_cast<K3bDataDoc*>(doc); + + dataDoc->setIsoOptions( K3bIsoOptions::load( c, false ) ); + + QString datamode = c->readEntry( "data_track_mode" ); + if( datamode == "mode1" ) + dataDoc->setDataMode( K3b::MODE1 ); + else if( datamode == "mode2" ) + dataDoc->setDataMode( K3b::MODE2 ); + else + dataDoc->setDataMode( K3b::DATA_MODE_AUTO ); + + dataDoc->setVerifyData( c->readBoolEntry( "verify data", false ) ); + + QString s = c->readEntry( "multisession mode" ); + if( s == "none" ) + dataDoc->setMultiSessionMode( K3bDataDoc::NONE ); + else if( s == "start" ) + dataDoc->setMultiSessionMode( K3bDataDoc::START ); + else if( s == "continue" ) + dataDoc->setMultiSessionMode( K3bDataDoc::CONTINUE ); + else if( s == "finish" ) + dataDoc->setMultiSessionMode( K3bDataDoc::FINISH ); + else + dataDoc->setMultiSessionMode( K3bDataDoc::AUTO ); + + break; + } + + case K3bDoc::VIDEODVD: { + // the only defaults we need here are the volume id and stuff + K3bDataDoc* dataDoc = static_cast<K3bDataDoc*>(doc); + dataDoc->setIsoOptions( K3bIsoOptions::load( c, false ) ); + dataDoc->setVerifyData( c->readBoolEntry( "verify data", false ) ); + break; + } + + case K3bDoc::MIXED: { + K3bMixedDoc* mixedDoc = static_cast<K3bMixedDoc*>(doc); + + mixedDoc->audioDoc()->writeCdText( c->readBoolEntry( "cd_text", true ) ); + mixedDoc->audioDoc()->setNormalize( c->readBoolEntry( "normalize", false ) ); + + // load mixed type + if( c->readEntry( "mixed_type" ) == "last_track" ) + mixedDoc->setMixedType( K3bMixedDoc::DATA_LAST_TRACK ); + else if( c->readEntry( "mixed_type" ) == "first_track" ) + mixedDoc->setMixedType( K3bMixedDoc::DATA_FIRST_TRACK ); + else + mixedDoc->setMixedType( K3bMixedDoc::DATA_SECOND_SESSION ); + + QString datamode = c->readEntry( "data_track_mode" ); + if( datamode == "mode1" ) + mixedDoc->dataDoc()->setDataMode( K3b::MODE1 ); + else if( datamode == "mode2" ) + mixedDoc->dataDoc()->setDataMode( K3b::MODE2 ); + else + mixedDoc->dataDoc()->setDataMode( K3b::DATA_MODE_AUTO ); + + mixedDoc->dataDoc()->setIsoOptions( K3bIsoOptions::load( c, false ) ); + + if( mixedDoc->dataDoc()->isoOptions().volumeID().isEmpty() ) + mixedDoc->dataDoc()->setVolumeID( doc->URL().fileName() ); + + break; + } + + case K3bDoc::VCD: { + K3bVcdDoc* vcdDoc = static_cast<K3bVcdDoc*>(doc); + + // FIXME: I think we miss a lot here! + + vcdDoc->vcdOptions()->setPbcEnabled( c->readBoolEntry( "Use Playback Control", false ) ); + vcdDoc->vcdOptions()->setPbcNumkeysEnabled( c->readBoolEntry( "Use numeric keys to navigate chapters", false ) ); + vcdDoc->vcdOptions()->setPbcPlayTime( c->readNumEntry( "Play each Sequence/Segment", 1 ) ); + vcdDoc->vcdOptions()->setPbcWaitTime( c->readNumEntry( "Time to wait after each Sequence/Segment", 2 ) ); + + if( vcdDoc->vcdOptions()->volumeId().isEmpty() ) + vcdDoc->vcdOptions()->setVolumeId( doc->URL().fileName() ); + + break; + } + } + + if( doc->type() == K3bDoc::DATA || + doc->type() == K3bDoc::MOVIX || + doc->type() == K3bDoc::MOVIX_DVD || + doc->type() == K3bDoc::VIDEODVD || + doc->type() == K3bDoc::DVD ) { + if( static_cast<K3bDataDoc*>(doc)->isoOptions().volumeID().isEmpty() ) + static_cast<K3bDataDoc*>(doc)->setVolumeID( doc->URL().fileName() ); + } + + doc->setModified( false ); + + c->setGroup( oldGroup ); +} + + +K3bProjectInterface* K3bProjectManager::dcopInterface( K3bDoc* doc ) +{ + QMap<K3bDoc*, K3bProjectInterface*>::iterator it = d->projectInterfaceMap.find( doc ); + if( it == d->projectInterfaceMap.end() ) { + K3bProjectInterface* dcopInterface = 0; + if( doc->type() == K3bDoc::DATA || doc->type() == K3bDoc::DVD ) + dcopInterface = new K3bDataProjectInterface( static_cast<K3bDataDoc*>(doc) ); + else if( doc->type() == K3bDoc::AUDIO ) + dcopInterface = new K3bAudioProjectInterface( static_cast<K3bAudioDoc*>(doc) ); + else if( doc->type() == K3bDoc::MIXED ) + dcopInterface = new K3bMixedProjectInterface( static_cast<K3bMixedDoc*>(doc) ); + else + dcopInterface = new K3bProjectInterface( doc ); + d->projectInterfaceMap[doc] = dcopInterface; + return dcopInterface; + } + else + return it.data(); +} + + +K3bDoc* K3bProjectManager::openProject( const KURL& url ) +{ + QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); + + QString tmpfile; + KIO::NetAccess::download( url, tmpfile, 0L ); + + // /////////////////////////////////////////////// + // first check if it's a store or an old plain xml file + bool success = false; + QDomDocument xmlDoc; + + // try opening a store + KoStore* store = KoStore::createStore( tmpfile, KoStore::Read ); + if( store ) { + if( !store->bad() ) { + // try opening the document inside the store + if( store->open( "maindata.xml" ) ) { + QIODevice* dev = store->device(); + dev->open( IO_ReadOnly ); + if( xmlDoc.setContent( dev ) ) + success = true; + dev->close(); + store->close(); + } + } + + delete store; + } + + if( !success ) { + // try reading an old plain document + QFile f( tmpfile ); + if ( f.open( IO_ReadOnly ) ) { + // + // First check if this is really an xml file beacuse if this is a very big file + // the setContent method blocks for a very long time + // + char test[5]; + if( f.readBlock( test, 5 ) ) { + if( ::strncmp( test, "<?xml", 5 ) ) { + kdDebug() << "(K3bDoc) " << url.path() << " seems to be no xml file." << endl; + QApplication::restoreOverrideCursor(); + return 0; + } + f.reset(); + } + else { + kdDebug() << "(K3bDoc) could not read from file." << endl; + QApplication::restoreOverrideCursor(); + return 0; + } + if( xmlDoc.setContent( &f ) ) + success = true; + f.close(); + } + } + + // /////////////////////////////////////////////// + KIO::NetAccess::removeTempFile( tmpfile ); + + if( !success ) { + kdDebug() << "(K3bDoc) could not open file " << url.path() << endl; + QApplication::restoreOverrideCursor(); + return 0; + } + + // check the documents DOCTYPE + K3bDoc::DocType type = K3bDoc::AUDIO; + if( xmlDoc.doctype().name() == "k3b_audio_project" ) + type = K3bDoc::AUDIO; + else if( xmlDoc.doctype().name() == "k3b_data_project" ) + type = K3bDoc::DATA; + else if( xmlDoc.doctype().name() == "k3b_vcd_project" ) + type = K3bDoc::VCD; + else if( xmlDoc.doctype().name() == "k3b_mixed_project" ) + type = K3bDoc::MIXED; + else if( xmlDoc.doctype().name() == "k3b_movix_project" ) + type = K3bDoc::MOVIX; + else if( xmlDoc.doctype().name() == "k3b_movixdvd_project" ) + type = K3bDoc::MOVIX_DVD; + else if( xmlDoc.doctype().name() == "k3b_dvd_project" ) + type = K3bDoc::DVD; + else if( xmlDoc.doctype().name() == "k3b_video_dvd_project" ) + type = K3bDoc::VIDEODVD; + else { + kdDebug() << "(K3bDoc) unknown doc type: " << xmlDoc.doctype().name() << endl; + QApplication::restoreOverrideCursor(); + return 0; + } + + // we do not know yet if we will be able to actually open the project, so don't inform others yet + K3bDoc* newDoc = createEmptyProject( type ); + + // --------- + // load the data into the document + QDomElement root = xmlDoc.documentElement(); + if( newDoc->loadDocumentData( &root ) ) { + newDoc->setURL( url ); + newDoc->setSaved( true ); + newDoc->setModified( false ); + + // ok, finish the doc setup, inform the others about the new project + dcopInterface( newDoc ); + addProject( newDoc ); + + // FIXME: find a better way to tell everyone (especially the projecttabwidget) + // that the doc is not changed + emit projectSaved( newDoc ); + + kdDebug() << "(K3bProjectManager) loading project done." << endl; + } + else { + delete newDoc; + newDoc = 0; + } + + QApplication::restoreOverrideCursor(); + + return newDoc; +} + + +bool K3bProjectManager::saveProject( K3bDoc* doc, const KURL& url ) +{ + QString tmpfile; + KIO::NetAccess::download( url, tmpfile, 0L ); + + bool success = false; + + // create the store + KoStore* store = KoStore::createStore( tmpfile, KoStore::Write, "application/x-k3b" ); + if( store ) { + if( store->bad() ) { + delete store; + } + else { + // open the document inside the store + store->open( "maindata.xml" ); + + // save the data in the document + QDomDocument xmlDoc( "k3b_" + doc->typeString() + "_project" ); + + xmlDoc.appendChild( xmlDoc.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" ) ); + QDomElement docElem = xmlDoc.createElement( "k3b_" + doc->typeString() + "_project" ); + xmlDoc.appendChild( docElem ); + success = doc->saveDocumentData( &docElem ); + if( success ) { + KoStoreDevice dev(store); + dev.open( IO_WriteOnly ); + QTextStream xmlStream( &dev ); + xmlDoc.save( xmlStream, 0 ); + + doc->setURL( url ); + doc->setModified( false ); + } + + // close the document inside the store + store->close(); + + // remove the store (destructor writes the store to disk) + delete store; + + doc->setSaved( success ); + + if( success ) { + emit projectSaved( doc ); + } + } + } + + KIO::NetAccess::removeTempFile( tmpfile ); + + return success; +} + + +void K3bProjectManager::slotProjectChanged( K3bDoc* doc ) +{ + emit projectChanged( doc ); +} + +#include "k3bprojectmanager.moc" diff --git a/src/k3bprojectmanager.h b/src/k3bprojectmanager.h new file mode 100644 index 0000000..60d9c80 --- /dev/null +++ b/src/k3bprojectmanager.h @@ -0,0 +1,89 @@ +/* + * + * $Id$ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_PROJECT_MANAGER_H_ +#define _K3B_PROJECT_MANAGER_H_ + +#include <qobject.h> +#include <qptrlist.h> +#include <k3bdoc.h> + + +class KURL; +class K3bProjectInterface; + + +class K3bProjectManager : public QObject +{ + Q_OBJECT + + public: + K3bProjectManager( QObject* parent = 0, const char* name = 0 ); + virtual ~K3bProjectManager(); + + const QPtrList<K3bDoc>& projects() const; + + /** + * Create a new project including loading user defaults and creating + * the dcop interface. + */ + K3bDoc* createProject( K3bDoc::DocType type ); + + /** + * Opens a K3b project. + * \return 0 if url does not point to a valid k3b project file, the new project otherwise. + */ + K3bDoc* openProject( const KURL &url ); + + /** + * saves the document under filename and format. + */ + bool saveProject( K3bDoc*, const KURL &url ); + + K3bDoc* activeDoc() const { return activeProject(); } + K3bDoc* activeProject() const; + K3bDoc* findByUrl( const KURL& url ); + bool isEmpty() const; + + /** + * Will create if none exists. + */ + K3bProjectInterface* dcopInterface( K3bDoc* doc ); + + public slots: + void addProject( K3bDoc* ); + void removeProject( K3bDoc* ); + void setActive( K3bDoc* ); + void loadDefaults( K3bDoc* ); + + signals: + void newProject( K3bDoc* ); + void projectSaved( K3bDoc* ); + void closingProject( K3bDoc* ); + void projectChanged( K3bDoc* doc ); + void activeProjectChanged( K3bDoc* ); + + private slots: + void slotProjectChanged( K3bDoc* doc ); + + private: + // used internal + K3bDoc* createEmptyProject( K3bDoc::DocType ); + + class Private; + Private* d; +}; + +#endif diff --git a/src/k3bprojecttabwidget.cpp b/src/k3bprojecttabwidget.cpp new file mode 100644 index 0000000..d86fad4 --- /dev/null +++ b/src/k3bprojecttabwidget.cpp @@ -0,0 +1,216 @@ +/* + * + * $Id: k3bprojecttabwidget.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + + +#include "k3bprojecttabwidget.h" +#include "k3bapplication.h" +#include "k3bprojectmanager.h" + +#include <k3bview.h> +#include <k3bdoc.h> + +#include <kaction.h> +#include <kiconloader.h> +#include <kdebug.h> +#include <kurldrag.h> +#include <klocale.h> + +#include <qevent.h> +#include <qtabbar.h> + + +class K3bProjectTabWidget::ProjectData +{ +public: + ProjectData() + : doc(0), + modified(false) { + } + + ProjectData( K3bDoc* doc_ ) + : doc(doc_), + modified(false) { + } + + // the project + K3bDoc* doc; + + // is the project marked modified here + bool modified; +}; + + + +K3bProjectTabWidget::K3bProjectTabWidget( QWidget *parent, const char *name, WFlags f ) + : QTabWidget( parent, name, f ) +{ + tabBar()->setAcceptDrops(true); + tabBar()->installEventFilter( this ); + + m_projectActionMenu = new KActionMenu( i18n("Project"), this ); +} + + +K3bProjectTabWidget::~K3bProjectTabWidget() +{ +} + + +void K3bProjectTabWidget::addTab( QWidget* child, const QString& label ) +{ + QTabWidget::addTab( child, label ); + tabBar()->setShown( count() != 1 ); +} + + +void K3bProjectTabWidget::addTab( QWidget* child, const QIconSet& iconset, const QString& label ) +{ + QTabWidget::addTab( child, iconset, label ); + tabBar()->setShown( count() != 1 ); +} + + +void K3bProjectTabWidget::addTab( QWidget* child, QTab* tab ) +{ + QTabWidget::addTab( child, tab ); + tabBar()->setShown( count() != 1 ); +} + + +void K3bProjectTabWidget::insertTab( QWidget* child, const QString& label, int index ) +{ + QTabWidget::insertTab( child, label, index ); + tabBar()->setShown( count() != 1 ); +} + + +void K3bProjectTabWidget::insertTab( QWidget* child, const QIconSet& iconset, const QString& label, int index ) +{ + QTabWidget::insertTab( child, iconset, label, index ); + tabBar()->setShown( count() != 1 ); +} + + +void K3bProjectTabWidget::insertTab( QWidget* child, QTab* tab, int index ) +{ + QTabWidget::insertTab( child, tab, index ); + tabBar()->setShown( count() != 1 ); +} + + +void K3bProjectTabWidget::removePage( QWidget* w ) +{ + QTabWidget::removePage( w ); + tabBar()->setShown( count() != 1 ); +} + + +void K3bProjectTabWidget::insertTab( K3bDoc* doc ) +{ + QTabWidget::insertTab( doc->view(), doc->URL().fileName() ); + connect( k3bappcore->projectManager(), SIGNAL(projectSaved(K3bDoc*)), this, SLOT(slotDocSaved(K3bDoc*)) ); + connect( doc, SIGNAL(changed(K3bDoc*)), this, SLOT(slotDocChanged(K3bDoc*)) ); + + m_projectDataMap[doc] = ProjectData( doc ); + + if( doc->isModified() ) + slotDocChanged( doc ); + else + slotDocSaved( doc ); +} + + +void K3bProjectTabWidget::insertAction( KAction* action ) +{ + m_projectActionMenu->insert( action ); +} + + +void K3bProjectTabWidget::slotDocChanged( K3bDoc* doc ) +{ + // we need to cache the icon changes since the changed() signal will be emitted very often + if( !m_projectDataMap[doc].modified ) { + setTabIconSet( doc->view(), SmallIconSet( "filesave" ) ); + m_projectDataMap[doc].modified = true; + + // we need this one for the session management + changeTab( doc->view(), doc->URL().fileName() ); + } +} + + +void K3bProjectTabWidget::slotDocSaved( K3bDoc* doc ) +{ + setTabIconSet( doc->view(), QIconSet() ); + changeTab( doc->view(), doc->URL().fileName() ); +} + + +K3bDoc* K3bProjectTabWidget::projectAt( const QPoint& pos ) const +{ + QTab* tab = tabBar()->selectTab( pos ); + if( tab ) { + QWidget* w = page( tabBar()->indexOf( tab->identifier() ) ); + if( K3bView* view = dynamic_cast<K3bView*>(w) ) + return view->doc(); + } + + return 0; +} + + +bool K3bProjectTabWidget::eventFilter( QObject* o, QEvent* e ) +{ + if( o == tabBar() ) { + if( e->type() == QEvent::MouseButtonPress ) { + QMouseEvent* me = static_cast<QMouseEvent*>(e); + if( me->button() == Qt::RightButton ) { + if( projectAt( me->pos() ) ) { + // we need change the tab because the actions work on the current tab + QTab* clickedTab = tabBar()->selectTab( me->pos() ); + if( clickedTab ) { + tabBar()->setCurrentTab( clickedTab ); + + // show the popup menu + m_projectActionMenu->popup( me->globalPos() ); + } + } + return true; + } + } + + else if( e->type() == QEvent::DragMove ) { + QDragMoveEvent* de = static_cast<QDragMoveEvent*>(e); + de->accept( KURLDrag::canDecode(de) && projectAt(de->pos()) ); + return true; + } + + else if( e->type() == QEvent::Drop ) { + QDropEvent* de = static_cast<QDropEvent*>(e); + KURL::List l; + if( KURLDrag::decode( de, l ) ) { + if( K3bDoc* doc = projectAt( de->pos() ) ) + dynamic_cast<K3bView*>(doc->view())->addUrls( l ); + } + return true; + } + } + + return QTabWidget::eventFilter( o, e ); +} + +#include "k3bprojecttabwidget.moc" + diff --git a/src/k3bprojecttabwidget.h b/src/k3bprojecttabwidget.h new file mode 100644 index 0000000..048a8bc --- /dev/null +++ b/src/k3bprojecttabwidget.h @@ -0,0 +1,78 @@ +/* + * + * $Id: k3bprojecttabwidget.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BPROJECTTABWIDGET_H +#define K3BPROJECTTABWIDGET_H + +#include <qtabwidget.h> +#include <kurl.h> + +class KAction; +class KActionMenu; +class K3bDoc; + + +/** + * An enhanced Tab Widget that hides the tabbar in case only one page has been inserted + * and shows a context menu fpr K3b projects. + * + * @author Sebastian Trueg + */ +class K3bProjectTabWidget : public QTabWidget +{ + Q_OBJECT + + public: + K3bProjectTabWidget( QWidget *parent = 0, const char *name = 0, WFlags = 0 ); + ~K3bProjectTabWidget(); + + void insertTab( K3bDoc* ); + + void addTab( QWidget * child, const QString & label ); + void addTab( QWidget * child, const QIconSet & iconset, const QString & label ); + void addTab( QWidget * child, QTab * tab ); + void insertTab( QWidget * child, const QString & label, int index = -1 ); + void insertTab( QWidget * child, const QIconSet & iconset, const QString & label, int index = -1 ); + void insertTab( QWidget * child, QTab * tab, int index = -1 ); + + /** + * \return the project for the tab at position \p pos or 0 in case the tab is + * not a project tab. + */ + K3bDoc* projectAt( const QPoint& pos ) const; + + /** + * inserts the given action into the popup menu for the tabs + */ + void insertAction( KAction* ); + + bool eventFilter( QObject* o, QEvent* e ); + + public slots: + void removePage( QWidget* ); + + private slots: + void slotDocChanged( K3bDoc* ); + void slotDocSaved( K3bDoc* ); + + private: + KActionMenu* m_projectActionMenu; + + class ProjectData; + QMap<K3bDoc*, ProjectData> m_projectDataMap; +}; + +#endif diff --git a/src/k3bservicemenuinstaller.cpp b/src/k3bservicemenuinstaller.cpp new file mode 100644 index 0000000..82122e2 --- /dev/null +++ b/src/k3bservicemenuinstaller.cpp @@ -0,0 +1,119 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bservicemenuinstaller.h" + +#include <kglobal.h> +#include <klocale.h> +#include <kstandarddirs.h> +#include <kmessagebox.h> +#include <kio/netaccess.h> +#include <kdebug.h> + + +class K3bServiceInstaller::Private +{ +public: + QString app; + QStringList allServiceMenus; + QStringList allServiceMenuFiles; + QString konqiServicemenusFolder; + + void update() { + // the list of installable servicemenus the application provides + allServiceMenus = KGlobal::dirs()->findAllResources( "data", + "k3b/servicemenus/*.desktop", + false, + true ); + + // just the filenames + allServiceMenuFiles.clear(); + for( unsigned int i = 0; i < allServiceMenus.count(); ++i ) + allServiceMenuFiles.append( allServiceMenus[i].section( '/', -1 ) ); + + // the local konqueror servicemenu folder (we just create it here to be on the safe side) + konqiServicemenusFolder = KGlobal::dirs()->saveLocation( "data", "konqueror/servicemenus/", true ); + } +}; + + +K3bServiceInstaller::K3bServiceInstaller( const QString& appname ) +{ + d = new Private; + d->app = appname; +} + + +K3bServiceInstaller::~K3bServiceInstaller() +{ + delete d; +} + + +bool K3bServiceInstaller::allInstalled() const +{ + d->update(); + + for( unsigned int i = 0; i < d->allServiceMenuFiles.count(); ++i ) + if( !KIO::NetAccess::exists( d->konqiServicemenusFolder + d->allServiceMenuFiles[i], true, 0 ) ) { + kdDebug() << "(K3bServiceInstaller) service menu " << d->konqiServicemenusFolder << d->allServiceMenuFiles[i] + << " does not exist." << endl; + return false; + } + + return true; +} + + +bool K3bServiceInstaller::install( QWidget* parent ) +{ + d->update(); + + bool success = true; + + // simply link all the globally installed K3b service menus to the local konqi service menu folder + for( unsigned int i = 0; i < d->allServiceMenus.count(); ++i ) + if( !KIO::NetAccess::file_copy( KURL::fromPathOrURL( d->allServiceMenus[i] ), + KURL::fromPathOrURL( d->konqiServicemenusFolder + d->allServiceMenuFiles[i] ), -1, + true, false, parent ) ) + success = false; + + if( !success && parent ) + KMessageBox::error( parent, + KIO::NetAccess::lastErrorString(), + i18n("Failed to copy service menu files") ); + + return success; +} + + +bool K3bServiceInstaller::remove( QWidget* parent ) +{ + d->update(); + + bool success = true; + + for( unsigned int i = 0; i < d->allServiceMenuFiles.count(); ++i ) + if( KIO::NetAccess::exists( d->konqiServicemenusFolder + d->allServiceMenuFiles[i], true, parent ) ) + if( !KIO::NetAccess::del( d->konqiServicemenusFolder + d->allServiceMenuFiles[i], parent ) ) + success = false; + + if( !success && parent ) + KMessageBox::error( parent, + KIO::NetAccess::lastErrorString(), + i18n("Failed to remove service menu files") ); + + return success; +} diff --git a/src/k3bservicemenuinstaller.h b/src/k3bservicemenuinstaller.h new file mode 100644 index 0000000..6e06caf --- /dev/null +++ b/src/k3bservicemenuinstaller.h @@ -0,0 +1,55 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_SERVICE_MENU_INSTALLER_H_ +#define _K3B_SERVICE_MENU_INSTALLER_H_ + +#include <qstring.h> + +class QWidget; + + +/** + * The K3bServiceInstaller installs konqueror servicemenus locally. + * These servicemenus have to be installed in the appdata dir under + * the subfolder "servicemenus". + */ +class K3bServiceInstaller +{ + public: + K3bServiceInstaller( const QString& appname = "k3b" ); + ~K3bServiceInstaller(); + + /** + * Checks if all servicemenus are properly installed. + */ + bool allInstalled() const; + + /** + * If parent != 0 a messagebox will be shown in case of an error. + */ + bool install( QWidget* parent = 0 ); + + /** + * If parent != 0 a messagebox will be shown in case of an error. + */ + bool remove( QWidget* parent = 0 ); + + private: + class Private; + Private* d; +}; + +#endif diff --git a/src/k3bsidepanel.cpp b/src/k3bsidepanel.cpp new file mode 100644 index 0000000..8e40352 --- /dev/null +++ b/src/k3bsidepanel.cpp @@ -0,0 +1,108 @@ +/* + * + * $Id: k3bsidepanel.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bsidepanel.h" +#include "k3b.h" +#include "k3bfiletreeview.h" + +#include <klocale.h> +#include <kiconloader.h> +#include <kdebug.h> + +#include <qtoolbutton.h> +#include <qframe.h> +#include <qlayout.h> + + + +K3bSidePanel::K3bSidePanel( K3bMainWindow* m, QWidget* parent, const char* name ) + : QToolBox( parent, name ), + m_mainWindow(m) +{ + // our first widget is the tree view + m_fileTreeView = new K3bFileTreeView( this ); + addItem( m_fileTreeView, SmallIconSet( "folder_open" ), i18n("Folders") ); + + // CD projects + QFrame* cdProjectsFrame = createPanel(); + addItem( cdProjectsFrame, SmallIconSet( "cdrom_unmount" ), i18n("CD Tasks") ); + addButton( cdProjectsFrame, m_mainWindow->action( "file_new_audio" ) ); + addButton( cdProjectsFrame, m_mainWindow->action( "file_new_data" ) ); + addButton( cdProjectsFrame, m_mainWindow->action( "file_new_mixed" ) ); + addButton( cdProjectsFrame, m_mainWindow->action( "file_new_vcd" ) ); + addButton( cdProjectsFrame, m_mainWindow->action( "file_new_movix" ) ); + QGridLayout* grid = (QGridLayout*)cdProjectsFrame->layout(); + grid->setRowSpacing( grid->numRows(), 15 ); + addButton( cdProjectsFrame, m_mainWindow->action( "tools_copy_cd" ) ); + addButton( cdProjectsFrame, m_mainWindow->action( "tools_write_cd_image" ) ); + addButton( cdProjectsFrame, m_mainWindow->action( "tools_blank_cdrw" ) ); + grid->setRowStretch( grid->numRows()+1, 1 ); + + // DVD projects + QFrame* dvdProjectsFrame = createPanel(); + addItem( dvdProjectsFrame, SmallIconSet( "dvd_unmount" ), i18n("DVD Tasks") ); + addButton( dvdProjectsFrame, m_mainWindow->action( "file_new_dvd" ) ); + addButton( dvdProjectsFrame, m_mainWindow->action( "file_new_video_dvd" ) ); + addButton( dvdProjectsFrame, m_mainWindow->action( "file_new_movix_dvd" ) ); + grid = (QGridLayout*)dvdProjectsFrame->layout(); + grid->setRowSpacing( grid->numRows(), 15 ); + addButton( dvdProjectsFrame, m_mainWindow->action( "tools_copy_dvd" ) ); + addButton( dvdProjectsFrame, m_mainWindow->action( "tools_write_dvd_iso" ) ); + addButton( dvdProjectsFrame, m_mainWindow->action( "tools_format_dvd" ) ); + grid->setRowStretch( grid->numRows()+1, 1 ); + + + // Tools + // TODO sidepanel tools +} + + +K3bSidePanel::~K3bSidePanel() +{ +} + + +QFrame* K3bSidePanel::createPanel() +{ + QFrame* frame = new QFrame( this ); + frame->setPaletteBackgroundColor( Qt::white ); + QGridLayout* grid = new QGridLayout( frame ); + grid->setMargin( 5 ); + grid->setSpacing( 5 ); + return frame; +} + + +void K3bSidePanel::addButton( QFrame* frame, KAction* a ) +{ + if( a ) { + QToolButton* b = new QToolButton( frame ); + b->setTextLabel( a->toolTip(), true ); + b->setTextLabel( a->text(), false ); + b->setIconSet( a->iconSet(KIcon::Small) ); + b->setUsesTextLabel( true ); + b->setAutoRaise( true ); + b->setTextPosition( QToolButton::BesideIcon ); + + connect( b, SIGNAL(clicked()), a, SLOT(activate()) ); + + QGridLayout* grid = (QGridLayout*)(frame->layout()); + grid->addWidget( b, grid->numRows(), 0 ); + } + else + kdDebug() << "(K3bSidePanel) null action." << endl; +} + +#include "k3bsidepanel.moc" diff --git a/src/k3bsidepanel.h b/src/k3bsidepanel.h new file mode 100644 index 0000000..2be17ff --- /dev/null +++ b/src/k3bsidepanel.h @@ -0,0 +1,49 @@ +/* + * + * $Id: k3bsidepanel.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_SIDE_PANEL_H_ +#define _K3B_SIDE_PANEL_H_ + +#include <qtoolbox.h> + +class K3bMainWindow; +class K3bFileTreeView; +class QFrame; +class KAction; + + +class K3bSidePanel : public QToolBox +{ + Q_OBJECT + + public: + K3bSidePanel( K3bMainWindow*, QWidget* parent = 0, const char* name = 0 ); + ~K3bSidePanel(); + + /** + * This should be removed in the future. For now we need it because of the + * bad design of the dirview. :( + */ + K3bFileTreeView* fileTreeView() const { return m_fileTreeView; } + + private: + K3bMainWindow* m_mainWindow; + K3bFileTreeView* m_fileTreeView; + + QFrame* createPanel(); + void addButton( QFrame* frame, KAction* action ); +}; + +#endif diff --git a/src/k3bsplash.cpp b/src/k3bsplash.cpp new file mode 100644 index 0000000..dc49bf5 --- /dev/null +++ b/src/k3bsplash.cpp @@ -0,0 +1,129 @@ +/* + * + * $Id: k3bsplash.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bsplash.h" + +#include <k3bthememanager.h> +#include <k3bapplication.h> + +#include <qapplication.h> +#include <qlabel.h> +#include <qpixmap.h> +#include <qevent.h> +#include <qstring.h> +#include <qfontmetrics.h> +#include <qpainter.h> + +#include <kstandarddirs.h> +#include <kapplication.h> +#include <kaboutdata.h> + + +K3bSplash::K3bSplash( QWidget* parent, const char* name ) + : QVBox( parent, name, + WStyle_Customize| + WDestructiveClose| + /* WStyle_Splash|*/ + WX11BypassWM| + WStyle_NoBorder| + WStyle_StaysOnTop ) +{ + setMargin( 0 ); + setSpacing( 0 ); + + QLabel* copyrightLabel = new QLabel( kapp->aboutData()->copyrightStatement(), this ); + copyrightLabel->setMargin( 5 ); + copyrightLabel->setPaletteBackgroundColor( black ); + copyrightLabel->setPaletteForegroundColor( white ); + copyrightLabel->setAlignment( AlignRight ); + + QLabel* picLabel = new QLabel( this ); + if( K3bTheme* theme = k3bappcore->themeManager()->currentTheme() ) { + picLabel->setPaletteBackgroundColor( theme->backgroundColor() ); + picLabel->setPixmap( theme->pixmap( K3bTheme::SPLASH ) ); + } + + m_infoBox = new QLabel( this ); + m_infoBox->setMargin( 5 ); + m_infoBox->setPaletteBackgroundColor( black ); + m_infoBox->setPaletteForegroundColor( white ); + + // Set geometry, with support for Xinerama systems + QRect r; + r.setSize(sizeHint()); + int ps = QApplication::desktop()->primaryScreen(); + r.moveCenter( QApplication::desktop()->screenGeometry(ps).center() ); + setGeometry(r); +} + + +K3bSplash::~K3bSplash() +{ +} + + +void K3bSplash::mousePressEvent( QMouseEvent* ) +{ + close(); +} + + +void K3bSplash::show() +{ + QVBox::show(); + // make sure the splash screen is shown immediately + qApp->processEvents(); +} + + +void K3bSplash::addInfo( const QString& s ) +{ + m_infoBox->setText( s ); + + qApp->processEvents(); +} + + +// void K3bSplash::paintEvent( QPaintEvent* e ) +// { +// // first let the window paint the background and the child widget +// QWidget::paintEvent( e ); + +// // now create the text we want to display +// // find the lower left corner and paint it on top of the pixmap +// QPainter p( this ); +// p.setPen( Qt::blue ); + +// QFontMetrics fm = p.fontMetrics(); + +// QString line1 = QString( "K3b version %1" ).arg(VERSION); +// QString line2( "(c) 2001 by Sebastian Trueg" ); +// QString line3( "licenced under the GPL" ); + +// QRect rect1 = fm.boundingRect( line1 ); +// QRect rect2 = fm.boundingRect( line2 ); +// QRect rect3 = fm.boundingRect( line3 ); + +// int textH = rect1.height() + rect2.height() + rect3.height() + 2 * fm.leading() + 2 + rect2.height() /*hack because the boundingRect method seems not to work properly! :-(*/; +// int textW = QMAX( rect1.width(), QMAX( rect2.width(), rect3.width() ) ) + 2; + +// int startX = 10; +// int startY = height() - 10 - textH; + +// p.drawText( startX, startY, textW, textH, 0, QString("%1\n%2\n%3").arg(line1).arg(line2).arg(line3) ); +// } + + +#include "k3bsplash.moc" diff --git a/src/k3bsplash.h b/src/k3bsplash.h new file mode 100644 index 0000000..c4e6979 --- /dev/null +++ b/src/k3bsplash.h @@ -0,0 +1,48 @@ +/* + * + * $Id: k3bsplash.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BSPLASH_H +#define K3BSPLASH_H + +#include <qvbox.h> + +class QLabel; +class QMouseEvent; +class QPaintEvent; +class QString; + + +class K3bSplash : public QVBox +{ +Q_OBJECT + + public: + K3bSplash( QWidget* parent = 0, const char* name = 0 ); + ~K3bSplash(); + + public slots: + void show(); + void addInfo( const QString& ); + + protected: + void mousePressEvent( QMouseEvent* ); + // void paintEvent( QPaintEvent* ); + + private: + QLabel* m_infoBox; +}; + +#endif diff --git a/src/k3bstatusbarmanager.cpp b/src/k3bstatusbarmanager.cpp new file mode 100644 index 0000000..b6e603d --- /dev/null +++ b/src/k3bstatusbarmanager.cpp @@ -0,0 +1,250 @@ +/* + * + * $Id: k3bstatusbarmanager.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bstatusbarmanager.h" +#include <k3bcore.h> +#include "k3bbusywidget.h" +#include "k3b.h" +#include <k3bversion.h> +#include <k3bglobals.h> +#include "k3bprojectmanager.h" +#include "k3bapplication.h" +#include <k3baudiodoc.h> +#include <k3bdatadoc.h> +#include <k3bmixeddoc.h> +#include <k3bvcddoc.h> +#include <k3bdiritem.h> +#include <k3bview.h> + +#include <kiconloader.h> +#include <klocale.h> +#include <kconfig.h> +#include <kstandarddirs.h> +#include <kio/global.h> +#include <kstatusbar.h> +#include <kaboutdata.h> +#include <kaction.h> + +#include <qlabel.h> +#include <qhbox.h> +#include <qfile.h> +#include <qtimer.h> +#include <qevent.h> +#include <qtooltip.h> + + + +K3bStatusBarManager::K3bStatusBarManager( K3bMainWindow* parent ) + : QObject(parent), + m_mainWindow(parent) +{ + // setup free temp space box + QHBox* boxFreeTemp = new QHBox( m_mainWindow->statusBar() ); + boxFreeTemp->setSpacing(2); + + m_labelProjectInfo = new QLabel( m_mainWindow->statusBar() ); + + m_pixFreeTemp = new QLabel( boxFreeTemp ); + (void)new QLabel( i18n("Temp:"), boxFreeTemp ); + m_pixFreeTemp->setPixmap( SmallIcon("folder_green") ); + m_labelFreeTemp = new QLabel( boxFreeTemp ); + boxFreeTemp->installEventFilter( this ); + + // setup info area + m_labelInfoMessage = new QLabel( " ", m_mainWindow->statusBar() ); + + // setup version info + m_versionBox = new QLabel( QString("K3b %1").arg(kapp->aboutData()->version()), m_mainWindow->statusBar() ); + m_versionBox->installEventFilter( this ); + + // setup the statusbar + m_mainWindow->statusBar()->addWidget( m_labelInfoMessage, 1 ); // for showing some info + m_mainWindow->statusBar()->addWidget( m_labelProjectInfo, 0, true ); + // a spacer item + m_mainWindow->statusBar()->addWidget( new QLabel( " ", m_mainWindow->statusBar() ), 0, true ); + m_mainWindow->statusBar()->addWidget( boxFreeTemp, 0, true ); + // a spacer item + m_mainWindow->statusBar()->addWidget( new QLabel( " ", m_mainWindow->statusBar() ), 0, true ); + m_mainWindow->statusBar()->addWidget( m_versionBox, 0, true ); + + connect( m_mainWindow, SIGNAL(configChanged(KConfig*)), this, SLOT(update()) ); + connect( m_mainWindow->actionCollection(), SIGNAL(actionStatusText(const QString&)), + this, SLOT(showActionStatusText(const QString&)) ); + connect( m_mainWindow->actionCollection(), SIGNAL(clearStatusText()), + this, SLOT(clearActionStatusText()) ); + connect( k3bappcore->projectManager(), SIGNAL(activeProjectChanged(K3bDoc*)), + this, SLOT(slotActiveProjectChanged(K3bDoc*)) ); + connect( k3bappcore->projectManager(), SIGNAL(projectChanged(K3bDoc*)), + this, SLOT(slotActiveProjectChanged(K3bDoc*)) ); + connect( (m_updateTimer = new QTimer( this )), SIGNAL(timeout()), this, SLOT(slotUpdateProjectStats()) ); + + update(); +} + + +K3bStatusBarManager::~K3bStatusBarManager() +{ +} + + +void K3bStatusBarManager::update() +{ + QString path = K3b::defaultTempPath(); + + if( !QFile::exists( path ) ) + path.truncate( path.findRev('/') ); + + unsigned long size, avail; + if( K3b::kbFreeOnFs( path, size, avail ) ) + slotFreeTempSpace( path, size, 0, avail ); + else + m_labelFreeTemp->setText(i18n("No info")); + + if( path != QToolTip::textFor( m_labelFreeTemp->parentWidget() ) ) { + QToolTip::remove( m_labelFreeTemp->parentWidget() ); + QToolTip::add( m_labelFreeTemp->parentWidget(), path ); + } +} + + +void K3bStatusBarManager::slotFreeTempSpace(const QString&, + unsigned long kbSize, + unsigned long, + unsigned long kbAvail) +{ + m_labelFreeTemp->setText(KIO::convertSizeFromKB(kbAvail) + "/" + + KIO::convertSizeFromKB(kbSize) ); + + // if we have less than 640 MB that is not good + if( kbAvail < 655360 ) + m_pixFreeTemp->setPixmap( SmallIcon("folder_red") ); + else + m_pixFreeTemp->setPixmap( SmallIcon("folder_green") ); + + // update the display every second + QTimer::singleShot( 2000, this, SLOT(update()) ); +} + + +void K3bStatusBarManager::showActionStatusText( const QString& text ) +{ + m_mainWindow->statusBar()->message( text ); +} + + +void K3bStatusBarManager::clearActionStatusText() +{ + m_mainWindow->statusBar()->clear(); +} + + +bool K3bStatusBarManager::eventFilter( QObject* o, QEvent* e ) +{ + if( e->type() == QEvent::MouseButtonDblClick ) { + if( o == m_labelFreeTemp->parentWidget() ) + m_mainWindow->showOptionDialog( 0 ); // FIXME: use an enumeration for the option pages + else if( o == m_versionBox ) + if( KAction* a = m_mainWindow->action( "help_about_app" ) ) + a->activate(); + } + + return QObject::eventFilter( o, e ); +} + + +static QString dataDocStats( K3bDataDoc* dataDoc ) +{ + return i18n("1 file in %1", "%n files in %1", dataDoc->root()->numFiles() ) + .arg( i18n("1 folder", "%n folders", dataDoc->root()->numDirs()+1 ) ); +} + + +void K3bStatusBarManager::slotActiveProjectChanged( K3bDoc* doc ) +{ + if( doc && doc == k3bappcore->projectManager()->activeProject() ) { + // cache updates + if( !m_updateTimer->isActive() ) { + slotUpdateProjectStats(); + m_updateTimer->start( 1000, false ); + } + } + else if( !doc ) { + m_labelProjectInfo->setText( QString() ); + } +} + + +void K3bStatusBarManager::slotUpdateProjectStats() +{ + K3bDoc* doc = k3bappcore->projectManager()->activeProject(); + if( doc ) { + switch( doc->type() ) { + case K3bDoc::AUDIO: { + K3bAudioDoc* audioDoc = static_cast<K3bAudioDoc*>( doc ); + m_labelProjectInfo->setText( i18n("Audio CD (1 track)", "Audio CD (%n tracks)", audioDoc->numOfTracks() ) ); + break; + } + + case K3bDoc::DATA: { + K3bDataDoc* dataDoc = static_cast<K3bDataDoc*>( doc ); + m_labelProjectInfo->setText( i18n("Data CD (%1)").arg(dataDocStats(dataDoc)) ); + break; + } + + case K3bDoc::MIXED: { + K3bAudioDoc* audioDoc = static_cast<K3bMixedDoc*>( doc )->audioDoc(); + K3bDataDoc* dataDoc = static_cast<K3bMixedDoc*>( doc )->dataDoc(); + m_labelProjectInfo->setText( i18n("Mixed CD (1 track and %1)", "Mixed CD (%n tracks and %1)", audioDoc->numOfTracks() ) + .arg( dataDocStats(dataDoc)) ); + break; + } + + case K3bDoc::VCD: { + K3bVcdDoc* vcdDoc = static_cast<K3bVcdDoc*>( doc ); + m_labelProjectInfo->setText( i18n("Video CD (1 track)", "Video CD (%n tracks)", vcdDoc->numOfTracks() ) ); + break; + } + + case K3bDoc::MOVIX: { + K3bDataDoc* dataDoc = static_cast<K3bDataDoc*>( doc ); + m_labelProjectInfo->setText( i18n("eMovix CD (%1)").arg(dataDocStats(dataDoc)) ); + break; + } + + case K3bDoc::MOVIX_DVD: { + K3bDataDoc* dataDoc = static_cast<K3bDataDoc*>( doc ); + m_labelProjectInfo->setText( i18n("eMovix DVD (%1)").arg(dataDocStats(dataDoc)) ); + break; + } + + case K3bDoc::DVD: { + K3bDataDoc* dataDoc = static_cast<K3bDataDoc*>( doc ); + m_labelProjectInfo->setText( i18n("Data DVD (%1)").arg(dataDocStats(dataDoc)) ); + break; + } + + case K3bDoc::VIDEODVD: { + K3bDataDoc* dataDoc = static_cast<K3bDataDoc*>( doc ); + m_labelProjectInfo->setText( i18n("Video DVD (%1)").arg(dataDocStats(dataDoc)) ); + break; + } + } + } + else { + m_labelProjectInfo->setText( QString() ); + } +} + +#include "k3bstatusbarmanager.moc" diff --git a/src/k3bstatusbarmanager.h b/src/k3bstatusbarmanager.h new file mode 100644 index 0000000..d8db737 --- /dev/null +++ b/src/k3bstatusbarmanager.h @@ -0,0 +1,61 @@ +/* + * + * $Id: k3bstatusbarmanager.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + + +#ifndef K3B_STATUSBAR_MANAGER_H +#define K3B_STATUSBAR_MANAGER_H + +#include <qobject.h> + +class QLabel; +class K3bMainWindow; +class QEvent; +class K3bDoc; +class QTimer; + +class K3bStatusBarManager : public QObject +{ + Q_OBJECT + + public: + K3bStatusBarManager( K3bMainWindow* parent ); + ~K3bStatusBarManager(); + + public slots: + void update(); + + private slots: + void slotFreeTempSpace( const QString&, unsigned long, unsigned long, unsigned long ); + void showActionStatusText( const QString& text ); + void clearActionStatusText(); + void slotActiveProjectChanged( K3bDoc* doc ); + void slotUpdateProjectStats(); + + private: + bool eventFilter( QObject* o, QEvent* e ); + + QLabel* m_labelInfoMessage; + QLabel* m_pixFreeTemp; + QLabel* m_labelFreeTemp; + QLabel* m_versionBox; + QLabel* m_labelProjectInfo; + + K3bMainWindow* m_mainWindow; + + QTimer* m_updateTimer; +}; + +#endif diff --git a/src/k3bsystemproblemdialog.cpp b/src/k3bsystemproblemdialog.cpp new file mode 100644 index 0000000..17f9376 --- /dev/null +++ b/src/k3bsystemproblemdialog.cpp @@ -0,0 +1,690 @@ +/* + * + * $Id: k3bsystemproblemdialog.cpp 655079 2007-04-17 17:17:08Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include <config.h> + + +#include "k3bapplication.h" +#include "k3bsystemproblemdialog.h" +#include "k3bpassivepopup.h" +#include "k3bthemedheader.h" +#include <k3btitlelabel.h> +#include <k3bexternalbinmanager.h> +#include <k3bstdguiitems.h> +#include <k3bdevicemanager.h> +#include <k3bdevice.h> +#include <k3bversion.h> +#include <k3bglobals.h> +#include <k3bpluginmanager.h> +#include <k3bplugin.h> +#include <k3bprocess.h> +#include <k3bthememanager.h> +#include <k3bcore.h> + +#include <qpushbutton.h> +#include <qcheckbox.h> +#include <qlayout.h> +#include <qlabel.h> +#include <qfileinfo.h> + +#include <klocale.h> +#include <kstandarddirs.h> +#include <ktextedit.h> +#include <kconfig.h> +#include <kapplication.h> +#include <kmessagebox.h> +#include <kprocess.h> +#include <kglobal.h> + +#ifdef HAVE_ICONV_H +#include <langinfo.h> +#endif + +#include <fstab.h> + + +static QString markupString( const QString& s_ ) +{ + QString s(s_); + s.replace( '<', "<" ); + s.replace( '>', ">" ); + return s; +} + + +K3bSystemProblem::K3bSystemProblem( int t, + const QString& p, + const QString& d, + const QString& s, + bool k ) + : type(t), + problem(p), + details(d), + solution(s), + solvableByK3bSetup(k) +{ +} + + +K3bSystemProblemDialog::K3bSystemProblemDialog( const QValueList<K3bSystemProblem>& problems, + QWidget* parent, + const char* name ) + : KDialog( parent, name ) +{ + setCaption( i18n("System Configuration Problems") ); + + // setup the title + // --------------------------------------------------------------------------------------------------- + K3bThemedHeader* titleFrame = new K3bThemedHeader( this ); + titleFrame->setTitle( i18n("System Configuration Problems"), + i18n("1 problem", "%n problems", problems.count() ) ); + + m_closeButton = new QPushButton( i18n("Close"), this ); + connect( m_closeButton, SIGNAL(clicked()), this, SLOT(close()) ); + m_checkDontShowAgain = new QCheckBox( i18n("Do not show again"), this ); + +#ifdef HAVE_K3BSETUP + m_k3bsetupButton = new QPushButton( i18n("Start K3bSetup2"), this ); + connect( m_k3bsetupButton, SIGNAL(clicked()), this, SLOT(slotK3bSetup()) ); +#endif + + // setup the problem view + // --------------------------------------------------------------------------------------------------- + KTextEdit* view = new KTextEdit( this ); + view->setReadOnly(true); + view->setTextFormat(RichText); + + + // layout everything + QGridLayout* grid = new QGridLayout( this ); + grid->setMargin( marginHint() ); + grid->setSpacing( spacingHint() ); + grid->addMultiCellWidget( titleFrame, 0, 0, 0, 1 ); + grid->addMultiCellWidget( view, 1, 1, 0, 1 ); + grid->addWidget( m_checkDontShowAgain, 2, 0 ); + QHBoxLayout* buttonBox = new QHBoxLayout; + buttonBox->setSpacing( spacingHint() ); + buttonBox->setMargin( 0 ); +#ifdef HAVE_K3BSETUP + buttonBox->addWidget( m_k3bsetupButton ); +#endif + buttonBox->addWidget( m_closeButton ); + grid->addLayout( buttonBox, 2, 1 ); + grid->setColStretch( 0, 1 ); + grid->setRowStretch( 1, 1 ); + + QString text = "<html>"; + + for( QValueList<K3bSystemProblem>::const_iterator it = problems.begin(); + it != problems.end(); ++it ) { + const K3bSystemProblem& p = *it; + + text.append( "<p><b>" ); + if( p.type == K3bSystemProblem::CRITICAL ) + text.append( "<span style=\"color:red\">" ); + text.append( markupString( p.problem ) ); + if( p.type == K3bSystemProblem::CRITICAL ) + text.append( "</span>" ); + text.append( "</b><br>" ); + text.append( markupString( p.details ) + "<br>" ); + if( !p.solution.isEmpty() ) + text.append( "<i>" + i18n("Solution") + "</i>: " + p.solution ); +#ifdef HAVE_K3BSETUP + else if( p.solvableByK3bSetup ) + text.append( "<i>" + i18n("Solution") + "</i>: " + i18n("Use K3bSetup to solve this problem.") ); +#endif + text.append( "</p>" ); + } + + text.append( "</html>" ); + + view->setText(text); + view->setCursorPosition(0,0); + view->ensureCursorVisible(); +} + + +void K3bSystemProblemDialog::closeEvent( QCloseEvent* e ) +{ + if( m_checkDontShowAgain->isChecked() ) { + KConfigGroup grp( kapp->config(), "General Options" ); + grp.writeEntry( "check system config", false ); + } + + e->accept(); +} + + +void K3bSystemProblemDialog::checkSystem( QWidget* parent, + const char* name ) +{ + QValueList<K3bSystemProblem> problems; + + if( k3bcore->deviceManager()->cdWriter().isEmpty() ) { + problems.append( K3bSystemProblem( K3bSystemProblem::NON_CRITICAL, + i18n("No CD/DVD writer found."), + i18n("K3b did not find an optical writing device in your system. Thus, " + "you will not be able to burn CDs or DVDs. However, you can still " + "use other K3b features like audio track extraction or audio " + "transcoding or ISO9660 image creation."), + false ) ); + } + else { + // 1. cdrecord, cdrdao + if( !k3bcore->externalBinManager()->foundBin( "cdrecord" ) ) { + problems.append( K3bSystemProblem( K3bSystemProblem::CRITICAL, + i18n("Unable to find %1 executable").arg("cdrecord"), + i18n("K3b uses cdrecord to actually write CDs."), + i18n("Install the cdrtools package which contains " + "cdrecord."), + false ) ); + } + else { + if( k3bcore->externalBinManager()->binObject( "cdrecord" )->hasFeature( "outdated" ) ) { + problems.append( K3bSystemProblem( K3bSystemProblem::NON_CRITICAL, + i18n("Used %1 version %2 is outdated").arg("cdrecord").arg(k3bcore->externalBinManager()->binObject( "cdrecord" )->version), + i18n("Although K3b supports all cdrtools versions since " + "1.10 it is highly recommended to at least use " + "version 2.0."), + i18n("Install a more recent version of the cdrtools."), + false ) ); + } + +/* +#ifdef Q_OS_LINUX + + // + // Since kernel 2.6.8 older cdrecord versions are not able to use the SCSI subsystem when running suid root anymore + // So far we ignore the suid root issue with kernel >= 2.6.8 and cdrecord < 2.01.01a02 + // + // Kernel 2.6.16.something seems to introduce another problem which was apparently worked around in cdrecord 2.01.01a05 + // + if( K3b::simpleKernelVersion() >= K3bVersion( 2, 6, 8 ) && + k3bcore->externalBinManager()->binObject( "cdrecord" )->version < K3bVersion( 2, 1, 1, "a05" ) && + !k3bcore->externalBinManager()->binObject( "cdrecord" )->hasFeature( "wodim" ) ) { + if( k3bcore->externalBinManager()->binObject( "cdrecord" )->hasFeature( "suidroot" ) ) + problems.append( K3bSystemProblem( K3bSystemProblem::CRITICAL, + i18n("%1 will be run with root privileges on kernel >= 2.6.8").arg("cdrecord <= 2.01.01a05"), + i18n("Since Linux kernel 2.6.8 %1 will not work when run suid " + "root for security reasons anymore.").arg("cdrecord <= 2.01.01a05"), + QString::null, + true ) ); + } +#ifdef CDRECORD_SUID_ROOT_CHECK + else if( !k3bcore->externalBinManager()->binObject( "cdrecord" )->hasFeature( "suidroot" ) && getuid() != 0 ) // not root + problems.append( K3bSystemProblem( K3bSystemProblem::CRITICAL, + i18n("%1 will be run without root privileges").arg("cdrecord"), + i18n("It is highly recommended to configure cdrecord " + "to run with root privileges. Only then cdrecord " + "runs with high priority which increases the overall " + "stability of the burning process. Apart from that " + "it allows changing the size of the used burning buffer. " + "A lot of user problems could be solved this way. This is also " + "true when using SuSE's resmgr."), + QString::null, + true ) ); +#endif // CDRECORD_SUID_ROOT_CHECK +#endif +*/ + } + if( !k3bcore->externalBinManager()->foundBin( "cdrdao" ) ) { + problems.append( K3bSystemProblem( K3bSystemProblem::CRITICAL, + i18n("Unable to find %1 executable").arg("cdrdao"), + i18n("K3b uses cdrdao to actually write CDs."), + i18n("Install the cdrdao package."), + false ) ); + } +/* + else { +#ifdef Q_OS_LINUX +#ifdef CDRECORD_SUID_ROOT_CHECK + if( !k3bcore->externalBinManager()->binObject( "cdrdao" )->hasFeature( "suidroot" ) && getuid() != 0 ) + problems.append( K3bSystemProblem( K3bSystemProblem::CRITICAL, + i18n("%1 will be run without root privileges").arg("cdrdao"), + i18n("It is highly recommended to configure cdrdao " + "to run with root privileges to increase the " + "overall stability of the burning process."), + QString::null, + true ) ); +#endif // CDRECORD_SUID_ROOT_CHECK +#endif + } +*/ + } + + if( !k3bcore->deviceManager()->dvdWriter().isEmpty() ) { + if( !k3bcore->externalBinManager()->foundBin( "growisofs" ) ) { + problems.append( K3bSystemProblem( K3bSystemProblem::CRITICAL, + i18n("Unable to find %1 executable").arg("growisofs"), + i18n("K3b uses growisofs to actually write dvds. " + "Without growisofs you will not be able to write dvds. " + "Make sure to install at least version 5.10."), + i18n("Install the dvd+rw-tools package."), + false ) ); + } + else { + if( k3bcore->externalBinManager()->binObject( "growisofs" )->version < K3bVersion( 5, 10 ) ) { + problems.append( K3bSystemProblem( K3bSystemProblem::CRITICAL, + i18n("Used %1 version %2 is outdated").arg("growisofs").arg(k3bcore->externalBinManager()->binObject( "growisofs" )->version), + i18n("K3b needs at least growisofs version 5.10 to write dvds. " + "All older versions will not work and K3b will refuse to use them."), + i18n("Install a more recent version of %1.").arg("growisofs"), + false ) ); + } + else if( k3bcore->externalBinManager()->binObject( "growisofs" )->version < K3bVersion( 5, 12 ) ) { + problems.append( K3bSystemProblem( K3bSystemProblem::NON_CRITICAL, + i18n("Used %1 version %2 is outdated").arg("growisofs").arg(k3bcore->externalBinManager()->binObject( "growisofs" )->version), + i18n("K3b will not be able to copy DVDs on-the-fly or write a DVD+RW in multiple " + "sessions using a growisofs " + "version older than 5.12."), + i18n("Install a more recent version of %1.").arg("growisofs"), + false ) ); + } + else if( k3bcore->externalBinManager()->binObject( "growisofs" )->version < K3bVersion( 7, 0 ) ) { + problems.append( K3bSystemProblem( K3bSystemProblem::NON_CRITICAL, + i18n("Used %1 version %2 is outdated").arg("growisofs").arg(k3bcore->externalBinManager()->binObject( "growisofs" )->version), + i18n("It is highly recommended to use growisofs 7.0 or higher. " + "K3b won't be able to write a DVD+RW in multiple " + "sessions using a growisofs version older than 7.0." ), + i18n("Install a more recent version of %1.").arg("growisofs"), + false ) ); + } + // for now we ignore the suid root bit becasue of the memorylocked issue +// else if( !k3bcore->externalBinManager()->binObject( "growisofs" )->hasFeature( "suidroot" ) ) { +// problems.append( K3bSystemProblem( K3bSystemProblem::CRITICAL, +// i18n("%1 will be run without root privileges").arg("growisofs"), +// i18n("It is highly recommended to configure growisofs " +// "to run with root privileges. Only then growisofs " +// "runs with high priority which increases the overall " +// "stability of the burning process."), +// QString::null, +// true ) ); +// } + } + + if( !k3bcore->externalBinManager()->foundBin( "dvd+rw-format" ) ) { + problems.append( K3bSystemProblem( K3bSystemProblem::CRITICAL, + i18n("Unable to find %1 executable").arg("dvd+rw-format"), + i18n("K3b uses dvd+rw-format to format DVD-RWs and DVD+RWs."), + i18n("Install the dvd+rw-tools package."), + false ) ); + } + } + + if( !k3bcore->externalBinManager()->foundBin( "mkisofs" ) ) { + + } + else if( k3bcore->externalBinManager()->binObject( "mkisofs" )->hasFeature( "outdated" ) ) { + problems.append( K3bSystemProblem( K3bSystemProblem::CRITICAL, + i18n("Used %1 version %2 is outdated") + .arg("mkisofs") + .arg(k3bcore->externalBinManager()->binObject( "mkisofs" )->version), + i18n("K3b needs at least mkisofs version 1.14. Older versions may introduce problems " + "when creating data projects."), + i18n("Install a more recent version of %1.").arg("mkisofs"), + false ) ); + } + + // 2. device check + bool atapiReader = false; + bool atapiWriter = false; + bool dvd_r_dl = false; + for( QPtrListIterator<K3bDevice::Device> it( k3bcore->deviceManager()->readingDevices() ); + it.current(); ++it ) { + if( it.current()->interfaceType() == K3bDevice::IDE ) + atapiReader = true; + if( it.current()->type() & K3bDevice::DEVICE_DVD_R_DL ) + dvd_r_dl = true; + } + + + // check automounted devices + QPtrList<K3bDevice::Device> automountedDevices = checkForAutomounting(); + for( QPtrListIterator<K3bDevice::Device> it( automountedDevices ); + it.current(); ++it ) { + problems.append( K3bSystemProblem( K3bSystemProblem::NON_CRITICAL, + i18n("Device %1 - %2 is automounted.") + .arg(it.current()->vendor()).arg(it.current()->description()), + i18n("K3b is not able to unmount automounted devices. Thus, especially " + "DVD+RW rewriting might fail. There is no need to report this as " + "a bug or feature wish; it is not possible to solve this problem " + "from within K3b."), + i18n("Replace the automounting entries in /etc/fstab with old-fashioned " + "ones or use a user-space mounting solution like pmount or ivman."), + false ) ); + } + + + if( atapiWriter ) { + if( !K3b::plainAtapiSupport() && + !K3b::hackedAtapiSupport() ) { + problems.append( K3bSystemProblem( K3bSystemProblem::CRITICAL, + i18n("No ATAPI writing support in kernel"), + i18n("Your kernel does not support writing without " + "SCSI emulation but there is at least one " + "writer in your system not configured to use " + "SCSI emulation."), + i18n("The best and recommended solution is to enable " + "ide-scsi (SCSI emulation) for all devices. " + "This way you won't have any problems." + "Be aware that you may still enable DMA on ide-scsi " + "emulated drives."), + false ) ); + } + else { + // we have atapi support in some way in the kernel + + if( k3bcore->externalBinManager()->foundBin( "cdrecord" ) ) { + + if( !( k3bcore->externalBinManager()->binObject( "cdrecord" )->hasFeature( "hacked-atapi" ) && + K3b::hackedAtapiSupport() ) && + !( k3bcore->externalBinManager()->binObject( "cdrecord" )->hasFeature( "plain-atapi" ) && + K3b::plainAtapiSupport() ) ) { + problems.append( K3bSystemProblem( K3bSystemProblem::CRITICAL, + i18n("%1 %2 does not support ATAPI").arg("cdrecord").arg(k3bcore->externalBinManager()->binObject("cdrecord")->version), + i18n("The configured version of %1 does not " + "support writing to ATAPI devices without " + "SCSI emulation and there is at least one writer " + "in your system not configured to use " + "SCSI emulation.").arg("cdrecord"), + i18n("The best and recommended solution is to enable " + "ide-scsi (SCSI emulation) for all devices. " + "This way you won't have any problems. Or you install " + "(or select as the default) a more recent version of %1.").arg("cdrtools"), + false ) ); + } + } + + if( k3bcore->externalBinManager()->foundBin( "cdrdao" ) ) { + + if( !k3bcore->externalBinManager()->binObject( "cdrdao" )->hasFeature( "hacked-atapi" ) && + !k3bcore->externalBinManager()->binObject( "cdrdao" )->hasFeature( "plain-atapi") ) { + // FIXME: replace ">" with ">" + problems.append( K3bSystemProblem( K3bSystemProblem::CRITICAL, + i18n("%1 %2 does not support ATAPI") + .arg("cdrdao").arg(k3bcore->externalBinManager()->binObject("cdrdao")->version), + i18n("The configured version of %1 does not " + "support writing to ATAPI devices without " + "SCSI emulation and there is at least one writer " + "in your system not configured to use " + "SCSI emulation.").arg("cdrdao"), + K3b::simpleKernelVersion() > K3bVersion( 2, 5, 0 ) + ? i18n("Install cdrdao >= 1.1.8 which supports writing to " + "ATAPI devices directly.") + : i18n("The best, and recommended, solution is to use " + "ide-scsi (SCSI emulation) for all writer devices: " + "this way you will not have any problems; or, you can install " + "(or select as the default) a more recent version of %1.").arg("cdrdao"), + false ) ); + } + } + } + } + + if( dvd_r_dl && k3bcore->externalBinManager()->foundBin( "growisofs" ) ) { + if( k3bcore->externalBinManager()->binObject( "growisofs" )->version < K3bVersion( 6, 0 ) ) + problems.append( K3bSystemProblem( K3bSystemProblem::NON_CRITICAL, + i18n("Used %1 version %2 is outdated").arg("growisofs").arg(k3bcore->externalBinManager()->binObject( "growisofs" )->version), + i18n("K3b won't be able to write DVD-R Dual Layer media using a growisofs " + "version older than 6.0."), + i18n("Install a more recent version of growisofs."), + false ) ); + } + + for( QPtrListIterator<K3bDevice::Device> it( k3bcore->deviceManager()->allDevices() ); + it.current(); ++it ) { + K3bDevice::Device* dev = it.current(); + + if( !QFileInfo( dev->blockDeviceName() ).isWritable() ) + problems.append( K3bSystemProblem( K3bSystemProblem::CRITICAL, + i18n("No write access to device %1").arg(dev->blockDeviceName()), + i18n("K3b needs write access to all the devices to perform certain tasks. " + "Without it you might encounter problems with %1 - %2").arg(dev->vendor()).arg(dev->description()), + i18n("Make sure you have write access to %1. In case you are not using " + "devfs or udev K3bSetup is able to do this for you.").arg(dev->blockDeviceName()), + false ) ); + + + if( !dev->genericDevice().isEmpty() && + !QFileInfo( dev->genericDevice() ).isWritable() ) + problems.append( K3bSystemProblem( K3bSystemProblem::CRITICAL, + i18n("No write access to generic SCSI device %1").arg(dev->genericDevice()), + i18n("Without write access to the generic device you might " + "encounter problems with Audio CD ripping from %1 - %2").arg(dev->vendor()).arg(dev->description()), + i18n("Make sure you have write access to %1. In case you are not using " + "devfs or udev K3bSetup is able to do this for you.").arg(dev->genericDevice()), + false ) ); + + if( dev->interfaceType() == K3bDevice::IDE && !dmaActivated( dev ) ) + problems.append( K3bSystemProblem( K3bSystemProblem::CRITICAL, + i18n("DMA disabled on device %1 - %2").arg(dev->vendor()).arg(dev->description()), + i18n("With most modern CD/DVD devices enabling DMA highly increases " + "read/write performance. If you experience very low writing speeds " + "this is probably the cause."), + i18n("Enable DMA temporarily as root with 'hdparm -d 1 %1'.").arg(dev->blockDeviceName()) ) ); + } + + + // + // Check if the user specified some user parameters and warn about it + // + const QMap<QString, K3bExternalProgram*>& programMap = k3bcore->externalBinManager()->programs(); + for( QMap<QString, K3bExternalProgram*>::const_iterator it = programMap.constBegin(); + it != programMap.constEnd(); ++it ) { + const K3bExternalProgram* p = it.data(); + if( !p->userParameters().isEmpty() ) { + problems.append( K3bSystemProblem( K3bSystemProblem::WARNING, + i18n("User parameters specified for external program %1").arg(p->name()), + i18n("Sometimes it may be nessessary to specify user parameters in addition to " + "the parameters generated by K3b. This is simply a warning to make sure that " + "these parameters are really wanted and won't be part of some bug report."), + i18n("To remove the user parameters for the external program %1 open the " + "K3b settings page 'Programs' and choose the tab 'User Parameters'.") + .arg(p->name()), + false ) ); + } + } + + // + // Way too many users are complaining about K3b not being able to decode mp3 files. So just warn them about + // the legal restrictions with many distros + // +/* + QPtrList<K3bPlugin> plugins = k3bcore->pluginManager()->plugins( "AudioDecoder" ); + bool haveMp3Decoder = false; + for( QPtrListIterator<K3bPlugin> it( plugins ); *it; ++it ) { + if( it.current()->pluginInfo().name() == "K3b MAD Decoder" ) { + haveMp3Decoder = true; + break; + } + } + if( !haveMp3Decoder ) { + problems.append( K3bSystemProblem( K3bSystemProblem::WARNING, + i18n("Mp3 Audio Decoder plugin not found."), + i18n("K3b could not load or find the Mp3 decoder plugin. This means that you will not " + "be able to create Audio CDs from Mp3 files. Many Linux distributions do not " + "include Mp3 support for legal reasons."), + i18n("To enable Mp3 support, please install the MAD Mp3 decoding library as well as the " + "K3b MAD Mp3 decoder plugin (the latter may already be installed but not functional " + "due to the missing libmad). Some distributions allow installation of Mp3 support " + "via an online update tool (i.e. SuSE's YOU)."), + false ) ); + } +*/ + +#ifdef HAVE_ICONV_H + char* codec = nl_langinfo( CODESET ); + if( strcmp( codec, "ANSI_X3.4-1968" ) == 0 ) { + // + // On a glibc system the system locale defaults to ANSI_X3.4-1968 + // It is very unlikely that one would set the locale to ANSI_X3.4-1968 + // intentionally + // + problems.append( K3bSystemProblem( K3bSystemProblem::WARNING, + i18n("System locale charset is ANSI_X3.4-1968"), + i18n("Your system's locale charset (i.e. the charset used to encode filenames) " + "is set to ANSI_X3.4-1968. It is highly unlikely that this has been done " + "intentionally. Most likely the locale is not set at all. An invalid setting " + "will result in problems when creating data projects."), + i18n("To properly set the locale charset make sure the LC_* environment variables " + "are set. Normally the distribution setup tools take care of this."), + false ) ); + } +#endif + + + // + // Never run K3b as root and especially not suid root! The latter is not possible anyway since + // the kdelibs refuse it. + // + if( ::getuid() == 0 ) { + problems.append( K3bSystemProblem( K3bSystemProblem::WARNING, + i18n("Running K3b as root user"), + i18n("It is not recommended to run K3b under the root user account. " + "This introduces unnecessary security risks."), + i18n("Run K3b from a proper user account and setup the device and " + "external tool permissions appropriately.") +#ifdef HAVE_K3BSETUP + + ' ' + i18n("The latter can be done via K3bSetup.") +#endif + , + true ) ); + } + + + kdDebug() << "(K3bCore) System problems:" << endl; + for( QValueList<K3bSystemProblem>::const_iterator it = problems.begin(); + it != problems.end(); ++it ) { + const K3bSystemProblem& p = *it; + + switch( p.type ) { + case K3bSystemProblem::CRITICAL: + kdDebug() << " CRITICAL" << endl; + break; + case K3bSystemProblem::NON_CRITICAL: + kdDebug() << " NON_CRITICAL" << endl; + break; + case K3bSystemProblem::WARNING: + kdDebug() << " WARNING" << endl; + break; + } + kdDebug() << " PROBLEM: " << p.problem << endl + << " DETAILS: " << p.details << endl + << " SOLUTION: " << p.solution << endl << endl; + + } + if( problems.isEmpty() ) { + kdDebug() << " - none - " << endl; + //K3bPassivePopup::showPopup( i18n("No problems found in system configuration."), i18n("System Problems") ); + } + else { + static K3bSystemProblemDialog* s_openDlg = 0; + if( s_openDlg ) + s_openDlg->close(); + K3bSystemProblemDialog dlg( problems, parent, name ); + s_openDlg = &dlg; + dlg.exec(); + s_openDlg = 0; + } + + // remember which version of K3b checked the system the last time + KConfigGroup cfg( k3bcore->config(), "General Options" ); + cfg.writeEntry( "Last system check version", k3bcore->version() ); +} + +void K3bSystemProblemDialog::slotK3bSetup() +{ + KProcess p; + p << "kdesu" << "kcmshell k3bsetup2 --lang " + KGlobal::locale()->language(); + if( !p.start( KProcess::DontCare ) ) + KMessageBox::error( 0, i18n("Unable to start K3bSetup2.") ); +} + + +int K3bSystemProblemDialog::dmaActivated( K3bDevice::Device* dev ) +{ + QString hdparm = K3b::findExe( "hdparm" ); + if( hdparm.isEmpty() ) + return -1; + + K3bProcess p; + K3bProcessOutputCollector out( &p ); + p << hdparm << "-d" << dev->blockDeviceName(); + if( !p.start( KProcess::Block, KProcess::AllOutput ) ) + return -1; + + // output is something like: + // + // /dev/hda: + // using_dma = 1 (on) + // + // But we ignore the on/off since it might be translated + // + if( out.output().contains( "1 (" ) ) + return 1; + else if( out.output().contains( "0 (" ) ) + return 0; + else + return -1; +} + + +QPtrList<K3bDevice::Device> K3bSystemProblemDialog::checkForAutomounting() +{ + QPtrList<K3bDevice::Device> l; + + ::setfsent(); + + struct fstab * mountInfo = 0; + while( (mountInfo = ::getfsent()) ) + { + // check if the entry corresponds to a device + QString md = K3b::resolveLink( QFile::decodeName( mountInfo->fs_spec ) ); + QString type = QFile::decodeName( mountInfo->fs_vfstype ); + + if( type == "supermount" || type == "subfs" ) { + // parse the device + QStringList opts = QStringList::split( ",", QString::fromLocal8Bit(mountInfo->fs_mntops) ); + for( QStringList::const_iterator it = opts.begin(); it != opts.end(); ++it ) { + if( (*it).startsWith("dev=") ) { + md = (*it).mid( 4 ); + break; + } + } + + if( K3bDevice::Device* dev = k3bcore->deviceManager()->findDevice( md ) ) + l.append( dev ); + } + } // while mountInfo + + ::endfsent(); + + return l; +} + + +bool K3bSystemProblemDialog::readCheckSystemConfig() +{ + KConfigGroup cfgGrp( k3bcore->config(), "General Options" ); + + K3bVersion configVersion( cfgGrp.readEntry( "Last system check version", "0.1" ) ); + if( configVersion < k3bcore->version() ) + cfgGrp.writeEntry( "check system config", true ); + + return cfgGrp.readBoolEntry( "check system config", true ); +} + +#include "k3bsystemproblemdialog.moc" diff --git a/src/k3bsystemproblemdialog.h b/src/k3bsystemproblemdialog.h new file mode 100644 index 0000000..ad3e1c3 --- /dev/null +++ b/src/k3bsystemproblemdialog.h @@ -0,0 +1,101 @@ +/* + * + * $Id: k3bsystemproblemdialog.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_SYSTEM_DIALOG_H_ +#define _K3B_SYSTEM_DIALOG_H_ + +#include <qstring.h> +#include <qvaluelist.h> + +#include <kdialog.h> + +class QPushButton; +class QCheckBox; +class QCloseEvent; +namespace K3bDevice { + class Device; +} + + +class K3bSystemProblem +{ + public: + K3bSystemProblem( int type = NON_CRITICAL, + const QString& problem = QString::null, + const QString& details = QString::null, + const QString& solution = QString::null, + bool k3bsetup = false ); + + enum { + CRITICAL, + NON_CRITICAL, + WARNING + }; + + int type; + QString problem; + QString details; + QString solution; + bool solvableByK3bSetup; +}; + + +/** + * The K3bSystemProblem checks for problems with the system setup + * that could prevent K3b from funcioning properly. Examples are + * missing external appplications like cdrecord or versions of + * external applications that are too old. + * + * Usage: + * <pre> + * if( K3bSystemProblemDialog::readCheckSystemConfig() ) + * K3bSystemProblemDialog::checkSystem( this ); + * </pre> + */ +class K3bSystemProblemDialog : public KDialog +{ + Q_OBJECT + + public: + /** + * Determines if the system problem dialog should be shown or not. + * It basicly reads a config entry. But in addition it + * always forces the system check if a new version has been installed + * or K3b is started for the first time. + */ + static bool readCheckSystemConfig(); + static void checkSystem( QWidget* parent = 0, + const char* name = 0 ); + + protected: + void closeEvent( QCloseEvent* ); + + private slots: + void slotK3bSetup(); + + private: + K3bSystemProblemDialog( const QValueList<K3bSystemProblem>&, + QWidget* parent = 0, + const char* name = 0 ); + static int dmaActivated( K3bDevice::Device* ); + static QPtrList<K3bDevice::Device> checkForAutomounting(); + + QPushButton* m_closeButton; + QPushButton* m_k3bsetupButton; + QCheckBox* m_checkDontShowAgain; +}; + +#endif diff --git a/src/k3btempdirselectionwidget.cpp b/src/k3btempdirselectionwidget.cpp new file mode 100644 index 0000000..ae850e1 --- /dev/null +++ b/src/k3btempdirselectionwidget.cpp @@ -0,0 +1,277 @@ +/* + * + * $Id: k3btempdirselectionwidget.cpp 690207 2007-07-20 10:40:19Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3btempdirselectionwidget.h" +#include <k3bglobals.h> +#include <k3bcore.h> + +#include <qlabel.h> +#include <qgroupbox.h> +#include <qlayout.h> +#include <qtimer.h> +#include <qhbox.h> +#include <qtooltip.h> +#include <qwhatsthis.h> +#include <qfileinfo.h> + +#include <kconfig.h> +#include <klocale.h> +#include <kfiledialog.h> +#include <kdialog.h> +#include <kstandarddirs.h> +#include <kiconloader.h> +#include <kurlrequester.h> +#include <kio/global.h> +#include <kconfig.h> +#include <klineedit.h> + + +K3bTempDirSelectionWidget::K3bTempDirSelectionWidget( QWidget *parent, const char *name ) + : QGroupBox( 4, Qt::Vertical, parent, name ), + m_labelCdSize(0), + m_defaultImageFileName( "k3b_image.iso" ) +{ + layout()->setSpacing( KDialog::spacingHint() ); + layout()->setMargin( KDialog::marginHint() ); + + m_imageFileLabel = new QLabel( this ); + m_editDirectory = new KURLRequester( this, "m_editDirectory" ); + + m_imageFileLabel->setBuddy( m_editDirectory ); + + QHBox* freeTempSpaceBox = new QHBox( this ); + freeTempSpaceBox->setSpacing( KDialog::spacingHint() ); + (void)new QLabel( i18n( "Free space in temporary directory:" ), freeTempSpaceBox, "TextLabel2" ); + m_labelFreeSpace = new QLabel( " ",freeTempSpaceBox, "m_labelFreeSpace" ); + m_labelFreeSpace->setAlignment( int( QLabel::AlignVCenter | QLabel::AlignRight ) ); + + + connect( m_editDirectory, SIGNAL(openFileDialog(KURLRequester*)), + this, SLOT(slotTempDirButtonPressed(KURLRequester*)) ); + connect( m_editDirectory, SIGNAL(textChanged(const QString&)), + this, SLOT(slotUpdateFreeTempSpace()) ); + connect( m_editDirectory->lineEdit(), SIGNAL(lostFocus()), + this, SLOT(slotFixTempPath()) ); + + // choose a default + setSelectionMode( DIR ); + + m_editDirectory->setURL( K3b::defaultTempPath() ); + slotUpdateFreeTempSpace(); + + // ToolTips + // -------------------------------------------------------------------------------- + QToolTip::add( m_editDirectory, i18n("The directory in which to save the image files") ); + + // What's This info + // -------------------------------------------------------------------------------- + QWhatsThis::add( m_editDirectory, i18n("<p>This is the directory in which K3b will save the <em>image files</em>." + "<p>Please make sure that it resides on a partition that has enough free space.") ); +} + + +K3bTempDirSelectionWidget::~K3bTempDirSelectionWidget() +{ +} + + +unsigned long K3bTempDirSelectionWidget::freeTempSpace() const +{ + QString path = m_editDirectory->url(); + + if( !QFile::exists( path ) ) + path.truncate( path.findRev('/') ); + + unsigned long size; + K3b::kbFreeOnFs( path, size, m_freeTempSpace ); + + return m_freeTempSpace; +} + + +void K3bTempDirSelectionWidget::slotUpdateFreeTempSpace() +{ + // update the temp space + freeTempSpace(); + + m_labelFreeSpace->setText( KIO::convertSizeFromKB(m_freeTempSpace) ); + + if( m_labelCdSize ) { + if( m_freeTempSpace < m_requestedSize/1024 ) + m_labelCdSize->setPaletteForegroundColor( red ); + else + m_labelCdSize->setPaletteForegroundColor( m_labelFreeSpace->paletteForegroundColor() ); + } + QTimer::singleShot( 1000, this, SLOT(slotUpdateFreeTempSpace()) ); +} + + +void K3bTempDirSelectionWidget::slotTempDirButtonPressed( KURLRequester* r ) +{ + // set the correct mode for the filedialog + if( m_mode == DIR ) { + r->setCaption( i18n("Select Temporary Directory") ); + r->setMode( KFile::Directory | KFile::ExistingOnly | KFile::LocalOnly ); + } + else { + r->setCaption( i18n("Select Temporary File") ); + r->setMode( KFile::File | KFile::LocalOnly ); + } +} + + +void K3bTempDirSelectionWidget::setTempPath( const QString& dir ) +{ + m_editDirectory->setURL( dir ); + slotUpdateFreeTempSpace(); +} + + +QString K3bTempDirSelectionWidget::tempPath() const +{ + QFileInfo fi( m_editDirectory->url() ); + + if( fi.exists() ) { + if( m_mode == DIR ) { + if( fi.isDir() ) + return fi.absFilePath(); + else + return fi.dirPath( true ); + } + else { + if( fi.isFile() ) + return fi.absFilePath(); + else + return fi.absFilePath() + "/k3b_image.iso"; + } + } + else { + return fi.absFilePath(); + } +} + + +QString K3bTempDirSelectionWidget::plainTempPath() const +{ + return m_editDirectory->url(); +} + + +QString K3bTempDirSelectionWidget::tempDirectory() const +{ + QString td( m_editDirectory->url() ); + + // remove a trailing slash + while( !td.isEmpty() && td[td.length()-1] == '/' ) + td.truncate( td.length()-1 ); + + QFileInfo fi( td ); + if( fi.exists() && fi.isDir() ) + return td + "/"; + + // now we treat the last section as a filename and return the path + // in front of it + td.truncate( td.findRev( '/' ) + 1 ); + return td; +} + + +void K3bTempDirSelectionWidget::setSelectionMode( int mode ) +{ + m_mode = mode; + + if( m_mode == DIR ) { + m_imageFileLabel->setText( i18n( "Wri&te image files to:" ) ); + setTitle( i18n("Temporary Directory") ); + } + else { + m_imageFileLabel->setText( i18n( "Wri&te image file to:" ) ); + setTitle( i18n("Temporary File") ); + } +} + + +void K3bTempDirSelectionWidget::setNeededSize( KIO::filesize_t bytes ) +{ + m_requestedSize = bytes; + if( !m_labelCdSize ) { + QHBox* cdSizeBox = new QHBox( this ); + cdSizeBox->setSpacing( KDialog::spacingHint() ); + (void)new QLabel( i18n( "Size of project:" ), cdSizeBox, "TextLabel4" ); + m_labelCdSize = new QLabel( KIO::convertSize(bytes), cdSizeBox, "m_labelCdSize" ); + m_labelCdSize->setAlignment( int( QLabel::AlignVCenter | QLabel::AlignRight ) ); + } + m_labelCdSize->setText( KIO::convertSize(bytes) ); +} + + +void K3bTempDirSelectionWidget::saveConfig() +{ + KConfigGroup grp( k3bcore->config(), "General Options" ); + grp.writePathEntry( "Temp Dir", tempDirectory() ); +} + + +void K3bTempDirSelectionWidget::readConfig( KConfigBase* c ) +{ + setTempPath( c->readPathEntry( "image path", K3b::defaultTempPath() ) ); +} + + +void K3bTempDirSelectionWidget::saveConfig( KConfigBase* c ) +{ + c->writePathEntry( "image path", tempPath() ); +} + + +void K3bTempDirSelectionWidget::setDefaultImageFileName( const QString& name ) +{ + if ( !name.isEmpty() ) { + bool changeImageName = false; + if ( selectionMode() == FILE ) { + if ( plainTempPath().section( '/', -1 ) == m_defaultImageFileName ) { + changeImageName = true; + } + } + + m_defaultImageFileName = name; + if ( !m_defaultImageFileName.contains( '.' ) ) { + m_defaultImageFileName += ".iso"; + } + fixTempPath( changeImageName ); + } +} + + +void K3bTempDirSelectionWidget::slotFixTempPath() +{ + fixTempPath( false ); +} + + +void K3bTempDirSelectionWidget::fixTempPath( bool forceNewImageName ) +{ + // if in file selection mode and no image file is specified or + // forceNewImageName is true set the default image file name + if ( selectionMode() == FILE ) { + if ( forceNewImageName || + QFileInfo( plainTempPath() ).isDir() ) { + setTempPath( tempDirectory() + m_defaultImageFileName ); + } + } +} + +#include "k3btempdirselectionwidget.moc" diff --git a/src/k3btempdirselectionwidget.h b/src/k3btempdirselectionwidget.h new file mode 100644 index 0000000..abad230 --- /dev/null +++ b/src/k3btempdirselectionwidget.h @@ -0,0 +1,100 @@ +/* + * + * $Id: k3btempdirselectionwidget.h 690207 2007-07-20 10:40:19Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BTEMPDIRSELECTIONWIDGET_H +#define K3BTEMPDIRSELECTIONWIDGET_H + +#include <qgroupbox.h> +#include <kio/global.h> + +class QTimer; +class QLabel; +class KURLRequester; +class KConfigBase; + + +/** + *@author Sebastian Trueg + */ +class K3bTempDirSelectionWidget : public QGroupBox +{ + Q_OBJECT + + public: + K3bTempDirSelectionWidget( QWidget *parent = 0, const char *name = 0 ); + ~K3bTempDirSelectionWidget(); + + /** determines if the selection dialog should ask for a dir or a file */ + enum mode { DIR, FILE }; + + int selectionMode() const { return m_mode; } + + /** + * \return Free space in KB + * FIXME: use KIO::filesize_t and return the number of bytes + */ + unsigned long freeTempSpace() const; + QString tempPath() const; + QString tempDirectory() const; + + /** + * Use this if you don't want K3bTempDirSelectionWidget to modify the + * user input based on the mode. + */ + QString plainTempPath() const; + + public slots: + void setTempPath( const QString& ); + void setSelectionMode( int mode ); + void setNeededSize( KIO::filesize_t bytes ); + + /** + * In file selection mode if the user enters a directory name it will + * automatically be expended to this filename. + * Default is k3b_image.iso + */ + void setDefaultImageFileName( const QString& name ); + + /** + * saves the current path as the global default tempd dir. + */ + void saveConfig(); + + void readConfig( KConfigBase* ); + void saveConfig( KConfigBase* ); + + private slots: + void slotUpdateFreeTempSpace(); + void slotTempDirButtonPressed( KURLRequester* ); + void slotFixTempPath(); + + private: + void fixTempPath( bool forceNewImageName ); + + QLabel* m_imageFileLabel; + QLabel* m_labelCdSize; + QLabel* m_labelFreeSpace; + KURLRequester* m_editDirectory; + + mutable unsigned long m_freeTempSpace; + unsigned long m_requestedSize; + + int m_mode; + + QString m_defaultImageFileName; +}; + +#endif diff --git a/src/k3bthemedheader.cpp b/src/k3bthemedheader.cpp new file mode 100644 index 0000000..4eb1c28 --- /dev/null +++ b/src/k3bthemedheader.cpp @@ -0,0 +1,129 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bthemedheader.h" +#include "k3bthememanager.h" +#include "k3bapplication.h" + +#include <k3btitlelabel.h> + +#include <qlabel.h> +#include <qlayout.h> + + +K3bThemedHeader::K3bThemedHeader( QWidget* parent ) + : QFrame( parent ) +{ + init(); +} + + +K3bThemedHeader::K3bThemedHeader( const QString& title, const QString& subtitle, QWidget* parent ) + : QFrame( parent ) +{ + setTitle( title ); + setSubTitle( subtitle ); + + init(); +} + + +K3bThemedHeader::~K3bThemedHeader() +{ +} + + +void K3bThemedHeader::setTitle( const QString& title, const QString& subtitle ) +{ + m_titleLabel->setTitle( title, subtitle ); +} + + +void K3bThemedHeader::setSubTitle( const QString& subtitle ) +{ + m_titleLabel->setSubTitle( subtitle ); +} + + +void K3bThemedHeader::setLeftPixmap( K3bTheme::PixmapType p ) +{ + m_leftPix = p; + slotThemeChanged(); +} + + +void K3bThemedHeader::setRightPixmap( K3bTheme::PixmapType p ) +{ + m_rightPix = p; + slotThemeChanged(); +} + + +void K3bThemedHeader::setAlignment( int align ) +{ + m_titleLabel->setAlignment( align ); +} + + +void K3bThemedHeader::init() +{ + setFrameShape( QFrame::StyledPanel ); + setFrameShadow( QFrame::Sunken ); + setLineWidth( 1 ); + setMargin( 1 ); + + QHBoxLayout* layout = new QHBoxLayout( this ); + layout->setMargin( 2 ); // to make sure the frame gets displayed + layout->setSpacing( 0 ); + + m_leftLabel = new QLabel( this ); + m_leftLabel->setScaledContents( false ); + m_titleLabel = new K3bTitleLabel( this ); + m_rightLabel = new QLabel( this ); + m_rightLabel->setScaledContents( false ); + + layout->addWidget( m_leftLabel ); + layout->addWidget( m_titleLabel ); + layout->setStretchFactor( m_titleLabel, 1 ); + layout->addWidget( m_rightLabel ); + + m_leftPix = K3bTheme::DIALOG_LEFT; + m_rightPix = K3bTheme::DIALOG_RIGHT; + + slotThemeChanged(); + + connect( k3bappcore->themeManager(), SIGNAL(themeChanged()), + this, SLOT(slotThemeChanged()) ); + connect( kapp, SIGNAL(appearanceChanged()), + this, SLOT(slotThemeChanged()) ); +} + + +void K3bThemedHeader::slotThemeChanged() +{ + if( K3bTheme* theme = k3bappcore->themeManager()->currentTheme() ) { +// setPaletteBackgroundColor( theme->backgroundColor() ); +// setPaletteForegroundColor( theme->foregroundColor() ); + + m_leftLabel->setPaletteBackgroundColor( theme->backgroundColor() ); + m_leftLabel->setPixmap( theme->pixmap( m_leftPix ) ); + m_rightLabel->setPaletteBackgroundColor( theme->backgroundColor() ); + m_rightLabel->setPixmap( theme->pixmap( m_rightPix ) ); + m_titleLabel->setPaletteBackgroundColor( theme->backgroundColor() ); + m_titleLabel->setPaletteForegroundColor( theme->foregroundColor() ); + } +} + +#include "k3bthemedheader.moc" diff --git a/src/k3bthemedheader.h b/src/k3bthemedheader.h new file mode 100644 index 0000000..3dda877 --- /dev/null +++ b/src/k3bthemedheader.h @@ -0,0 +1,55 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_THEMED_HEADER_H_ +#define _K3B_THEMED_HEADER_H_ + +#include <qframe.h> + +#include "k3bthememanager.h" + +class K3bTitleLabel; +class QLabel; + +class K3bThemedHeader : public QFrame +{ + Q_OBJECT + + public: + K3bThemedHeader( QWidget* parent = 0 ); + K3bThemedHeader( const QString& title, const QString& subtitle, QWidget* parent = 0 ); + ~K3bThemedHeader(); + + public slots: + void setTitle( const QString& title, const QString& subtitle = QString::null ); + void setSubTitle( const QString& subtitle ); + void setAlignment( int ); + void setLeftPixmap( K3bTheme::PixmapType ); + void setRightPixmap( K3bTheme::PixmapType ); + + private slots: + void slotThemeChanged(); + + private: + void init(); + + K3bTitleLabel* m_titleLabel; + QLabel* m_leftLabel; + QLabel* m_rightLabel; + K3bTheme::PixmapType m_leftPix; + K3bTheme::PixmapType m_rightPix; +}; + +#endif diff --git a/src/k3bthemedlabel.cpp b/src/k3bthemedlabel.cpp new file mode 100644 index 0000000..d2ea05b --- /dev/null +++ b/src/k3bthemedlabel.cpp @@ -0,0 +1,76 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bthemedlabel.h" +#include "k3bapplication.h" + +K3bThemedLabel::K3bThemedLabel( QWidget* parent ) + : KCutLabel( parent ), + m_themePixmapCode( -1 ) +{ + slotThemeChanged(); + + connect( k3bappcore->themeManager(), SIGNAL(themeChanged()), + this, SLOT(slotThemeChanged()) ); + connect( kapp, SIGNAL(appearanceChanged()), + this, SLOT(slotThemeChanged()) ); +} + + +K3bThemedLabel::K3bThemedLabel( const QString& text, QWidget* parent ) + : KCutLabel( text, parent ), + m_themePixmapCode( -1 ) +{ + slotThemeChanged(); + + connect( k3bappcore->themeManager(), SIGNAL(themeChanged()), + this, SLOT(slotThemeChanged()) ); + connect( kapp, SIGNAL(appearanceChanged()), + this, SLOT(slotThemeChanged()) ); +} + + +K3bThemedLabel::K3bThemedLabel( K3bTheme::PixmapType pix, QWidget* parent ) + : KCutLabel( parent ) +{ + setThemePixmap( pix ); + + connect( k3bappcore->themeManager(), SIGNAL(themeChanged()), + this, SLOT(slotThemeChanged()) ); + connect( kapp, SIGNAL(appearanceChanged()), + this, SLOT(slotThemeChanged()) ); +} + + +void K3bThemedLabel::setThemePixmap( K3bTheme::PixmapType pix ) +{ + m_themePixmapCode = pix; + slotThemeChanged(); +} + + +void K3bThemedLabel::slotThemeChanged() +{ + if( K3bTheme* theme = k3bappcore->themeManager()->currentTheme() ) { + setPaletteBackgroundColor( theme->backgroundColor() ); + setPaletteForegroundColor( theme->foregroundColor() ); + if( m_themePixmapCode > -1 ) { + setPixmap( theme->pixmap( (K3bTheme::PixmapType)m_themePixmapCode ) ); + setScaledContents( false ); + } + } +} + +#include "k3bthemedlabel.moc" diff --git a/src/k3bthemedlabel.h b/src/k3bthemedlabel.h new file mode 100644 index 0000000..06d4851 --- /dev/null +++ b/src/k3bthemedlabel.h @@ -0,0 +1,42 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_THEMED_LABEL_H_ +#define _K3B_THEMED_LABEL_H_ + +#include <kcutlabel.h> +#include <k3bthememanager.h> + + +class K3bThemedLabel : public KCutLabel +{ + Q_OBJECT + + public: + K3bThemedLabel( QWidget* parent = 0 ); + K3bThemedLabel( const QString& text, QWidget* parent = 0 ); + K3bThemedLabel( K3bTheme::PixmapType, QWidget* parent = 0 ); + + public slots: + void setThemePixmap( K3bTheme::PixmapType ); + + private slots: + void slotThemeChanged(); + + private: + int m_themePixmapCode; +}; + +#endif diff --git a/src/k3bthememanager.cpp b/src/k3bthememanager.cpp new file mode 100644 index 0000000..2d7177f --- /dev/null +++ b/src/k3bthememanager.cpp @@ -0,0 +1,324 @@ +/* + * + * $Id$ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bthememanager.h" + +#include <k3bversion.h> + +#include <kstandarddirs.h> +#include <kglobalsettings.h> +#include <ksimpleconfig.h> +#include <kdebug.h> +#include <kglobal.h> + +#include <qpixmap.h> +#include <qfile.h> +#include <qfileinfo.h> +#include <qdir.h> +#include <qstringlist.h> +#include <qvaluelist.h> + + +K3bTheme::K3bTheme() + : m_bgMode(BG_TILE) +{ +} + + +QColor K3bTheme::backgroundColor() const +{ + if( m_bgColor.isValid() ) + return m_bgColor; + else + return KGlobalSettings::activeTitleColor(); +} + + +QColor K3bTheme::foregroundColor() const +{ + if( m_fgColor.isValid() ) + return m_fgColor; + else + return KGlobalSettings::activeTextColor(); +} + + +const QPixmap& K3bTheme::pixmap( const QString& name ) const +{ + QMap<QString, QPixmap>::const_iterator it = m_pixmapMap.find( name ); + if( it != m_pixmapMap.end() ) + return *it; + + // try loading the image + if( QFile::exists( m_path + name ) ) + return *m_pixmapMap.insert( name, QPixmap( m_path + name ) ); + + kdDebug() << "(K3bTheme) " << m_name << ": could not load image " << name << endl; + + return m_emptyPixmap; +} + + +const QPixmap& K3bTheme::pixmap( K3bTheme::PixmapType t ) const +{ + return pixmap( filenameForPixmapType( t ) ); +} + + +QString K3bTheme::filenameForPixmapType( PixmapType t ) +{ + QString name; + + switch( t ) { + case MEDIA_AUDIO: + name = "media_audio"; + break; + case MEDIA_DATA: + name = "media_data"; + break; + case MEDIA_VIDEO: + name = "media_video"; + break; + case MEDIA_EMPTY: + name = "media_empty"; + break; + case MEDIA_MIXED: + name = "media_mixed"; + break; + case MEDIA_NONE: + name = "media_none"; + break; + case MEDIA_LEFT: + name = "media_left"; + break; + case PROGRESS_WORKING: + name = "progress_working"; + break; + case PROGRESS_SUCCESS: + name = "progress_success"; + break; + case PROGRESS_FAIL: + name = "progress_fail"; + break; + case PROGRESS_RIGHT: + name = "progress_right"; + break; + case DIALOG_LEFT: + name = "dialog_left"; + break; + case DIALOG_RIGHT: + name = "dialog_right"; + break; + case SPLASH: + name = "splash"; + break; + case PROJECT_LEFT: + name = "project_left"; + break; + case PROJECT_RIGHT: + name = "project_right"; + break; + case WELCOME_BG: + name = "welcome_bg"; + break; + default: + break; + } + + name.append( ".png" ); + + return name; +} + + +K3bTheme::BackgroundMode K3bTheme::backgroundMode() const +{ + return m_bgMode; +} + + + +class K3bThemeManager::Private +{ +public: + Private() + : currentTheme(&emptyTheme) { + } + + QValueList<K3bTheme*> themes; + K3bTheme* currentTheme; + QString currentThemeName; + + K3bTheme emptyTheme; +}; + + + +K3bThemeManager::K3bThemeManager( QObject* parent, const char* name ) + : QObject( parent, name ) +{ + d = new Private(); + d->emptyTheme.m_name = "Empty Theme"; +} + + +K3bThemeManager::~K3bThemeManager() +{ + delete d; +} + + +const QValueList<K3bTheme*>& K3bThemeManager::themes() const +{ + return d->themes; +} + + +K3bTheme* K3bThemeManager::currentTheme() const +{ + return d->currentTheme; +} + + +void K3bThemeManager::readConfig( KConfigBase* c ) +{ + KConfigGroup generalOptions( c, "General Options" ); + + // allow to override the default theme by packaging a default config file + QString defaultTheme = generalOptions.readEntry( "default theme", "quant" ); + + K3bVersion configVersion( generalOptions.readEntry( "config version", "0.1" ) ); + if( configVersion >= K3bVersion("0.98") ) + setCurrentTheme( generalOptions.readEntry( "current theme", defaultTheme ) ); + else + setCurrentTheme( defaultTheme ); +} + + +void K3bThemeManager::saveConfig( KConfigBase* c ) +{ + if( !d->currentThemeName.isEmpty() ) + KConfigGroup( c, "General Options" ).writeEntry( "current theme", d->currentThemeName ); +} + + +void K3bThemeManager::setCurrentTheme( const QString& name ) +{ + if( name != d->currentThemeName ) { + if( K3bTheme* theme = findTheme( name ) ) + setCurrentTheme( theme ); + } +} + + +void K3bThemeManager::setCurrentTheme( K3bTheme* theme ) +{ + if( !theme ) + theme = d->themes.first(); + + if( theme ) { + if( theme != d->currentTheme ) { + d->currentTheme = theme; + d->currentThemeName = theme->name(); + + emit themeChanged(); + emit themeChanged( theme ); + } + } +} + + +K3bTheme* K3bThemeManager::findTheme( const QString& name ) const +{ + for( QValueList<K3bTheme*>::iterator it = d->themes.begin(); it != d->themes.end(); ++it ) + if( (*it)->name() == name ) + return *it; + return 0; +} + + +void K3bThemeManager::loadThemes() +{ + // first we cleanup the loaded themes + for( QValueList<K3bTheme*>::iterator it = d->themes.begin(); it != d->themes.end(); ++it ) + delete *it; + d->themes.clear(); + + QStringList dirs = KGlobal::dirs()->findDirs( "data", "k3b/pics" ); + // now search for themes. As there may be multiple themes with the same name + // we only use the names from this list and then use findResourceDir to make sure + // the local is preferred over the global stuff (like testing a theme by copying it + // to the .kde dir) + QStringList themeNames; + for( QStringList::const_iterator dirIt = dirs.begin(); dirIt != dirs.end(); ++dirIt ) { + QDir dir( *dirIt ); + QStringList entries = dir.entryList( QDir::Dirs ); + entries.remove( "." ); + entries.remove( ".." ); + // every theme dir needs to contain a k3b.theme file + for( QStringList::const_iterator entryIt = entries.begin(); entryIt != entries.end(); ++entryIt ) { + QString themeDir = *dirIt + *entryIt + "/"; + if( !themeNames.contains( *entryIt ) && QFile::exists( themeDir + "k3b.theme" ) ) { + bool themeValid = true; + + // check for all nessessary pixmaps (this is a little evil hacking) + for( int i = 0; i <= K3bTheme::WELCOME_BG; ++i ) { + if( !QFile::exists( themeDir + K3bTheme::filenameForPixmapType( (K3bTheme::PixmapType)i ) ) ) { + kdDebug() << "(K3bThemeManager) theme misses pixmap: " << K3bTheme::filenameForPixmapType( (K3bTheme::PixmapType)i ) << endl; + themeValid = false; + break; + } + } + + if( themeValid ) + themeNames.append( *entryIt ); + } + } + } + + // now load the themes + for( QStringList::const_iterator themeIt = themeNames.begin(); themeIt != themeNames.end(); ++themeIt ) + loadTheme( *themeIt ); + + // load the current theme + setCurrentTheme( findTheme(d->currentThemeName) ); +} + + +void K3bThemeManager::loadTheme( const QString& name ) +{ + QString path = KGlobal::dirs()->findResource( "data", "k3b/pics/" + name + "/k3b.theme" ); + if( !path.isEmpty() ) { + K3bTheme* t = new K3bTheme(); + t->m_name = name; + t->m_path = path.left( path.length() - 9 ); + QFileInfo fi( t->m_path ); + t->m_local = fi.isWritable(); + + // load the stuff + KSimpleConfig cfg( path, true ); + t->m_author = cfg.readEntry( "Author" ); + t->m_comment = cfg.readEntry( "Comment" ); + t->m_version = cfg.readEntry( "Version" ); + t->m_bgColor = cfg.readColorEntry( "Backgroundcolor" ); + t->m_fgColor = cfg.readColorEntry( "Foregroundcolor" ); + t->m_bgMode = ( cfg.readEntry( "BackgroundMode" ) == "Scaled" ? K3bTheme::BG_SCALE : K3bTheme::BG_TILE ); + + d->themes.append( t ); + } +} + + +#include "k3bthememanager.moc" diff --git a/src/k3bthememanager.h b/src/k3bthememanager.h new file mode 100644 index 0000000..f00e62f --- /dev/null +++ b/src/k3bthememanager.h @@ -0,0 +1,146 @@ +/* + * + * $Id$ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_THEME_MANAGER_H_ +#define _K3B_THEME_MANAGER_H_ + +#include <qobject.h> +#include <qvaluelist.h> +#include <qstring.h> +#include <qmap.h> +#include <qcolor.h> +#include <qpixmap.h> + + + +class KConfigBase; + + +class K3bTheme +{ + public: + K3bTheme(); + + QColor backgroundColor() const; + QColor foregroundColor() const; + + enum PixmapType { + MEDIA_AUDIO, /**< Media information header, right side when showing an audio CD. */ + MEDIA_DATA, /**< Media information header, right side when showing a data media. */ + MEDIA_VIDEO, /**< Media information header, right side when showing a video media. */ + MEDIA_EMPTY, /**< Media information header, right side when showing an empty media. */ + MEDIA_MIXED, /**< Media information header, right side when showing a mixed mode CD. */ + MEDIA_NONE, /**< Media information header, right side default pixmap (no media). */ + MEDIA_LEFT, /**< Media information header, left side. */ + PROGRESS_WORKING, /**< Progress dialog, left top while working. */ + PROGRESS_SUCCESS, /**< Progress dialog, left top on success. */ + PROGRESS_FAIL, /**< Progress dialog, left top on failure. */ + PROGRESS_RIGHT, /**< Progress dialog, right top. */ + DIALOG_LEFT, /**< Action dialog, left top. */ + DIALOG_RIGHT, /**< Action dialog, right top. */ + SPLASH, /**< K3b splash screen. Size not important. */ + PROJECT_LEFT, /**< Project header left side. */ + PROJECT_RIGHT, /**< Project header right side. */ + WELCOME_BG /**< Background pixmap of the welcome window. */ + }; + + enum BackgroundMode { + BG_TILE, /**< Keep the pixmap's size and tile the welcome widget */ + BG_SCALE /**< Scale the pixmap to fill the welcome widget. */ + }; + + const QPixmap& pixmap( PixmapType ) const; + + /** + * \deprecated use pixmap( PixmapType ) + */ + const QPixmap& pixmap( const QString& name ) const; + + BackgroundMode backgroundMode() const; + + const QString& name() const { return m_name; } + const QString& author() const { return m_author; } + const QString& comment() const { return m_comment; } + const QString& version() const { return m_version; } + + /** + * Global themes are installed for all users and cannot be deleted. + */ + bool global() const { return !local(); } + + /** + * Local themes are installed in the user's home directory and can be deleted. + */ + bool local() const { return m_local; } + + const QString& path() const { return m_path; } + + static QString filenameForPixmapType( PixmapType ); + + private: + QString m_path; + bool m_local; + QString m_name; + QString m_author; + QString m_comment; + QString m_version; + QColor m_bgColor; + QColor m_fgColor; + BackgroundMode m_bgMode; + + mutable QMap<QString, QPixmap> m_pixmapMap; + + QPixmap m_emptyPixmap; + + friend class K3bThemeManager; +}; + + +class K3bThemeManager : public QObject +{ + Q_OBJECT + + public: + K3bThemeManager( QObject* parent = 0, const char* name = 0 ); + ~K3bThemeManager(); + + const QValueList<K3bTheme*>& themes() const; + + /** + * This is never null. If no theme could be found an empty dummy theme + * will be returnes which does not contains any pixmaps. + */ + K3bTheme* currentTheme() const; + K3bTheme* findTheme( const QString& ) const; + + signals: + void themeChanged(); + void themeChanged( K3bTheme* ); + + public slots: + void readConfig( KConfigBase* ); + void saveConfig( KConfigBase* ); + void setCurrentTheme( const QString& ); + void setCurrentTheme( K3bTheme* ); + void loadThemes(); + + private: + void loadTheme( const QString& name ); + + class Private; + Private* d; +}; + +#endif diff --git a/src/k3btimeoutwidget.cpp b/src/k3btimeoutwidget.cpp new file mode 100644 index 0000000..156963f --- /dev/null +++ b/src/k3btimeoutwidget.cpp @@ -0,0 +1,149 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3btimeoutwidget.h" +#include "k3bthememanager.h" +#include "k3bapplication.h" + +#include <kiconloader.h> + +#include <qpainter.h> +#include <qtimer.h> +#include <qbitmap.h> + + +class K3bTimeoutWidget::Private +{ +public: + int timeout; + int margin; + + QTimer timer; + int currentTime; +}; + + +K3bTimeoutWidget::K3bTimeoutWidget( QWidget* parent ) + : QWidget( parent ) +{ + d = new Private; + d->timeout = 10000; + d->margin = 4; + connect( &d->timer, SIGNAL(timeout()), this, SLOT(timeStep()) ); +} + + +K3bTimeoutWidget::~K3bTimeoutWidget() +{ + delete d; +} + + +void K3bTimeoutWidget::start() +{ + d->currentTime = 0; + startTimer(); +} + + +void K3bTimeoutWidget::stop() +{ + d->timer.stop(); + d->currentTime = 0; +} + + +void K3bTimeoutWidget::pause() +{ + d->timer.stop(); +} + + +void K3bTimeoutWidget::resume() +{ + startTimer(); +} + + +void K3bTimeoutWidget::timeStep() +{ + d->currentTime += 100; + update(); + if( d->currentTime >= d->timeout ) { + stop(); + emit timeout(); + } +} + + +QSize K3bTimeoutWidget::sizeHint() const +{ + return minimumSizeHint(); +} + + +QSize K3bTimeoutWidget::minimumSizeHint() const +{ + int fw = fontMetrics().width( QString::number( d->timeout/1000 ) ); + int fh = fontMetrics().height(); + + int diam = QMAX( fw, fh ) + 2*d->margin; + + return QSize( diam, diam ); +} + + +void K3bTimeoutWidget::setTimeout( int msecs ) +{ + d->timeout = msecs; +} + + +void K3bTimeoutWidget::startTimer() +{ + d->timer.start( 100 ); +} + + +void K3bTimeoutWidget::paintEvent( QPaintEvent* ) +{ + if( d->timer.isActive() ) { + QPainter p(this); + + if( K3bTheme* theme = k3bappcore->themeManager()->currentTheme() ) { + p.setBrush( theme->backgroundColor() ); + p.setPen( theme->backgroundColor() ); + } + + QRect r; + r.setSize( minimumSizeHint() ); + r.moveCenter( rect().center() ); + + p.drawArc( r, 0, 360*16 ); + p.drawPie( r, 90*16, 360*16*d->currentTime/d->timeout ); + + p.setPen( Qt::black ); + p.drawText( rect(), Qt::AlignCenter, QString::number( (d->timeout - d->currentTime + 500)/1000 ) ); + } +} + + +void K3bTimeoutWidget::resizeEvent( QResizeEvent* e ) +{ + QWidget::resizeEvent( e ); +} + + +#include "k3btimeoutwidget.moc" diff --git a/src/k3btimeoutwidget.h b/src/k3btimeoutwidget.h new file mode 100644 index 0000000..6f47deb --- /dev/null +++ b/src/k3btimeoutwidget.h @@ -0,0 +1,59 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_TIMEOUT_WIDGET_H_ +#define _K3B_TIMEOUT_WIDGET_H_ + +#include <qwidget.h> + +class QPaintEvent; +class QResizeEvent; + + +class K3bTimeoutWidget : public QWidget +{ + Q_OBJECT + + public: + K3bTimeoutWidget( QWidget* parent ); + ~K3bTimeoutWidget(); + + QSize sizeHint() const; + QSize minimumSizeHint() const; + + public slots: + void setTimeout( int msecs ); + void start(); + void stop(); + void pause(); + void resume(); + + signals: + void timeout(); + + protected: + void paintEvent( QPaintEvent* ); + void resizeEvent( QResizeEvent* ); + + private slots: + void timeStep(); + void startTimer(); + + private: + class Private; + Private* d; +}; + +#endif diff --git a/src/k3btooltip.cpp b/src/k3btooltip.cpp new file mode 100644 index 0000000..570c23b --- /dev/null +++ b/src/k3btooltip.cpp @@ -0,0 +1,195 @@ +/* + * + * $Id: sourceheader 380067 2005-01-19 13:03:46Z trueg $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3btooltip.h" +#include "k3bwidgetshoweffect.h" + +#include <k3bthememanager.h> +#include <k3bapplication.h> + +#include <qtimer.h> +#include <qapplication.h> +#include <qlabel.h> + +#include <kdebug.h> +#include <fixx11h.h> + + +K3bToolTip::K3bToolTip( QWidget* widget ) + : QObject( widget ), + m_parentWidget( widget ), + m_currentTip( 0 ), + m_tipTimer( new QTimer( this ) ), + m_tipTimeout( 700 ) +{ + m_parentWidget->installEventFilter( this ); + connect( m_tipTimer, SIGNAL(timeout()), + this, SLOT(slotCheckShowTip()) ); +} + + +K3bToolTip::~K3bToolTip() +{ +} + + +void K3bToolTip::tip( const QRect& rect, const QString& text, int effect ) +{ + QLabel* label = new QLabel( text, parentWidget() ); + label->setMargin( 6 ); + if( K3bTheme* theme = k3bappcore->themeManager()->currentTheme() ) { + label->setPaletteBackgroundColor( theme->backgroundColor() ); + label->setPaletteForegroundColor( theme->foregroundColor() ); + } + tip( rect, label, (K3bWidgetShowEffect::Effect)effect ); +} + + +void K3bToolTip::tip( const QRect& rect, const QPixmap& pix, int effect ) +{ + QLabel* label = new QLabel( parentWidget() ); + label->setMargin( 6 ); + if( K3bTheme* theme = k3bappcore->themeManager()->currentTheme() ) { + label->setPaletteBackgroundColor( theme->backgroundColor() ); + label->setPaletteForegroundColor( theme->foregroundColor() ); + } + label->setPixmap( pix ); + tip( rect, label, (K3bWidgetShowEffect::Effect)effect ); +} + + +void K3bToolTip::tip( const QRect& rect, QWidget* w, int effect ) +{ + // stop the timer + m_tipTimer->stop(); + + // hide any previous tip + hideTip(); + + // which screen are we on? + int scr; + if( QApplication::desktop()->isVirtualDesktop() ) + scr = QApplication::desktop()->screenNumber( m_parentWidget->mapToGlobal( m_lastMousePos ) ); + else + scr = QApplication::desktop()->screenNumber( m_parentWidget ); + + // make sure the widget is displayed correcly + w->reparent( QApplication::desktop()->screen( scr ), + WStyle_StaysOnTop | WStyle_Customize | WStyle_NoBorder | WStyle_Tool | WX11BypassWM, + QPoint( 0, 0 ), false ); + w->polish(); + w->adjustSize(); + + // positioning code from qtooltip.cpp + QRect screen = QApplication::desktop()->screenGeometry( scr ); + + // FIXME: why (2,16) and (4,24) below? Why not use the cursors' size? + + QPoint p = m_parentWidget->mapToGlobal( m_lastMousePos ) + QPoint( 2, 16 ); + + if( p.x() + w->width() > screen.x() + screen.width() ) + p.rx() -= 4 + w->width(); + if( p.y() + w->height() > screen.y() + screen.height() ) + p.ry() -= 24 + w->height(); + + if( p.y() < screen.y() ) + p.setY( screen.y() ); + if( p.x() + w->width() > screen.x() + screen.width() ) + p.setX( screen.x() + screen.width() - w->width() ); + if( p.x() < screen.x() ) + p.setX( screen.x() ); + if( p.y() + w->height() > screen.y() + screen.height() ) + p.setY( screen.y() + screen.height() - w->height() ); + + m_currentTip = w; + m_currentTipRect = rect; + w->move( p ); + if( effect ) + K3bWidgetShowEffect::showWidget( w, (K3bWidgetShowEffect::Effect)effect ); + else + w->show(); + w->raise(); +} + + +void K3bToolTip::hideTip() +{ + // just remove the tip + delete m_currentTip; + m_currentTip = 0; +} + + +bool K3bToolTip::eventFilter( QObject* o, QEvent* e ) +{ + if( o == parentWidget() ) { + switch( e->type() ) { + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseButtonDblClick: + case QEvent::KeyPress: + case QEvent::KeyRelease: + // input - turn off tool tip mode + hideTip(); + m_tipTimer->stop(); + break; + + case QEvent::MouseMove: { + QMouseEvent* m = (QMouseEvent*)e; + m_lastMousePos = m_parentWidget->mapFromGlobal( m->globalPos() ); + + m_tipTimer->stop(); + if( m_currentTip ) { + // see if we have to hide it + if( !m_currentTipRect.contains( m_lastMousePos ) ) { + hideTip(); + + // in case we moved the mouse from one tip area to the next without leaving + // the widget just popup the new tip immedeately + m_tipTimer->start( 0, true ); + } + } + + // if we are not showing a tip currently start the tip timer + else + m_tipTimer->start( m_tipTimeout, true ); + + break; + } + + case QEvent::Leave: + case QEvent::Hide: + case QEvent::Destroy: + case QEvent::FocusOut: + hideTip(); + m_tipTimer->stop(); + break; + + default: + break; + } + } + + return false; +} + + +void K3bToolTip::slotCheckShowTip() +{ + maybeTip( m_lastMousePos ); +} + + +#include "k3btooltip.moc" diff --git a/src/k3btooltip.h b/src/k3btooltip.h new file mode 100644 index 0000000..878f512 --- /dev/null +++ b/src/k3btooltip.h @@ -0,0 +1,81 @@ +/* + * + * $Id: sourceheader 380067 2005-01-19 13:03:46Z trueg $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_TOOLTIP_H_ +#define _K3B_TOOLTIP_H_ + +#include <qobject.h> +#include <qpixmap.h> + +#include "k3bwidgetshoweffect.h" + +class QTimer; + +/** + * More beautiful tooltip + */ +class K3bToolTip : public QObject +{ + Q_OBJECT + + public: + K3bToolTip( QWidget* widget ); + ~K3bToolTip(); + + QWidget* parentWidget() const { return m_parentWidget; } + + public slots: + /** + * default is 700 mseconds (same as QToolTip) + */ + void setTipTimeout( int msec ) { m_tipTimeout = msec; } + + protected: + /** + * \see QToolTip::maybeTip + */ + virtual void maybeTip( const QPoint& ) = 0; + + /** + * Show a tooltip. + */ + void tip( const QRect&, const QString&, int effect = K3bWidgetShowEffect::Dissolve ); + void tip( const QRect& rect, const QPixmap& pix, int effect = K3bWidgetShowEffect::Dissolve ); + + /** + * Use some arbitrary widget as the tooltip + * \param effect Use 0 for no effect + */ + void tip( const QRect&, QWidget* w, int effect = K3bWidgetShowEffect::Dissolve ); + + bool eventFilter( QObject* o, QEvent* e ); + + private slots: + void slotCheckShowTip(); + + private: + void hideTip(); + + QWidget* m_parentWidget; + QWidget* m_currentTip; + QRect m_currentTipRect; + + QTimer* m_tipTimer; + QPoint m_lastMousePos; + + int m_tipTimeout; +}; + +#endif diff --git a/src/k3btrm.cpp b/src/k3btrm.cpp new file mode 100644 index 0000000..9d4f24d --- /dev/null +++ b/src/k3btrm.cpp @@ -0,0 +1,93 @@ +/* + * + * $Id: k3btrm.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include <config.h> + +#ifdef HAVE_MUSICBRAINZ + +#include "k3btrm.h" +#include "musicbrainz/mb_c.h" + +#include <kdebug.h> +#include <kprotocolmanager.h> +#include <kurl.h> + + +class K3bTRM::Private +{ +public: + trm_t trm; + QCString sig; + QCString rawSig; +}; + + +K3bTRM::K3bTRM() +{ + d = new Private; + d->trm = trm_New(); + d->rawSig.resize( 17 ); + d->sig.resize( 37 ); +} + + +K3bTRM::~K3bTRM() +{ + trm_Delete( d->trm ); + delete d; +} + + +void K3bTRM::start( const K3b::Msf& length ) +{ + if( KProtocolManager::useProxy() ) { + KURL proxy = KProtocolManager::proxyFor("http"); + trm_SetProxy( d->trm, const_cast<char*>(proxy.host().latin1()), short(proxy.port()) ); + } + + trm_SetPCMDataInfo( d->trm, 44100, 2, 16 ); + trm_SetSongLength( d->trm, length.totalFrames()/75 ); +} + + +bool K3bTRM::generate( char* data, int len ) +{ + return ( trm_GenerateSignature( d->trm, data, len ) == 1 ); +} + + +bool K3bTRM::finalize() +{ + if( trm_FinalizeSignature( d->trm, d->rawSig.data(), 0 ) == 0 ) { + trm_ConvertSigToASCII( d->trm, d->rawSig.data(), d->sig.data() ); + return true; + } + else + return false; +} + + +const QCString& K3bTRM::rawSignature() const +{ + return d->rawSig; +} + + +const QCString& K3bTRM::signature() const +{ + return d->sig; +} + +#endif diff --git a/src/k3btrm.h b/src/k3btrm.h new file mode 100644 index 0000000..722a769 --- /dev/null +++ b/src/k3btrm.h @@ -0,0 +1,60 @@ +/* + * + * $Id: k3btrm.h 630384 2007-02-05 09:33:17Z mlaurent $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_TRM_H_ +#define _K3B_TRM_H_ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#ifdef HAVE_MUSICBRAINZ + +#include <k3bmsf.h> + +/** + * This class is a wrapper around the trm part of libmusicbrainz. + * It handles proxy settings automatically through KDE. + * + * K3bTRM always treats audio data as 44100, 2 channel, 16 bit data. + */ +class K3bTRM +{ + public: + K3bTRM(); + ~K3bTRM(); + + void start( const K3b::Msf& length ); + + /** + * \return true if no more data is needed + */ + bool generate( char* data, int len ); + + /** + * \return true on success, false on error. + */ + bool finalize(); + + const QCString& rawSignature() const; + const QCString& signature() const; + + private: + class Private; + Private* d; +}; + +#endif +#endif diff --git a/src/k3bui.rc b/src/k3bui.rc new file mode 100644 index 0000000..24a8af8 --- /dev/null +++ b/src/k3bui.rc @@ -0,0 +1,78 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui name="k3b" version="8"> +<MenuBar> + <Menu name="project"><text>&Project</text> + <Action name="project_add_files" /> + <Action name="project_clear_project" /> + </Menu> + + <Menu name="tools"><text>&Tools</text> + <Action name="tools_copy_cd" /> + <Action name="tools_copy_dvd" /> + <Separator /> + <Action name="tools_blank_cdrw" /> + <Action name="tools_format_dvd" /> + <Separator /> + <Action name="tools_write_cd_image" /> + <Action name="tools_write_dvd_iso" /> + <Separator /> + <Action name="tools_cdda_rip" /> + <Action name="tools_videodvd_rip" /> + <Action name="tools_videocd_rip" /> + </Menu> + + <Menu name="device"><text>&Device</text> + <Action name ="device_diskinfo" /> + <Separator /> + <Action name ="device_unmount" /> + <Action name ="device_mount" /> + <Separator /> + <Action name ="device_eject" /> + <Action name ="device_load" /> + <Separator /> + <Action name ="device_set_read_speed" /> + </Menu> + + <Menu name="settings"> + <Action name="view_show_project_view" append="show_merge" /> + <Action name="view_dir_tree" append="show_merge" /> + <Action name="view_contents" append="show_merge" /> + <Action name="view_audio_player" append="show_merge" /> + <Action name="view_document_header" append="show_merge" /> + <Action name="settings_k3bsetup" append="configure_merge" /> + </Menu> + + <Menu name="help"><text>&Help</text> + <Action name="help_check_system" /> + </Menu> +</MenuBar> + +<ToolBar name="mainToolBar" noMerge="1"><text>Main Toolbar</text> + <Action name="file_new" /> + <Action name="file_open" /> + <Action name="file_save" /> +</ToolBar> + +<ToolBar name="toolsToolBar"><text>Tools</text> + <Action name="tools_copy_cd" /> + <Action name="tools_copy_dvd" /> + <Action name="tools_blank_cdrw" /> + <Action name="tools_format_dvd" /> +</ToolBar> + +<ToolBar name="quickDirSelector" fullWidth="true"><text>Quick Dir Selector</text> + <Action name="quick_dir_selector" /> + <Action name="go_url" /> +</ToolBar> + +<State name="state_project_active"> + <enable> + <Action name="file_save" /> + <Action name="file_save_as" /> + <Action name="file_close" /> + <Action name="file_close_all" /> + <Action name="project_add_files" /> + <Action name="project_clear_project" /> + </enable> +</State> +</kpartgui> diff --git a/src/k3bwelcomewidget.cpp b/src/k3bwelcomewidget.cpp new file mode 100644 index 0000000..a3915d5 --- /dev/null +++ b/src/k3bwelcomewidget.cpp @@ -0,0 +1,489 @@ +/* + * + * $Id: k3bwelcomewidget.cpp 676186 2007-06-16 08:53:46Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bwelcomewidget.h" +#include "k3b.h" +#include "k3bflatbutton.h" +#include <k3bstdguiitems.h> +#include "k3bapplication.h" +#include <k3bversion.h> +#include "k3bthememanager.h" + +#include <qpixmap.h> +#include <qtoolbutton.h> +#include <qlabel.h> +#include <qpainter.h> +#include <qsimplerichtext.h> +#include <qptrlist.h> +#include <qmap.h> +#include <qtooltip.h> +#include <qcursor.h> +#include <qimage.h> + +#include <kurl.h> +#include <kurldrag.h> +#include <klocale.h> +#include <kstandarddirs.h> +#include <kapplication.h> +#include <kiconloader.h> +#include <kglobal.h> +#include <kconfig.h> +#include <kdebug.h> +#include <kpopupmenu.h> +#include <kaboutdata.h> +#include <kactionclasses.h> + + +static const char* s_allActions[] = { + "file_new_data", + "file_new_dvd", + "file_continue_multisession", + "_sep_", + "file_new_audio", + "_sep_", + "file_new_mixed", + "_sep_", + "file_new_vcd", + "file_new_video_dvd", + "_sep_", + "file_new_movix", + "file_new_movix_dvd", + "_sep_", + "tools_copy_cd", + "tools_copy_dvd", + "_sep_", + "tools_blank_cdrw", + "tools_format_dvd", + "_sep_", + "tools_write_cd_image", + "tools_write_dvd_iso", + "_sep_", + "tools_cdda_rip", + "tools_videodvd_rip", + "tools_videocd_rip", + 0 +}; + +K3bWelcomeWidget::Display::Display( K3bWelcomeWidget* parent ) + : QWidget( parent->viewport() ) +{ + setWFlags( Qt::WNoAutoErase ); + + QFont fnt(font()); + fnt.setBold(true); + fnt.setPointSize( 16 ); + m_header = new QSimpleRichText( i18n("Welcome to K3b - The CD and DVD Kreator"), fnt ); + m_infoText = new QSimpleRichText( QString::fromUtf8("<qt align=\"center\">K3b %1 (c) 1999 - 2007 Sebastian Trüg") + .arg(kapp->aboutData()->version()), font() ); + + // set a large width just to be sure no linebreak occurs + m_header->setWidth( 800 ); + + setAcceptDrops( true ); + setBackgroundMode( PaletteBase ); + m_rows = m_cols = 1; + + m_buttonMore = new K3bFlatButton( i18n("Further actions..."), this ); + connect( m_buttonMore, SIGNAL(pressed()), parent, SLOT(slotMoreActions()) ); + + connect( k3bappcore->themeManager(), SIGNAL(themeChanged()), this, SLOT(slotThemeChanged()) ); + + slotThemeChanged(); +} + + +K3bWelcomeWidget::Display::~Display() +{ + delete m_header; + delete m_infoText; +} + + +void K3bWelcomeWidget::Display::addAction( KAction* action ) +{ + if( action ) { + m_actions.append(action); + rebuildGui(); + } +} + + +void K3bWelcomeWidget::Display::removeAction( KAction* action ) +{ + if( action ) { + m_actions.removeRef( action ); + rebuildGui(); + } +} + + +void K3bWelcomeWidget::Display::removeButton( K3bFlatButton* b ) +{ + removeAction( m_buttonMap[b] ); +} + + +void K3bWelcomeWidget::Display::rebuildGui( const QPtrList<KAction>& actions ) +{ + m_actions = actions; + rebuildGui(); +} + + +static void calculateButtons( int width, int numActions, int buttonWidth, int& cols, int& rows ) +{ + // always try to avoid horizontal scrollbars + int wa = width - 40; + cols = QMAX( 1, QMIN( wa / (buttonWidth+4), numActions ) ); + rows = numActions/cols; + int over = numActions%cols; + if( over ) { + rows++; + // try to avoid useless cols + while( over && cols - over - 1 >= rows-1 ) { + --cols; + over = numActions%cols; + } + } +} + + +void K3bWelcomeWidget::Display::rebuildGui() +{ + // step 1: delete all old buttons in the buttons QPtrList<K3bFlatButton> + m_buttonMap.clear(); + m_buttons.setAutoDelete(true); + m_buttons.clear(); + + int numActions = m_actions.count(); + if( numActions > 0 ) { + + // create buttons + for( QPtrListIterator<KAction> it( m_actions ); it.current(); ++it ) { + KAction* a = it.current(); + + K3bFlatButton* b = new K3bFlatButton( a, this ); + + m_buttons.append( b ); + m_buttonMap.insert( b, a ); + } + + // determine the needed button size (since all buttons should be equal in size + // we use the max of all sizes) + m_buttonSize = m_buttons.first()->sizeHint(); + for( QPtrListIterator<K3bFlatButton> it( m_buttons ); it.current(); ++it ) { + m_buttonSize = m_buttonSize.expandedTo( it.current()->sizeHint() ); + } + + repositionButtons(); + } +} + + +void K3bWelcomeWidget::Display::repositionButtons() +{ + // calculate rows and columns + calculateButtons( width(), m_actions.count(), m_buttonSize.width(), m_cols, m_rows ); + + int availHor = width() - 40; + int availVert = height() - 20 - 10 - m_header->height() - 10; + availVert -= m_infoText->height() - 10; + int leftMargin = 20 + (availHor - (m_buttonSize.width()+4)*m_cols)/2; + int topOffset = m_header->height() + 20 + ( availVert - (m_buttonSize.height()+4)*m_rows - m_buttonMore->height() )/2; + + int row = 0; + int col = 0; + + for( QPtrListIterator<K3bFlatButton> it( m_buttons ); it.current(); ++it ) { + K3bFlatButton* b = it.current(); + + b->setGeometry( QRect( QPoint( leftMargin + (col*(m_buttonSize.width()+4) + 2 ), + topOffset + (row*(m_buttonSize.height()+4)) + 2 ), + m_buttonSize ) ); + b->show(); + + col++; + if( col == m_cols ) { + col = 0; + row++; + } + } + if( col > 0 ) + ++row; + + m_buttonMore->setGeometry( QRect( QPoint( leftMargin + 2, + topOffset + (row*(m_buttonSize.height()+4)) + 2 ), + QSize( m_cols*(m_buttonSize.width()+4) - 4, m_buttonMore->height() ) ) ); +} + + +QSizePolicy K3bWelcomeWidget::Display::sizePolicy () const +{ + return QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum, true ); +} + + +int K3bWelcomeWidget::Display::heightForWidth( int w ) const +{ + int ow = m_infoText->width(); + m_infoText->setWidth( w ); + int h = m_infoText->height(); + m_infoText->setWidth( ow ); + + int cols, rows; + calculateButtons( w, m_actions.count(), m_buttonSize.width(), cols, rows ); + + return (20 + m_header->height() + 20 + 10 + ((m_buttonSize.height()+4)*rows) + 4 + m_buttonMore->height() + 10 + h + 20); +} + + +QSize K3bWelcomeWidget::Display::minimumSizeHint() const +{ + QSize size( QMAX(40+m_header->widthUsed(), 40+m_buttonSize.width()), + 20 + m_header->height() + 20 + 10 + m_buttonSize.height() + 10 + m_infoText->height() + 20 ); + + return size; +} + + +void K3bWelcomeWidget::Display::resizeEvent( QResizeEvent* e ) +{ + m_infoText->setWidth( width() - 20 ); + QWidget::resizeEvent(e); + repositionButtons(); + if( e->size() != m_bgPixmap.size() ) + updateBgPix(); +} + + +void K3bWelcomeWidget::Display::slotThemeChanged() +{ + if( K3bTheme* theme = k3bappcore->themeManager()->currentTheme() ) + if( theme->backgroundMode() == K3bTheme::BG_SCALE ) + m_bgImage = theme->pixmap( K3bTheme::WELCOME_BG ).convertToImage(); + + updateBgPix(); + update(); +} + +#include "fastscale/scale.h" +void K3bWelcomeWidget::Display::updateBgPix() +{ + if( K3bTheme* theme = k3bappcore->themeManager()->currentTheme() ) { + if( theme->backgroundMode() == K3bTheme::BG_SCALE ) + m_bgPixmap.convertFromImage( ImageUtils::scale( m_bgImage, rect().width(), rect().height(), ImageUtils::SMOOTH_FAST ) ); + else + m_bgPixmap = theme->pixmap( K3bTheme::WELCOME_BG ); + } +} + + +void K3bWelcomeWidget::Display::paintEvent( QPaintEvent* ) +{ + if( K3bTheme* theme = k3bappcore->themeManager()->currentTheme() ) { + QPainter p( this ); + p.setPen( theme->foregroundColor() ); + + // draw the background including first filling with the bg color for transparent images + p.fillRect( rect(), theme->backgroundColor() ); + p.drawTiledPixmap( rect(), m_bgPixmap ); + + // rect around the header + QRect rect( 10, 10, QMAX( m_header->widthUsed() + 20, width() - 20 ), m_header->height() + 20 ); + p.fillRect( rect, theme->backgroundColor() ); + p.drawRect( rect ); + + // big rect around the whole thing + p.drawRect( 10, 10, width()-20, height()-20 ); + + // draw the header text + QColorGroup grp( colorGroup() ); + grp.setColor( QColorGroup::Text, theme->foregroundColor() ); + int pos = 20; + pos += QMAX( (width()-40-m_header->widthUsed())/2, 0 ); + m_header->draw( &p, pos, 20, QRect(), grp ); + + // draw the info box + // int boxWidth = 20 + m_infoText->widthUsed(); + int boxHeight = 10 + m_infoText->height(); + QRect infoBoxRect( 10/*QMAX( (width()-20-m_infoText->widthUsed())/2, 10 )*/, + height()-10-boxHeight, + width()-20/*boxWidth*/, + boxHeight ); + p.fillRect( infoBoxRect, theme->backgroundColor() ); + p.drawRect( infoBoxRect ); + m_infoText->draw( &p, infoBoxRect.left()+5, infoBoxRect.top()+5, QRect(), grp ); + } +} + + +void K3bWelcomeWidget::Display::dragEnterEvent( QDragEnterEvent* event ) +{ + event->accept( KURLDrag::canDecode(event) ); +} + + +void K3bWelcomeWidget::Display::dropEvent( QDropEvent* e ) +{ + KURL::List urls; + KURLDrag::decode( e, urls ); + emit dropped( urls ); +} + + + +K3bWelcomeWidget::K3bWelcomeWidget( K3bMainWindow* mw, QWidget* parent, const char* name ) + : QScrollView( parent, name ), + m_mainWindow( mw ) +{ + main = new Display( this ); + addChild( main ); + + connect( main, SIGNAL(dropped(const KURL::List&)), m_mainWindow, SLOT(addUrls(const KURL::List&)) ); + + connect( kapp, SIGNAL(appearanceChanged()), main, SLOT(update()) ); +} + + +K3bWelcomeWidget::~K3bWelcomeWidget() +{ +} + + +void K3bWelcomeWidget::loadConfig( KConfigBase* c ) +{ + QStringList sl = KConfigGroup( c, "Welcome Widget" ).readListEntry( "welcome_actions" ); + + if( sl.isEmpty() ) { + sl.append( "file_new_audio" ); + sl.append( "file_new_data" ); + sl.append( "file_new_dvd" ); + sl.append( "tools_copy_cd" ); + sl.append( "tools_write_cd_image" ); + sl.append( "tools_write_dvd_iso" ); + } + + QPtrList<KAction> actions; + for( QStringList::const_iterator it = sl.begin(); it != sl.end(); ++it ) + if( KAction* a = m_mainWindow->actionCollection()->action( (*it).latin1() ) ) + actions.append(a); + + main->rebuildGui( actions ); + + fixSize(); +} + + +void K3bWelcomeWidget::saveConfig( KConfigBase* c ) +{ + KConfigGroup grp( c, "Welcome Widget" ); + + QStringList sl; + for( QPtrListIterator<KAction> it( main->m_actions ); it.current(); ++it ) + sl.append( it.current()->name() ); + + grp.writeEntry( "welcome_actions", sl ); +} + + +void K3bWelcomeWidget::resizeEvent( QResizeEvent* e ) +{ + QScrollView::resizeEvent( e ); + fixSize(); +} + + +void K3bWelcomeWidget::showEvent( QShowEvent* e ) +{ + QScrollView::showEvent( e ); + fixSize(); +} + + +void K3bWelcomeWidget::fixSize() +{ + QSize s = contentsRect().size(); + s.setWidth( QMAX( main->minimumSizeHint().width(), s.width() ) ); + s.setHeight( QMAX( main->heightForWidth(s.width()), s.height() ) ); + + main->resize( s ); + viewport()->resize( s ); +} + + +void K3bWelcomeWidget::contentsMousePressEvent( QMouseEvent* e ) +{ + if( e->button() == QMouseEvent::RightButton ) { + QMap<int, KAction*> map; + KPopupMenu addPop; + + for ( int i = 0; s_allActions[i]; ++i ) { + if ( s_allActions[i][0] != '_' ) { + KAction* a = m_mainWindow->actionCollection()->action( s_allActions[i] ); + if ( a && !main->m_actions.containsRef(a) ) { + map.insert( addPop.insertItem( a->iconSet(), a->text() ), a ); + } + } + } + + // menu identifiers in QT are always < 0 (when automatically generated) + // and unique throughout the entire application! + int r = 0; + int removeAction = 0; + + QWidget* widgetAtPos = viewport()->childAt(e->pos()); + if( widgetAtPos && widgetAtPos->inherits( "K3bFlatButton" ) ) { + KPopupMenu pop; + removeAction = pop.insertItem( SmallIcon("remove"), i18n("Remove Button") ); + if ( addPop.count() > 0 ) + pop.insertItem( i18n("Add Button"), &addPop ); + pop.insertSeparator(); + r = pop.exec( e->globalPos() ); + } + else { + addPop.insertTitle( i18n("Add Button"), -1, 0 ); + addPop.insertSeparator(); + r = addPop.exec( e->globalPos() ); + } + + if( r != 0 ) { + if( r == removeAction ) + main->removeButton( static_cast<K3bFlatButton*>(widgetAtPos) ); + else + main->addAction( map[r] ); + } + + fixSize(); + } +} + + +void K3bWelcomeWidget::slotMoreActions() +{ + KPopupMenu popup; + + for ( int i = 0; s_allActions[i]; ++i ) { + if ( s_allActions[i][0] == '_' ) { + (new KActionSeparator( &popup ))->plug( &popup ); + } + else { + m_mainWindow->actionCollection()->action( s_allActions[i] )->plug( &popup ); + } + } + + popup.exec( QCursor::pos() ); +} + +#include "k3bwelcomewidget.moc" diff --git a/src/k3bwelcomewidget.h b/src/k3bwelcomewidget.h new file mode 100644 index 0000000..df1945f --- /dev/null +++ b/src/k3bwelcomewidget.h @@ -0,0 +1,124 @@ +/* + * + * $Id: k3bwelcomewidget.h 642063 2007-03-13 09:40:13Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_WELCOME_WIDGET_H_ +#define _K3B_WELCOME_WIDGET_H_ + +#include <qscrollview.h> +#include <qptrlist.h> +#include <qmap.h> +#include <qimage.h> + +#include <kurl.h> +#include <kaction.h> + +class K3bMainWindow; +class QDropEvent; +class QDragEnterEvent; +class K3bFlatButton; +class QPaintEvent; +class QResizeEvent; +class QSimpleRichText; +class KConfigBase; +class QMouseEvent; +class QShowEvent; + + +class K3bWelcomeWidget : public QScrollView +{ + Q_OBJECT + + public: + K3bWelcomeWidget( K3bMainWindow*, QWidget* parent = 0, const char* name = 0 ); + ~K3bWelcomeWidget(); + + void loadConfig( KConfigBase* c ); + void saveConfig( KConfigBase* c ); + + class Display; + + public slots: + void slotMoreActions(); + + protected: + void resizeEvent( QResizeEvent* ); + void showEvent( QShowEvent* ); + void contentsMousePressEvent( QMouseEvent* e ); + + private: + void fixSize(); + + K3bMainWindow* m_mainWindow; + Display* main; +}; + + +class K3bWelcomeWidget::Display : public QWidget +{ + Q_OBJECT + + public: + Display( K3bWelcomeWidget* parent ); + ~Display(); + + QSize minimumSizeHint() const; + QSizePolicy sizePolicy () const; + int heightForWidth ( int w ) const; + + void addAction( KAction* ); + void removeAction( KAction* ); + void removeButton( K3bFlatButton* ); + void rebuildGui(); + void rebuildGui( const QPtrList<KAction>& ); + + signals: + void dropped( const KURL::List& ); + + protected: + void resizeEvent( QResizeEvent* ); + void paintEvent( QPaintEvent* ); + void dropEvent( QDropEvent* event ); + void dragEnterEvent( QDragEnterEvent* event ); + + private slots: + void slotThemeChanged(); + + private: + void repositionButtons(); + void updateBgPix(); + + QSimpleRichText* m_header; + QSimpleRichText* m_infoText; + + QSize m_buttonSize; + int m_cols; + int m_rows; + + QPtrList<KAction> m_actions; + QPtrList<K3bFlatButton> m_buttons; + QMap<K3bFlatButton*, KAction*> m_buttonMap; + + K3bFlatButton* m_buttonMore; + + bool m_infoTextVisible; + + QPixmap m_bgPixmap; + QImage m_bgImage; + + friend class K3bWelcomeWidget; +}; + +#endif diff --git a/src/k3bwidgetshoweffect.cpp b/src/k3bwidgetshoweffect.cpp new file mode 100644 index 0000000..1caa971 --- /dev/null +++ b/src/k3bwidgetshoweffect.cpp @@ -0,0 +1,203 @@ +/* + * + * $Id: sourceheader 380067 2005-01-19 13:03:46Z trueg $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * Based on the effects in popupMessage.cpp + * Copyright (C) 2005 by Max Howell <max.howell@methylblue.com> + * 2005 by Seb Ruiz <me@sebruiz.net> + * + * Dissolve Mask (c) Kicker Authors kickertip.cpp, 2005/08/17 + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bwidgetshoweffect.h" + +#include <qpainter.h> +#include <qwidget.h> + + +K3bWidgetShowEffect::K3bWidgetShowEffect( QWidget* widget, Effect e ) + : QObject( widget ), + m_effect( e ), + m_widget( widget ), + m_dissolveSize( 0 ), + m_dissolveDelta( -1 ), + m_offset( 0 ), + m_deleteSelf( false ), + m_bEffectOnly( false ) +{ +} + + +K3bWidgetShowEffect::~K3bWidgetShowEffect() +{ +} + + +void K3bWidgetShowEffect::hide( bool effectOnly ) +{ + m_bEffectOnly = effectOnly; + m_bShow = false; + m_offset = m_widget->height(); + killTimer( m_timerId ); + m_timerId = startTimer( 6 ); +} + + +void K3bWidgetShowEffect::show( bool effectOnly ) +{ + m_bShow = true; + m_offset = 0; + m_dissolveSize = 24; + m_dissolveDelta = -1; + + m_widget->polish(); + + if( m_effect == Dissolve ) { + // necessary to create the mask + m_mask.resize( m_widget->width(), m_widget->height() ); + // make the mask empty and hence will not show widget with show() called below + dissolveMask(); + m_timerId = startTimer( 1000 / 30 ); + } + else { + m_widget->move( 0, m_widget->parentWidget()->height() ); + m_timerId = startTimer( 6 ); + } + + if( !effectOnly ) + m_widget->show(); +} + + +void K3bWidgetShowEffect::timerEvent( QTimerEvent* ) +{ + switch( m_effect ) { + case Slide: + slideMask(); + break; + + case Dissolve: + dissolveMask(); + break; + } +} + + +void K3bWidgetShowEffect::dissolveMask() +{ + if( m_bShow ) { + m_widget->repaint( false ); + QPainter maskPainter(&m_mask); + + m_mask.fill(Qt::black); + + maskPainter.setBrush(Qt::white); + maskPainter.setPen(Qt::white); + maskPainter.drawRect( m_mask.rect() ); + + m_dissolveSize += m_dissolveDelta; + + if( m_dissolveSize > 0 ) { + maskPainter.setRasterOp( Qt::EraseROP ); + + int x, y, s; + const int size = 16; + + for( y = 0; y < m_widget->height() + size; y += size ) { + x = m_widget->width(); + s = m_dissolveSize * x / 128; + + for( ; x > size; x -= size, s -= 2 ) { + if( s < 0 ) + break; + + maskPainter.drawEllipse(x - s / 2, y - s / 2, s, s); + } + } + } + else if( m_dissolveSize < 0 ) { + m_dissolveDelta = 1; + killTimer( m_timerId ); + + emit widgetShown( m_widget ); + + if( m_deleteSelf ) + deleteLater(); + } + + m_widget->setMask( m_mask ); + } + + else { + // just hide it for now + emit widgetHidden( m_widget ); + if( !m_bEffectOnly ) + m_widget->hide(); + + if( m_deleteSelf ) + deleteLater(); + } +} + + +void K3bWidgetShowEffect::slideMask() +{ + if( m_bShow ) { + m_widget->move( 0, m_widget->parentWidget()->height() - m_offset ); + + m_offset++; + if( m_offset > m_widget->height() ) { + killTimer( m_timerId ); + + emit widgetShown( m_widget ); + + if( m_deleteSelf ) + deleteLater(); + } + } + else { + m_offset--; + m_widget->move( 0, m_widget->parentWidget()->height() - m_offset ); + + if( m_offset < 0 ) { + // finally hide the widget + emit widgetHidden( m_widget ); + if( !m_bEffectOnly ) + m_widget->hide(); + + if( m_deleteSelf ) + deleteLater(); + } + } +} + + + +K3bWidgetShowEffect* K3bWidgetShowEffect::showWidget( QWidget* w, Effect m ) +{ + K3bWidgetShowEffect* e = new K3bWidgetShowEffect( w, m ); + e->m_deleteSelf = true; + e->show(); + return e; +} + + +K3bWidgetShowEffect* K3bWidgetShowEffect::hideWidget( QWidget* w, Effect m ) +{ + K3bWidgetShowEffect* e = new K3bWidgetShowEffect( w, m ); + e->m_deleteSelf = true; + e->hide(); + return e; +} + +#include "k3bwidgetshoweffect.moc" diff --git a/src/k3bwidgetshoweffect.h b/src/k3bwidgetshoweffect.h new file mode 100644 index 0000000..9e0de9b --- /dev/null +++ b/src/k3bwidgetshoweffect.h @@ -0,0 +1,115 @@ +/* + * + * $Id: sourceheader 380067 2005-01-19 13:03:46Z trueg $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * Based on the effects in popupMessage.cpp + * Copyright (C) 2005 by Max Howell <max.howell@methylblue.com> + * 2005 by Seb Ruiz <me@sebruiz.net> + * + * Dissolve Mask (c) Kicker Authors kickertip.cpp, 2005/08/17 + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_WIDGET_SHOW_EFFECT_H_ +#define _K3B_WIDGET_SHOW_EFFECT_H_ + +#include <qobject.h> +#include <qbitmap.h> + + +/** + * Helper class to show and hide a widget in a fancy way. + */ +class K3bWidgetShowEffect : public QObject +{ + Q_OBJECT + + public: + // FIXME: add an effect direction + enum Effect { + Dissolve = 1, + Slide + }; + + K3bWidgetShowEffect( QWidget* widget, Effect e = Slide ); + ~K3bWidgetShowEffect(); + + void setEffect( Effect e ) { m_effect = e; } + + /** + * Using the widget effects the easy way. + * \returns the K3bWidgetShowEffect instance used to show the widget. + * Can be used to connect to signals. + */ + static K3bWidgetShowEffect* showWidget( QWidget* w, Effect ); + + /** + * Using the widget effects the easy way. + * \returns the K3bWidgetShowEffect instance used to hide the widget. + * Can be used to connect to signals. + */ + static K3bWidgetShowEffect* hideWidget( QWidget* w, Effect ); + + signals: + void widgetShown( QWidget* ); + void widgetHidden( QWidget* ); + + public slots: + /** + * \param effectOnly If true K3bWidgetShowEffect will not call QWidget::show(). + * This is only useful in case onw uses K3bWidgetShowEffect + * to reimplement QWidget::show(). In that case the caller + * has to take care of showing the widget. + */ + void show( bool effectOnly = false ); + + /** + * \param effectOnly If true K3bWidgetShowEffect will not call QWidget::hide(). + * This is only useful in case onw uses K3bWidgetShowEffect + * to reimplement QWidget::hide(). In that case the caller + * has to take care of hiding the widget by connecting to + * K3bWidgetShowEffect::widgetHidden() + */ + void hide( bool effectOnly = false ); + + private: + void timerEvent( QTimerEvent* ); + + /** + * @short Gradually show widget by dissolving from background + */ + void dissolveMask(); + + /** + * @short animation to slide the widget into view + */ + void slideMask(); + + Effect m_effect; + QWidget* m_widget; + + QBitmap m_mask; + + int m_dissolveSize; + int m_dissolveDelta; + + int m_offset; + int m_timerId; + + // if true we show, otherwise we hide the widget + bool m_bShow; + + bool m_deleteSelf; + bool m_bEffectOnly; +}; + +#endif diff --git a/src/k3bwriterselectionwidget.cpp b/src/k3bwriterselectionwidget.cpp new file mode 100644 index 0000000..29a11f9 --- /dev/null +++ b/src/k3bwriterselectionwidget.cpp @@ -0,0 +1,607 @@ +/* + * + * $Id: k3bwriterselectionwidget.cpp 690635 2007-07-21 16:47:29Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bwriterselectionwidget.h" +#include "k3bapplication.h" +#include "k3bmediacache.h" + +#include <k3bmediaselectioncombobox.h> +#include <k3bdevice.h> +#include <k3bdevicemanager.h> +#include <k3bglobals.h> +#include <k3bcore.h> + +#include <klocale.h> +#include <kdialog.h> +#include <kconfig.h> +#include <kcombobox.h> +#include <kmessagebox.h> +#include <kiconloader.h> +#include <kinputdialog.h> + +#include <qlabel.h> +#include <qlayout.h> +#include <qgroupbox.h> +#include <qtooltip.h> +#include <qtoolbutton.h> +#include <qwhatsthis.h> +#include <qmap.h> +#include <qptrvector.h> +#include <qcursor.h> +#include <qapplication.h> + + +class K3bWriterSelectionWidget::MediaSelectionComboBox : public K3bMediaSelectionComboBox +{ +public: + MediaSelectionComboBox( QWidget* parent ) + : K3bMediaSelectionComboBox( parent ), + m_overrideDevice( 0 ) { + } + + void setOverrideDevice( K3bDevice::Device* dev, const QString& s, const QString& t ) { + m_overrideDevice = dev; + m_overrideString = s; + m_overrideToolTip = t; + updateMedia(); + } + + K3bDevice::Device* overrideDevice() const { + return m_overrideDevice; + } + + protected: + bool showMedium( const K3bMedium& m ) const { + return ( m.device() == m_overrideDevice || + K3bMediaSelectionComboBox::showMedium( m ) ); + } + + QString mediumString( const K3bMedium& m ) const { + if( m.device() == m_overrideDevice ) + return m_overrideString; + else + return K3bMediaSelectionComboBox::mediumString( m ); + } + + QString mediumToolTip( const K3bMedium& m ) const { + if( m.device() == m_overrideDevice ) + return m_overrideToolTip; + else { + QString s = K3bMediaSelectionComboBox::mediumToolTip( m ); + if( !m.diskInfo().empty() && !(wantedMediumState() & m.diskInfo().diskState()) ) + s.append( "<p><i>" + i18n("Medium will be overwritten.") + "</i>" ); + return s; + } + } + +private: + K3bDevice::Device* m_overrideDevice; + QString m_overrideString; + QString m_overrideToolTip; +}; + + +class K3bWriterSelectionWidget::Private +{ +public: + bool forceAutoSpeed; + bool haveIgnoreSpeed; + bool haveManualSpeed; + + int supportedWritingApps; + + int lastSetSpeed; + + QMap<int, int> indexSpeedMap; + QMap<int, int> speedIndexMap; +}; + + +K3bWriterSelectionWidget::K3bWriterSelectionWidget( QWidget *parent, const char *name ) + : QWidget( parent, name ) +{ + d = new Private; + d->forceAutoSpeed = false; + d->supportedWritingApps = K3b::CDRECORD|K3b::CDRDAO|K3b::GROWISOFS; + d->lastSetSpeed = -1; + + QGroupBox* groupWriter = new QGroupBox( this ); + groupWriter->setTitle( i18n( "Burn Medium" ) ); + groupWriter->setColumnLayout(0, Qt::Vertical ); + groupWriter->layout()->setSpacing( 0 ); + groupWriter->layout()->setMargin( 0 ); + + QGridLayout* groupWriterLayout = new QGridLayout( groupWriter->layout() ); + groupWriterLayout->setAlignment( Qt::AlignTop ); + groupWriterLayout->setSpacing( KDialog::spacingHint() ); + groupWriterLayout->setMargin( KDialog::marginHint() ); + + QLabel* labelSpeed = new QLabel( groupWriter, "TextLabel1" ); + labelSpeed->setText( i18n( "Speed:" ) ); + + m_comboSpeed = new KComboBox( false, groupWriter, "m_comboSpeed" ); + m_comboSpeed->setAutoMask( false ); + m_comboSpeed->setDuplicatesEnabled( false ); + + m_comboMedium = new MediaSelectionComboBox( groupWriter ); + + m_writingAppLabel = new QLabel( i18n("Writing app:"), groupWriter ); + m_comboWritingApp = new KComboBox( groupWriter ); + + groupWriterLayout->addWidget( m_comboMedium, 0, 0 ); + groupWriterLayout->addWidget( labelSpeed, 0, 1 ); + groupWriterLayout->addWidget( m_comboSpeed, 0, 2 ); + groupWriterLayout->addWidget( m_writingAppLabel, 0, 3 ); + groupWriterLayout->addWidget( m_comboWritingApp, 0, 4 ); + groupWriterLayout->setColStretch( 0, 1 ); + + + QGridLayout* mainLayout = new QGridLayout( this ); + mainLayout->setAlignment( Qt::AlignTop ); + mainLayout->setSpacing( KDialog::spacingHint() ); + mainLayout->setMargin( 0 ); + + mainLayout->addWidget( groupWriter, 0, 0 ); + + // tab order + setTabOrder( m_comboMedium, m_comboSpeed ); + setTabOrder( m_comboSpeed, m_comboWritingApp ); + + connect( m_comboMedium, SIGNAL(selectionChanged(K3bDevice::Device*)), this, SIGNAL(writerChanged()) ); + connect( m_comboMedium, SIGNAL(selectionChanged(K3bDevice::Device*)), + this, SIGNAL(writerChanged(K3bDevice::Device*)) ); + connect( m_comboMedium, SIGNAL(newMedia()), this, SIGNAL(newMedia()) ); + connect( m_comboMedium, SIGNAL(newMedium(K3bDevice::Device*)), this, SIGNAL(newMedium(K3bDevice::Device*)) ); + connect( m_comboMedium, SIGNAL(newMedium(K3bDevice::Device*)), this, SLOT(slotNewBurnMedium(K3bDevice::Device*)) ); + connect( m_comboWritingApp, SIGNAL(activated(int)), this, SLOT(slotWritingAppSelected(int)) ); + connect( this, SIGNAL(writerChanged()), SLOT(slotWriterChanged()) ); + connect( m_comboSpeed, SIGNAL(activated(int)), this, SLOT(slotSpeedChanged(int)) ); + + + QToolTip::add( m_comboMedium, i18n("The medium that will be used for burning") ); + QToolTip::add( m_comboSpeed, i18n("The speed at which to burn the medium") ); + QToolTip::add( m_comboWritingApp, i18n("The external application to actually burn the medium") ); + + QWhatsThis::add( m_comboMedium, i18n("<p>Select the medium that you want to use for burning." + "<p>In most cases there will only be one medium available which " + "does not leave much choice.") ); + QWhatsThis::add( m_comboSpeed, i18n("<p>Select the speed with which you want to burn." + "<p><b>Auto</b><br>" + "This will choose the maximum writing speed possible with the used " + "medium. " + "This is the recommended selection for most media.</p>" + "<p><b>Ignore</b> (DVD only)<br>" + "This will leave the speed selection to the writer device. " + "Use this if K3b is unable to set the writing speed." + "<p>1x refers to 1385 KB/s for DVD and 175 KB/s for CD.</p>" + "<p><b>Caution:</b> Make sure your system is able to send the data " + "fast enough to prevent buffer underruns.") ); + QWhatsThis::add( m_comboWritingApp, i18n("<p>K3b uses the command line tools cdrecord, growisofs, and cdrdao " + "to actually write a CD or DVD." + "<p>Normally K3b chooses the best " + "suited application for every task automatically but in some cases it " + "may be possible that one of the applications does not work as intended " + "with a certain writer. In this case one may select the " + "application manually.") ); + + clearSpeedCombo(); + + slotConfigChanged(k3bcore->config()); + slotWriterChanged(); +} + + +K3bWriterSelectionWidget::~K3bWriterSelectionWidget() +{ + delete d; +} + + +void K3bWriterSelectionWidget::setWantedMediumType( int type ) +{ + m_comboMedium->setWantedMediumType( type ); +} + + +void K3bWriterSelectionWidget::setWantedMediumState( int state ) +{ + m_comboMedium->setWantedMediumState( state ); +} + + +int K3bWriterSelectionWidget::wantedMediumType() const +{ + return m_comboMedium->wantedMediumType(); +} + + +int K3bWriterSelectionWidget::wantedMediumState() const +{ + return m_comboMedium->wantedMediumState(); +} + + +void K3bWriterSelectionWidget::slotConfigChanged( KConfigBase* c ) +{ + KConfigGroup g( c, "General Options" ); + if( g.readBoolEntry( "Manual writing app selection", false ) ) { + m_comboWritingApp->show(); + m_writingAppLabel->show(); + } + else { + m_comboWritingApp->hide(); + m_writingAppLabel->hide(); + } +} + + +void K3bWriterSelectionWidget::slotRefreshWriterSpeeds() +{ + if( writerDevice() ) { + QValueList<int> speeds = k3bappcore->mediaCache()->writingSpeeds( writerDevice() ); + + int lastSpeed = writerSpeed(); + + clearSpeedCombo(); + + m_comboSpeed->insertItem( i18n("Auto") ); + if( k3bappcore->mediaCache()->diskInfo( writerDevice() ).isDvdMedia() ) { + m_comboSpeed->insertItem( i18n("Ignore") ); + d->haveIgnoreSpeed = true; + } + else + d->haveIgnoreSpeed = false; + + if( !d->forceAutoSpeed ) { + if( speeds.isEmpty() || writerDevice() == m_comboMedium->overrideDevice() ) { + // + // In case of the override device we do not know which medium will actually be used + // So this is the only case in which we need to use the device's max writing speed + // + // But we need to know if it will be a CD or DVD medium. Since the override device + // is only used for CD/DVD copy anyway we simply reply on the inserted medium's type. + // + int i = 1; + int speed = ( k3bappcore->mediaCache()->diskInfo( writerDevice() ).isDvdMedia() ? 1385 : 175 ); + int max = writerDevice()->maxWriteSpeed(); + while( i*speed <= max ) { + insertSpeedItem( i*speed ); + // a little hack to handle the stupid 2.4x DVD speed + if( i == 2 && speed == 1385 ) + insertSpeedItem( (int)(2.4*1385.0) ); + i = ( i == 1 ? 2 : i+2 ); + } + + // + // Since we do not know the exact max writing speed if an override device is set (we can't becasue + // the writer always returns the speed relative to the inserted medium) we allow the user to specify + // the speed manually + // + m_comboSpeed->insertItem( i18n("More...") ); + d->haveManualSpeed = true; + } + else { + for( QValueList<int>::iterator it = speeds.begin(); it != speeds.end(); ++it ) + insertSpeedItem( *it ); + } + } + + // try to reload last set speed + if( d->lastSetSpeed == -1 ) + setSpeed( lastSpeed ); + else + setSpeed( d->lastSetSpeed ); + } + + m_comboSpeed->setEnabled( writerDevice() != 0 ); +} + + +void K3bWriterSelectionWidget::clearSpeedCombo() +{ + m_comboSpeed->clear(); + d->indexSpeedMap.clear(); + d->speedIndexMap.clear(); + d->haveManualSpeed = false; + d->haveIgnoreSpeed = false; +} + + +void K3bWriterSelectionWidget::insertSpeedItem( int speed ) +{ + if( !d->speedIndexMap.contains( speed ) ) { + d->indexSpeedMap[m_comboSpeed->count()] = speed; + d->speedIndexMap[speed] = m_comboSpeed->count(); + + if( k3bappcore->mediaCache()->diskInfo( writerDevice() ).isDvdMedia() ) + m_comboSpeed->insertItem( ( speed%1385 > 0 + ? QString::number( (float)speed/1385.0, 'f', 1 ) // example: DVD+R(W): 2.4x + : QString::number( speed/1385 ) ) + + "x" ); + else + m_comboSpeed->insertItem( QString("%1x").arg(speed/175) ); + } +} + + +void K3bWriterSelectionWidget::slotWritingAppSelected( int ) +{ + emit writingAppChanged( selectedWritingApp() ); +} + + +K3bDevice::Device* K3bWriterSelectionWidget::writerDevice() const +{ + return m_comboMedium->selectedDevice(); +} + + +QValueList<K3bDevice::Device*> K3bWriterSelectionWidget::allDevices() const +{ + return m_comboMedium->allDevices(); +} + + +void K3bWriterSelectionWidget::setWriterDevice( K3bDevice::Device* dev ) +{ + m_comboMedium->setSelectedDevice( dev ); +} + + +void K3bWriterSelectionWidget::setSpeed( int s ) +{ + d->lastSetSpeed = -1; + + if( d->haveIgnoreSpeed && s < 0 ) + m_comboSpeed->setCurrentItem( 1 ); // Ignore + else if( d->speedIndexMap.contains( s ) ) + m_comboSpeed->setCurrentItem( d->speedIndexMap[s] ); + else { + m_comboSpeed->setCurrentItem( 0 ); // Auto + d->lastSetSpeed = s; // remember last set speed + } +} + + +void K3bWriterSelectionWidget::setWritingApp( int app ) +{ + switch( app ) { + case K3b::CDRECORD: + m_comboWritingApp->setCurrentItem( "cdrecord" ); + break; + case K3b::CDRDAO: + m_comboWritingApp->setCurrentItem( "cdrdao" ); + break; + case K3b::DVDRECORD: + m_comboWritingApp->setCurrentItem( "dvdrecord" ); + break; + case K3b::GROWISOFS: + m_comboWritingApp->setCurrentItem( "growisofs" ); + break; + case K3b::DVD_RW_FORMAT: + m_comboWritingApp->setCurrentItem( "dvd+rw-format" ); + break; + default: + m_comboWritingApp->setCurrentItem( 0 ); // Auto + break; + } +} + + +int K3bWriterSelectionWidget::writerSpeed() const +{ + if( m_comboSpeed->currentItem() == 0 ) + return 0; // Auto + else if( d->haveIgnoreSpeed && m_comboSpeed->currentItem() == 1 ) + return -1; // Ignore + else + return d->indexSpeedMap[m_comboSpeed->currentItem()]; +} + + +int K3bWriterSelectionWidget::writingApp() const +{ + KConfigGroup g( k3bcore->config(), "General Options" ); + if( g.readBoolEntry( "Manual writing app selection", false ) ) { + return selectedWritingApp(); + } + else + return K3b::DEFAULT; +} + + +int K3bWriterSelectionWidget::selectedWritingApp() const +{ + return K3b::writingAppFromString( m_comboWritingApp->currentText() ); +} + + +void K3bWriterSelectionWidget::slotSpeedChanged( int s ) +{ + // the last item is the manual speed selection item + if( d->haveManualSpeed && s == m_comboSpeed->count() - 1 ) { + slotManualSpeed(); + } + else { + d->lastSetSpeed = d->indexSpeedMap[s]; + + if( K3bDevice::Device* dev = writerDevice() ) + dev->setCurrentWriteSpeed( writerSpeed() ); + } +} + + +void K3bWriterSelectionWidget::slotWriterChanged() +{ + slotRefreshWriterSpeeds(); + slotRefreshWritingApps(); + + // save last selected writer + if( K3bDevice::Device* dev = writerDevice() ) { + KConfigGroup g( k3bcore->config(), "General Options" ); + g.writeEntry( "current_writer", dev->devicename() ); + } +} + + +void K3bWriterSelectionWidget::setSupportedWritingApps( int i ) +{ + int oldApp = writingApp(); + + d->supportedWritingApps = i; + + slotRefreshWritingApps(); + + setWritingApp( oldApp ); +} + + +void K3bWriterSelectionWidget::slotRefreshWritingApps() +{ + int i = 0; + + // select the ones that make sense + if( k3bappcore->mediaCache()->diskInfo( writerDevice() ).isDvdMedia() ) + i = K3b::GROWISOFS|K3b::DVD_RW_FORMAT|K3b::DVDRECORD; + else + i = K3b::CDRDAO|K3b::CDRECORD; + + // now strip it down to the ones we support + i &= d->supportedWritingApps; + + m_comboWritingApp->clear(); + m_comboWritingApp->insertItem( i18n("Auto") ); + + if( i & K3b::CDRDAO ) + m_comboWritingApp->insertItem( "cdrdao" ); + if( i & K3b::CDRECORD ) + m_comboWritingApp->insertItem( "cdrecord" ); + if( i & K3b::DVDRECORD ) + m_comboWritingApp->insertItem( "dvdrecord" ); + if( i & K3b::GROWISOFS ) + m_comboWritingApp->insertItem( "growisofs" ); + if( i & K3b::DVD_RW_FORMAT ) + m_comboWritingApp->insertItem( "dvd+rw-format" ); + + m_comboWritingApp->setEnabled( writerDevice() != 0 ); +} + + +void K3bWriterSelectionWidget::loadConfig( KConfigBase* c ) +{ + setWriterDevice( k3bcore->deviceManager()->findDevice( c->readEntry( "writer_device" ) ) ); + setSpeed( c->readNumEntry( "writing_speed", 0 ) ); + setWritingApp( K3b::writingAppFromString( c->readEntry( "writing_app" ) ) ); +} + + +void K3bWriterSelectionWidget::saveConfig( KConfigBase* c ) +{ + c->writeEntry( "writing_speed", writerSpeed() ); + c->writeEntry( "writer_device", writerDevice() ? writerDevice()->devicename() : QString::null ); + c->writeEntry( "writing_app", m_comboWritingApp->currentText() ); +} + +void K3bWriterSelectionWidget::loadDefaults() +{ + // ignore the writer + m_comboSpeed->setCurrentItem( 0 ); // Auto + setWritingApp( K3b::DEFAULT ); +} + + +void K3bWriterSelectionWidget::setForceAutoSpeed( bool b ) +{ + d->forceAutoSpeed = b; + slotRefreshWriterSpeeds(); +} + + +void K3bWriterSelectionWidget::setOverrideDevice( K3bDevice::Device* dev, const QString& overrideString, const QString& tooltip ) +{ + m_comboMedium->setOverrideDevice( dev, overrideString, tooltip ); +} + + +void K3bWriterSelectionWidget::slotNewBurnMedium( K3bDevice::Device* dev ) +{ + // + // Try to select a medium that is better suited than the current one + // + if( dev && dev != writerDevice() ) { + K3bMedium medium = k3bappcore->mediaCache()->medium( dev ); + + // + // Always prefer newly inserted media over the override device + // + if( writerDevice() == m_comboMedium->overrideDevice() ) { + setWriterDevice( dev ); + } + + // + // Prefer an empty medium over one that has to be erased + // + else if( wantedMediumState() & K3bDevice::STATE_EMPTY && + !k3bappcore->mediaCache()->diskInfo( writerDevice() ).empty() && + medium.diskInfo().empty() ) { + setWriterDevice( dev ); + } + } +} + + +void K3bWriterSelectionWidget::slotManualSpeed() +{ + // + // We need to know if it will be a CD or DVD medium. Since the override device + // is only used for CD/DVD copy anyway we simply reply on the inserted medium's type. + // + int speedFactor = ( k3bappcore->mediaCache()->diskInfo( writerDevice() ).isDvdMedia() ? 1385 : 175 ); + + bool ok = true; + int newSpeed = KInputDialog::getInteger( i18n("Set writing speed manually"), + i18n("<p>K3b is not able to perfectly determine the maximum " + "writing speed of an optical writer. Writing speed is always " + "reported subject to the inserted medium." + "<p>Please enter the writing speed here and K3b will remember it " + "for future sessions (Example: 16x)."), + writerDevice()->maxWriteSpeed()/speedFactor, + 1, + 10000, + 1, + 10, + &ok, + this ) * speedFactor; + if( ok ) { + writerDevice()->setMaxWriteSpeed( QMAX( newSpeed, writerDevice()->maxWriteSpeed() ) ); + slotRefreshWriterSpeeds(); + setSpeed( newSpeed ); + } + else { + if( d->lastSetSpeed == -1 ) + m_comboSpeed->setCurrentItem( 0 ); // Auto + else + setSpeed( d->lastSetSpeed ); + } +} + + +void K3bWriterSelectionWidget::setIgnoreDevice( K3bDevice::Device* dev ) +{ + m_comboMedium->setIgnoreDevice( dev ); +} + +#include "k3bwriterselectionwidget.moc" diff --git a/src/k3bwriterselectionwidget.h b/src/k3bwriterselectionwidget.h new file mode 100644 index 0000000..8174637 --- /dev/null +++ b/src/k3bwriterselectionwidget.h @@ -0,0 +1,146 @@ +/* + * + * $Id: k3bwriterselectionwidget.h 690635 2007-07-21 16:47:29Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BWRITERSELECTIONWIDGET_H +#define K3BWRITERSELECTIONWIDGET_H + +#include <qwidget.h> + +class KComboBox; +class KConfigBase; +class QLabel; +class K3bMediaSelectionComboBox; +namespace K3bDevice { + class Device; + class DeviceManager; +} + + +/** + *@author Sebastian Trueg + */ +class K3bWriterSelectionWidget : public QWidget +{ + Q_OBJECT + + public: + /** + * Creates a writerselectionwidget + */ + K3bWriterSelectionWidget( QWidget* parent = 0, const char* name = 0 ); + ~K3bWriterSelectionWidget(); + + int writerSpeed() const; + K3bDevice::Device* writerDevice() const; + + QValueList<K3bDevice::Device*> allDevices() const; + + /** + * returns K3b::WritingApp + */ + int writingApp() const; + + int wantedMediumType() const; + int wantedMediumState() const; + + void loadDefaults(); + void loadConfig( KConfigBase* ); + void saveConfig( KConfigBase* ); + + public slots: + void setWriterDevice( K3bDevice::Device* ); + void setSpeed( int ); + void setWritingApp( int ); + + /** + * K3b::WritingApp or'ed together + * + * Defaults to cdrecord and cdrdao for CD and growisofs for DVD + */ + void setSupportedWritingApps( int ); + + /** + * A simple hack to disable the speed selection for DVD formatting + */ + void setForceAutoSpeed( bool ); + + /** + * Set the wanted medium type. Defaults to writable CD. + * + * \param type a bitwise combination of the K3bDevice::MediaType enum + */ + void setWantedMediumType( int type ); + + /** + * Set the wanted medium state. Defaults to empty media. + * + * \param state a bitwise combination of the K3bDevice::State enum + */ + void setWantedMediumState( int state ); + + /** + * This is a hack to allow the copy dialogs to use the same device for reading + * and writing without having the user to choose the same medium. + * + * \param overrideString A string which will be shown in place of the medium string. + * For example: "Burn to the same device". Set it to 0 in order + * to disable the feature. + */ + void setOverrideDevice( K3bDevice::Device* dev, const QString& overrideString = QString::null, const QString& tooltip = QString::null ); + + /** + * Compare K3bMediaSelectionComboBox::setIgnoreDevice + */ + void setIgnoreDevice( K3bDevice::Device* dev ); + + signals: + void writerChanged(); + void writerChanged( K3bDevice::Device* ); + void writingAppChanged( int app ); + + /** + * \see K3bMediaSelectionComboBox + */ + void newMedia(); + void newMedium( K3bDevice::Device* dev ); + + private slots: + void slotRefreshWriterSpeeds(); + void slotRefreshWritingApps(); + void slotWritingAppSelected( int id ); + void slotConfigChanged( KConfigBase* c ); + void slotSpeedChanged( int index ); + void slotWriterChanged(); + void slotNewBurnMedium( K3bDevice::Device* dev ); + void slotManualSpeed(); + + private: + void clearSpeedCombo(); + void insertSpeedItem( int ); + int selectedWritingApp() const; + + class MediaSelectionComboBox; + + KComboBox* m_comboSpeed; + MediaSelectionComboBox* m_comboMedium; + KComboBox* m_comboWritingApp; + QLabel* m_writingAppLabel; + + class Private; + Private* d; +}; + +#endif diff --git a/src/k3bwritingmodewidget.cpp b/src/k3bwritingmodewidget.cpp new file mode 100644 index 0000000..a2bd696 --- /dev/null +++ b/src/k3bwritingmodewidget.cpp @@ -0,0 +1,247 @@ +/* + * + * $Id: k3bwritingmodewidget.cpp 621084 2007-01-08 09:17:21Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bwritingmodewidget.h" +#include "k3bmediacache.h" +#include "k3bapplication.h" + +#include <k3bglobals.h> + +#include <klocale.h> +#include <kconfig.h> + +#include <qtooltip.h> +#include <qwhatsthis.h> + +static const QString s_autoHelp = i18n("Let K3b select the best-suited mode. This is the recommended selection."); +static const QString s_daoHelp = i18n("<em>Disk At Once</em> or more properly <em>Session At Once</em>. " + "The laser is never turned off while writing the CD or DVD. " + "This is the preferred mode to write audio CDs since it allows " + "pregaps other than 2 seconds. Not all writers support DAO.<br>" + "DVD-R(W)s written in DAO provide the best DVD-Video compatibility."); +static const QString s_taoHelp = i18n("<em>Track At Once</em> should be supported by every CD writer. " + "The laser will be turned off after every track.<br>" + "Most CD writers need this mode for writing multisession CDs."); +// TODO: add something like: "No CD-TEXT writing in TAO mode." + +static const QString s_rawHelp = i18n("RAW writing mode. The error correction data is created by the " + "software instead of the writer device.<br>" + "Try this if your CD writer fails to write in DAO and TAO."); +static const QString s_seqHelp = i18n("Incremental sequential is the default writing mode for DVD-R(W). " + "It allows multisession DVD-R(W)s. It only applies to DVD-R(W)."); +static const QString s_ovwHelp = i18n("Restricted Overwrite allows to use a DVD-RW just like a DVD-RAM " + "or a DVD+RW. The media may just be overwritten. It is not possible " + "to write multisession DVD-RWs in this mode but K3b uses growisofs " + "to grow an ISO9660 filesystem within the first session, thus allowing " + "new files to be added to an already burned disk."); + + +class K3bWritingModeWidget::Private +{ +public: + // modes set via setSupportedModes + int supportedModes; + + // filtered modes + int selectedModes; + + K3bDevice::Device* device; +}; + + +K3bWritingModeWidget::K3bWritingModeWidget( int modes, QWidget* parent, const char* name ) + : K3bIntMapComboBox( parent, name ) +{ + init(); + setSupportedModes( modes ); +} + + +K3bWritingModeWidget::K3bWritingModeWidget( QWidget* parent, const char* name ) + : K3bIntMapComboBox( parent, name ) +{ + init(); + setSupportedModes( K3b::DAO | K3b::TAO | K3b::RAW ); // default: support all CD-R(W) modes +} + + +K3bWritingModeWidget::~K3bWritingModeWidget() +{ + delete d; +} + + +void K3bWritingModeWidget::init() +{ + d = new Private(); + d->device = 0; + + connect( this, SIGNAL(valueChanged(int)), this, SIGNAL(writingModeChanged(int)) ); + + QToolTip::add( this, i18n("Select the writing mode to use") ); + + initWhatsThisHelp(); +} + + +void K3bWritingModeWidget::initWhatsThisHelp() +{ + addGlobalWhatsThisText( "<p><b>" + i18n("Writing mode") + "</b></p>", + i18n("Be aware that the writing mode is ignored when writing DVD+R(W) since " + "there is only one way to write them.") + + "<p><i>" + + i18n("The selection of writing modes depends on the inserted burning medium.") + + "</i>" ); +} + + +int K3bWritingModeWidget::writingMode() const +{ + return selectedValue(); +} + + +void K3bWritingModeWidget::setWritingMode( int m ) +{ + if( m & d->selectedModes ) { + setSelectedValue( m ); + } + else { + setCurrentItem( 0 ); // WRITING_MODE_AUTO + } +} + + +void K3bWritingModeWidget::setSupportedModes( int m ) +{ + d->supportedModes = m|K3b::WRITING_MODE_AUTO; // we always support the Auto mode + updateModes(); +} + + +void K3bWritingModeWidget::setDevice( K3bDevice::Device* dev ) +{ + d->device = dev; + updateModes(); +} + + +void K3bWritingModeWidget::updateModes() +{ + // save current mode + int currentMode = writingMode(); + + clear(); + + if( d->device ) + d->selectedModes = d->supportedModes & d->device->writingModes(); + else + d->selectedModes = d->supportedModes; + + insertItem( 0, i18n("Auto"), s_autoHelp ); + if( d->selectedModes & K3b::DAO ) + insertItem( K3b::DAO, i18n("DAO"), s_daoHelp ); + if( d->selectedModes & K3b::TAO ) + insertItem( K3b::TAO, i18n("TAO"), s_taoHelp ); + if( d->selectedModes & K3b::RAW ) + insertItem( K3b::RAW, i18n("RAW"), s_rawHelp ); + if( d->selectedModes & K3b::WRITING_MODE_RES_OVWR ) + insertItem( K3b::WRITING_MODE_RES_OVWR, i18n("Restricted Overwrite"), s_ovwHelp ); + if( d->selectedModes & K3b::WRITING_MODE_INCR_SEQ ) + insertItem( K3b::WRITING_MODE_INCR_SEQ, i18n("Incremental"), s_seqHelp ); + + setWritingMode( currentMode ); +} + + +void K3bWritingModeWidget::saveConfig( KConfigBase* c ) +{ + switch( writingMode() ) { + case K3b::DAO: + c->writeEntry( "writing_mode", "dao" ); + break; + case K3b::TAO: + c->writeEntry( "writing_mode", "tao" ); + break; + case K3b::RAW: + c->writeEntry( "writing_mode", "raw" ); + break; + case K3b::WRITING_MODE_INCR_SEQ: + c->writeEntry( "writing_mode", "incremental" ); + break; + case K3b::WRITING_MODE_RES_OVWR: + c->writeEntry( "writing_mode", "overwrite" ); + break; + default: + c->writeEntry( "writing_mode", "auto" ); + break; + } +} + +void K3bWritingModeWidget::loadConfig( KConfigBase* c ) +{ + QString mode = c->readEntry( "writing_mode" ); + if ( mode == "dao" ) + setWritingMode( K3b::DAO ); + else if( mode == "tao" ) + setWritingMode( K3b::TAO ); + else if( mode == "raw" ) + setWritingMode( K3b::RAW ); + else if( mode == "incremental" ) + setWritingMode( K3b::WRITING_MODE_INCR_SEQ ); + else if( mode == "overwrite" ) + setWritingMode( K3b::WRITING_MODE_RES_OVWR ); + else + setWritingMode( K3b::WRITING_MODE_AUTO ); +} + + +void K3bWritingModeWidget::determineSupportedModesFromMedium( const K3bMedium& m ) +{ + int modes = 0; + + if( m.diskInfo().mediaType() & (K3bDevice::MEDIA_CD_R|K3bDevice::MEDIA_CD_RW) ) { + modes |= K3b::TAO; + if( m.device()->supportsWritingMode( K3bDevice::WRITINGMODE_SAO ) ) + modes |= K3b::DAO; + if( m.device()->supportsWritingMode( K3bDevice::WRITINGMODE_RAW ) ) + modes |= K3b::RAW; + } + + if( m.diskInfo().mediaType() & K3bDevice::MEDIA_DVD_MINUS_ALL ) { + modes |= K3b::DAO; + if( m.device()->featureCurrent( K3bDevice::FEATURE_INCREMENTAL_STREAMING_WRITABLE ) != 0 ) + modes |= K3b::WRITING_MODE_INCR_SEQ; + } + + if( m.diskInfo().mediaType() & (K3bDevice::MEDIA_DVD_RW| + K3bDevice::MEDIA_DVD_RW_SEQ| + K3bDevice::MEDIA_DVD_RW_OVWR) ) + modes |= K3b::WRITING_MODE_RES_OVWR; + + setSupportedModes( modes ); + setDevice( m.device() ); +} + + +void K3bWritingModeWidget::determineSupportedModesFromMedium( K3bDevice::Device* dev ) +{ + if( dev ) + determineSupportedModesFromMedium( k3bappcore->mediaCache()->medium( dev ) ); + else + determineSupportedModesFromMedium( K3bMedium() ); // no medium +} + +#include "k3bwritingmodewidget.moc" diff --git a/src/k3bwritingmodewidget.h b/src/k3bwritingmodewidget.h new file mode 100644 index 0000000..f399f14 --- /dev/null +++ b/src/k3bwritingmodewidget.h @@ -0,0 +1,91 @@ +/* + * + * $Id: k3bwritingmodewidget.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_WRITING_MODE_WIDGET_H_ +#define _K3B_WRITING_MODE_WIDGET_H_ + +#include <k3bintmapcombobox.h> + +#include <k3bmedium.h> + +class KConfigBase; + + +/** + * Allows selection of K3b::WritingMode + */ +class K3bWritingModeWidget : public K3bIntMapComboBox +{ + Q_OBJECT + + public: + K3bWritingModeWidget( QWidget* parent = 0, const char* name = 0 ); + K3bWritingModeWidget( int modes, QWidget* parent = 0, const char* name = 0 ); + ~K3bWritingModeWidget(); + + int writingMode() const; + + void saveConfig( KConfigBase* ); + /** + * This will not emit the writingModeChanged signal + */ + void loadConfig( KConfigBase* ); + + public slots: + /** + * This will not emit the writingModeChanged signal + */ + void setWritingMode( int m ); + void setSupportedModes( int ); + + /** + * If the device is set the supported writing modes + * will be filtered by the ones supported by the drive. + */ + void setDevice( K3bDevice::Device* ); + + /** + * Set the writing modes which make sense with the provided medium. + * This will also reset the device from the medium. + * + * \param m The medium. May even be non-writable or no medium at all + * in which case only the auto mode will be selected. + * + * \sa setDevice + */ + void determineSupportedModesFromMedium( const K3bMedium& m ); + + /** + * Convinience method. Does the same as the one above. + * + * \param dev The device which contains the medium. May even be 0 in + * which case only the auto mode will be selected. + */ + void determineSupportedModesFromMedium( K3bDevice::Device* dev ); + + signals: + void writingModeChanged( int ); + + private: + void init(); + void updateModes(); + void initWhatsThisHelp(); + + class Private; + Private* d; +}; + +#endif diff --git a/src/konqi/Makefile.am b/src/konqi/Makefile.am new file mode 100644 index 0000000..e13f9d2 --- /dev/null +++ b/src/konqi/Makefile.am @@ -0,0 +1,16 @@ +k3bservice_DATA = k3b_create_data_cd.desktop \ + k3b_create_data_dvd.desktop \ + k3b_create_audio_cd.desktop \ + k3b_create_video_cd.desktop \ + k3b_write_bin_image.desktop \ + k3b_write_iso_image.desktop + +konqservice_DATA = k3b_audiocd_rip.desktop \ + k3b_videodvd_rip.desktop \ + k3b_cd_copy.desktop \ + k3b_dvd_copy.desktop \ + k3b_handle_empty_dvd.desktop \ + k3b_handle_empty_cd.desktop + +k3bservicedir = $(kde_datadir)/k3b/servicemenus +konqservicedir = $(kde_datadir)/konqueror/servicemenus diff --git a/src/konqi/k3b_audiocd_rip.desktop b/src/konqi/k3b_audiocd_rip.desktop new file mode 100644 index 0000000..c118cd4 --- /dev/null +++ b/src/konqi/k3b_audiocd_rip.desktop @@ -0,0 +1,49 @@ +[Desktop Entry] +ServiceTypes=media/audiocd,media/mixedcd +Actions=K3bRip; +X-KDE-Priority=TopLevel + +[Desktop Action K3bRip] +Name=Extract Digital Audio with K3b +Name[af]=Onttrek digitale oudio m.b.v. K3b +Name[ar]= استعمل K3b لاستخراج الصوتي الرقمي. +Name[bg]=Извличане на цифров звук с K3b +Name[br]=Eztennañ klevet niverel gant K3b +Name[ca]=Extreu àudio digital amb el K3b +Name[cs]=Extrahovat digitální zvuk pomocí K3b +Name[da]=Rip digitallyd med K3b +Name[de]=Digital-Audio mit K3b auslesen +Name[el]=Εξαγωγή ψηφιακού ήχου με το K3b +Name[eo]=Ekstraktu ciferecan sonon per K3b +Name[es]=Extraer audio digital con K3b +Name[et]=Ekstrakti digitaalne audio K3b abil +Name[fa]=استخراج صوتی رقمی با K3b +Name[fi]=Pura sisältö digitaalisesti K3b:llä +Name[fr]=Extraction Audio avec K3b +Name[gl]=Extrair Áudio Dixital con K3b +Name[hu]=Digitális hanganyag kimásolása a K3b-vel +Name[is]=Afrita stafrænt hljóð með K3b +Name[it]=Estrai audio digitale con K3b +Name[ja]=K3b でデジタルオーディオを吸い出し +Name[km]=ស្រង់​ចេញ​អូឌីយ៉ូ​ឌីជីថល​ដោយ​ប្រើ K3b +Name[lt]=Nurašyti skaitmeninį audio su K3b +Name[ms]=Ekstrak Audio Digital dengan K3b +Name[nds]=Digitaal Audiodaten mit K3b ruttrecken +Name[nl]=Digitale audio rippen met K3b +Name[nn]=Hent ut digitallyd med K3b +Name[pa]=K3b ਨਾਲ ਡਿਜ਼ੀਟਲ ਆਡੀਓ ਖੋਲ੍ਹੋ +Name[pl]=Zgraj utwory za pomocą K3b +Name[pt]=Extrair o Áudio Digital com o K3b +Name[pt_BR]=Extrair Áudio Digital com o K3b +Name[sk]=Extrahovať digitálne audio pomocou K3b +Name[sr]=Издвој дигитални звук помоћу K3b-а +Name[sr@Latn]=Izdvoj digitalni zvuk pomoću K3b-a +Name[sv]=Lagra digitalljud med K3b +Name[tr]=K3b ile Sayısal Ses Aktar +Name[uk]=Витягування цифрового аудіо за допомогою K3b +Name[uz]=K3b yordamida qoʻshiqlarni audio-faylga aylantirish +Name[uz@cyrillic]=K3b ёрдамида қўшиқларни аудио-файлга айлантириш +Name[zh_CN]=用 K3b 提取数字音频 +Name[zh_TW]=使用 K3b 以數位方式提取音樂 +Exec=k3b --cddarip %u +Icon=k3b diff --git a/src/konqi/k3b_cd_copy.desktop b/src/konqi/k3b_cd_copy.desktop new file mode 100644 index 0000000..51f0ab0 --- /dev/null +++ b/src/konqi/k3b_cd_copy.desktop @@ -0,0 +1,52 @@ +[Desktop Entry] +ServiceTypes=media/cdrom_unmounted,media/cdwriter_unmounted,media/audiocd +Actions=K3bCDCopy; +X-KDE-Priority=TopLevel + +[Desktop Action K3bCDCopy] +Name=Copy CD with K3b +Name[af]=Kopiëer CD m.b.v. K3b... +Name[ar]= انقل القرص المدمج بواسطة K3b . +Name[bg]=Копиране на CD с K3b +Name[br]=Eilañ ur CD gant K3b +Name[ca]=Copia CD amb el K3b +Name[cs]=Kopírovat CD pomocí K3b +Name[da]=Kopiér cd med K3b +Name[de]=CD mit K3b kopieren +Name[el]=Αντιγραφή CD με το K3b +Name[eo]=Kopiu KD per K3b +Name[es]=Copiar CD con K3b +Name[et]=Kopeeri CD K3b abil +Name[fa]=رونوشت دیسک فشرده با K3b +Name[fi]=Kopioi cd K3b:llä +Name[fr]=Copier le CD avec K3b +Name[gl]=Copiar CD con K3b +Name[hu]=CD-másolás a K3b-vel +Name[is]=Afrita geisladisk með K3b +Name[it]=Copia CD con K3b +Name[ja]=K3b で CD をコピー +Name[ka]=CD-ს ასლი K3b-ით +Name[km]=ចម្លង​ស៊ីឌី​ដោយ​ប្រើ K3b +Name[lt]=Kopijuoti CD su K3b +Name[mk]=Копирајте CD со K3b +Name[ms]=Salin CD dengan K3b +Name[nds]=CD mit K3b koperen +Name[nl]=CD kopiëren met K3b +Name[nn]=Kopier CD med K3b +Name[pa]=K3b ਨਾਲ CD ਨਕਲ +Name[pl]=Skopiuj płytę CD za pomocą K3b +Name[pt]=Copiar o CD com o K3b +Name[pt_BR]=Copiar CD com o K3b +Name[ru]=Записать компакт-диск, используя K3b... +Name[sk]=Kopírovať CD pomocou K3b +Name[sr]=Копирај CD помоћу K3b-а +Name[sr@Latn]=Kopiraj CD pomoću K3b-a +Name[sv]=Kopiera cd med K3b +Name[tr]=K3b ile CD Kopyala +Name[uk]=Копіювати КД за допомогою K3b +Name[uz]=K3b yordamida CD'dan nusxa olish +Name[uz@cyrillic]=K3b ёрдамида CD'дан нусха олиш +Name[zh_CN]=用 K3b 复制 CD +Name[zh_TW]=使用 K3b 複製 CD +Exec=k3b --copycd %u +Icon=k3b diff --git a/src/konqi/k3b_create_audio_cd.desktop b/src/konqi/k3b_create_audio_cd.desktop new file mode 100644 index 0000000..e4ecad9 --- /dev/null +++ b/src/konqi/k3b_create_audio_cd.desktop @@ -0,0 +1,62 @@ +[Desktop Entry] +Actions=CreateK3bAudioProject; +Encoding=UTF-8 +ServiceTypes=audio/x-mp3,audio/x-vorbis,application/x-ogg,audio/x-mp2,audio/x-mpegurl,audio/x-wav + +[Desktop Action CreateK3bAudioProject] +Exec=k3b --audiocd %F +Name=Create Audio CD with K3b... +Name[af]=Skep oudio CD met K3b... +Name[ar]= انشيء القرص المدمج السمعي بواسطة K3b ... +Name[bg]=Създаване на аудио CD с K3b... +Name[bn]=কে-থ্রি-বি দিয়ে অডিও সিডি তৈরি করো... +Name[br]=Krouiñ ur CD klevet gant K3b ... +Name[bs]=Napravio audio CD koristeći K3b... +Name[ca]=Crea un CD d'àudio amb el K3b... +Name[cs]=Vytvořit zvukové CD... +Name[da]=Lav lyd-cd med K3b... +Name[de]=Audio-CD mit K3b erstellen ... +Name[el]=Δημιουργία CD ήχου με το K3b... +Name[eo]=Kreu sonan KD per K3b... +Name[es]=Crear CD de audio con K3b... +Name[et]=Kirjuta audio-CD K3b abil... +Name[fa]=ایجاد دیسک فشردۀ صوتی با K3b... +Name[fi]=Luo musiikki-cd K3b:llä... +Name[fr]=Créer un CD audio avec K3b... +Name[gl]=Criar un CD de Áudio con K3b... +Name[he]=צור תקליטור שמע בעזרת K3b... +Name[hi]=के3बी के साथ ऑडियो सीडी बनाए... +Name[hu]=Hang-CD létrehozása a K3b-vel... +Name[is]=Búa til hljóðdisk með K3b... +Name[it]=Crea CD audio con K3b... +Name[ja]=K3b でオーディオ CD を作成... +Name[ka]=K3b-ით Audio CD-ის ჩაწერა... +Name[km]=បង្កើត​ស៊ីឌី​អូឌីយ៉ូ​ជាមួយ​នឹង K3b... +Name[lt]=Kurti audio CD su K3b... +Name[mk]=Креирајте аудио-CD со K3b... +Name[ms]= Cipta Audio CD dengan K3b... +Name[nb]=Lag lyd-CD med K3b . . . +Name[nds]=Audio-CD mit K3b opstellen... +Name[ne]=K3b सँग अडियो सीडी सिर्जना गर्नुहोस्... +Name[nl]=Audio-cd aanmaken met K3b... +Name[nn]=Lag lyd-CD med K3b … +Name[pa]=K2b ਨਾਲ ਆਡੀਓ CD ਬਣਾਓ... +Name[pl]=Stwórz płytę CD Audio za pomocą K3b... +Name[pt]=Criar um CD de Áudio com o K3b... +Name[pt_BR]=Criar CD de Áudio com o K3b... +Name[ru]=Записать аудио компакт-диск, используя K3b... +Name[sk]=Vytvoriť audio CD pomocou K3b... +Name[sl]=Ustvari avdio CD s K3b ... +Name[sr]=Направи аудио CD помоћу K3b-а... +Name[sr@Latn]=Napravi audio CD pomoću K3b-a... +Name[sv]=Skapa ljud-cd med K3b... +Name[ta]=ஒலிக் குறுந்தகட்டோடு K3bயை உருவாக்குக... +Name[tg]=Сабт кардани аудио компакт-диск бо истифодаи K3b... +Name[tr]=K3b ile Ses CD'si oluştur... +Name[uk]=Створити аудіо-КД за допомогою K3b... +Name[uz]=K3b yordamida audio CD yaratish +Name[uz@cyrillic]=K3b ёрдамида аудио CD яратиш +Name[xh]=Yenza i CD Yokuvakalayo nge K3b... +Name[zh_CN]=用 K3b 创建音频 CD... +Name[zh_TW]=使用 K3b 建立音樂 CD... +Icon=k3b diff --git a/src/konqi/k3b_create_data_cd.desktop b/src/konqi/k3b_create_data_cd.desktop new file mode 100644 index 0000000..af6bcaa --- /dev/null +++ b/src/konqi/k3b_create_data_cd.desktop @@ -0,0 +1,63 @@ +[Desktop Entry] +Actions=CreateK3bDataCDProject; +Encoding=UTF-8 +ServiceTypes=all/allfiles,inode/directory +ExcludeServiceTypes=application/x-iso,kdedevice/* + +[Desktop Action CreateK3bDataCDProject] +Exec=k3b --datacd %F +Name=Create Data CD with K3b... +Name[af]=Skep data CD met K3b... +Name[ar]= انشيء القرص المدمج لحفظ البيانات (Data) بواسطة K3b ... +Name[bg]=Създаване на CD с данни с K3b... +Name[bn]=কে-থ্রি-বি দিয়ে ডেটা-সিডি তৈরি করো... +Name[br]=Krouiñ ur CD roadoù gant K3b ... +Name[bs]=Napravi podatkovni CD koristeći K3b... +Name[ca]=Crea un CD de dades amb el K3b... +Name[cs]=Vytvořit datové CD... +Name[da]=Lav data-cd med K3b... +Name[de]=Daten-CD mit K3b erstellen ... +Name[el]=Δημιουργία CD δεδομένων με το K3b... +Name[eo]=Kreu datuman KD per K3b... +Name[es]=Crear CD de datos con K3b... +Name[et]=Kirjuta andme-CD K3b abil... +Name[fa]=ایجاد دیسک فشردۀ داده با K3b... +Name[fi]=Luo data-cd K3b:llä... +Name[fr]=Créer un CD de données avec K3b... +Name[gl]=Criar un CD de Dados con K3b... +Name[he]=צור תקליטורי מידע CD בעזרת K3b... +Name[hi]=के3बी के साथ डाटा सीडी बनाए... +Name[hu]=Adat-CD létrehozása a K3b-vel... +Name[is]=Búa til gagnadisk með K3b... +Name[it]=Crea CD dati con K3b... +Name[ja]=K3b でデータ CD を作成... +Name[ka]=K3b-ით მონაცემთა CD-ის ჩაწერა... +Name[km]=បង្កើត​ស៊ីឌី​ទិន្ន័យ​ជាមួយនឹង K3b... +Name[lt]=Kurti duomenų CD su K3b... +Name[mk]=Креирајте податочно CD со K3b... +Name[ms]= Cipta CD Data dengan K3b... +Name[nb]=Lag data-CD med K3b . . . +Name[nds]=Daten-CD mit K3b opstellen... +Name[ne]=K3b... +Name[nl]=Gegevens-cd aanmaken met K3b... +Name[nn]=Lag data-CD med K3b … +Name[pa]=K2b ਨਾਲ ਡਾਟਾ CD ਬਣਾਓ... +Name[pl]=Stwórz płytę CD z danymi za pomocą K3b... +Name[pt]=Criar um CD de Dados com o K3b... +Name[pt_BR]=Criar CD de Dados com o K3b... +Name[ru]=Записать компакт-диск с данными, используя K3b... +Name[sk]=Vytvoriť dátové CD pomocou K3b... +Name[sl]=Ustvari podatkovni CD s K3b ... +Name[sr]=Направи CD са подацима помоћу K3b-а... +Name[sr@Latn]=Napravi CD sa podacima pomoću K3b-a... +Name[sv]=Skapa data-cd med K3b... +Name[ta]=தகவல் குறுந்தகட்டோடு K3b ஐ உருவாக்குக... +Name[tg]=Сабт кардани CD бо маълумотҳо,бо истифодабарии K3b... +Name[tr]=K3b ile Veri CD'si oluştur... +Name[uk]=Створити КД з даними за допомогою K3b... +Name[uz]=K3b yordamida maʼlumot CD yaratish +Name[uz@cyrillic]=K3b ёрдамида маълумот CD яратиш +Name[xh]=Yenza i CD yolwazi nge K3b... +Name[zh_CN]=用 K3b 创建数据 CD... +Name[zh_TW]=使用 K3b 建立資料 CD... +Icon=k3b diff --git a/src/konqi/k3b_create_data_dvd.desktop b/src/konqi/k3b_create_data_dvd.desktop new file mode 100644 index 0000000..d03e5b5 --- /dev/null +++ b/src/konqi/k3b_create_data_dvd.desktop @@ -0,0 +1,57 @@ +[Desktop Entry] +Actions=CreateK3bDataDVDProject +Encoding=UTF-8 +ServiceTypes=all/allfiles,inode/directory +ExcludeServiceTypes=application/x-iso + +[Desktop Action CreateK3bDataDVDProject] +Exec=k3b --datadvd %F +Name=Create Data DVD with K3b... +Name[af]=Skep 'n Data DVD m.b.v. K3b... +Name[ar]= انشيء القرص المرئي الرقمي (DVD) لحفظ البيانات (Data) بواسطة K3b ... +Name[bg]=Създаване на DVD с данни с K3b... +Name[bn]=কে-থ্রি-বি দিয়ে ডেটা-ডিভিডি তৈরি করো... +Name[br]=Krouiñ un DVD roadoù gant K3b ... +Name[ca]=Crea un DVD de dades amb el K3b... +Name[cs]=Vytvořit datové DVD... +Name[da]=Lav data-cd med K3b... +Name[de]=Daten-DVD mit K3b erstellen ... +Name[el]=Δημιουργία DVD δεδομένων με το K3b... +Name[eo]=Kreu datuman DVD per K3b... +Name[es]=Crear DVD de datos con K3b... +Name[et]=Kirjuta andme-DVD K3b abil... +Name[fa]=ایجاد دی وی دی داده با K3b... +Name[fi]=Luo data-dvd K3b:llä... +Name[fr]=Créer un DVD de données avec K3b... +Name[gl]=Criar un DVD de Dados con K3b... +Name[he]=צור תקליטורי מידע DVD בעזרת K3b... +Name[hu]=Adat-DVD létrehozása a K3b-vel... +Name[is]=Búa til DVD gagnadisk með K3b... +Name[it]=Crea DVD dati con K3b... +Name[ja]=K3b でデータ DVD を作成... +Name[ka]=K3b-ით მონაცემთა DVD-ის ჩაწერა... +Name[km]=បង្កើត​ឌីវីឌី​ទិន្នន័យ​ដោយ​ប្រើ K3b... +Name[lt]=Kurti duomenų DVD su K3b... +Name[mk]=Креирајте податочно DVD со K3b... +Name[ms]=Cipta DVD Data dengan K3b... +Name[nb]=Lag data-DVD med K3b . . . +Name[nds]=Daten-DVD mit K3b opstellen... +Name[nl]=Gegevens-dvd aanmaken met K3b... +Name[nn]=Lag data-DVD med K3b … +Name[pa]=K3b ਨਾਲ ਡਾਟਾ DVD ਬਣਾਓ... +Name[pl]=Stwórz płytę DVD z danymi za pomocą K3b... +Name[pt]=Criar um DVD de Dados com o K3b... +Name[pt_BR]=Criar DVD de Dados com o K3b... +Name[ru]=Записать DVD с данными, используя K3b... +Name[sk]=Vytvoriť dátové DVD pomocou K3b... +Name[sr]=Направи DVD са подацима помоћу K3b-а... +Name[sr@Latn]=Napravi DVD sa podacima pomoću K3b-a... +Name[sv]=Skapa data-dvd med K3b... +Name[tg]=Сабт кардани Маълумотҳои CD бо истифодабарии K3b... +Name[tr]=K3b ile Veri DVD'si oluştur... +Name[uk]=Створити DVD з даними у K3b... +Name[uz]=K3b yordamida maʼlumot DVD yaratish +Name[uz@cyrillic]=K3b ёрдамида маълумот DVD яратиш +Name[zh_CN]=用 K3b 创建数据 DVD... +Name[zh_TW]=使用 K3b 建立資料 DVD... +Icon=k3b diff --git a/src/konqi/k3b_create_video_cd.desktop b/src/konqi/k3b_create_video_cd.desktop new file mode 100644 index 0000000..bb5ca3a --- /dev/null +++ b/src/konqi/k3b_create_video_cd.desktop @@ -0,0 +1,61 @@ +[Desktop Entry] +Actions=CreateK3bVcdProject; +Encoding=UTF-8 +ServiceTypes=video/mpeg + +[Desktop Action CreateK3bVcdProject] +Exec=k3b --videocd %F +Name=Create Video CD with K3b... +Name[af]=Skep video CD met K3b... +Name[ar]= انشيء القرص المدمج المرئي (CD) بواسطة K3b . +Name[bg]=Създаване на видео CD с K3b... +Name[bn]=কে-থ্রি-বি দিয়ে ভিডিও সিডি তৈরি করো... +Name[br]=Krouiñ ur CD video gant K3b ... +Name[bs]=Napravi video CD koristeći K3b... +Name[ca]=Crea un CD de vídeo amb el K3b... +Name[cs]=Vytvořit video CD... +Name[da]=Lav video-cd med K3b... +Name[de]=Video-CD mit K3b erstellen ... +Name[el]=Δημιουργία Video CD με το K3b... +Name[eo]=Kreu videan KD per K3b... +Name[es]=Crear CD de vídeo con K3b... +Name[et]=Kirjuta video-CD K3b abil... +Name[fa]=ایجاد دیسک فشردۀ ویدیویی با K3b... +Name[fi]=Luo videocd K3b:llä... +Name[fr]=Créer un CD vidéo avec K3b... +Name[gl]=Criar un Video CD con K3b... +Name[he]=צור תקליטורי וידאו VCD בעזרת K3b... +Name[hi]=के3बी के साथ वीडियो सीडी बनाए... +Name[hu]=Video CD létrehozása a K3b-vel... +Name[is]=Búa til vídeódisk með K3b... +Name[it]=Crea Video CD con K3b... +Name[ja]=K3b でビデオ CD を作成... +Name[ka]=K3b-ით Video CD-ის ჩაწერა... +Name[km]=បង្កើត​ស៊ីឌី​វីដេអូ​ជាមួយ​នឹង K3b... +Name[lt]=Kurti video CD su K3b... +Name[mk]=Креирајте видео-CD со K3b... +Name[ms]= Cipta CD Video dengan K3b... +Name[nb]=Lag video-CD med K3b . . . +Name[nds]=Video-CD mit K3b opstellen... +Name[ne]=K3b सँग भिडियो सीडी सिर्जना गर्नुहोस्... +Name[nl]=Video-cd aanmaken K3b... +Name[nn]=Lag film-CD med K3b … +Name[pa]=K2b ਨਾਲ ਵੀਡਿਓ CD ਬਣਾਓ... +Name[pl]=Stwórz płytę Video CD za pomocą K3b... +Name[pt]=Criar um CD de Vídeo com o K3b... +Name[pt_BR]=Criar CD de Vídeo com o K3b... +Name[ru]=Записать видео компакт-диск, используя K3b... +Name[sk]=Vytvoriť video CD pomocou K3b... +Name[sl]=Ustvari video CD s K3b ... +Name[sr]=Направи видео CD помоћу K3b-а... +Name[sr@Latn]=Napravi video CD pomoću K3b-a... +Name[sv]=Skapa video-cd med K3b... +Name[ta]=ஒளிக் குறுந்தகட்டோடு K3bஐ உருவாக்குக... +Name[tg]=Сабт кардани видео компакт-диск бо истифодаи K3b... +Name[tr]=K3b ile Görüntü CD'si oluştur... +Name[uk]=Створити відео-КД за допомогою K3b... +Name[uz]=K3b yordamida video CD yaratish +Name[uz@cyrillic]=K3b ёрдамида видео CD яратиш +Name[zh_CN]=用 K3b 创建视频 CD... +Name[zh_TW]=使用 K3b 建立 VCD... +Icon=k3b diff --git a/src/konqi/k3b_dvd_copy.desktop b/src/konqi/k3b_dvd_copy.desktop new file mode 100644 index 0000000..88ce0bd --- /dev/null +++ b/src/konqi/k3b_dvd_copy.desktop @@ -0,0 +1,52 @@ +[Desktop Entry] +ServiceTypes=media/dvdrom_unmounted,media/dvdwriter_unmounted,media/dvdvideo +Actions=K3bDVDCopy; +X-KDE-Priority=TopLevel + +[Desktop Action K3bDVDCopy] +Name=Copy DVD with K3b +Name[af]=Kopiëer DVD m.b.v. K3b +Name[ar]= انسخ القرص الرقمي المرئي (DVD) بواسطة K3b . +Name[bg]=Копиране на DVD с K3b +Name[br]=Eilañ un DVD gant K3b +Name[ca]=Copia un DVD amb el K3b +Name[cs]=Kopírovat DVD pomocí K3b +Name[da]=Kopiér dvd med K3b +Name[de]=DVD mit K3b kopieren +Name[el]=Αντιγραφή DVD με το K3b +Name[eo]=Kopiu DVD per K3b +Name[es]=Copiar DVD con K3b +Name[et]=Kopeeri DVD K3b abil +Name[fa]=رونوشت دی وی دی با K3b +Name[fi]=Kopioi dvd K3b:llä +Name[fr]=Copier le DVD avec K3b +Name[gl]=Copiar DVD con K3b +Name[hu]=DVD-másolás a K3b-vel +Name[is]=Afrita DVD með K3b +Name[it]=Copia DVD con K3b +Name[ja]=K3b で DVD をコピー... +Name[ka]=DVD-ს ასლი K3b-ით +Name[km]=ចម្លង​ឌីវីឌី​ដោយ​ប្រើ K3b +Name[lt]=Kopijuoti DVD su K3b +Name[mk]=Копирајте DVD со K3b... +Name[ms]=Salin DVD dengan K3b +Name[nds]=DVD mit K3b koperen +Name[nl]=DVD kopiëren met K3b +Name[nn]=Kopier DVD med K3b +Name[pa]=K3b ਨਾਲ DVD ਨਕਲ +Name[pl]=Skopiuj DVD za pomocą K3b +Name[pt]=Copiar o DVD com o K3b +Name[pt_BR]=Copiar DVD com o K3b +Name[ru]=Копировать DVD, используя K3b... +Name[sk]=Vytvoriť DVD pomocou K3b +Name[sr]=Копирај DVD помоћу K3b-а +Name[sr@Latn]=Kopiraj DVD pomoću K3b-a +Name[sv]=Kopiera dvd med K3b +Name[tr]=K3b ile Veri DVD'si Kopyala +Name[uk]=Копіювати DVD за допомогою K3b +Name[uz]=K3b yordamida DVD'dan nusxa olish +Name[uz@cyrillic]=K3b ёрдамида DVD'дан нусха олиш +Name[zh_CN]=用 K3b 复制 DVD +Name[zh_TW]=使用 K3b 複製 DVD +Exec=k3b --copydvd %u +Icon=k3b diff --git a/src/konqi/k3b_handle_empty_cd.desktop b/src/konqi/k3b_handle_empty_cd.desktop new file mode 100644 index 0000000..33287bd --- /dev/null +++ b/src/konqi/k3b_handle_empty_cd.desktop @@ -0,0 +1,120 @@ +[Desktop Entry] +ServiceTypes=media/blankcd +Actions=K3bDataProject;K3bAudioCDProject; +X-KDE-Priority=TopLevel + +[Desktop Action K3bDataProject] +Exec=k3b --device %u --datacd +Name=Create Data CD with K3b... +Name[af]=Skep data CD met K3b... +Name[ar]= انشيء القرص المدمج لحفظ البيانات (Data) بواسطة K3b ... +Name[bg]=Създаване на CD с данни с K3b... +Name[bn]=কে-থ্রি-বি দিয়ে ডেটা-সিডি তৈরি করো... +Name[br]=Krouiñ ur CD roadoù gant K3b ... +Name[bs]=Napravi podatkovni CD koristeći K3b... +Name[ca]=Crea un CD de dades amb el K3b... +Name[cs]=Vytvořit datové CD... +Name[da]=Lav data-cd med K3b... +Name[de]=Daten-CD mit K3b erstellen ... +Name[el]=Δημιουργία CD δεδομένων με το K3b... +Name[eo]=Kreu datuman KD per K3b... +Name[es]=Crear CD de datos con K3b... +Name[et]=Kirjuta andme-CD K3b abil... +Name[fa]=ایجاد دیسک فشردۀ داده با K3b... +Name[fi]=Luo data-cd K3b:llä... +Name[fr]=Créer un CD de données avec K3b... +Name[gl]=Criar un CD de Dados con K3b... +Name[he]=צור תקליטורי מידע CD בעזרת K3b... +Name[hi]=के3बी के साथ डाटा सीडी बनाए... +Name[hu]=Adat-CD létrehozása a K3b-vel... +Name[is]=Búa til gagnadisk með K3b... +Name[it]=Crea CD dati con K3b... +Name[ja]=K3b でデータ CD を作成... +Name[ka]=K3b-ით მონაცემთა CD-ის ჩაწერა... +Name[km]=បង្កើត​ស៊ីឌី​ទិន្ន័យ​ជាមួយនឹង K3b... +Name[lt]=Kurti duomenų CD su K3b... +Name[mk]=Креирајте податочно CD со K3b... +Name[ms]= Cipta CD Data dengan K3b... +Name[nb]=Lag data-CD med K3b . . . +Name[nds]=Daten-CD mit K3b opstellen... +Name[ne]=K3b... +Name[nl]=Gegevens-cd aanmaken met K3b... +Name[nn]=Lag data-CD med K3b … +Name[pa]=K2b ਨਾਲ ਡਾਟਾ CD ਬਣਾਓ... +Name[pl]=Stwórz płytę CD z danymi za pomocą K3b... +Name[pt]=Criar um CD de Dados com o K3b... +Name[pt_BR]=Criar CD de Dados com o K3b... +Name[ru]=Записать компакт-диск с данными, используя K3b... +Name[sk]=Vytvoriť dátové CD pomocou K3b... +Name[sl]=Ustvari podatkovni CD s K3b ... +Name[sr]=Направи CD са подацима помоћу K3b-а... +Name[sr@Latn]=Napravi CD sa podacima pomoću K3b-a... +Name[sv]=Skapa data-cd med K3b... +Name[ta]=தகவல் குறுந்தகட்டோடு K3b ஐ உருவாக்குக... +Name[tg]=Сабт кардани CD бо маълумотҳо,бо истифодабарии K3b... +Name[tr]=K3b ile Veri CD'si oluştur... +Name[uk]=Створити КД з даними за допомогою K3b... +Name[uz]=K3b yordamida maʼlumot CD yaratish +Name[uz@cyrillic]=K3b ёрдамида маълумот CD яратиш +Name[xh]=Yenza i CD yolwazi nge K3b... +Name[zh_CN]=用 K3b 创建数据 CD... +Name[zh_TW]=使用 K3b 建立資料 CD... +Icon=k3b + +[Desktop Action K3bAudioCDProject] +Exec=k3b --device %u --audiocd +Name=Create Audio CD with K3b... +Name[af]=Skep oudio CD met K3b... +Name[ar]= انشيء القرص المدمج السمعي بواسطة K3b ... +Name[bg]=Създаване на аудио CD с K3b... +Name[bn]=কে-থ্রি-বি দিয়ে অডিও সিডি তৈরি করো... +Name[br]=Krouiñ ur CD klevet gant K3b ... +Name[bs]=Napravio audio CD koristeći K3b... +Name[ca]=Crea un CD d'àudio amb el K3b... +Name[cs]=Vytvořit zvukové CD... +Name[da]=Lav lyd-cd med K3b... +Name[de]=Audio-CD mit K3b erstellen ... +Name[el]=Δημιουργία CD ήχου με το K3b... +Name[eo]=Kreu sonan KD per K3b... +Name[es]=Crear CD de audio con K3b... +Name[et]=Kirjuta audio-CD K3b abil... +Name[fa]=ایجاد دیسک فشردۀ صوتی با K3b... +Name[fi]=Luo musiikki-cd K3b:llä... +Name[fr]=Créer un CD audio avec K3b... +Name[gl]=Criar un CD de Áudio con K3b... +Name[he]=צור תקליטור שמע בעזרת K3b... +Name[hi]=के3बी के साथ ऑडियो सीडी बनाए... +Name[hu]=Hang-CD létrehozása a K3b-vel... +Name[is]=Búa til hljóðdisk með K3b... +Name[it]=Crea CD audio con K3b... +Name[ja]=K3b でオーディオ CD を作成... +Name[ka]=K3b-ით Audio CD-ის ჩაწერა... +Name[km]=បង្កើត​ស៊ីឌី​អូឌីយ៉ូ​ជាមួយ​នឹង K3b... +Name[lt]=Kurti audio CD su K3b... +Name[mk]=Креирајте аудио-CD со K3b... +Name[ms]= Cipta Audio CD dengan K3b... +Name[nb]=Lag lyd-CD med K3b . . . +Name[nds]=Audio-CD mit K3b opstellen... +Name[ne]=K3b सँग अडियो सीडी सिर्जना गर्नुहोस्... +Name[nl]=Audio-cd aanmaken met K3b... +Name[nn]=Lag lyd-CD med K3b … +Name[pa]=K2b ਨਾਲ ਆਡੀਓ CD ਬਣਾਓ... +Name[pl]=Stwórz płytę CD Audio za pomocą K3b... +Name[pt]=Criar um CD de Áudio com o K3b... +Name[pt_BR]=Criar CD de Áudio com o K3b... +Name[ru]=Записать аудио компакт-диск, используя K3b... +Name[sk]=Vytvoriť audio CD pomocou K3b... +Name[sl]=Ustvari avdio CD s K3b ... +Name[sr]=Направи аудио CD помоћу K3b-а... +Name[sr@Latn]=Napravi audio CD pomoću K3b-a... +Name[sv]=Skapa ljud-cd med K3b... +Name[ta]=ஒலிக் குறுந்தகட்டோடு K3bயை உருவாக்குக... +Name[tg]=Сабт кардани аудио компакт-диск бо истифодаи K3b... +Name[tr]=K3b ile Ses CD'si oluştur... +Name[uk]=Створити аудіо-КД за допомогою K3b... +Name[uz]=K3b yordamida audio CD yaratish +Name[uz@cyrillic]=K3b ёрдамида аудио CD яратиш +Name[xh]=Yenza i CD Yokuvakalayo nge K3b... +Name[zh_CN]=用 K3b 创建音频 CD... +Name[zh_TW]=使用 K3b 建立音樂 CD... +Icon=k3b diff --git a/src/konqi/k3b_handle_empty_dvd.desktop b/src/konqi/k3b_handle_empty_dvd.desktop new file mode 100644 index 0000000..a4e5de1 --- /dev/null +++ b/src/konqi/k3b_handle_empty_dvd.desktop @@ -0,0 +1,110 @@ +[Desktop Entry] +ServiceTypes=media/blankdvd +Actions=K3bDataProject; +X-KDE-Priority=TopLevel + +[Desktop Action K3bDataProject] +Exec=k3b --device %u --datadvd +Name=Create Data CD with K3b... +Name[af]=Skep data CD met K3b... +Name[ar]= انشيء القرص المدمج لحفظ البيانات (Data) بواسطة K3b ... +Name[bg]=Създаване на CD с данни с K3b... +Name[bn]=কে-থ্রি-বি দিয়ে ডেটা-সিডি তৈরি করো... +Name[br]=Krouiñ ur CD roadoù gant K3b ... +Name[bs]=Napravi podatkovni CD koristeći K3b... +Name[ca]=Crea un CD de dades amb el K3b... +Name[cs]=Vytvořit datové CD... +Name[da]=Lav data-cd med K3b... +Name[de]=Daten-CD mit K3b erstellen ... +Name[el]=Δημιουργία CD δεδομένων με το K3b... +Name[eo]=Kreu datuman KD per K3b... +Name[es]=Crear CD de datos con K3b... +Name[et]=Kirjuta andme-CD K3b abil... +Name[fa]=ایجاد دیسک فشردۀ داده با K3b... +Name[fi]=Luo data-cd K3b:llä... +Name[fr]=Créer un CD de données avec K3b... +Name[gl]=Criar un CD de Dados con K3b... +Name[he]=צור תקליטורי מידע CD בעזרת K3b... +Name[hi]=के3बी के साथ डाटा सीडी बनाए... +Name[hu]=Adat-CD létrehozása a K3b-vel... +Name[is]=Búa til gagnadisk með K3b... +Name[it]=Crea CD dati con K3b... +Name[ja]=K3b でデータ CD を作成... +Name[ka]=K3b-ით მონაცემთა CD-ის ჩაწერა... +Name[km]=បង្កើត​ស៊ីឌី​ទិន្ន័យ​ជាមួយនឹង K3b... +Name[lt]=Kurti duomenų CD su K3b... +Name[mk]=Креирајте податочно CD со K3b... +Name[ms]= Cipta CD Data dengan K3b... +Name[nb]=Lag data-CD med K3b . . . +Name[nds]=Daten-CD mit K3b opstellen... +Name[ne]=K3b... +Name[nl]=Gegevens-cd aanmaken met K3b... +Name[nn]=Lag data-CD med K3b … +Name[pa]=K2b ਨਾਲ ਡਾਟਾ CD ਬਣਾਓ... +Name[pl]=Stwórz płytę CD z danymi za pomocą K3b... +Name[pt]=Criar um CD de Dados com o K3b... +Name[pt_BR]=Criar CD de Dados com o K3b... +Name[ru]=Записать компакт-диск с данными, используя K3b... +Name[sk]=Vytvoriť dátové CD pomocou K3b... +Name[sl]=Ustvari podatkovni CD s K3b ... +Name[sr]=Направи CD са подацима помоћу K3b-а... +Name[sr@Latn]=Napravi CD sa podacima pomoću K3b-a... +Name[sv]=Skapa data-cd med K3b... +Name[ta]=தகவல் குறுந்தகட்டோடு K3b ஐ உருவாக்குக... +Name[tg]=Сабт кардани CD бо маълумотҳо,бо истифодабарии K3b... +Name[tr]=K3b ile Veri CD'si oluştur... +Name[uk]=Створити КД з даними за допомогою K3b... +Name[uz]=K3b yordamida maʼlumot CD yaratish +Name[uz@cyrillic]=K3b ёрдамида маълумот CD яратиш +Name[xh]=Yenza i CD yolwazi nge K3b... +Name[zh_CN]=用 K3b 创建数据 CD... +Name[zh_TW]=使用 K3b 建立資料 CD... +Name=Create Data DVD with K3b... +Name[af]=Skep 'n Data DVD m.b.v. K3b... +Name[ar]= انشيء القرص المرئي الرقمي (DVD) لحفظ البيانات (Data) بواسطة K3b ... +Name[bg]=Създаване на DVD с данни с K3b... +Name[bn]=কে-থ্রি-বি দিয়ে ডেটা-ডিভিডি তৈরি করো... +Name[br]=Krouiñ un DVD roadoù gant K3b ... +Name[ca]=Crea un DVD de dades amb el K3b... +Name[cs]=Vytvořit datové DVD... +Name[da]=Lav data-cd med K3b... +Name[de]=Daten-DVD mit K3b erstellen ... +Name[el]=Δημιουργία DVD δεδομένων με το K3b... +Name[eo]=Kreu datuman DVD per K3b... +Name[es]=Crear DVD de datos con K3b... +Name[et]=Kirjuta andme-DVD K3b abil... +Name[fa]=ایجاد دی وی دی داده با K3b... +Name[fi]=Luo data-dvd K3b:llä... +Name[fr]=Créer un DVD de données avec K3b... +Name[gl]=Criar un DVD de Dados con K3b... +Name[he]=צור תקליטורי מידע DVD בעזרת K3b... +Name[hu]=Adat-DVD létrehozása a K3b-vel... +Name[is]=Búa til DVD gagnadisk með K3b... +Name[it]=Crea DVD dati con K3b... +Name[ja]=K3b でデータ DVD を作成... +Name[ka]=K3b-ით მონაცემთა DVD-ის ჩაწერა... +Name[km]=បង្កើត​ឌីវីឌី​ទិន្នន័យ​ដោយ​ប្រើ K3b... +Name[lt]=Kurti duomenų DVD su K3b... +Name[mk]=Креирајте податочно DVD со K3b... +Name[ms]=Cipta DVD Data dengan K3b... +Name[nb]=Lag data-DVD med K3b . . . +Name[nds]=Daten-DVD mit K3b opstellen... +Name[nl]=Gegevens-dvd aanmaken met K3b... +Name[nn]=Lag data-DVD med K3b … +Name[pa]=K3b ਨਾਲ ਡਾਟਾ DVD ਬਣਾਓ... +Name[pl]=Stwórz płytę DVD z danymi za pomocą K3b... +Name[pt]=Criar um DVD de Dados com o K3b... +Name[pt_BR]=Criar DVD de Dados com o K3b... +Name[ru]=Записать DVD с данными, используя K3b... +Name[sk]=Vytvoriť dátové DVD pomocou K3b... +Name[sr]=Направи DVD са подацима помоћу K3b-а... +Name[sr@Latn]=Napravi DVD sa podacima pomoću K3b-a... +Name[sv]=Skapa data-dvd med K3b... +Name[tg]=Сабт кардани Маълумотҳои CD бо истифодабарии K3b... +Name[tr]=K3b ile Veri DVD'si oluştur... +Name[uk]=Створити DVD з даними у K3b... +Name[uz]=K3b yordamida maʼlumot DVD yaratish +Name[uz@cyrillic]=K3b ёрдамида маълумот DVD яратиш +Name[zh_CN]=用 K3b 创建数据 DVD... +Name[zh_TW]=使用 K3b 建立資料 DVD... +Icon=k3b diff --git a/src/konqi/k3b_videodvd_rip.desktop b/src/konqi/k3b_videodvd_rip.desktop new file mode 100644 index 0000000..1c7a8d5 --- /dev/null +++ b/src/konqi/k3b_videodvd_rip.desktop @@ -0,0 +1,48 @@ +[Desktop Entry] +ServiceTypes=media/dvdvideo +Actions=K3bRip; +X-KDE-Priority=TopLevel + +[Desktop Action K3bRip] +Name=Rip Video DVD Titles with K3b +Name[af]=Kopiëer Video DVD titels m.b.v. K3b +Name[ar]= استخرج عناوين مرئيات من القرص المرئي الرقمي (DVD) بواسطة K3b +Name[bg]=Извличане на DVD заглавия с K3b +Name[ca]=Extreure pistes de DVD amb el K3b +Name[cs]=Ripovat titulky video DVD pomocí K3b +Name[da]=Rip dvd-titler med K3b +Name[de]=DVD-Titel mit K3b auslesen +Name[el]=Εξαγωγή τίτλων DVD με το K3b +Name[eo]=Ekstraktu videan DVD titolojn per K3b +Name[es]=Extraer títulos de DVD de vídeo con K3b +Name[et]=Ripi video-DVD tiitlid K3b abil +Name[fa]=تبدیل عناوین دی وی دی ویدئویی با K3b +Name[fi]=Pura dvd K3b:llä +Name[fr]=Extraire les titres du DVD avec K3b +Name[gl]=Gravar título de Vídeo DVD con K3b +Name[hu]=Video DVD-címek beolvasása a K3b-vel +Name[is]=Afrita DVD titla með K3b +Name[it]=Estrai titoli DVD video con K3b +Name[ja]=K3b で DVD タイトルを吸い出し... +Name[km]=ច្រៀក​ចំណង​ជើង​ឌីវីឌី​វីដេអូ​ដោយ​ប្រើ K3b +Name[lt]=Nurašyti video DVD su K3b +Name[ms]=Keluarkan Tajuk Video DVD dengan K3b +Name[nds]=Video-DVD-Stücken mit K3b utlesen +Name[nl]=Video-dvd-titels rippen met K3b +Name[nn]=Hent ut film-DVD-titlar med K3b +Name[pa]=K3b ਨਾਲ ਵੀਡਿਓ DVD ਟਾਇਟਲ ਰਿਪ +Name[pl]=Zgraj filmy z płyty DVD Video za pomocą K3b +Name[pt]=Extrair os Títulos do DVD de Vídeo com o K3b +Name[pt_BR]=Ripar DVD de Vídeo com o K3b +Name[sk]=Ripovať video DVD titulky pomocou K3b +Name[sr]=Исчупај титлове са видео DVD-а помоћу K3b-а +Name[sr@Latn]=Isčupaj titlove sa video DVD-a pomoću K3b-a +Name[sv]=Lagra dvd-titlar med K3b +Name[tr]=K3b ile Görüntü DVD'si Başlıklarını Aktar +Name[uk]=Видерти заголовки з відео-DVD за допомогою K3b +Name[uz]=K3b yordamida filmlarni video-faylga aylantirish +Name[uz@cyrillic]=K3b ёрдамида филмларни видео-файлга айлантириш +Name[zh_CN]=用 K3b 提取视频 DVD +Name[zh_TW]=使用 K3b 提取視像 DVD Titles +Exec=k3b --videodvdrip %u +Icon=k3b diff --git a/src/konqi/k3b_write_bin_image.desktop b/src/konqi/k3b_write_bin_image.desktop new file mode 100644 index 0000000..40a021c --- /dev/null +++ b/src/konqi/k3b_write_bin_image.desktop @@ -0,0 +1,62 @@ +[Desktop Entry] +Actions=WriteCdImage; +Encoding=UTF-8 +ServiceTypes=application/x-cue + +[Desktop Action WriteCdImage] +Exec=k3b --cdimage %F +Name=Write CD Image with K3b... +Name[af]=Skryf CD beeld met K3b... +Name[ar]= اكتب صورة (Image DATA) على القرص المدمج (CD) بواسطة K3b . +Name[bg]=Запис на CD образ с K3b... +Name[bn]=কে-থ্রি-বি দিয়ে সিডি ইমেজ লেখো... +Name[br]=srivañ ar skeudenn CD gant K3b ... +Name[bs]=Zapiši CD image koristeći K3b... +Name[ca]=Escriu imatge de CD amb el K3b... +Name[cs]=Vypálit obraz CD... +Name[da]=Skriv cd-billede med K3b... +Name[de]=CD-Abbild mit K3b brennen ... +Name[el]=Εγγραφή εικόνας CD με το K3b... +Name[eo]=Skribu KD imagon per K3b... +Name[es]=Grabar imagen de CD con K3b... +Name[et]=Kirjuta CD-tõmmis K3b abil plaadile... +Name[fa]=نوشتن تصویر دیسک فشرده با K3b... +Name[fi]=Polta levykuva cd-levylle K3b:llä... +Name[fr]=Graver une image CD avec K3b... +Name[gl]=Escrever unha Imaxe de CD con K3b... +Name[he]=כתוב תבנית CD בעזרת K3b... +Name[hi]=के3बी के साथ सीडी इमेज लिखें... +Name[hu]=CD-képmásfájl írása a K3b-vel... +Name[is]=Skrifa diskmynd með K3b... +Name[it]=Scrivi immagine CD con K3b... +Name[ja]=K3b で CD イメージを書き込み... +Name[ka]=K3b-ით CD-ის გამოსახულების ჩაწერა... +Name[km]=សរសេរ​រូបភាព​ស៊ីឌី​ជាមួយ​នឹង K3b... +Name[lt]=Įrašyti CD atvaizdą su K3b... +Name[mk]=Запишете CD-слика со K3b... +Name[ms]= Tulis Imej CD dengan K3b... +Name[nb]=Skriv CD-bilde med K3b . . . +Name[nds]=CD-Afbild mit K3b schrieven... +Name[ne]=K3b सँग सीडी छवि सिर्जना गर्नुहोस्... +Name[nl]=CD-image schrijven met K3b... +Name[nn]=Brenn CD-bilete med K3b … +Name[pa]=K3b ਨਾਲ CD ਪ੍ਰਤੀਬਿੰਬ ਲਿਖੋ... +Name[pl]=Stwórz obraz płyty CD za pomocą K3b... +Name[pt]=Gravar uma Imagem de CD com o K3b... +Name[pt_BR]=Gravar Imagem de CD com o K3b... +Name[ru]=Записать образ CD, используя K3b... +Name[sk]=Zapísať obraz CD pomocou K3b... +Name[sl]=Zapiši sliko CD-ja s K3b ... +Name[sr]=Упиши одраз CD-а помоћу K3b-а... +Name[sr@Latn]=Upiši odraz CD-a pomoću K3b-a... +Name[sv]=Skriv cd-avbild med K3b... +Name[ta]=குறுந்தகட்டு நிழலுடன் K3bஐ உருவாக்குக... +Name[tg]=Сабт кардани намуди CD бо истифодабарии K3b... +Name[tr]=K3b ile CD Kalıbı Yazdır... +Name[uk]=Записати штамп КД за допомогою K3b... +Name[uz]=K3b yordamida CD tasvirini yozish +Name[uz@cyrillic]=K3b ёрдамида CD тасвирини ёзиш +Name[xh]=Bhala Umfanekiso we CD nge K3b... +Name[zh_CN]=用 K3b 刻录 CD 映像... +Name[zh_TW]=使用 K3b 燒錄 CD 影像... +Icon=k3b diff --git a/src/konqi/k3b_write_iso_image.desktop b/src/konqi/k3b_write_iso_image.desktop new file mode 100644 index 0000000..4e3e91e --- /dev/null +++ b/src/konqi/k3b_write_iso_image.desktop @@ -0,0 +1,55 @@ +[Desktop Entry] +Actions=WriteCdImage; +Encoding=UTF-8 +ServiceTypes=application/x-iso,inode/ISO-image + +[Desktop Action WriteCdImage] +Exec=k3b --image %F +Name=Write CD or DVD Image with K3b... +Name[af]=Skryf CD of DVD beeld lêer m.b.v. K3b... +Name[ar]= اكتب صورة على القرص المدمج (CD) او على القرص المرئي الرقمي (DVD) بواسطة K3b . +Name[bg]=Запис на CD или DVD образ с K3b... +Name[bn]=কে-থ্রি-বি দিয়ে সিডি অথবা ডিভিডি ইমেজ লেখো... +Name[br]=srivañ ur skeudenn CD pe DVD gant K3b ... +Name[ca]=Escriu imatge de CD o DVD amb el K3b... +Name[cs]=Vypálit obraz CD nebo DVD pomocí K3b... +Name[da]=Skriv cd- eller dvd-billede med K3b... +Name[de]=CD/DVD-Abbild mit K3b brennen ... +Name[el]=Εγγραφή εικόνας CD ή DVD με το K3b... +Name[eo]=Skribu KD aŭ DVD imagon per K3b... +Name[es]=Grabar imagen de CD o DVD con K3b... +Name[et]=Kirjuta CD- või DVD-tõmmis K3b abil plaadile... +Name[fa]=نوشتن تصویر دیسک فشرده یا دی وی دی با K3b... +Name[fi]=Polta levykuva cd- tai dvd-levylle K3b:llä... +Name[fr]=Graver une image CD ou DVD avec K3b... +Name[gl]=Escrever unha Imaxe de CD ou DVD con K3b... +Name[hu]=CD- vagy DVD-képmásfájl írása a K3b-vel... +Name[is]=Skrifa CD eða DVD mynd með K3b... +Name[it]=Scrivi immagine CD o DVD con K3b... +Name[ja]=K3b で CD/DVD イメージを書き込み... +Name[ka]=K3b-ით CD ან DVD გამოსახულების ჩაწერა... +Name[km]=សរសេរ​​រូបភាព​ស៊ីឌី ឬ​ឌីវីឌី​ដោយ​ប្រើ K3b... +Name[lt]=Įrašyti CD ar DVD atvaizdą su K3b... +Name[mk]=Запишете CD или DVD-слика со K3b... +Name[ms]=Tulis Imej CD atau DVD dengan K3b... +Name[nb]=Skriv CD- eller DVD-bilde med K3b . . . +Name[nds]=CD- oder DVD-Afbild mit K3b schrieven... +Name[nl]=CD of DVD-image schrijven met K3b... +Name[nn]=Brenn CD- eller DVD-bilete med K3b … +Name[pa]=K3b ਨਾਲ CD ਜਾਂ DVD ਪ੍ਰਤੀਬਿੰਬ ਲਿਖੋ... +Name[pl]=Nagraj obraz płyty CD lub DVD na płytę za pomocą K3b... +Name[pt]=Escrever uma Imagem de CD ou DVD com o K3b... +Name[pt_BR]=Gravar Imagem de CD ou DVD com o K3b... +Name[ru]=Записать образ CD или DVD, используя K3b... +Name[sk]=Zapísať obraz CD alebo DVD pomocou K3b... +Name[sr]=Упиши CD или DVD одраз помоћу K3b-а... +Name[sr@Latn]=Upiši CD ili DVD odraz pomoću K3b-a... +Name[sv]=Skriv cd- eller dvd-avbild med K3b... +Name[tg]=Сабт кардани тасвири CD ё DVD бо истифодабарии K3b... +Name[tr]=K3b ile CD ya da DVD görüntüsü Yazdır... +Name[uk]=Записати штамп КД або DVD у K3b... +Name[uz]=K3b yordamida CD yoki DVD tasvirini yozish +Name[uz@cyrillic]=K3b ёрдамида CD ёки DVD тасвирини ёзиш +Name[zh_CN]=用 K3b 刻录 CD 或 DVD 映像... +Name[zh_TW]=使用 K3b 燒錄 CD 或 DVD 影像... +Icon=k3b diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..d595281 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,152 @@ + +/* + * + * $Id: main.cpp 689578 2007-07-18 15:56:58Z trueg $ + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include <kcmdlineargs.h> +#include <kaboutdata.h> +#include <klocale.h> +#include <kprocess.h> +#include <kmessagebox.h> +#include <kstandarddirs.h> +#include <ksimpleconfig.h> +#include <kstdguiitem.h> +#include <kdebug.h> +#include <dcopclient.h> +#include <dcopref.h> +#include <kurl.h> + +#include <qfile.h> +#include <qcstring.h> +#include <qdatastream.h> +#include <qtimer.h> + +#include <stdlib.h> + +#include "k3bapplication.h" +#include <k3bglobals.h> +#include <k3bcore.h> + + +#include <config.h> + +static const char* description = I18N_NOOP("A CD and DVD burning application"); + + +static KCmdLineOptions options[] = + { + { "+[URL(s)]", I18N_NOOP("file(s) to open"), 0 }, + { "datacd", I18N_NOOP("Create a new data CD project and add all given files"), 0 }, + { "audiocd", I18N_NOOP("Create a new audio CD project and add all given files"), 0 }, + { "videocd", I18N_NOOP("Create a new video CD project and add all given files"), 0 }, + { "mixedcd", I18N_NOOP("Create a new mixed mode CD project and add all given files"), 0 }, + { "emovixcd", I18N_NOOP("Create a new eMovix CD project and add all given files"), 0 }, + { "datadvd", I18N_NOOP("Create a new data DVD project and add all given files"), 0 }, + { "emovixdvd", I18N_NOOP("Create a new eMovix DVD project and add all given files"), 0 }, + { "videodvd", I18N_NOOP("Create a new Video DVD project and add all given files"), 0 }, + { "burn", I18N_NOOP("Open the project burn dialog for the current project"), 0 }, + { "copycd <device>", I18N_NOOP("Open the CD copy dialog, optionally specify the source device"), 0 }, + { "copydvd <device>", I18N_NOOP("Open the DVD copy dialog"), 0 }, + { "cdimage <url>", I18N_NOOP("Write a CD image to a CD-R(W)"), 0 }, + { "dvdimage <url>", I18N_NOOP("Write a DVD ISO9660 image to a DVD"), 0 }, + { "image <url>", I18N_NOOP("Write a CD or DVD image to a CD-R(W) or DVD depending on the size"), 0 }, + { "erasecd <device>", I18N_NOOP("Erase a CDRW"), 0 }, + { "formatdvd <device>", I18N_NOOP("Format a DVD-RW or DVD+RW"), 0 }, + { "cddarip <device>", I18N_NOOP("Extract Audio tracks digitally (+encoding)"), 0 }, + { "videodvdrip <device>", I18N_NOOP("Rip Video DVD Titles (+transcoding)"), 0 }, + { "videocdrip <device>", I18N_NOOP("Rip Video CD Tracks"), 0 }, + { "lang <language>", I18N_NOOP("Set the GUI language"), 0 }, + { "nosplash", I18N_NOOP("Disable the splash screen"), 0 }, + { "ao <method>", I18N_NOOP("Set the audio output method (like arts or alsa depending on the installed plugins)"), 0 }, + { "device <device>", I18N_NOOP( "Set the device to be used for new projects (This option has no effect. " + "Its main purpose is to enable handling of empty media from the KDE Media Manager)." ), 0 }, + KCmdLineLastOption + }; + +int main( int argc, char* argv[] ) +{ + KAboutData aboutData( "k3b", "K3b", + LIBK3B_VERSION, description, KAboutData::License_GPL, + "(c) 1999 - 2007, Sebastian Trüg", 0, "http://www.k3b.org" ); + aboutData.addAuthor("Sebastian Trüg",I18N_NOOP("Maintainer and Lead Developer"), "trueg@k3b.org"); + aboutData.addAuthor("Christian Kvasny",I18N_NOOP("VideoCD Project and VideoCD ripping"), "chris@k3b.org"); + aboutData.addCredit("Klaus-Dieter Krannich", I18N_NOOP("Advanced Cdrdao integration"), "kd@k3b.org" ); + + aboutData.addCredit("Thomas Froescher", + I18N_NOOP("VideoDVD ripping and video encoding in pre-1.0 versions."), + "tfroescher@k3b.org"); + aboutData.addCredit("Alexis Younes aka Ayo", + I18N_NOOP("For his bombastic artwork."), + "73lab@free.fr" ); + aboutData.addCredit("Christoph Thielecke", + I18N_NOOP("For extensive testing and the first German translation."), + "crissi99@gmx.de"); + aboutData.addCredit("Andy Polyakov", + I18N_NOOP("For the great dvd+rw-tools and the nice cooperation."), + "appro@fy.chalmers.se" ); + aboutData.addCredit("Roberto De Leo", + I18N_NOOP("For the very cool eMovix package and his accommodating work."), + "peggish@users.sf.net" ); + aboutData.addCredit("John Steele Scott", + I18N_NOOP("For the flac decoding plugin."), + "toojays@toojays.net" ); + aboutData.addCredit("György Szombathelyi", + I18N_NOOP("For the very useful isofslib."), + "gyurco@users.sourceforge.net" ); + aboutData.addCredit("Erik de Castro Lopo", + I18N_NOOP("For libsamplerate which is used for generic resampling in the audio decoder framework."), + "erikd@mega-nerd.com" ); + aboutData.addCredit("Jakob Petsovits", + I18N_NOOP("For the very cool conditional audio ripping pattern."), + "jpetso@gmx.at" ); + aboutData.addCredit("Heiner Eichmann", + I18N_NOOP("For his work on the BSD port and some great patches."), + "h.eichmann@gmx.de" ); + aboutData.addCredit("Adriaan De Groot", + I18N_NOOP("For his work on the BSD port."), + "" ); + aboutData.addCredit("Thiago Macieira", + I18N_NOOP("For his help with the many invalid k3b entries on bugs.kde.org."), + "thiago@kde.org" ); + aboutData.addCredit("Marcel Dierkes", + I18N_NOOP("For the great K3b icon eyecandy."), + "marcel.dierkes@gmx.de" ); + aboutData.addCredit("Christoph Burger-Scheidlin", + I18N_NOOP("For his neverending help cleaning out the K3b bug database."), + "andersin@freenet.de" ); + aboutData.addCredit( "Robert Wadley", + I18N_NOOP( "Rob created a great theme and came up with the idea for transparent themes." ), + "rob@robntina.fastmail.us" ); + aboutData.addCredit( "Dmitry Novikov", + I18N_NOOP( "For the amazing K3b 1.0 theme." ), + "quant@trktvs.ru" ); + + KCmdLineArgs::init( argc, argv, &aboutData ); + KCmdLineArgs::addCmdLineOptions( options ); // Add our own options. + + if( K3bApplication::start() ) { + KCmdLineArgs* args = KCmdLineArgs::parsedArgs(); + if( args->isSet("lang") ) + if( !KGlobal::locale()->setLanguage(args->getOption("lang")) ) + kdDebug() << "Unable to set to language " << args->getOption("lang") + << " current is: " << KGlobal::locale()->language() << endl; + + K3bApplication app; + + // we need a running app for the init method + QTimer::singleShot( 0, &app, SLOT(init()) ); + + return app.exec(); + } +} diff --git a/src/mimetypes/Makefile.am b/src/mimetypes/Makefile.am new file mode 100644 index 0000000..8f0fb98 --- /dev/null +++ b/src/mimetypes/Makefile.am @@ -0,0 +1,3 @@ +kdemime_DATA = x-k3b.desktop +kdemimedir = $(kde_mimedir)/application + diff --git a/src/mimetypes/x-k3b.desktop b/src/mimetypes/x-k3b.desktop new file mode 100644 index 0000000..49c7c34 --- /dev/null +++ b/src/mimetypes/x-k3b.desktop @@ -0,0 +1,65 @@ +# KDE Config File +[Desktop Entry] +Encoding=UTF-8 +MimeType=application/x-k3b +Comment=K3b Project +Comment[af]=K3b Projek +Comment[ar]= مشروع K3b +Comment[bg]=K3b проект +Comment[bn]=কে-থ্রি-বি প্রকল্প +Comment[br]=Raktres K3b +Comment[bs]=K3b projekat +Comment[ca]=Projecte de K3b +Comment[cs]=K3b projekt +Comment[da]=K3b-projekt +Comment[de]=K3b-Projekt +Comment[el]=Έργο K3b +Comment[eo]=K3b projekto +Comment[es]=Proyecto de K3b +Comment[et]=K3b Projekt +Comment[fa]=پروژۀ K3b +Comment[fi]=K3b-projekti +Comment[fr]=Projet K3b +Comment[gl]=Proxecto de K3b +Comment[he]=פרוייקט K3b +Comment[hi]=के3बी परियोजना +Comment[hu]=K3b-projekt +Comment[is]=K3b verkefni +Comment[it]=Progetto K3b +Comment[ja]=K3b プロジェクト +Comment[ka]=K3b-ის პროექტი +Comment[km]=គម្រោង K3b +Comment[lt]=K3b projektas +Comment[mk]=Проект за K3b +Comment[ms]=Projek K3b +Comment[nb]=K3b-prosjekt +Comment[nds]=K3b-Projekt +Comment[ne]=K3b परियोजना +Comment[nl]=K3b-project +Comment[nn]=K3b-prosjekt +Comment[pa]=K3b ਪ੍ਰੋਜੈੱਕਟ +Comment[pl]=Projekt K3b +Comment[pt]=Projecto do K3b +Comment[pt_BR]=Projeto do K3b +Comment[ru]=Проект K3b +Comment[sk]=K3b Projekt +Comment[sl]=Projekt K3b +Comment[sr]=K3b-ов пројекат +Comment[sr@Latn]=K3b-ov projekat +Comment[sv]=K3b-projekt +Comment[ta]=K3bதிட்டம் +Comment[tg]=Лоиҳаи K3b +Comment[tr]=K3b Projesi +Comment[uk]=Проект K3b +Comment[uz]=K3b loyihasi +Comment[uz@cyrillic]=K3b лойиҳаси +Comment[xh]=Iprojekti ye K3b +Comment[zh_CN]=K3b 方案 +Comment[zh_TW]=K3b 專案 +Icon=k3b +Type=MimeType +Patterns=*.k3b; +X-KDE-AutoEmbed=false +[Property::X-KDE-NativeExtension] +Type=QString +Value=.k3b diff --git a/src/misc/Makefile.am b/src/misc/Makefile.am new file mode 100644 index 0000000..ea1809b --- /dev/null +++ b/src/misc/Makefile.am @@ -0,0 +1,14 @@ +AM_CPPFLAGS = -I$(srcdir)/../../libk3b/core \ + -I$(srcdir)/../../libk3bdevice \ + -I$(srcdir)/../../libk3b/tools \ + -I$(srcdir)/../../libk3b/jobs \ + -I$(srcdir)/../../libk3b/projects \ + -I$(srcdir)/.. \ + $(all_includes) + +METASOURCES = AUTO + +noinst_LTLIBRARIES = libmisc.la + +libmisc_la_SOURCES = k3bdvdformattingdialog.cpp k3bcdcopydialog.cpp k3bdvdcopydialog.cpp \ + k3bcdimagewritingdialog.cpp k3bisoimagewritingdialog.cpp k3bblankingdialog.cpp diff --git a/src/misc/k3bblankingdialog.cpp b/src/misc/k3bblankingdialog.cpp new file mode 100644 index 0000000..5f4b531 --- /dev/null +++ b/src/misc/k3bblankingdialog.cpp @@ -0,0 +1,343 @@ +/* + * + * $Id: k3bblankingdialog.cpp 689551 2007-07-18 14:53:32Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bblankingdialog.h" +#include "k3bdebuggingoutputdialog.h" +#include "k3bdebuggingoutputfile.h" + +#include <k3bdevice.h> +#include <k3bdevicemanager.h> +#include "k3bblankingjob.h" +#include "k3bwriterselectionwidget.h" +#include <k3bprogressdialog.h> +#include <k3bglobals.h> +#include <k3bcore.h> +#include <k3bemptydiscwaiter.h> + +#include <klocale.h> +#include <kmessagebox.h> +#include <klistview.h> +#include <kiconloader.h> +#include <kguiitem.h> +#include <kstdguiitem.h> +#include <kconfig.h> + +#include <qgroupbox.h> +#include <qpushbutton.h> +#include <qcheckbox.h> +#include <qlayout.h> +#include <qtextview.h> +#include <qcombobox.h> +#include <qlabel.h> +#include <qheader.h> +#include <qmap.h> +#include <qtooltip.h> +#include <qwhatsthis.h> + + + +class K3bBlankingDialog::Private +{ +public: + Private() + : job(0), + erasingDlg(0) { + } + + K3bBlankingJob* job; + K3bProgressDialog* erasingDlg; + K3bDebuggingOutputDialog* debugDialog; + K3bDebuggingOutputFile debugFile; + QMap<int, int> comboTypeMap; + QMap<int, int> typeComboMap; + + bool jobRunning; +}; + + +K3bBlankingDialog::K3bBlankingDialog( QWidget* parent, const char* name ) + : K3bInteractionDialog( parent, name, + i18n("Erase CD-RW"), + QString::null, + START_BUTTON|CANCEL_BUTTON, + START_BUTTON, + "CDRW Erasing" ) +{ + d = new Private(); + d->debugDialog = new K3bDebuggingOutputDialog( this ); + + setupGui(); + + connect( m_writerSelectionWidget, SIGNAL(writerChanged()), this, SLOT(slotWriterChanged()) ); + connect( m_writerSelectionWidget, SIGNAL(writingAppChanged(int)), this, SLOT(slotWritingAppChanged(int)) ); + slotWriterChanged(); + slotWritingAppChanged( m_writerSelectionWidget->writingApp() ); +} + + +K3bBlankingDialog::~K3bBlankingDialog() +{ + delete d; +} + + +void K3bBlankingDialog::setDevice( K3bDevice::Device* dev ) +{ + m_writerSelectionWidget->setWriterDevice( dev ); +} + + +void K3bBlankingDialog::setupGui() +{ + QWidget* frame = mainWidget(); + + m_writerSelectionWidget = new K3bWriterSelectionWidget( frame ); + m_writerSelectionWidget->setWantedMediumType( K3bDevice::MEDIA_CD_RW ); + m_writerSelectionWidget->setWantedMediumState( K3bDevice::STATE_COMPLETE|K3bDevice::STATE_INCOMPLETE ); + + // --- setup the blanking type button group ----------------------------- + QGroupBox* groupBlankType = new QGroupBox( 1, Qt::Vertical, i18n("&Erase Type"), frame ); + groupBlankType->layout()->setSpacing( spacingHint() ); + groupBlankType->layout()->setMargin( marginHint() ); + + m_comboEraseMode = new QComboBox( groupBlankType ); + // ---------------------------------------------------------------------- + + QGridLayout* grid = new QGridLayout( frame ); + grid->setSpacing( spacingHint() ); + grid->setMargin( 0 ); + grid->addWidget( m_writerSelectionWidget, 0, 0 ); + grid->addWidget( groupBlankType, 1, 0 ); +} + + +void K3bBlankingDialog::slotStartClicked() +{ + // start the blankingjob and connect to the info-signal + // disable the user1 button and enable the cancel button + d->debugDialog->clear(); + d->debugFile.open(); + + if( d->job == 0 ) { + d->job = new K3bBlankingJob( this, this ); + connect( d->job, SIGNAL(debuggingOutput(const QString&, const QString&)), + d->debugDialog, SLOT(addOutput(const QString&, const QString&)) ); + connect( d->job, SIGNAL(debuggingOutput(const QString&, const QString&)), + &d->debugFile, SLOT(addOutput(const QString&, const QString&)) ); + connect( d->job, SIGNAL(finished(bool)), + this, SLOT(slotJobFinished(bool)) ); + } + + d->job->setDevice( m_writerSelectionWidget->writerDevice() ); + d->job->setSpeed( m_writerSelectionWidget->writerSpeed() ); + // why should one ever not want to force? + d->job->setForce( true ); + d->job->setWritingApp(m_writerSelectionWidget->writingApp()); + d->job->setMode( d->comboTypeMap[m_comboEraseMode->currentItem()] ); + + if( !d->erasingDlg ) + d->erasingDlg = new K3bProgressDialog( i18n("Erasing CD-RW"), this ); + + connect( d->erasingDlg, SIGNAL(cancelClicked()), d->job, SLOT(cancel()) ); + + if( !exitLoopOnHide() ) + hide(); + + d->jobRunning = true; + d->job->start(); + if( d->jobRunning ) // in case the job already finished in the start slot + d->erasingDlg->exec(false); + + if( KConfigGroup( k3bcore->config(), "General Options" ).readBoolEntry( "keep action dialogs open", false ) && + !exitLoopOnHide() ) + show(); + else + close(); +} + + +void K3bBlankingDialog::slotJobFinished( bool success ) +{ + d->jobRunning = false; + d->erasingDlg->hide(); + d->debugFile.close(); + + if( success ) + KMessageBox::information( this, + i18n("Successfully erased CD-RW."), + i18n("Success") ); + else if( d->job->hasBeenCanceled() ) + KMessageBox::information( this, + i18n("Erasing CD-RW canceled."), + i18n("Canceled") ); + else if( KMessageBox::warningYesNo( this, + i18n("The Erasing process failed. Do you want to see the debugging output?"), + i18n("Erasing failed.") ) == KMessageBox::Yes ) + d->debugDialog->exec(); +} + + +void K3bBlankingDialog::slotWriterChanged() +{ + // check if it is a cdrw writer + K3bDevice::Device* dev = m_writerSelectionWidget->writerDevice(); + + if( !dev ) + setButtonEnabled( START_BUTTON, false ); + else if( dev->writesCdrw() ) + setButtonEnabled( START_BUTTON, true ); + else { + setButtonEnabled( START_BUTTON, false ); + KMessageBox::sorry( this, i18n("%1 does not support CD-RW writing.").arg(dev->devicename()) ); + } +} + +void K3bBlankingDialog::slotWritingAppChanged(int app) +{ + QWhatsThis::remove( m_comboEraseMode ); + QString whatsThisInfo; + + static QString wsComplete = i18n("Erases the complete disk. This takes as long " + "as writing the complete CD."); + static QString wsFast = i18n("Erases just the TOC, the PMA, and the pregap."); + static QString wsTrack = i18n("Erases just the last track."); + static QString wsUnclose = i18n("Reopen the last session to make it possible to append " + "further data."); + static QString wsSession = i18n("Erases the last session of a multisession CD."); + + int lastMode = d->comboTypeMap[m_comboEraseMode->currentItem()]; + + m_comboEraseMode->clear(); + d->comboTypeMap.clear(); + d->typeComboMap.clear(); + + m_comboEraseMode->insertItem( i18n("Fast") ); + d->comboTypeMap[0] = K3bBlankingJob::Fast; + d->typeComboMap[K3bBlankingJob::Fast] = 0; + m_comboEraseMode->insertItem( i18n("Complete") ); + d->comboTypeMap[1] = K3bBlankingJob::Complete; + d->typeComboMap[K3bBlankingJob::Complete] = 1; + + whatsThisInfo = "<p>" + i18n("Blanking mode:") + + "<p><b>" + i18n("Fast") + "</b><br>" + wsFast; + whatsThisInfo += "<p><b>" + i18n("Complete") + "</b><br>" + wsComplete; + + if ( app != K3b::CDRDAO ) { + m_comboEraseMode->insertItem( i18n("Erase Last Track") ); + d->comboTypeMap[2] = K3bBlankingJob::Track; + d->typeComboMap[K3bBlankingJob::Track] = 2; + whatsThisInfo += "<p><b>" + i18n("Erase Last Track") + "</b><br>" + wsTrack; + m_comboEraseMode->insertItem( i18n("Reopen Last Session") ); + d->comboTypeMap[3] = K3bBlankingJob::Unclose; + d->typeComboMap[K3bBlankingJob::Unclose] = 3; + whatsThisInfo += "<p><b>" + i18n("Reopen Last Session") + "</b><br>" + wsUnclose; + m_comboEraseMode->insertItem( i18n("Erase Last Session") ); + d->comboTypeMap[4] = K3bBlankingJob::Session; + d->typeComboMap[K3bBlankingJob::Session] = 4; + whatsThisInfo += "<p><b>" + i18n("Erase Last Session") + "</b><br>" + wsSession; + } + + QWhatsThis::add( m_comboEraseMode, whatsThisInfo ); + + // try to reset last mode + if( d->typeComboMap.contains( lastMode ) ) + m_comboEraseMode->setCurrentItem( d->typeComboMap[lastMode] ); + else + m_comboEraseMode->setCurrentItem( d->typeComboMap[K3bBlankingJob::Fast] ); +} + + +void K3bBlankingDialog::loadK3bDefaults() +{ + m_writerSelectionWidget->loadDefaults(); + m_comboEraseMode->setCurrentItem( d->typeComboMap[K3bBlankingJob::Fast] ); +} + +void K3bBlankingDialog::loadUserDefaults( KConfigBase* c ) +{ + m_writerSelectionWidget->loadConfig( c ); + slotWritingAppChanged( m_writerSelectionWidget->writingApp() ); + + QString mode = c->readEntry( "erase_mode" ); + kdDebug() << "(K3bBlankingDialog) slotWritingAppChanged mode: " << mode << endl; + m_comboEraseMode->setCurrentItem( d->typeComboMap[K3bBlankingJob::Fast] ); + if( mode == "complete" ) + m_comboEraseMode->setCurrentItem( d->typeComboMap[K3bBlankingJob::Complete] ); + else if( d->typeComboMap.size() > 2 ) { + if( mode == "session" ) + m_comboEraseMode->setCurrentItem( d->typeComboMap[K3bBlankingJob::Session] ); + else if( mode == "track" ) + m_comboEraseMode->setCurrentItem( d->typeComboMap[K3bBlankingJob::Track] ); + else if( mode == "unclose_session" ) + m_comboEraseMode->setCurrentItem( d->typeComboMap[K3bBlankingJob::Unclose] ); + } +} + +void K3bBlankingDialog::saveUserDefaults( KConfigBase* c ) +{ + QString mode; + switch( d->comboTypeMap[m_comboEraseMode->currentItem()] ) { + case K3bBlankingJob::Complete: + mode = "complete"; + break; + case K3bBlankingJob::Session: + mode = "session"; + break; + case K3bBlankingJob::Track: + mode = "track"; + break; + case K3bBlankingJob::Unclose: + mode = "unclose_session"; + break; + default: + mode = "fast"; + break; + } + c->writeEntry( "erase_mode", mode ); + + m_writerSelectionWidget->saveConfig( c ); +} + + +int K3bBlankingDialog::waitForMedia( K3bDevice::Device* device, + int mediaState, + int mediaType, + const QString& message ) +{ + // this is only needed for the formatting + return K3bEmptyDiscWaiter::wait( device, mediaState, mediaType, message, this ); +} + + +bool K3bBlankingDialog::questionYesNo( const QString& text, + const QString& caption, + const QString& yesText, + const QString& noText ) +{ + return ( KMessageBox::questionYesNo( this, + text, + caption, + yesText.isEmpty() ? KStdGuiItem::yes() : KGuiItem(yesText), + noText.isEmpty() ? KStdGuiItem::no() : KGuiItem(noText) ) == KMessageBox::Yes ); +} + + +void K3bBlankingDialog::blockingInformation( const QString& text, + const QString& caption ) +{ + KMessageBox::information( this, text, caption ); +} + +#include "k3bblankingdialog.moc" diff --git a/src/misc/k3bblankingdialog.h b/src/misc/k3bblankingdialog.h new file mode 100644 index 0000000..cbd5583 --- /dev/null +++ b/src/misc/k3bblankingdialog.h @@ -0,0 +1,86 @@ +/* + * + * $Id: k3bblankingdialog.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3B_BLANKING_DIALOG_H +#define K3B_BLANKING_DIALOG_H + +#include "k3binteractiondialog.h" +#include <k3bjobhandler.h> + +class QGroupBox; +class QComboBox; +class QCloseEvent; +class KListView; +class K3bWriterSelectionWidget; +namespace K3bDevice { + class Device; +} + + +class K3bBlankingDialog : public K3bInteractionDialog, public K3bJobHandler +{ +Q_OBJECT + + public: + K3bBlankingDialog( QWidget*, const char* ); + ~K3bBlankingDialog(); + + /** + * @reimplemented from K3bJobHandler + */ + int waitForMedia( K3bDevice::Device*, + int mediaState = K3bDevice::STATE_EMPTY, + int mediaType = K3bDevice::MEDIA_WRITABLE_CD, + const QString& message = QString::null ); + + /** + * @reimplemented from K3bJobHandler + */ + bool questionYesNo( const QString& text, + const QString& caption = QString::null, + const QString& yesText = QString::null, + const QString& noText = QString::null ); + + /** + * reimplemented from K3bJobHandler + */ + void blockingInformation( const QString& text, + const QString& caption = QString::null ); + + public slots: + void setDevice( K3bDevice::Device* ); + + protected slots: + void slotStartClicked(); + void slotWriterChanged(); + void slotWritingAppChanged( int ); + void slotJobFinished( bool ); + + private: + void setupGui(); + void loadK3bDefaults(); + void loadUserDefaults( KConfigBase* ); + void saveUserDefaults( KConfigBase* ); + + K3bWriterSelectionWidget* m_writerSelectionWidget; + + QComboBox* m_comboEraseMode; + + class Private; + Private* d; +}; + +#endif diff --git a/src/misc/k3bcdcopydialog.cpp b/src/misc/k3bcdcopydialog.cpp new file mode 100644 index 0000000..4f1ce3b --- /dev/null +++ b/src/misc/k3bcdcopydialog.cpp @@ -0,0 +1,556 @@ +/* + * + * $Id: k3bcdcopydialog.cpp 733470 2007-11-06 12:10:29Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * Klaus-Dieter Krannich <kd@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bcdcopydialog.h" + +#include "k3bmediaselectioncombobox.h" +#include "k3bcdcopyjob.h" +#include "k3bclonejob.h" + +#include <k3bwriterselectionwidget.h> +#include <k3btempdirselectionwidget.h> +#include <k3bcore.h> +#include <k3bstdguiitems.h> +#include <k3bdevice.h> +#include <k3bdevicemanager.h> +#include <k3bburnprogressdialog.h> +#include <k3bglobals.h> +#include <k3bexternalbinmanager.h> +#include <k3bthememanager.h> +#include <k3bwritingmodewidget.h> +#include <k3bapplication.h> +#include <k3bmediacache.h> + +#include <kguiitem.h> +#include <klocale.h> +#include <kstdguiitem.h> +#include <kstandarddirs.h> +#include <kmessagebox.h> +#include <kconfig.h> +#include <kapplication.h> +#include <kiconloader.h> + +#include <qcheckbox.h> +#include <qspinbox.h> +#include <qcombobox.h> +#include <qlayout.h> +#include <qgroupbox.h> +#include <qptrlist.h> +#include <qlabel.h> +#include <qtooltip.h> +#include <qtabwidget.h> +#include <qwhatsthis.h> +#include <qhbox.h> +#include <qpushbutton.h> +#include <qbuttongroup.h> +#include <qradiobutton.h> +#include <qsizepolicy.h> +#include <qfile.h> +#include <qfileinfo.h> + + +K3bCdCopyDialog::K3bCdCopyDialog( QWidget *parent, const char *name, bool modal ) + : K3bInteractionDialog( parent, name, i18n("CD Copy"), i18n("and CD Cloning"), + START_BUTTON|CANCEL_BUTTON, + START_BUTTON, + "CD Copy", + modal ) +{ + QWidget* main = mainWidget(); + + QGridLayout* mainGrid = new QGridLayout( main ); + mainGrid->setSpacing( spacingHint() ); + mainGrid->setMargin( 0 ); + + QGroupBox* groupSource = new QGroupBox( 1, Qt::Vertical, i18n("Source Medium"), main ); + groupSource->setInsideSpacing( spacingHint() ); + groupSource->setInsideMargin( marginHint() ); + m_comboSourceDevice = new K3bMediaSelectionComboBox( groupSource ); + m_comboSourceDevice->setWantedMediumType( K3bDevice::MEDIA_WRITABLE_CD|K3bDevice::MEDIA_CD_ROM ); + m_comboSourceDevice->setWantedMediumState( K3bDevice::STATE_COMPLETE|K3bDevice::STATE_INCOMPLETE ); + + m_writerSelectionWidget = new K3bWriterSelectionWidget( main ); + m_writerSelectionWidget->setWantedMediumType( K3bDevice::MEDIA_WRITABLE_CD ); + m_writerSelectionWidget->setWantedMediumState( K3bDevice::STATE_EMPTY ); + m_writerSelectionWidget->setSupportedWritingApps( K3b::CDRECORD ); + + // tab widget -------------------- + QTabWidget* tabWidget = new QTabWidget( main ); + + // + // option tab -------------------- + // + QWidget* optionTab = new QWidget( tabWidget ); + QGridLayout* optionTabGrid = new QGridLayout( optionTab ); + optionTabGrid->setSpacing( spacingHint() ); + optionTabGrid->setMargin( marginHint() ); + + QGroupBox* groupCopyMode = new QGroupBox( 1, Qt::Vertical, i18n("Copy Mode"), optionTab ); + groupCopyMode->setInsideMargin( marginHint() ); + groupCopyMode->setInsideSpacing( spacingHint() ); + m_comboCopyMode = new QComboBox( groupCopyMode ); + m_comboCopyMode->insertItem( i18n("Normal Copy") ); + m_comboCopyMode->insertItem( i18n("Clone Copy") ); + + QGroupBox* groupWritingMode = new QGroupBox( 1, Qt::Vertical, i18n("Writing Mode"), optionTab ); + groupWritingMode->setInsideMargin( marginHint() ); + m_writingModeWidget = new K3bWritingModeWidget( groupWritingMode ); + + QGroupBox* groupCopies = new QGroupBox( 2, Qt::Horizontal, i18n("Copies"), optionTab ); + groupCopies->setInsideSpacing( spacingHint() ); + groupCopies->setInsideMargin( marginHint() ); + QLabel* pixLabel = new QLabel( groupCopies ); + pixLabel->setPixmap( SmallIcon( "cdcopy", KIcon::SizeMedium ) ); + pixLabel->setScaledContents( false ); + m_spinCopies = new QSpinBox( 1, 999, 1, groupCopies ); + + QGroupBox* groupOptions = new QGroupBox( 5, Qt::Vertical, i18n("Settings"), optionTab ); + groupOptions->setInsideSpacing( spacingHint() ); + groupOptions->setInsideMargin( marginHint() ); + m_checkSimulate = K3bStdGuiItems::simulateCheckbox( groupOptions ); + m_checkCacheImage = K3bStdGuiItems::createCacheImageCheckbox( groupOptions ); + m_checkOnlyCreateImage = K3bStdGuiItems::onlyCreateImagesCheckbox( groupOptions ); + m_checkDeleteImages = K3bStdGuiItems::removeImagesCheckbox( groupOptions ); + + optionTabGrid->addWidget( groupCopyMode, 0, 0 ); + optionTabGrid->addWidget( groupWritingMode, 1, 0 ); + optionTabGrid->addMultiCellWidget( groupOptions, 0, 2, 1, 1 ); + optionTabGrid->addWidget( groupCopies, 2, 0 ); + optionTabGrid->setRowStretch( 2, 1 ); + optionTabGrid->setColStretch( 1, 1 ); + + tabWidget->addTab( optionTab, i18n("&Options") ); + + + // + // image tab ------------------ + // + QWidget* imageTab = new QWidget( tabWidget ); + QGridLayout* imageTabGrid = new QGridLayout( imageTab ); + imageTabGrid->setSpacing( spacingHint() ); + imageTabGrid->setMargin( marginHint() ); + + m_tempDirSelectionWidget = new K3bTempDirSelectionWidget( imageTab ); + + imageTabGrid->addWidget( m_tempDirSelectionWidget, 0, 0 ); + + tabWidget->addTab( imageTab, i18n("&Image") ); + + + // + // advanced tab ------------------ + // + QWidget* advancedTab = new QWidget( tabWidget ); + QGridLayout* advancedTabGrid = new QGridLayout( advancedTab ); + advancedTabGrid->setSpacing( spacingHint() ); + advancedTabGrid->setMargin( marginHint() ); + + m_groupAdvancedDataOptions = new QGroupBox( 3, Qt::Vertical, i18n("Data"), advancedTab, "data_options" ); + m_groupAdvancedDataOptions->setInsideSpacing( spacingHint() ); + m_groupAdvancedDataOptions->setInsideMargin( marginHint() ); + QHBox* box = new QHBox( m_groupAdvancedDataOptions ); + box->setSpacing( spacingHint() ); + box->setStretchFactor( new QLabel( i18n("Read retries:"), box ), 1 ); + m_spinDataRetries = new QSpinBox( 1, 128, 1, box ); + m_checkIgnoreDataReadErrors = K3bStdGuiItems::ignoreAudioReadErrorsCheckBox( m_groupAdvancedDataOptions ); + m_checkNoCorrection = new QCheckBox( i18n("No error correction"), m_groupAdvancedDataOptions ); + + m_groupAdvancedAudioOptions = new QGroupBox( 5, Qt::Vertical, i18n("Audio"), advancedTab, "audio_options" ); + m_groupAdvancedAudioOptions->setInsideSpacing( spacingHint() ); + m_groupAdvancedAudioOptions->setInsideMargin( marginHint() ); + box = new QHBox( m_groupAdvancedAudioOptions ); + box->setSpacing( spacingHint() ); + box->setStretchFactor( new QLabel( i18n("Read retries:"), box ), 1 ); + m_spinAudioRetries = new QSpinBox( 1, 128, 1, box ); + m_checkIgnoreAudioReadErrors = K3bStdGuiItems::ignoreAudioReadErrorsCheckBox( m_groupAdvancedAudioOptions ); + box = new QHBox( m_groupAdvancedAudioOptions ); + box->setSpacing( spacingHint() ); + box->setStretchFactor(new QLabel( i18n("Paranoia mode:"), box ), 1 ); + m_comboParanoiaMode = K3bStdGuiItems::paranoiaModeComboBox( box ); + m_checkReadCdText = new QCheckBox( i18n("Copy CD-Text"), m_groupAdvancedAudioOptions ); + m_checkPrefereCdText = new QCheckBox( i18n("Prefer CD-Text"), m_groupAdvancedAudioOptions ); + + advancedTabGrid->addWidget( m_groupAdvancedDataOptions, 0, 1 ); + advancedTabGrid->addWidget( m_groupAdvancedAudioOptions, 0, 0 ); + + tabWidget->addTab( advancedTab, i18n("&Advanced") ); + + mainGrid->addWidget( groupSource, 0, 0 ); + mainGrid->addWidget( m_writerSelectionWidget, 1, 0 ); + mainGrid->addWidget( tabWidget, 2, 0 ); + mainGrid->setRowStretch( 2, 1 ); + + + connect( m_comboSourceDevice, SIGNAL(selectionChanged(K3bDevice::Device*)), this, SLOT(slotToggleAll()) ); + connect( m_comboSourceDevice, SIGNAL(selectionChanged(K3bDevice::Device*)), + this, SLOT(slotSourceMediumChanged(K3bDevice::Device*)) ); + connect( m_writerSelectionWidget, SIGNAL(writerChanged()), this, SLOT(slotToggleAll()) ); + connect( m_writerSelectionWidget, SIGNAL(writerChanged(K3bDevice::Device*)), + m_writingModeWidget, SLOT(setDevice(K3bDevice::Device*)) ); + connect( m_writingModeWidget, SIGNAL(writingModeChanged(int)), this, SLOT(slotToggleAll()) ); + connect( m_checkCacheImage, SIGNAL(toggled(bool)), this, SLOT(slotToggleAll()) ); + connect( m_checkSimulate, SIGNAL(toggled(bool)), this, SLOT(slotToggleAll()) ); + connect( m_checkOnlyCreateImage, SIGNAL(toggled(bool)), this, SLOT(slotToggleAll()) ); + connect( m_comboCopyMode, SIGNAL(activated(int)), this, SLOT(slotToggleAll()) ); + connect( m_checkReadCdText, SIGNAL(toggled(bool)), this, SLOT(slotToggleAll()) ); + + QToolTip::add( m_checkIgnoreDataReadErrors, i18n("Skip unreadable data sectors") ); + QToolTip::add( m_checkNoCorrection, i18n("Disable the source drive's error correction") ); + QToolTip::add( m_checkPrefereCdText, i18n("Use CD-Text instead of cddb if available.") ); + QToolTip::add( m_checkReadCdText, i18n("Copy CD-Text from the source CD if available.") ); + + QWhatsThis::add( m_checkNoCorrection, i18n("<p>If this option is checked K3b will disable the " + "source drive's ECC/EDC error correction. This way sectors " + "that are unreadable by intention can be read." + "<p>This may be useful for cloning CDs with copy " + "protection based on corrupted sectors.") ); + QWhatsThis::add( m_checkReadCdText, i18n("<p>If this option is checked K3b will search for CD-Text on the source CD. " + "Disable it if your CD drive has problems with reading CD-Text or you want " + "to stick to Cddb info.") ); + QWhatsThis::add( m_checkPrefereCdText, i18n("<p>If this option is checked and K3b finds CD-Text on the source media it will be " + "copied to the resulting CD ignoring any potentially existing Cddb entries.") ); + QWhatsThis::add( m_checkIgnoreDataReadErrors, i18n("<p>If this option is checked and K3b is not able to read a data sector from the " + "source CD/DVD it will be replaced with zeros on the resulting copy.") ); + + QWhatsThis::add( m_comboCopyMode, + "<p><b>" + i18n("Normal Copy") + "</b>" + + i18n("<p>This is the normal copy mode recommended for most CD types. " + "It allows copying Audio CDs, multi and single session Data CDs, and " + "Enhanced Audio CDs (an Audio CD containing an additional data session)." + "<p>For VideoCDs please use the CD Cloning mode.") + + "<p><b>" + i18n("Clone Copy") + "</b>" + + i18n("<p>In CD Cloning mode K3b performs a raw copy of the CD. That means it does " + "not care about the content but simply copies the CD bit by bit. It may be used " + "to copy VideoCDs or CDs which contain erroneous sectors." + "<p><b>Caution:</b> Only single session CDs can be cloned.") ); +} + + +K3bCdCopyDialog::~K3bCdCopyDialog() +{ +} + + +void K3bCdCopyDialog::init() +{ + slotSourceMediumChanged( m_comboSourceDevice->selectedDevice() ); +} + + +void K3bCdCopyDialog::setReadingDevice( K3bDevice::Device* dev ) +{ + m_comboSourceDevice->setSelectedDevice( dev ); +} + + +K3bDevice::Device* K3bCdCopyDialog::readingDevice() const +{ + return m_comboSourceDevice->selectedDevice(); +} + + +void K3bCdCopyDialog::slotStartClicked() +{ + // + // Let's check the available size + // + if( m_checkCacheImage->isChecked() || m_checkOnlyCreateImage->isChecked() ) { + if( neededSize()/1024 > m_tempDirSelectionWidget->freeTempSpace() ) { + if( KMessageBox::warningContinueCancel( this, i18n("There seems to be not enough free space in temporary directory. " + "Write anyway?") ) == KMessageBox::Cancel ) + return; + } + } + + + K3bJobProgressDialog* dlg = 0; + if( m_checkOnlyCreateImage->isChecked() ) { + dlg = new K3bJobProgressDialog( kapp->mainWidget() ); + } + else { + dlg = new K3bBurnProgressDialog( kapp->mainWidget() ); + } + + K3bBurnJob* burnJob = 0; + + if( m_comboCopyMode->currentItem() == 1 ) { + + // + // check for m_tempDirSelectionWidget->tempPath() and + // m_tempDirSelectionWidget-tempPath() + ".toc" + // + if( QFileInfo( m_tempDirSelectionWidget->tempPath() ).isFile() ) { + if( KMessageBox::warningContinueCancel( this, + i18n("Do you want to overwrite %1?").arg(m_tempDirSelectionWidget->tempPath()), + i18n("File Exists"), i18n("Overwrite") ) + != KMessageBox::Continue ) + return; + } + + if( QFileInfo( m_tempDirSelectionWidget->tempPath() + ".toc" ).isFile() ) { + if( KMessageBox::warningContinueCancel( this, + i18n("Do you want to overwrite %1?").arg(m_tempDirSelectionWidget->tempPath() + ".toc"), + i18n("File Exists"), i18n("Overwrite") ) + != KMessageBox::Continue ) + return; + } + + K3bCloneJob* job = new K3bCloneJob( dlg, this ); + + job->setWriterDevice( m_writerSelectionWidget->writerDevice() ); + job->setReaderDevice( m_comboSourceDevice->selectedDevice() ); + job->setImagePath( m_tempDirSelectionWidget->tempPath() ); + job->setNoCorrection( m_checkNoCorrection->isChecked() ); + job->setRemoveImageFiles( m_checkDeleteImages->isChecked() && !m_checkOnlyCreateImage->isChecked() ); + job->setOnlyCreateImage( m_checkOnlyCreateImage->isChecked() ); + job->setSimulate( m_checkSimulate->isChecked() ); + job->setWriteSpeed( m_writerSelectionWidget->writerSpeed() ); + job->setCopies( m_checkSimulate->isChecked() ? 1 : m_spinCopies->value() ); + job->setReadRetries( m_spinDataRetries->value() ); + + burnJob = job; + } + else { + K3bCdCopyJob* job = new K3bCdCopyJob( dlg, this ); + + job->setWriterDevice( m_writerSelectionWidget->writerDevice() ); + job->setReaderDevice( m_comboSourceDevice->selectedDevice() ); + job->setSpeed( m_writerSelectionWidget->writerSpeed() ); + job->setSimulate( m_checkSimulate->isChecked() ); + job->setOnTheFly( !m_checkCacheImage->isChecked() ); + job->setKeepImage( !m_checkDeleteImages->isChecked() || m_checkOnlyCreateImage->isChecked() ); + job->setOnlyCreateImage( m_checkOnlyCreateImage->isChecked() ); + job->setTempPath( m_tempDirSelectionWidget->plainTempPath() ); + job->setCopies( m_checkSimulate->isChecked() ? 1 : m_spinCopies->value() ); + job->setParanoiaMode( m_comboParanoiaMode->currentText().toInt() ); + job->setDataReadRetries( m_spinDataRetries->value() ); + job->setAudioReadRetries( m_spinAudioRetries->value() ); + job->setCopyCdText( m_checkReadCdText->isChecked() ); + job->setPreferCdText( m_checkPrefereCdText->isChecked() ); + job->setIgnoreDataReadErrors( m_checkIgnoreDataReadErrors->isChecked() ); + job->setIgnoreAudioReadErrors( m_checkIgnoreAudioReadErrors->isChecked() ); + job->setNoCorrection( m_checkNoCorrection->isChecked() ); + job->setWritingMode( m_writingModeWidget->writingMode() ); + + burnJob = job; + } + + if( !exitLoopOnHide() ) + hide(); + + dlg->startJob( burnJob ); + + delete dlg; + delete burnJob; + + if( KConfigGroup( k3bcore->config(), "General Options" ).readBoolEntry( "keep action dialogs open", false ) && + !exitLoopOnHide() ) + show(); + else + close(); +} + + +void K3bCdCopyDialog::toggleAll() +{ + updateOverrideDevice(); + + K3bDevice::Device* dev = m_writerSelectionWidget->writerDevice(); + + m_checkSimulate->setEnabled( !m_checkOnlyCreateImage->isChecked() ); + m_checkDeleteImages->setEnabled( !m_checkOnlyCreateImage->isChecked() && m_checkCacheImage->isChecked() ); + m_spinCopies->setDisabled( m_checkSimulate->isChecked() || m_checkOnlyCreateImage->isChecked() ); + m_tempDirSelectionWidget->setDisabled( !m_checkCacheImage->isChecked() ); + m_checkOnlyCreateImage->setEnabled( m_checkCacheImage->isChecked() ); + m_writerSelectionWidget->setDisabled( m_checkOnlyCreateImage->isChecked() ); + m_checkCacheImage->setEnabled( !m_checkOnlyCreateImage->isChecked() ); + + if( m_comboCopyMode->currentItem() == 1 ) { + // cdrecord does not support cloning on-the-fly + m_checkCacheImage->setChecked(true); + m_checkCacheImage->setEnabled(false); + + m_writingModeWidget->setSupportedModes( K3b::RAW ); + } + else { + m_writingModeWidget->setSupportedModes( K3b::TAO|K3b::DAO|K3b::RAW ); + } + + + + static_cast<QWidget*>( child( "audio_options" ) )->setDisabled( m_comboCopyMode->currentItem() == 1 ); + + m_checkIgnoreDataReadErrors->setDisabled( m_comboCopyMode->currentItem() == 1 ); + + m_groupAdvancedAudioOptions->setEnabled( k3bappcore->mediaCache()->medium( m_comboSourceDevice->selectedDevice() ).content() & K3bMedium::CONTENT_AUDIO && + m_comboCopyMode->currentItem() == 0 ); + + m_writingModeWidget->setEnabled( !m_checkOnlyCreateImage->isChecked() ); + + m_tempDirSelectionWidget->setNeededSize( neededSize() ); + + setButtonEnabled( START_BUTTON, m_comboSourceDevice->selectedDevice() && + (dev || m_checkOnlyCreateImage->isChecked()) ); +} + + +void K3bCdCopyDialog::slotSourceMediumChanged( K3bDevice::Device* dev ) +{ + updateOverrideDevice(); + + K3bMedium medium = k3bappcore->mediaCache()->medium( dev ); + + m_tempDirSelectionWidget->setNeededSize( neededSize() ); + + if( k3bappcore->mediaCache()->toc( dev ).contentType() == K3bDevice::DATA ) { + m_tempDirSelectionWidget->setSelectionMode( K3bTempDirSelectionWidget::FILE ); + m_tempDirSelectionWidget->setDefaultImageFileName( medium.volumeId().lower() + + ( medium.toc().count() == 1 ? QString(".iso") : QString::null ) ); + } + else { + m_tempDirSelectionWidget->setSelectionMode( K3bTempDirSelectionWidget::DIR ); + } + + m_groupAdvancedAudioOptions->setEnabled( k3bappcore->mediaCache()->medium( dev ).content() & K3bMedium::CONTENT_AUDIO ); + m_groupAdvancedDataOptions->setEnabled( k3bappcore->mediaCache()->medium( dev ).content() & K3bMedium::CONTENT_DATA ); + + // we can only clone single session CDs + if( k3bappcore->mediaCache()->toc( dev ).sessions() > 1 ) { + m_comboCopyMode->setEnabled( false ); + m_comboCopyMode->setCurrentItem( 0 ); + } + else { + m_comboCopyMode->setEnabled( true ); + } + + toggleAll(); +} + + +void K3bCdCopyDialog::updateOverrideDevice() +{ + if( !m_checkCacheImage->isChecked() ) { + m_writerSelectionWidget->setOverrideDevice( 0 ); + m_writerSelectionWidget->setIgnoreDevice( m_comboSourceDevice->selectedDevice() ); + } + else { + m_writerSelectionWidget->setIgnoreDevice( 0 ); + m_writerSelectionWidget->setOverrideDevice( m_comboSourceDevice->selectedDevice(), + i18n("Use the same device for burning"), + i18n("<qt>Use the same device for burning <i>(Or insert another medium)</i>") ); + } +} + + +void K3bCdCopyDialog::loadUserDefaults( KConfigBase* c ) +{ + m_writerSelectionWidget->loadConfig( c ); + m_comboSourceDevice->setSelectedDevice( k3bcore->deviceManager()->findDevice( c->readEntry( "source_device" ) ) ); + m_writingModeWidget->loadConfig( c ); + m_checkSimulate->setChecked( c->readBoolEntry( "simulate", false ) ); + m_checkCacheImage->setChecked( !c->readBoolEntry( "on_the_fly", false ) ); + m_checkDeleteImages->setChecked( c->readBoolEntry( "delete_images", true ) ); + m_checkOnlyCreateImage->setChecked( c->readBoolEntry( "only_create_image", false ) ); + m_comboParanoiaMode->setCurrentItem( c->readNumEntry( "paranoia_mode", 0 ) ); + + m_spinCopies->setValue( c->readNumEntry( "copies", 1 ) ); + + m_tempDirSelectionWidget->readConfig( c ); + + if( c->readEntry( "copy mode", "normal" ) == "normal" ) + m_comboCopyMode->setCurrentItem( 0 ); + else + m_comboCopyMode->setCurrentItem( 1 ); + + m_checkReadCdText->setChecked( c->readBoolEntry( "copy cdtext", true ) ); + m_checkPrefereCdText->setChecked( c->readBoolEntry( "prefer cdtext", false ) ); + m_checkIgnoreDataReadErrors->setChecked( c->readBoolEntry( "ignore data read errors", false ) ); + m_checkIgnoreAudioReadErrors->setChecked( c->readBoolEntry( "ignore audio read errors", true ) ); + m_checkNoCorrection->setChecked( c->readBoolEntry( "no correction", false ) ); + + m_spinDataRetries->setValue( c->readNumEntry( "data retries", 128 ) ); + m_spinAudioRetries->setValue( c->readNumEntry( "audio retries", 5 ) ); + + slotToggleAll(); +} + + +void K3bCdCopyDialog::saveUserDefaults( KConfigBase* c ) +{ + m_writingModeWidget->saveConfig( c ); + c->writeEntry( "simulate", m_checkSimulate->isChecked() ); + c->writeEntry( "on_the_fly", !m_checkCacheImage->isChecked() ); + c->writeEntry( "delete_images", m_checkDeleteImages->isChecked() ); + c->writeEntry( "only_create_image", m_checkOnlyCreateImage->isChecked() ); + c->writeEntry( "paranoia_mode", m_comboParanoiaMode->currentText().toInt() ); + c->writeEntry( "copies", m_spinCopies->value() ); + + m_writerSelectionWidget->saveConfig( c ); + m_tempDirSelectionWidget->saveConfig( c ); + + c->writeEntry( "source_device", m_comboSourceDevice->selectedDevice() ? m_comboSourceDevice->selectedDevice()->devicename() : QString() ); + + c->writeEntry( "copy cdtext", m_checkReadCdText->isChecked() ); + c->writeEntry( "prefer cdtext", m_checkPrefereCdText->isChecked() ); + c->writeEntry( "ignore data read errors", m_checkIgnoreDataReadErrors->isChecked() ); + c->writeEntry( "ignore audio read errors", m_checkIgnoreAudioReadErrors->isChecked() ); + c->writeEntry( "no correction", m_checkNoCorrection->isChecked() ); + c->writeEntry( "data retries", m_spinDataRetries->value() ); + c->writeEntry( "audio retries", m_spinAudioRetries->value() ); + + QString s; + if( m_comboCopyMode->currentItem() == 1 ) + s = "clone"; + else + s = "normal"; + c->writeEntry( "copy mode", s ); +} + + +void K3bCdCopyDialog::loadK3bDefaults() +{ + m_writingModeWidget->setWritingMode( K3b::WRITING_MODE_AUTO ); + m_writerSelectionWidget->loadDefaults(); + m_checkSimulate->setChecked( false ); + m_checkCacheImage->setChecked( true ); + m_checkDeleteImages->setChecked( true ); + m_checkOnlyCreateImage->setChecked( false ); + m_comboParanoiaMode->setCurrentItem(0); + m_spinCopies->setValue(1); + m_checkReadCdText->setChecked(true); + m_checkPrefereCdText->setChecked(false); + m_checkIgnoreDataReadErrors->setChecked(false); + m_checkIgnoreAudioReadErrors->setChecked(true); + m_checkNoCorrection->setChecked(false); + m_comboCopyMode->setCurrentItem( 0 ); // normal + m_spinDataRetries->setValue(128); + m_spinAudioRetries->setValue(5); + m_tempDirSelectionWidget->setTempPath( K3b::defaultTempPath() ); + + slotToggleAll(); +} + + +KIO::filesize_t K3bCdCopyDialog::neededSize() const +{ + if( m_comboCopyMode->currentItem() == 0 ) + return k3bappcore->mediaCache()->medium( m_comboSourceDevice->selectedDevice() ).diskInfo().size().mode1Bytes(); + else + return k3bappcore->mediaCache()->medium( m_comboSourceDevice->selectedDevice() ).diskInfo().size().rawBytes(); +} + +#include "k3bcdcopydialog.moc" diff --git a/src/misc/k3bcdcopydialog.h b/src/misc/k3bcdcopydialog.h new file mode 100644 index 0000000..b7a4bd2 --- /dev/null +++ b/src/misc/k3bcdcopydialog.h @@ -0,0 +1,96 @@ +/* + * + * $Id: k3bcdcopydialog.h 733470 2007-11-06 12:10:29Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * Klaus-Dieter Krannich <kd@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BCDCOPYDIALOG_H +#define K3BCDCOPYDIALOG_H + + +#include <k3binteractiondialog.h> + +#include <kio/global.h> + +namespace K3bDevice { + class Device; + class DeviceManager; +} + +class K3bWriterSelectionWidget; +class K3bTempDirSelectionWidget; +class K3bMediaSelectionComboBox; +class QCheckBox; +class QSpinBox; +class QComboBox; +class K3bWritingModeWidget; +class QButtonGroup; +class QGroupBox; + + +/** + *@author Sebastian Trueg + */ +class K3bCdCopyDialog : public K3bInteractionDialog +{ + Q_OBJECT + + public: + K3bCdCopyDialog(QWidget *parent = 0, const char *name = 0, bool modal = true ); + ~K3bCdCopyDialog(); + + void setReadingDevice( K3bDevice::Device* ); + K3bDevice::Device* readingDevice() const; + + private slots: + void slotStartClicked(); + + void slotSourceMediumChanged( K3bDevice::Device* ); + void updateOverrideDevice(); + + protected: + void init(); + void toggleAll(); + + private: + void loadUserDefaults( KConfigBase* ); + void saveUserDefaults( KConfigBase* ); + void loadK3bDefaults(); + + KIO::filesize_t neededSize() const; + + K3bWriterSelectionWidget* m_writerSelectionWidget; + K3bTempDirSelectionWidget* m_tempDirSelectionWidget; + QCheckBox* m_checkSimulate; + QCheckBox* m_checkCacheImage; + QCheckBox* m_checkDeleteImages; + QCheckBox* m_checkOnlyCreateImage; + QCheckBox* m_checkReadCdText; + QCheckBox* m_checkPrefereCdText; + QCheckBox* m_checkIgnoreDataReadErrors; + QCheckBox* m_checkIgnoreAudioReadErrors; + QCheckBox* m_checkNoCorrection; + K3bMediaSelectionComboBox* m_comboSourceDevice; + QComboBox* m_comboParanoiaMode; + QSpinBox* m_spinCopies; + QSpinBox* m_spinDataRetries; + QSpinBox* m_spinAudioRetries; + K3bWritingModeWidget* m_writingModeWidget; + QComboBox* m_comboCopyMode; + + QGroupBox* m_groupAdvancedDataOptions; + QGroupBox* m_groupAdvancedAudioOptions; +}; + +#endif diff --git a/src/misc/k3bcdimagewritingdialog.cpp b/src/misc/k3bcdimagewritingdialog.cpp new file mode 100644 index 0000000..b071d94 --- /dev/null +++ b/src/misc/k3bcdimagewritingdialog.cpp @@ -0,0 +1,1049 @@ +/* + * + * $Id: k3bcdimagewritingdialog.cpp 630454 2007-02-05 13:06:45Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include <config.h> + +#include "k3bcdimagewritingdialog.h" +#include "k3biso9660imagewritingjob.h" +#include "k3bbinimagewritingjob.h" +#include "k3bcuefileparser.h" +#include "k3bclonetocreader.h" +#include "k3baudiocuefilewritingjob.h" +#include <k3bclonejob.h> + +#include <k3btempdirselectionwidget.h> +#include <k3bdevicemanager.h> +#include <k3bdevice.h> +#include <k3bwriterselectionwidget.h> +#include <k3bburnprogressdialog.h> +#include <kcutlabel.h> +#include <k3bstdguiitems.h> +#include <k3bmd5job.h> +#include <k3bdatamodewidget.h> +#include <k3bglobals.h> +#include <k3bwritingmodewidget.h> +#include <k3bcore.h> +#include <k3blistview.h> +#include <k3biso9660.h> +#include <k3btoc.h> +#include <k3btrack.h> +#include <k3bcdtext.h> + +#include <kapplication.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kurlrequester.h> +#include <kfiledialog.h> +#include <kstdguiitem.h> +#include <kguiitem.h> +#include <kiconloader.h> +#include <kconfig.h> +#include <kio/global.h> +#include <kurl.h> +#include <kinputdialog.h> +#include <kurldrag.h> + +#include <qheader.h> +#include <qgroupbox.h> +#include <qcheckbox.h> +#include <qlabel.h> +#include <qcombobox.h> +#include <qlayout.h> +#include <qptrlist.h> +#include <qfile.h> +#include <qfileinfo.h> +#include <qfont.h> +#include <qfontmetrics.h> +#include <qpushbutton.h> +#include <qtabwidget.h> +#include <qtooltip.h> +#include <qwhatsthis.h> +#include <qspinbox.h> +#include <qmap.h> +#include <qptrqueue.h> +#include <qpopupmenu.h> +#include <qclipboard.h> + + +class K3bCdImageWritingDialog::Private +{ +public: + Private() + : md5SumItem(0), + haveMd5Sum( false ), + foundImageType( IMAGE_UNKNOWN ), + imageForced( false ) { + } + + K3bListViewItem* md5SumItem; + QString lastCheckedFile; + + K3bMd5Job* md5Job; + bool haveMd5Sum; + + int foundImageType; + + QMap<int,int> imageTypeSelectionMap; + QMap<int,int> imageTypeSelectionMapRev; + QString imageFile; + QString tocFile; + + QTabWidget* optionTabbed; + + QWidget* advancedTab; + QWidget* tempPathTab; + bool advancedTabVisible; + bool tempPathTabVisible; + + bool imageForced; +}; + + +K3bCdImageWritingDialog::K3bCdImageWritingDialog( QWidget* parent, const char* name, bool modal ) + : K3bInteractionDialog( parent, name, + i18n("Burn CD Image"), + "iso cue toc", + START_BUTTON|CANCEL_BUTTON, + START_BUTTON, + "image writing", // config group + modal ) +{ + d = new Private(); + + setAcceptDrops( true ); + + setupGui(); + + d->md5Job = new K3bMd5Job( 0, this ); + connect( d->md5Job, SIGNAL(finished(bool)), + this, SLOT(slotMd5JobFinished(bool)) ); + connect( d->md5Job, SIGNAL(percent(int)), + this, SLOT(slotMd5JobPercent(int)) ); + + connect( m_writerSelectionWidget, SIGNAL(writerChanged()), + this, SLOT(slotToggleAll()) ); + connect( m_writerSelectionWidget, SIGNAL(writingAppChanged(int)), + this, SLOT(slotToggleAll()) ); + connect( m_writerSelectionWidget, SIGNAL(writerChanged(K3bDevice::Device*)), + m_writingModeWidget, SLOT(setDevice(K3bDevice::Device*)) ); + connect( m_comboImageType, SIGNAL(activated(int)), + this, SLOT(slotToggleAll()) ); + connect( m_writingModeWidget, SIGNAL(writingModeChanged(int)), + this, SLOT(slotToggleAll()) ); + connect( m_editImagePath, SIGNAL(textChanged(const QString&)), + this, SLOT(slotUpdateImage(const QString&)) ); + connect( m_checkDummy, SIGNAL(toggled(bool)), + this, SLOT(slotToggleAll()) ); + connect( m_checkCacheImage, SIGNAL(toggled(bool)), + this, SLOT(slotToggleAll()) ); +} + + +K3bCdImageWritingDialog::~K3bCdImageWritingDialog() +{ + d->md5Job->cancel(); + delete d; +} + + +void K3bCdImageWritingDialog::init() +{ + if( !d->imageForced ) { + // when opening the dialog first the default settings are loaded and afterwards we set the + // last written image because that's what most users want + KConfig* c = k3bcore->config(); + c->setGroup( configGroup() ); + QString image = c->readPathEntry( "last written image" ); + if( QFile::exists( image ) ) + m_editImagePath->setURL( image ); + } +} + + +void K3bCdImageWritingDialog::setupGui() +{ + QWidget* frame = mainWidget(); + + // image + // ----------------------------------------------------------------------- + QGroupBox* groupImageUrl = new QGroupBox( 1, Qt::Horizontal, i18n("Image to Burn"), frame ); + m_editImagePath = new KURLRequester( groupImageUrl ); + m_editImagePath->setMode( KFile::File|KFile::ExistingOnly ); + m_editImagePath->setCaption( i18n("Choose Image File") ); + m_editImagePath->setFilter( i18n("*.iso *.toc *.ISO *.TOC *.cue *.CUE|Image Files") + + "\n" + + i18n("*.iso *.ISO|ISO9660 Image Files") + + "\n" + + i18n("*.cue *.CUE|Cue Files") + + "\n" + + i18n("*.toc *.TOC|Cdrdao TOC Files and Cdrecord Clone Images") + + "\n" + + i18n("*|All Files") ); + + QGroupBox* groupImageType = new QGroupBox( 1, Qt::Horizontal, i18n("Image Type"), frame ); + m_comboImageType = new QComboBox( groupImageType ); + m_comboImageType->insertItem( i18n("Auto Detection") ); + m_comboImageType->insertItem( i18n("ISO9660 Image") ); + m_comboImageType->insertItem( i18n("Cue/Bin Image") ); + m_comboImageType->insertItem( i18n("Audio Cue File") ); + m_comboImageType->insertItem( i18n("Cdrdao TOC File") ); + m_comboImageType->insertItem( i18n("Cdrecord Clone Image") ); + d->imageTypeSelectionMap[1] = IMAGE_ISO; + d->imageTypeSelectionMap[2] = IMAGE_CUE_BIN; + d->imageTypeSelectionMap[3] = IMAGE_AUDIO_CUE; + d->imageTypeSelectionMap[4] = IMAGE_CDRDAO_TOC; + d->imageTypeSelectionMap[5] = IMAGE_CDRECORD_CLONE; + d->imageTypeSelectionMapRev[IMAGE_ISO] = 1; + d->imageTypeSelectionMapRev[IMAGE_CUE_BIN] = 2; + d->imageTypeSelectionMapRev[IMAGE_AUDIO_CUE] = 3; + d->imageTypeSelectionMapRev[IMAGE_CDRDAO_TOC] = 4; + d->imageTypeSelectionMapRev[IMAGE_CDRECORD_CLONE] = 5; + + + // image info + // ----------------------------------------------------------------------- + m_infoView = new K3bListView( frame ); + m_infoView->addColumn( "key" ); + m_infoView->addColumn( "value" ); + m_infoView->header()->hide(); + m_infoView->setNoItemText( i18n("No image file selected") ); + m_infoView->setSorting( -1 ); + m_infoView->setAlternateBackground( QColor() ); + m_infoView->setFullWidth(true); + m_infoView->setSelectionMode( QListView::NoSelection ); + + connect( m_infoView, SIGNAL(contextMenu(KListView*, QListViewItem*, const QPoint&)), + this, SLOT(slotContextMenu(KListView*, QListViewItem*, const QPoint&)) ); + + + m_writerSelectionWidget = new K3bWriterSelectionWidget( frame ); + m_writerSelectionWidget->setWantedMediumType( K3bDevice::MEDIA_WRITABLE_CD ); + m_writerSelectionWidget->setWantedMediumState( K3bDevice::STATE_EMPTY ); + + // options + // ----------------------------------------------------------------------- + d->optionTabbed = new QTabWidget( frame ); + + QWidget* optionTab = new QWidget( d->optionTabbed ); + QGridLayout* optionTabLayout = new QGridLayout( optionTab ); + optionTabLayout->setAlignment( Qt::AlignTop ); + optionTabLayout->setSpacing( spacingHint() ); + optionTabLayout->setMargin( marginHint() ); + + QGroupBox* writingModeGroup = new QGroupBox( 1, Vertical, i18n("Writing Mode"), optionTab ); + writingModeGroup->setInsideMargin( marginHint() ); + m_writingModeWidget = new K3bWritingModeWidget( writingModeGroup ); + + + // copies -------- + QGroupBox* groupCopies = new QGroupBox( 2, Qt::Horizontal, i18n("Copies"), optionTab ); + groupCopies->setInsideSpacing( spacingHint() ); + groupCopies->setInsideMargin( marginHint() ); + QLabel* pixLabel = new QLabel( groupCopies ); + pixLabel->setPixmap( SmallIcon( "cdcopy", KIcon::SizeMedium ) ); + pixLabel->setScaledContents( false ); + m_spinCopies = new QSpinBox( groupCopies ); + m_spinCopies->setMinValue( 1 ); + m_spinCopies->setMaxValue( 999 ); + // -------- copies + + QGroupBox* optionGroup = new QGroupBox( 3, Vertical, i18n("Settings"), optionTab ); + optionGroup->setInsideMargin( marginHint() ); + optionGroup->setInsideSpacing( spacingHint() ); + m_checkDummy = K3bStdGuiItems::simulateCheckbox( optionGroup ); + m_checkCacheImage = K3bStdGuiItems::createCacheImageCheckbox( optionGroup ); + m_checkVerify = K3bStdGuiItems::verifyCheckBox( optionGroup ); + + optionTabLayout->addWidget( writingModeGroup, 0, 0 ); + optionTabLayout->addWidget( groupCopies, 1, 0 ); + optionTabLayout->addMultiCellWidget( optionGroup, 0, 1, 1, 1 ); + optionTabLayout->setRowStretch( 1, 1 ); + optionTabLayout->setColStretch( 1, 1 ); + + d->optionTabbed->addTab( optionTab, i18n("Settings") ); + + + // image tab ------------------------------------ + d->tempPathTab = new QWidget( d->optionTabbed ); + QGridLayout* imageTabGrid = new QGridLayout( d->tempPathTab ); + imageTabGrid->setSpacing( spacingHint() ); + imageTabGrid->setMargin( marginHint() ); + + m_tempDirSelectionWidget = new K3bTempDirSelectionWidget( d->tempPathTab ); + + imageTabGrid->addWidget( m_tempDirSelectionWidget, 0, 0 ); + + d->optionTabbed->addTab( d->tempPathTab, i18n("&Image") ); + d->tempPathTabVisible = true; + // ------------------------------------------------------------- + + + // advanced --------------------------------- + d->advancedTab = new QWidget( d->optionTabbed ); + QGridLayout* advancedTabLayout = new QGridLayout( d->advancedTab ); + advancedTabLayout->setAlignment( Qt::AlignTop ); + advancedTabLayout->setSpacing( spacingHint() ); + advancedTabLayout->setMargin( marginHint() ); + + m_dataModeWidget = new K3bDataModeWidget( d->advancedTab ); + m_checkNoFix = K3bStdGuiItems::startMultisessionCheckBox( d->advancedTab ); + + advancedTabLayout->addWidget( new QLabel( i18n("Data mode:"), d->advancedTab ), 0, 0 ); + advancedTabLayout->addWidget( m_dataModeWidget, 0, 1 ); + advancedTabLayout->addMultiCellWidget( m_checkNoFix, 1, 1, 0, 2 ); + advancedTabLayout->setRowStretch( 2, 1 ); + advancedTabLayout->setColStretch( 2, 1 ); + + d->optionTabbed->addTab( d->advancedTab, i18n("Advanced") ); + d->advancedTabVisible = true; + // ----------------------------------------------------------------------- + + + + + QGridLayout* grid = new QGridLayout( frame ); + grid->setSpacing( spacingHint() ); + grid->setMargin( 0 ); + + grid->addWidget( groupImageUrl, 0, 0 ); + grid->addWidget( groupImageType, 0, 1 ); + grid->addMultiCellWidget( m_infoView, 1, 1, 0, 1 ); + grid->addMultiCellWidget( m_writerSelectionWidget, 2, 2, 0, 1 ); + grid->addMultiCellWidget( d->optionTabbed, 3, 3, 0, 1 ); + + grid->setRowStretch( 1, 1 ); +} + + +void K3bCdImageWritingDialog::slotStartClicked() +{ + // FIXME: this results in a call to slotMd5JobFinished + // if this dialog is deleted becasue it is not opened with exec(false) + // this results in a crash. + // For now this is not a problem in K3b since the dialog is not deleted + // when hiding (due to the exec(false) call in k3b.cpp + d->md5Job->cancel(); + + // save the path + KConfig* c = k3bcore->config(); + c->setGroup( configGroup() ); + c->writePathEntry( "last written image", imagePath() ); + + if( d->imageFile.isEmpty() ) + d->imageFile = imagePath(); + if( d->tocFile.isEmpty() ) + d->tocFile = imagePath(); + + // create a progresswidget + K3bBurnProgressDialog dlg( kapp->mainWidget(), "burnProgress", true ); + + // create the job + K3bBurnJob* job = 0; + switch( currentImageType() ) { + case IMAGE_CDRECORD_CLONE: + { + K3bCloneJob* _job = new K3bCloneJob( &dlg, this ); + _job->setWriterDevice( m_writerSelectionWidget->writerDevice() ); + _job->setImagePath( d->imageFile ); + _job->setSimulate( m_checkDummy->isChecked() ); + _job->setWriteSpeed( m_writerSelectionWidget->writerSpeed() ); + _job->setCopies( m_checkDummy->isChecked() ? 1 : m_spinCopies->value() ); + _job->setOnlyBurnExistingImage( true ); + + job = _job; + } + break; + + case IMAGE_AUDIO_CUE: + { + K3bAudioCueFileWritingJob* job_ = new K3bAudioCueFileWritingJob( &dlg, this ); + + job_->setBurnDevice( m_writerSelectionWidget->writerDevice() ); + job_->setSpeed( m_writerSelectionWidget->writerSpeed() ); + job_->setSimulate( m_checkDummy->isChecked() ); + job_->setWritingMode( m_writingModeWidget->writingMode() ); + job_->setCueFile( d->tocFile ); + job_->setCopies( m_checkDummy->isChecked() ? 1 : m_spinCopies->value() ); + job_->setOnTheFly( !m_checkCacheImage->isChecked() ); + job_->setTempDir( m_tempDirSelectionWidget->tempPath() ); + + job = job_; + } + break; + + case IMAGE_CUE_BIN: + // for now the K3bBinImageWritingJob decides if it's a toc or a cue file + case IMAGE_CDRDAO_TOC: + { + K3bBinImageWritingJob* job_ = new K3bBinImageWritingJob( &dlg, this ); + + job_->setWriter( m_writerSelectionWidget->writerDevice() ); + job_->setSpeed( m_writerSelectionWidget->writerSpeed() ); + job_->setTocFile( d->tocFile ); + job_->setSimulate(m_checkDummy->isChecked()); + job_->setMulti( false /*m_checkNoFix->isChecked()*/ ); + job_->setCopies( m_checkDummy->isChecked() ? 1 : m_spinCopies->value() ); + + job = job_; + } + break; + + case IMAGE_ISO: + { + K3bIso9660 isoFs( d->imageFile ); + if( isoFs.open() ) { + if( K3b::filesize( KURL::fromPathOrURL(d->imageFile) ) < (KIO::filesize_t)(isoFs.primaryDescriptor().volumeSpaceSize*2048) ) { + if( KMessageBox::questionYesNo( this, + i18n("<p>This image has an invalid file size." + "If it has been downloaded make sure the download is complete." + "<p>Only continue if you know what you are doing."), + i18n("Warning"), + i18n("Continue"), + i18n("Cancel") ) == KMessageBox::No ) + return; + } + } + + K3bIso9660ImageWritingJob* job_ = new K3bIso9660ImageWritingJob( &dlg ); + + job_->setBurnDevice( m_writerSelectionWidget->writerDevice() ); + job_->setSpeed( m_writerSelectionWidget->writerSpeed() ); + job_->setSimulate( m_checkDummy->isChecked() ); + job_->setWritingMode( m_writingModeWidget->writingMode() ); + job_->setVerifyData( m_checkVerify->isChecked() ); + job_->setNoFix( m_checkNoFix->isChecked() ); + job_->setDataMode( m_dataModeWidget->dataMode() ); + job_->setImagePath( d->imageFile ); + job_->setCopies( m_checkDummy->isChecked() ? 1 : m_spinCopies->value() ); + + job = job_; + } + break; + + default: + kdDebug() << "(K3bCdImageWritingDialog) this should really not happen!" << endl; + break; + } + + if( job ) { + job->setWritingApp( m_writerSelectionWidget->writingApp() ); + + if( !exitLoopOnHide() ) + hide(); + + dlg.startJob(job); + + delete job; + + if( KConfigGroup( k3bcore->config(), "General Options" ).readBoolEntry( "keep action dialogs open", false ) && + !exitLoopOnHide() ) + show(); + else + close(); + } +} + + +void K3bCdImageWritingDialog::slotUpdateImage( const QString& ) +{ + QString path = imagePath(); + + // check the image types + + d->haveMd5Sum = false; + d->md5Job->cancel(); + m_infoView->clear(); + m_infoView->header()->resizeSection( 0, 20 ); + d->md5SumItem = 0; + d->foundImageType = IMAGE_UNKNOWN; + d->tocFile.truncate(0); + d->imageFile.truncate(0); + + QFileInfo info( path ); + if( info.isFile() ) { + + // ------------------------------------------------ + // Test for iso9660 image + // ------------------------------------------------ + K3bIso9660 isoF( path ); + if( isoF.open() ) { +#ifdef K3B_DEBUG + isoF.debug(); +#endif + + createIso9660InfoItems( &isoF ); + isoF.close(); + calculateMd5Sum( path ); + + d->foundImageType = IMAGE_ISO; + d->imageFile = path; + } + + if( d->foundImageType == IMAGE_UNKNOWN ) { + + // check for cdrecord clone image + // try both path and path.toc as tocfiles + K3bCloneTocReader cr; + + if( path.right(4) == ".toc" ) { + cr.openFile( path ); + if( cr.isValid() ) { + d->tocFile = path; + d->imageFile = cr.imageFilename(); + } + } + if( d->imageFile.isEmpty() ) { + cr.openFile( path + ".toc" ); + if( cr.isValid() ) { + d->tocFile = cr.filename(); + d->imageFile = cr.imageFilename(); + } + } + + if( !d->imageFile.isEmpty() ) { + // we have a cdrecord clone image + createCdrecordCloneItems( d->tocFile, d->imageFile ); + calculateMd5Sum( d->imageFile ); + + d->foundImageType = IMAGE_CDRECORD_CLONE; + } + } + + if( d->foundImageType == IMAGE_UNKNOWN ) { + + // check for cue/bin stuff + // once again we try both path and path.cue + K3bCueFileParser cp; + + if( path.right(4).lower() == ".cue" ) + cp.openFile( path ); + else if( path.right(4).lower() == ".bin" ) + cp.openFile( path.left( path.length()-3) + "cue" ); + + if( cp.isValid() ) { + d->tocFile = cp.filename(); + d->imageFile = cp.imageFilename(); + } + + if( d->imageFile.isEmpty() ) { + cp.openFile( path + ".cue" ); + if( cp.isValid() ) { + d->tocFile = cp.filename(); + d->imageFile = cp.imageFilename(); + } + } + + if( !d->imageFile.isEmpty() ) { + // we have a cue file + if( cp.toc().contentType() == K3bDevice::AUDIO ) { + d->foundImageType = IMAGE_AUDIO_CUE; + createAudioCueItems( cp ); + } + else { + d->foundImageType = IMAGE_CUE_BIN; // we cannot be sure if writing will work... :( + createCueBinItems( d->tocFile, d->imageFile ); + calculateMd5Sum( d->imageFile ); + } + } + } + + if( d->foundImageType == IMAGE_UNKNOWN ) { + // TODO: check for cdrdao tocfile + } + + + + if( d->foundImageType == IMAGE_UNKNOWN ) { + K3bListViewItem* item = new K3bListViewItem( m_infoView, m_infoView->lastItem(), + i18n("Seems not to be a usable image") ); + item->setForegroundColor( 0, Qt::red ); + item->setPixmap( 0, SmallIcon( "stop") ); + } + } + else { + K3bListViewItem* item = new K3bListViewItem( m_infoView, m_infoView->lastItem(), + i18n("File not found") ); + item->setForegroundColor( 0, Qt::red ); + item->setPixmap( 0, SmallIcon( "stop") ); + } + + slotToggleAll(); +} + + +void K3bCdImageWritingDialog::createIso9660InfoItems( K3bIso9660* isoF ) +{ + K3bListViewItem* isoRootItem = new K3bListViewItem( m_infoView, m_infoView->lastItem(), + i18n("Detected:"), + i18n("Iso9660 image") ); + isoRootItem->setForegroundColor( 0, palette().disabled().foreground() ); + isoRootItem->setPixmap( 0, SmallIcon( "cdimage") ); + + KIO::filesize_t size = K3b::filesize( KURL::fromPathOrURL(isoF->fileName()) ); + K3bListViewItem* item = new K3bListViewItem( isoRootItem, m_infoView->lastItem(), + i18n("Filesize:"), + KIO::convertSize( size ) ); + item->setForegroundColor( 0, palette().disabled().foreground() ); + + item = new K3bListViewItem( isoRootItem, + m_infoView->lastItem(), + i18n("System Id:"), + isoF->primaryDescriptor().systemId.isEmpty() + ? QString("-") + : isoF->primaryDescriptor().systemId ); + item->setForegroundColor( 0, palette().disabled().foreground() ); + + item = new K3bListViewItem( isoRootItem, + m_infoView->lastItem(), + i18n("Volume Id:"), + isoF->primaryDescriptor().volumeId.isEmpty() + ? QString("-") + : isoF->primaryDescriptor().volumeId ); + item->setForegroundColor( 0, palette().disabled().foreground() ); + + item = new K3bListViewItem( isoRootItem, + m_infoView->lastItem(), + i18n("Volume Set Id:"), + isoF->primaryDescriptor().volumeSetId.isEmpty() + ? QString("-") + : isoF->primaryDescriptor().volumeSetId ); + item->setForegroundColor( 0, palette().disabled().foreground() ); + + item = new K3bListViewItem( isoRootItem, + m_infoView->lastItem(), + i18n("Publisher Id:"), + isoF->primaryDescriptor().publisherId.isEmpty() + ? QString("-") + : isoF->primaryDescriptor().publisherId ); + item->setForegroundColor( 0, palette().disabled().foreground() ); + + item = new K3bListViewItem( isoRootItem, + m_infoView->lastItem(), + i18n("Preparer Id:"), + isoF->primaryDescriptor().preparerId.isEmpty() + ? QString("-") : isoF->primaryDescriptor().preparerId ); + item->setForegroundColor( 0, palette().disabled().foreground() ); + + item = new K3bListViewItem( isoRootItem, + m_infoView->lastItem(), + i18n("Application Id:"), + isoF->primaryDescriptor().applicationId.isEmpty() + ? QString("-") + : isoF->primaryDescriptor().applicationId ); + item->setForegroundColor( 0, palette().disabled().foreground() ); + + isoRootItem->setOpen( true ); +} + + +void K3bCdImageWritingDialog::createCdrecordCloneItems( const QString& tocFile, const QString& imageFile ) +{ + K3bListViewItem* isoRootItem = new K3bListViewItem( m_infoView, m_infoView->lastItem(), + i18n("Detected:"), + i18n("Cdrecord clone image") ); + isoRootItem->setForegroundColor( 0, palette().disabled().foreground() ); + isoRootItem->setPixmap( 0, SmallIcon( "cdimage") ); + + K3bListViewItem* item = new K3bListViewItem( isoRootItem, m_infoView->lastItem(), + i18n("Filesize:"), KIO::convertSize( K3b::filesize(KURL::fromPathOrURL(imageFile)) ) ); + item->setForegroundColor( 0, palette().disabled().foreground() ); + + item = new K3bListViewItem( isoRootItem, + m_infoView->lastItem(), + i18n("Image file:"), + imageFile ); + item->setForegroundColor( 0, palette().disabled().foreground() ); + + item = new K3bListViewItem( isoRootItem, + m_infoView->lastItem(), + i18n("TOC file:"), + tocFile ); + item->setForegroundColor( 0, palette().disabled().foreground() ); + + isoRootItem->setOpen( true ); +} + + +void K3bCdImageWritingDialog::createCueBinItems( const QString& cueFile, const QString& imageFile ) +{ + K3bListViewItem* isoRootItem = new K3bListViewItem( m_infoView, m_infoView->lastItem(), + i18n("Detected:"), + i18n("Cue/bin image") ); + isoRootItem->setForegroundColor( 0, palette().disabled().foreground() ); + isoRootItem->setPixmap( 0, SmallIcon( "cdimage") ); + + K3bListViewItem* item = new K3bListViewItem( isoRootItem, m_infoView->lastItem(), + i18n("Filesize:"), KIO::convertSize( K3b::filesize(KURL::fromPathOrURL(imageFile)) ) ); + item->setForegroundColor( 0, palette().disabled().foreground() ); + + item = new K3bListViewItem( isoRootItem, + m_infoView->lastItem(), + i18n("Image file:"), + imageFile ); + item->setForegroundColor( 0, palette().disabled().foreground() ); + + item = new K3bListViewItem( isoRootItem, + m_infoView->lastItem(), + i18n("Cue file:"), + cueFile ); + item->setForegroundColor( 0, palette().disabled().foreground() ); + + isoRootItem->setOpen( true ); +} + + +void K3bCdImageWritingDialog::createAudioCueItems( const K3bCueFileParser& cp ) +{ + K3bListViewItem* rootItem = new K3bListViewItem( m_infoView, m_infoView->lastItem(), + i18n("Detected:"), + i18n("Audio Cue Image") ); + rootItem->setForegroundColor( 0, palette().disabled().foreground() ); + rootItem->setPixmap( 0, SmallIcon( "sound") ); + + K3bListViewItem* trackParent = new K3bListViewItem( rootItem, + i18n("%n track", "%n tracks", cp.toc().count() ), + cp.toc().length().toString() ); + if( !cp.cdText().isEmpty() ) + trackParent->setText( 1, + QString("%1 (%2 - %3)") + .arg(trackParent->text(1)) + .arg(cp.cdText().performer()) + .arg(cp.cdText().title()) ); + + unsigned int i = 1; + for( K3bDevice::Toc::const_iterator it = cp.toc().begin(); + it != cp.toc().end(); ++it ) { + + K3bListViewItem* trackItem = + new K3bListViewItem( trackParent, m_infoView->lastItem(), + i18n("Track") + " " + QString::number(i).rightJustify( 2, '0' ), + " " + ( i < cp.toc().count() + ? (*it).length().toString() + : QString("??:??:??") ) ); + + if( !cp.cdText().isEmpty() && !cp.cdText()[i-1].isEmpty() ) + trackItem->setText( 1, + QString("%1 (%2 - %3)") + .arg(trackItem->text(1)) + .arg(cp.cdText()[i-1].performer()) + .arg(cp.cdText()[i-1].title()) ); + + ++i; + } + + rootItem->setOpen( true ); + trackParent->setOpen( true ); +} + + +void K3bCdImageWritingDialog::toggleAll() +{ + // enable the Write-Button if we found a valid image or the user forced an image type + setButtonEnabled( START_BUTTON, m_writerSelectionWidget->writerDevice() + && currentImageType() != IMAGE_UNKNOWN + && QFile::exists( imagePath() ) ); + + // cdrecord clone and cue both need DAO + if( m_writerSelectionWidget->writingApp() != K3b::CDRDAO + && ( currentImageType() == IMAGE_ISO || + currentImageType() == IMAGE_AUDIO_CUE ) ) + m_writingModeWidget->setSupportedModes( K3b::TAO|K3b::DAO|K3b::RAW ); // stuff supported by cdrecord + else + m_writingModeWidget->setSupportedModes( K3b::DAO ); + + // some stuff is only available for iso images + if( currentImageType() == IMAGE_ISO ) { + m_checkVerify->show(); + if( !d->advancedTabVisible ) + d->optionTabbed->addTab( d->advancedTab, i18n("Advanced") ); + d->advancedTabVisible = true; + if( m_checkDummy->isChecked() ) { + m_checkVerify->setEnabled( false ); + m_checkVerify->setChecked( false ); + } + else + m_checkVerify->setEnabled( true ); + } + else { + if( d->advancedTabVisible ) + d->optionTabbed->removePage( d->advancedTab ); + d->advancedTabVisible = false; + m_checkVerify->hide(); + } + + // and some other stuff only makes sense for audio cues + if( currentImageType() == IMAGE_AUDIO_CUE ) { + if( !d->tempPathTabVisible ) + d->optionTabbed->addTab( d->tempPathTab, i18n("&Image") ); + d->tempPathTabVisible = true; + m_tempDirSelectionWidget->setDisabled( !m_checkCacheImage->isChecked() ); + } + else { + if( d->tempPathTabVisible ) + d->optionTabbed->removePage( d->tempPathTab ); + d->tempPathTabVisible = false; + } + m_checkCacheImage->setShown( currentImageType() == IMAGE_AUDIO_CUE ); + + m_spinCopies->setEnabled( !m_checkDummy->isChecked() ); + + switch( currentImageType() ) { + case IMAGE_CDRDAO_TOC: + m_writerSelectionWidget->setSupportedWritingApps( K3b::CDRDAO ); + break; + case IMAGE_CDRECORD_CLONE: + m_writerSelectionWidget->setSupportedWritingApps( K3b::CDRECORD ); + break; + default: + m_writerSelectionWidget->setSupportedWritingApps( K3b::CDRECORD|K3b::CDRDAO ); + break; + } + + K3bListViewItem* item = dynamic_cast<K3bListViewItem*>(m_infoView->firstChild()); + if( item ) + item->setForegroundColor( 1, + currentImageType() != d->foundImageType + ? Qt::red + : m_infoView->colorGroup().foreground() ); +} + + +void K3bCdImageWritingDialog::setImage( const KURL& url ) +{ + d->imageForced = true; +#if KDE_IS_VERSION(3,4,0) + m_editImagePath->setKURL( url ); +#else + m_editImagePath->setURL( url.path() ); +#endif +} + + +void K3bCdImageWritingDialog::calculateMd5Sum( const QString& file ) +{ + d->haveMd5Sum = false; + + if( !d->md5SumItem ) + d->md5SumItem = new K3bListViewItem( m_infoView, m_infoView->firstChild() ); + + d->md5SumItem->setText( 0, i18n("Md5 Sum:") ); + d->md5SumItem->setForegroundColor( 0, palette().disabled().foreground() ); + d->md5SumItem->setProgress( 1, 0 ); + d->md5SumItem->setPixmap( 0, SmallIcon( "exec") ); + + if( file != d->lastCheckedFile ) { + d->lastCheckedFile = file; + d->md5Job->setFile( file ); + d->md5Job->start(); + } + else + slotMd5JobFinished( true ); +} + + +void K3bCdImageWritingDialog::slotMd5JobPercent( int p ) +{ + d->md5SumItem->setProgress( 1, p ); +} + + +void K3bCdImageWritingDialog::slotMd5JobFinished( bool success ) +{ + if( success ) { + d->md5SumItem->setText( 1, d->md5Job->hexDigest() ); + d->haveMd5Sum = true; + } + else { + d->md5SumItem->setForegroundColor( 1, Qt::red ); + if( d->md5Job->hasBeenCanceled() ) + d->md5SumItem->setText( 1, i18n("Calculation cancelled") ); + else + d->md5SumItem->setText( 1, i18n("Calculation failed") ); + d->md5SumItem->setPixmap( 0, SmallIcon( "stop") ); + d->lastCheckedFile.truncate(0); + } + + d->md5SumItem->setDisplayProgressBar( 1, false ); +} + + +void K3bCdImageWritingDialog::slotContextMenu( KListView*, QListViewItem*, const QPoint& pos ) +{ + if( !d->haveMd5Sum ) + return; + + QPopupMenu popup; + int copyItem = popup.insertItem( i18n("Copy checksum to clipboard") ); + int compareItem = popup.insertItem( i18n("Compare checksum...") ); + + int r = popup.exec( pos ); + + if( r == compareItem ) { + bool ok; + QString md5sumToCompare = KInputDialog::getText( i18n("MD5 Sum Check"), + i18n("Please insert the MD5 Sum to compare:"), + QString::null, + &ok, + this ); + if( ok ) { + if( md5sumToCompare.lower().utf8() == d->md5Job->hexDigest().lower() ) + KMessageBox::information( this, i18n("The MD5 Sum of %1 equals the specified.").arg(imagePath()), + i18n("MD5 Sums Equal") ); + else + KMessageBox::sorry( this, i18n("The MD5 Sum of %1 differs from the specified.").arg(imagePath()), + i18n("MD5 Sums Differ") ); + } + } + else if( r == copyItem ) { + QApplication::clipboard()->setText( d->md5Job->hexDigest().lower(), QClipboard::Clipboard ); + } +} + + +void K3bCdImageWritingDialog::loadUserDefaults( KConfigBase* c ) +{ + m_writingModeWidget->loadConfig( c ); + m_checkDummy->setChecked( c->readBoolEntry("simulate", false ) ); + m_checkNoFix->setChecked( c->readBoolEntry("multisession", false ) ); + m_checkCacheImage->setChecked( !c->readBoolEntry("on_the_fly", true ) ); + + m_dataModeWidget->loadConfig(c); + + m_spinCopies->setValue( c->readNumEntry( "copies", 1 ) ); + + m_checkVerify->setChecked( c->readBoolEntry( "verify_data", false ) ); + + m_writerSelectionWidget->loadConfig( c ); + + if( !d->imageForced ) { + QString image = c->readPathEntry( "image path", c->readPathEntry( "last written image" ) ); + if( QFile::exists( image ) ) + m_editImagePath->setURL( image ); + } + + QString imageType = c->readEntry( "image type", "auto" ); + int x = 0; + if( imageType == "iso9660" ) + x = d->imageTypeSelectionMapRev[IMAGE_ISO]; + else if( imageType == "cue-bin" ) + x = d->imageTypeSelectionMapRev[IMAGE_CUE_BIN]; + else if( imageType == "audio-cue" ) + x = d->imageTypeSelectionMapRev[IMAGE_AUDIO_CUE]; + else if( imageType == "cdrecord-clone" ) + x = d->imageTypeSelectionMapRev[IMAGE_CDRECORD_CLONE]; + else if( imageType == "cdrdao-toc" ) + x = d->imageTypeSelectionMapRev[IMAGE_CDRDAO_TOC]; + + m_comboImageType->setCurrentItem( x ); + + m_tempDirSelectionWidget->setTempPath( K3b::defaultTempPath() ); + + slotToggleAll(); +} + + +void K3bCdImageWritingDialog::saveUserDefaults( KConfigBase* c ) +{ + m_writingModeWidget->saveConfig( c ), + c->writeEntry( "simulate", m_checkDummy->isChecked() ); + c->writeEntry( "multisession", m_checkNoFix->isChecked() ); + c->writeEntry( "on_the_fly", !m_checkCacheImage->isChecked() ); + m_dataModeWidget->saveConfig(c); + + c->writeEntry( "verify_data", m_checkVerify->isChecked() ); + + m_writerSelectionWidget->saveConfig( c ); + + c->writePathEntry( "image path", imagePath() ); + + c->writeEntry( "copies", m_spinCopies->value() ); + + QString imageType; + if( m_comboImageType->currentItem() == 0 ) + imageType = "auto"; + else { + switch( d->imageTypeSelectionMap[m_comboImageType->currentItem()] ) { + case IMAGE_ISO: + imageType = "iso9660"; + break; + case IMAGE_CUE_BIN: + imageType = "cue-bin"; + break; + case IMAGE_AUDIO_CUE: + imageType = "audio-cue"; + break; + case IMAGE_CDRECORD_CLONE: + imageType = "cdrecord-clone"; + break; + case IMAGE_CDRDAO_TOC: + imageType = "cdrdao-toc"; + break; + } + } + c->writeEntry( "image type", imageType ); + + if( m_tempDirSelectionWidget->isEnabled() ) + m_tempDirSelectionWidget->saveConfig(); +} + +void K3bCdImageWritingDialog::loadK3bDefaults() +{ + m_writerSelectionWidget->loadDefaults(); + m_writingModeWidget->setWritingMode( K3b::WRITING_MODE_AUTO ); + m_checkDummy->setChecked( false ); + m_checkVerify->setChecked( false ); + m_checkNoFix->setChecked( false ); + m_checkCacheImage->setChecked( false ); + m_dataModeWidget->setDataMode( K3b::DATA_MODE_AUTO ); + m_comboImageType->setCurrentItem(0); + m_spinCopies->setValue( 1 ); + + slotToggleAll(); +} + + +int K3bCdImageWritingDialog::currentImageType() +{ + if( m_comboImageType->currentItem() == 0 ) + return d->foundImageType; + else + return d->imageTypeSelectionMap[m_comboImageType->currentItem()]; +} + + +QString K3bCdImageWritingDialog::imagePath() const +{ + return K3b::convertToLocalUrl( KURL::fromPathOrURL( m_editImagePath->url() ) ).path(); +} + + +void K3bCdImageWritingDialog::dragEnterEvent( QDragEnterEvent* e ) +{ + e->accept( KURLDrag::canDecode(e) ); +} + + +void K3bCdImageWritingDialog::dropEvent( QDropEvent* e ) +{ + KURL::List urls; + KURLDrag::decode( e, urls ); +#if KDE_IS_VERSION(3,4,0) + m_editImagePath->setKURL( urls.first() ); +#else + m_editImagePath->setURL( urls.first().path() ); +#endif +} + +#include "k3bcdimagewritingdialog.moc" diff --git a/src/misc/k3bcdimagewritingdialog.h b/src/misc/k3bcdimagewritingdialog.h new file mode 100644 index 0000000..143f023 --- /dev/null +++ b/src/misc/k3bcdimagewritingdialog.h @@ -0,0 +1,116 @@ +/* + * + * $Id$ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_CDIMAGEWRITINGDIALOG_H_ +#define _K3B_CDIMAGEWRITINGDIALOG_H_ + +#include <k3binteractiondialog.h> + + +class QCheckBox; +class K3bWriterSelectionWidget; +class QLabel; +class KURL; +class KActiveLabel; +class KProgress; +class K3bDataModeWidget; +class K3bWritingModeWidget; +class K3bTempDirSelectionWidget; +class KURLRequester; +class K3bListView; +class QSpinBox; +class QComboBox; +class K3bIso9660; +class K3bCueFileParser; +class QDragEnterEvent; +class QDropEvent; +class KListView; +class QListViewItem; +class QPoint; + + +/** + *@author Sebastian Trueg + */ +class K3bCdImageWritingDialog : public K3bInteractionDialog +{ + Q_OBJECT + + public: + K3bCdImageWritingDialog( QWidget* = 0, const char* = 0, bool = true ); + ~K3bCdImageWritingDialog(); + + void setImage( const KURL& url ); + + protected slots: + void slotStartClicked(); + + void slotMd5JobPercent( int ); + void slotMd5JobFinished( bool ); + void slotContextMenu( KListView*, QListViewItem*, const QPoint& pos ); + + void slotUpdateImage( const QString& ); + + protected: + void loadUserDefaults( KConfigBase* ); + void saveUserDefaults( KConfigBase* ); + void loadK3bDefaults(); + + void calculateMd5Sum( const QString& ); + void dragEnterEvent( QDragEnterEvent* ); + void dropEvent( QDropEvent* ); + + void init(); + + void toggleAll(); + + private: + enum { + IMAGE_UNKNOWN, + IMAGE_ISO, + IMAGE_CUE_BIN, + IMAGE_AUDIO_CUE, + IMAGE_CDRDAO_TOC, + IMAGE_CDRECORD_CLONE }; + + void setupGui(); + void createIso9660InfoItems( K3bIso9660* ); + void createCdrecordCloneItems( const QString&, const QString& ); + void createCueBinItems( const QString&, const QString& ); + void createAudioCueItems( const K3bCueFileParser& cp ); + int currentImageType(); + QString imagePath() const; + + K3bWriterSelectionWidget* m_writerSelectionWidget; + QCheckBox* m_checkDummy; + QCheckBox* m_checkNoFix; + QCheckBox* m_checkCacheImage; + QCheckBox* m_checkVerify; + K3bDataModeWidget* m_dataModeWidget; + K3bWritingModeWidget* m_writingModeWidget; + QSpinBox* m_spinCopies; + + KURLRequester* m_editImagePath; + QComboBox* m_comboImageType; + + K3bListView* m_infoView; + K3bTempDirSelectionWidget* m_tempDirSelectionWidget; + + class Private; + Private* d; +}; + +#endif diff --git a/src/misc/k3bdvdcopydialog.cpp b/src/misc/k3bdvdcopydialog.cpp new file mode 100644 index 0000000..f93abba --- /dev/null +++ b/src/misc/k3bdvdcopydialog.cpp @@ -0,0 +1,455 @@ +/* + * + * $Id: k3bdvdcopydialog.cpp 733470 2007-11-06 12:10:29Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bdvdcopydialog.h" +#include "k3bdvdcopyjob.h" + +#include <k3btempdirselectionwidget.h> +#include <k3bwriterselectionwidget.h> +#include <k3bglobals.h> +#include <k3bstdguiitems.h> +#include <k3bmediaselectioncombobox.h> +#include <k3bdevice.h> +#include <k3bdevicemanager.h> +#include <k3bexternalbinmanager.h> +#include <k3bburnprogressdialog.h> +#include <k3bwritingmodewidget.h> +#include <k3bthememanager.h> +#include <k3bapplication.h> +#include <k3bmediacache.h> +#include <k3biso9660.h> + +#include <qlayout.h> +#include <qgroupbox.h> +#include <qcheckbox.h> +#include <qlabel.h> +#include <qtabwidget.h> +#include <qspinbox.h> +#include <qptrlist.h> +#include <qfile.h> +#include <qpushbutton.h> +#include <qtooltip.h> +#include <qwhatsthis.h> +#include <qhbox.h> + +#include <kdebug.h> +#include <klocale.h> +#include <kconfig.h> +#include <kapplication.h> +#include <kstandarddirs.h> +#include <kiconloader.h> +#include <kmessagebox.h> +#include <kglobal.h> + + + +K3bDvdCopyDialog::K3bDvdCopyDialog( QWidget* parent, const char* name, bool modal ) + : K3bInteractionDialog( parent, name, + i18n("DVD Copy"), + i18n("No video transcoding!"), + START_BUTTON|CANCEL_BUTTON, + START_BUTTON, + "default dvd copy settings", + modal ) +{ + QWidget* w = mainWidget(); + + // + // Source group + // ////////////////////////////////////////////////////////////////////////// + QGroupBox* groupSource = new QGroupBox( 1, Qt::Vertical, i18n("Source Medium"), w ); + groupSource->setInsideSpacing( spacingHint() ); + groupSource->setInsideMargin( marginHint() ); + m_comboSourceDevice = new K3bMediaSelectionComboBox( groupSource ); + m_comboSourceDevice->setWantedMediumType( K3bDevice::MEDIA_WRITABLE_DVD|K3bDevice::MEDIA_DVD_ROM ); + m_comboSourceDevice->setWantedMediumState( K3bDevice::STATE_COMPLETE|K3bDevice::STATE_INCOMPLETE ); + // ////////////////////////////////////////////////////////////////////////// + + // + // Writer group + // ////////////////////////////////////////////////////////////////////////// + m_writerSelectionWidget = new K3bWriterSelectionWidget( w ); + m_writerSelectionWidget->setSupportedWritingApps( K3b::GROWISOFS ); + m_writerSelectionWidget->setWantedMediumType( K3bDevice::MEDIA_WRITABLE_DVD ); + m_writerSelectionWidget->setWantedMediumState( K3bDevice::STATE_EMPTY ); + // ////////////////////////////////////////////////////////////////////////// + + // + // Option tab + // ////////////////////////////////////////////////////////////////////////// + QTabWidget* tabWidget = new QTabWidget( w ); + + // option tab -------------------- + QWidget* optionTab = new QWidget( tabWidget ); + QGridLayout* optionTabGrid = new QGridLayout( optionTab ); + optionTabGrid->setSpacing( spacingHint() ); + optionTabGrid->setMargin( marginHint() ); + + QGroupBox* groupWritingMode = new QGroupBox( 1, Qt::Vertical, i18n("Writing Mode"), optionTab ); + groupWritingMode->setInsideMargin( marginHint() ); + m_writingModeWidget = new K3bWritingModeWidget( groupWritingMode ); + + QGroupBox* groupOptions = new QGroupBox( 5, Qt::Vertical, i18n("Settings"), optionTab ); + groupOptions->setInsideSpacing( spacingHint() ); + groupOptions->setInsideMargin( marginHint() ); + m_checkSimulate = K3bStdGuiItems::simulateCheckbox( groupOptions ); + m_checkCacheImage = K3bStdGuiItems::createCacheImageCheckbox( groupOptions ); + m_checkOnlyCreateImage = K3bStdGuiItems::onlyCreateImagesCheckbox( groupOptions ); + m_checkDeleteImages = K3bStdGuiItems::removeImagesCheckbox( groupOptions ); + m_checkVerifyData = K3bStdGuiItems::verifyCheckBox( groupOptions ); + + QGroupBox* groupCopies = new QGroupBox( 2, Qt::Horizontal, i18n("Copies"), optionTab ); + groupCopies->setInsideSpacing( spacingHint() ); + groupCopies->setInsideMargin( marginHint() ); + QLabel* pixLabel = new QLabel( groupCopies ); + pixLabel->setPixmap( SmallIcon( "cdcopy", KIcon::SizeMedium ) ); + pixLabel->setScaledContents( false ); + m_spinCopies = new QSpinBox( groupCopies ); + m_spinCopies->setMinValue( 1 ); + m_spinCopies->setMaxValue( 999 ); + + optionTabGrid->addWidget( groupWritingMode, 0, 0 ); + optionTabGrid->addMultiCellWidget( groupOptions, 0, 1, 1, 1 ); + optionTabGrid->addWidget( groupCopies, 1, 0 ); + optionTabGrid->setRowStretch( 1, 1 ); + optionTabGrid->setColStretch( 1, 1 ); + + tabWidget->addTab( optionTab, i18n("&Options") ); + + + // + // Image tab + // ////////////////////////////////////////////////////////////////////////// + QWidget* imageTab = new QWidget( tabWidget ); + QGridLayout* imageTabGrid = new QGridLayout( imageTab ); + imageTabGrid->setSpacing( spacingHint() ); + imageTabGrid->setMargin( marginHint() ); + + m_tempDirSelectionWidget = new K3bTempDirSelectionWidget( imageTab ); + m_tempDirSelectionWidget->setSelectionMode( K3bTempDirSelectionWidget::FILE ); + + imageTabGrid->addWidget( m_tempDirSelectionWidget, 0, 0 ); + + tabWidget->addTab( imageTab, i18n("&Image") ); + + + // + // advanced tab ------------------ + // ////////////////////////////////////////////////////////////////////////// + QWidget* advancedTab = new QWidget( tabWidget ); + QGridLayout* advancedTabGrid = new QGridLayout( advancedTab ); + advancedTabGrid->setSpacing( spacingHint() ); + advancedTabGrid->setMargin( marginHint() ); + + QGroupBox* groupGeneral = new QGroupBox( 2, Qt::Vertical, i18n("General"), advancedTab ); + groupGeneral->setInsideSpacing( spacingHint() ); + groupGeneral->setInsideMargin( marginHint() ); + QHBox* box = new QHBox( groupGeneral ); + box->setSpacing( spacingHint() ); + box->setStretchFactor( new QLabel( i18n("Read retries:"), box ), 1 ); + m_spinRetries = new QSpinBox( 1, 128, 1, box ); + m_checkIgnoreReadErrors = new QCheckBox( i18n("Ignore read errors"), groupGeneral ); + + advancedTabGrid->addWidget( groupGeneral, 0, 0 ); + + tabWidget->addTab( advancedTab, i18n("&Advanced") ); + // ////////////////////////////////////////////////////////////////////////// + + + // + // setup layout + // ////////////////////////////////////////////////////////////////////////// + QGridLayout* grid = new QGridLayout( w ); + grid->setMargin( 0 ); + grid->setSpacing( spacingHint() ); + + grid->addWidget( groupSource, 0, 0 ); + grid->addWidget( m_writerSelectionWidget, 1, 0 ); + grid->addWidget( tabWidget, 2, 0 ); + grid->setRowStretch( 2, 1 ); + // ////////////////////////////////////////////////////////////////////////// + + + // tab order + setTabOrder( m_writingModeWidget, m_spinCopies ); + setTabOrder( m_spinCopies, groupOptions ); + + + // + // setup connections + // ////////////////////////////////////////////////////////////////////////// + connect( m_writerSelectionWidget, SIGNAL(writerChanged()), this, SLOT(slotToggleAll()) ); + connect( m_comboSourceDevice, SIGNAL(selectionChanged(K3bDevice::Device*)), this, SLOT(slotToggleAll()) ); + connect( m_comboSourceDevice, SIGNAL(selectionChanged(K3bDevice::Device*)), + this, SLOT(slotSourceMediumChanged(K3bDevice::Device*)) ); + connect( m_checkSimulate, SIGNAL(toggled(bool)), this, SLOT(slotToggleAll()) ); + connect( m_checkCacheImage, SIGNAL(toggled(bool)), this, SLOT(slotToggleAll()) ); + connect( m_checkOnlyCreateImage, SIGNAL(toggled(bool)), this, SLOT(slotToggleAll()) ); + connect( m_writingModeWidget, SIGNAL(writingModeChanged(int)), this, SLOT(slotToggleAll()) ); + + QToolTip::add( m_checkIgnoreReadErrors, i18n("Skip unreadable sectors") ); + QWhatsThis::add( m_checkIgnoreReadErrors, i18n("<p>If this option is checked and K3b is not able to read a sector from the " + "source CD/DVD it will be replaced with zeros on the resulting copy.") ); +} + + +K3bDvdCopyDialog::~K3bDvdCopyDialog() +{ +} + + +void K3bDvdCopyDialog::init() +{ + slotSourceMediumChanged( m_comboSourceDevice->selectedDevice() ); +} + + +void K3bDvdCopyDialog::setReadingDevice( K3bDevice::Device* dev ) +{ + m_comboSourceDevice->setSelectedDevice( dev ); +} + + +K3bDevice::Device* K3bDvdCopyDialog::readingDevice() const +{ + return m_comboSourceDevice->selectedDevice(); +} + + +void K3bDvdCopyDialog::slotStartClicked() +{ + // + // Let's check the available size + // + if( m_checkCacheImage->isChecked() || m_checkOnlyCreateImage->isChecked() ) { + if( neededSize()/1024 > m_tempDirSelectionWidget->freeTempSpace() ) { + if( KMessageBox::warningContinueCancel( this, i18n("There seems to be not enough free space in temporary directory. " + "Write anyway?") ) == KMessageBox::Cancel ) + return; + } + } + + // + // The job asks if we want to overwrite. + // + + K3bJobProgressDialog* dlg = 0; + if( m_checkOnlyCreateImage->isChecked() ) { + dlg = new K3bJobProgressDialog( kapp->mainWidget() ); + } + else { + dlg = new K3bBurnProgressDialog( kapp->mainWidget() ); + } + + K3bDvdCopyJob* job = new K3bDvdCopyJob( dlg, this ); + + job->setWriterDevice( m_writerSelectionWidget->writerDevice() ); + job->setReaderDevice( m_comboSourceDevice->selectedDevice() ); + job->setImagePath( m_tempDirSelectionWidget->tempPath() ); + job->setRemoveImageFiles( m_checkDeleteImages->isChecked() && !m_checkOnlyCreateImage->isChecked() ); + job->setOnlyCreateImage( m_checkOnlyCreateImage->isChecked() ); + job->setSimulate( m_checkSimulate->isChecked() ); + job->setOnTheFly( !m_checkCacheImage->isChecked() ); + job->setWriteSpeed( m_writerSelectionWidget->writerSpeed() ); + job->setCopies( m_checkSimulate->isChecked() ? 1 : m_spinCopies->value() ); + job->setWritingMode( m_writingModeWidget->writingMode() ); + job->setIgnoreReadErrors( m_checkIgnoreReadErrors->isChecked() ); + job->setReadRetries( m_spinRetries->value() ); + job->setVerifyData( m_checkVerifyData->isChecked() ); + + if( !exitLoopOnHide() ) + hide(); + + dlg->startJob( job ); + + delete dlg; + delete job; + + if( KConfigGroup( k3bcore->config(), "General Options" ).readBoolEntry( "keep action dialogs open", false ) && + !exitLoopOnHide() ) + show(); + else + close(); +} + + +void K3bDvdCopyDialog::loadUserDefaults( KConfigBase* c ) +{ + m_comboSourceDevice->setSelectedDevice( k3bcore->deviceManager()->findDevice( c->readEntry( "source_device" ) ) ); + + m_writerSelectionWidget->loadConfig( c ); + + m_writingModeWidget->loadConfig( c ); + + m_tempDirSelectionWidget->readConfig( c ); + + m_checkSimulate->setChecked( c->readBoolEntry( "simulate", false ) ); + m_checkCacheImage->setChecked( !c->readBoolEntry( "on_the_fly", false ) ); + m_checkOnlyCreateImage->setChecked( c->readBoolEntry( "only_create_image", false ) ); + m_checkDeleteImages->setChecked( c->readBoolEntry( "remove_image", true ) ); + m_checkIgnoreReadErrors->setChecked( c->readBoolEntry( "ignore read errors", false ) ); + m_spinRetries->setValue( c->readNumEntry( "retries", 128 ) ); + m_spinCopies->setValue( c->readNumEntry( "copies", 1 ) ); + m_checkVerifyData->setChecked( c->readBoolEntry( "verify data", false ) ); + + slotToggleAll(); +} + + +void K3bDvdCopyDialog::saveUserDefaults( KConfigBase* c ) +{ + m_tempDirSelectionWidget->saveConfig(); + + m_writingModeWidget->saveConfig( c ); + m_tempDirSelectionWidget->saveConfig( c ); + + c->writeEntry( "source_device", m_comboSourceDevice->selectedDevice() ? m_comboSourceDevice->selectedDevice()->devicename() : QString() ); + + c->writeEntry( "simulate", m_checkSimulate->isChecked() ); + c->writeEntry( "on_the_fly", !m_checkCacheImage->isChecked() ); + c->writeEntry( "only_create_image", m_checkOnlyCreateImage->isChecked() ); + c->writeEntry( "remove_image", m_checkDeleteImages->isChecked() ); + c->writeEntry( "ignore read errors", m_checkIgnoreReadErrors->isChecked() ); + c->writeEntry( "retries", m_spinRetries->value() ); + c->writeEntry( "copies", m_spinCopies->value() ); + c->writeEntry( "verify data", m_checkVerifyData->isChecked() ); + + m_writerSelectionWidget->saveConfig( c ); + + if( m_tempDirSelectionWidget->isEnabled() ) + m_tempDirSelectionWidget->saveConfig(); +} + + +void K3bDvdCopyDialog::loadK3bDefaults() +{ + m_writerSelectionWidget->loadDefaults(); + m_tempDirSelectionWidget->setTempPath( K3b::defaultTempPath() ); + + m_writingModeWidget->setWritingMode( K3b::WRITING_MODE_AUTO ); + + m_checkSimulate->setChecked( false ); + m_checkCacheImage->setChecked( true ); + m_checkOnlyCreateImage->setChecked( false ); + m_checkDeleteImages->setChecked( true ); + m_checkIgnoreReadErrors->setChecked(false); + m_spinCopies->setValue( 1 ); + m_spinRetries->setValue(128); + m_checkVerifyData->setChecked( false ); + + slotToggleAll(); +} + + +void K3bDvdCopyDialog::toggleAll() +{ + updateOverrideDevice(); + + m_checkSimulate->setDisabled( m_checkOnlyCreateImage->isChecked() ); + m_checkCacheImage->setDisabled( m_checkOnlyCreateImage->isChecked() ); + + K3bDevice::Device* dev = m_writerSelectionWidget->writerDevice(); + if( dev ) { + // select the proper writing modes + // if writing and reading devices are the same we cannot use + // K3bWritingModeWidget::determineSupportedModesFromMedium since the inserted medium is not the one we + // will be using for burning. In that case we go the old fashioned way. + if( dev == m_comboSourceDevice->selectedDevice() ) { + int modes = 0; + if( dev->type() & (K3bDevice::DVDR|K3bDevice::DVDRW) ) { + modes |= K3b::DAO|K3b::WRITING_MODE_RES_OVWR; + if( dev->featureCurrent( K3bDevice::FEATURE_INCREMENTAL_STREAMING_WRITABLE ) != 0 ) + modes |= K3b::WRITING_MODE_INCR_SEQ; + } + + m_writingModeWidget->setSupportedModes( modes ); + m_checkSimulate->setDisabled( m_checkOnlyCreateImage->isChecked() ); + } + else { + m_writingModeWidget->determineSupportedModesFromMedium( dev ); + + if( k3bappcore->mediaCache()->diskInfo( dev ).mediaType() & K3bDevice::MEDIA_DVD_PLUS_ALL ) { + // no simulation support for DVD+R(W) media + m_checkSimulate->setChecked(false); + m_checkSimulate->setEnabled(false); + } + else { + m_checkSimulate->setDisabled( m_checkOnlyCreateImage->isChecked() ); + } + } + } + + + + m_writingModeWidget->setDisabled( m_checkOnlyCreateImage->isChecked() ); + m_writerSelectionWidget->setDisabled( m_checkOnlyCreateImage->isChecked() ); + m_tempDirSelectionWidget->setDisabled( !m_checkCacheImage->isChecked() && !m_checkOnlyCreateImage->isChecked() ); + m_writingModeWidget->setDisabled( m_checkOnlyCreateImage->isChecked() ); + m_checkDeleteImages->setDisabled( m_checkOnlyCreateImage->isChecked() || !m_checkCacheImage->isChecked() ); + m_spinCopies->setDisabled( m_checkSimulate->isChecked() || m_checkOnlyCreateImage->isChecked() ); + m_checkVerifyData->setDisabled( m_checkOnlyCreateImage->isChecked() || m_checkSimulate->isChecked() ); + + setButtonEnabled( START_BUTTON, m_comboSourceDevice->selectedDevice() && + (dev || m_checkOnlyCreateImage->isChecked()) ); +} + + +void K3bDvdCopyDialog::slotSourceMediumChanged( K3bDevice::Device* dev ) +{ + updateOverrideDevice(); + + K3bMedium medium = k3bappcore->mediaCache()->medium( dev ); + + m_writerSelectionWidget->setWantedMediumType( k3bappcore->mediaCache()->diskInfo( dev ).numLayers() > 1 && + k3bappcore->mediaCache()->diskInfo( dev ).size().mode1Bytes() > 4700372992LL + ? K3bDevice::MEDIA_WRITABLE_DVD_DL + : K3bDevice::MEDIA_WRITABLE_DVD_SL ); + + m_tempDirSelectionWidget->setNeededSize( neededSize() ); + + m_tempDirSelectionWidget->setDefaultImageFileName( medium.volumeId().lower() + ".iso" ); + + toggleAll(); +} + + +void K3bDvdCopyDialog::updateOverrideDevice() +{ + if( !m_checkCacheImage->isChecked() ) { + m_writerSelectionWidget->setOverrideDevice( 0 ); + m_writerSelectionWidget->setIgnoreDevice( m_comboSourceDevice->selectedDevice() ); + } + else { + m_writerSelectionWidget->setIgnoreDevice( 0 ); + m_writerSelectionWidget->setOverrideDevice( m_comboSourceDevice->selectedDevice(), + i18n("Use the same device for burning"), + i18n("<qt>Use the same device for burning <i>(Or insert another medium)</i>") ); + } +} + + +KIO::filesize_t K3bDvdCopyDialog::neededSize() const +{ + K3bMedium medium = k3bappcore->mediaCache()->medium( m_comboSourceDevice->selectedDevice() ); + + if( medium.diskInfo().diskState() == K3bDevice::STATE_NO_MEDIA ) + return 0; + else if( medium.diskInfo().mediaType() & (K3bDevice::MEDIA_DVD_RW_OVWR|K3bDevice::MEDIA_DVD_PLUS_RW) ) + return (KIO::filesize_t)medium.iso9660Descriptor().volumeSpaceSize * (KIO::filesize_t)2048; + else + return medium.diskInfo().size().mode1Bytes(); +} + +#include "k3bdvdcopydialog.moc" diff --git a/src/misc/k3bdvdcopydialog.h b/src/misc/k3bdvdcopydialog.h new file mode 100644 index 0000000..be696c4 --- /dev/null +++ b/src/misc/k3bdvdcopydialog.h @@ -0,0 +1,79 @@ +/* + * + * $Id: k3bdvdcopydialog.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_DVD_COPY_DIALOG_H_ +#define _K3B_DVD_COPY_DIALOG_H_ + +#include <k3binteractiondialog.h> + +#include <kio/global.h> + + +namespace K3bDevice { + class Device; + class DeviceManager; +} + +class K3bTempDirSelectionWidget; +class K3bWriterSelectionWidget; +class K3bMediaSelectionComboBox; +class QCheckBox; +class QSpinBox; +class K3bWritingModeWidget; + + +class K3bDvdCopyDialog : public K3bInteractionDialog +{ + Q_OBJECT + + public: + K3bDvdCopyDialog( QWidget* parent = 0, const char* name = 0, bool modal = true ); + ~K3bDvdCopyDialog(); + + void setReadingDevice( K3bDevice::Device* ); + K3bDevice::Device* readingDevice() const; + + private slots: + void slotStartClicked(); + void slotSourceMediumChanged( K3bDevice::Device* ); + void updateOverrideDevice(); + + protected: + void init(); + void toggleAll(); + + private: + void loadUserDefaults( KConfigBase* ); + void saveUserDefaults( KConfigBase* ); + void loadK3bDefaults(); + + KIO::filesize_t neededSize() const; + + K3bWriterSelectionWidget* m_writerSelectionWidget; + K3bTempDirSelectionWidget* m_tempDirSelectionWidget; + K3bMediaSelectionComboBox* m_comboSourceDevice; + QCheckBox* m_checkSimulate; + QCheckBox* m_checkDeleteImages; + QCheckBox* m_checkOnlyCreateImage; + QCheckBox* m_checkCacheImage; + QCheckBox* m_checkVerifyData; + QSpinBox* m_spinCopies; + QSpinBox* m_spinRetries; + QCheckBox* m_checkIgnoreReadErrors; + K3bWritingModeWidget* m_writingModeWidget; +}; + +#endif diff --git a/src/misc/k3bdvdformattingdialog.cpp b/src/misc/k3bdvdformattingdialog.cpp new file mode 100644 index 0000000..d84c4fc --- /dev/null +++ b/src/misc/k3bdvdformattingdialog.cpp @@ -0,0 +1,185 @@ +/* + * + * $Id: k3bdvdformattingdialog.cpp 640188 2007-03-07 09:15:25Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bdvdformattingdialog.h" +#include "k3bdvdformattingjob.h" + +#include <k3bdevice.h> +#include <k3bdevicemanager.h> +#include <k3bglobals.h> +#include <k3bcore.h> +#include <k3bwriterselectionwidget.h> +#include <k3bwritingmodewidget.h> +#include <k3bjobprogressdialog.h> + +#include <klocale.h> +#include <kmessagebox.h> +#include <kconfig.h> +#include <kapplication.h> + +#include <qgroupbox.h> +#include <qlayout.h> +#include <qcheckbox.h> +#include <qframe.h> +#include <qpushbutton.h> +#include <qtooltip.h> +#include <qwhatsthis.h> + + +K3bDvdFormattingDialog::K3bDvdFormattingDialog( QWidget* parent, const char* name, bool modal ) + : K3bInteractionDialog( parent, name, + i18n("DVD Formatting"), + i18n("DVD%1RW").arg(""), + START_BUTTON|CANCEL_BUTTON, + START_BUTTON, + "DVD Formatting", // config group + modal ) +{ + QWidget* frame = mainWidget(); + + m_writerSelectionWidget = new K3bWriterSelectionWidget( frame ); + m_writerSelectionWidget->setWantedMediumType( K3bDevice::MEDIA_REWRITABLE_DVD ); + // we need state empty here for preformatting DVD+RW. + m_writerSelectionWidget->setWantedMediumState( K3bDevice::STATE_COMPLETE| + K3bDevice::STATE_INCOMPLETE| + K3bDevice::STATE_EMPTY ); + m_writerSelectionWidget->setSupportedWritingApps( K3b::DVD_RW_FORMAT ); + m_writerSelectionWidget->setForceAutoSpeed(true); + + QGroupBox* groupWritingMode = new QGroupBox( 1, Qt::Vertical, i18n("Writing Mode"), frame ); + groupWritingMode->layout()->setMargin( marginHint() ); + groupWritingMode->layout()->setSpacing( spacingHint() ); + m_writingModeWidget = new K3bWritingModeWidget( K3b::WRITING_MODE_INCR_SEQ|K3b::WRITING_MODE_RES_OVWR, + groupWritingMode ); + + + QGroupBox* groupOptions = new QGroupBox( 2, Qt::Vertical, i18n("Settings"), frame ); + groupOptions->layout()->setMargin( marginHint() ); + groupOptions->layout()->setSpacing( spacingHint() ); + m_checkForce = new QCheckBox( i18n("Force"), groupOptions ); + m_checkQuickFormat = new QCheckBox( i18n("Quick format"), groupOptions ); + + QGridLayout* grid = new QGridLayout( frame ); + grid->setMargin( 0 ); + grid->setSpacing( spacingHint() ); + + grid->addMultiCellWidget( m_writerSelectionWidget, 0, 0, 0, 1 ); + grid->addWidget( groupWritingMode, 1, 0 ); + grid->addWidget( groupOptions, 1, 1 ); + grid->setRowStretch( 1, 1 ); + + + QToolTip::add( m_checkForce, i18n("Force formatting of empty DVDs") ); + QWhatsThis::add( m_checkForce, i18n("<p>If this option is checked K3b will format a " + "DVD-RW even if it is empty. It may also be used to " + "force K3b to format a DVD+RW or a DVD-RW in restricted " + "overwrite mode." + "<p><b>Caution:</b> It is not recommended to often format a DVD " + "since it may already be unusable after 10-20 reformat procedures." + "<p>DVD+RW media only needs to be formatted once. After that it " + "just needs to be overwritten. The same applies to DVD-RW in " + "restricted overwrite mode.") ); + + QToolTip::add( m_checkQuickFormat, i18n("Try to perform quick formatting") ); + QWhatsThis::add( m_checkQuickFormat, i18n("<p>If this option is checked K3b will tell the writer " + "to perform a quick format." + "<p>Formatting a DVD-RW completely can take a very long " + "time and some DVD writers perform a full format even if " + "quick format is enabled." ) ); + + connect( m_writerSelectionWidget, SIGNAL(writerChanged()), this, SLOT(slotWriterChanged()) ); + connect( m_writerSelectionWidget, SIGNAL(writerChanged(K3bDevice::Device*)), + m_writingModeWidget, SLOT(determineSupportedModesFromMedium(K3bDevice::Device*)) ); + + slotWriterChanged(); +} + + +K3bDvdFormattingDialog::~K3bDvdFormattingDialog() +{ +} + + +void K3bDvdFormattingDialog::setDevice( K3bDevice::Device* dev ) +{ + m_writerSelectionWidget->setWriterDevice( dev ); +} + + +void K3bDvdFormattingDialog::slotStartClicked() +{ + // + // create a jobprogressdialog and start the job + // + + + + K3bJobProgressDialog d( kapp->mainWidget(), "formattingProgress", false ); + + K3bDvdFormattingJob* job = new K3bDvdFormattingJob( &d, this ); + job->setDevice( m_writerSelectionWidget->writerDevice() ); + job->setMode( m_writingModeWidget->writingMode() ); + job->setForce( m_checkForce->isChecked() ); + job->setQuickFormat( m_checkQuickFormat->isChecked() ); + + if( !exitLoopOnHide() ) + hide(); + + d.startJob( job ); + + delete job; + + if( KConfigGroup( k3bcore->config(), "General Options" ).readBoolEntry( "keep action dialogs open", false ) && + !exitLoopOnHide() ) + show(); + else + close(); +} + + +void K3bDvdFormattingDialog::slotWriterChanged() +{ + setButtonEnabled( START_BUTTON, m_writerSelectionWidget->writerDevice() != 0 ); +} + + +void K3bDvdFormattingDialog::loadUserDefaults( KConfigBase* c ) +{ + m_checkForce->setChecked( c->readBoolEntry( "force", false ) ); + m_checkQuickFormat->setChecked( c->readBoolEntry( "quick format", true ) ); + m_writerSelectionWidget->loadConfig( c ); + m_writingModeWidget->loadConfig( c ); +} + + +void K3bDvdFormattingDialog::saveUserDefaults( KConfigBase* c ) +{ + c->writeEntry( "force", m_checkForce->isChecked() ); + c->writeEntry( "quick format", m_checkQuickFormat->isChecked() ); + m_writerSelectionWidget->saveConfig( c ); + m_writingModeWidget->saveConfig( c ); +} + + +void K3bDvdFormattingDialog::loadK3bDefaults() +{ + m_writerSelectionWidget->loadDefaults(); + m_checkForce->setChecked( false ); + m_checkQuickFormat->setChecked( true ); + m_writingModeWidget->setWritingMode( K3b::WRITING_MODE_AUTO ); +} + + +#include "k3bdvdformattingdialog.moc" diff --git a/src/misc/k3bdvdformattingdialog.h b/src/misc/k3bdvdformattingdialog.h new file mode 100644 index 0000000..1314ae1 --- /dev/null +++ b/src/misc/k3bdvdformattingdialog.h @@ -0,0 +1,55 @@ +/* + * + * $Id: k3bdvdformattingdialog.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_DVD_FORMATTING_DIALOG_H_ +#define _K3B_DVD_FORMATTING_DIALOG_H_ + +#include <k3binteractiondialog.h> + + +class QCheckBox; +class K3bWritingModeWidget; +class K3bWriterSelectionWidget; +namespace K3bDevice { + class Device; +} + +class K3bDvdFormattingDialog : public K3bInteractionDialog +{ + Q_OBJECT + + public: + K3bDvdFormattingDialog( QWidget* = 0, const char* = 0, bool modal = true ); + ~K3bDvdFormattingDialog(); + + public slots: + void setDevice( K3bDevice::Device* ); + + protected slots: + void slotStartClicked(); + void slotWriterChanged(); + + private: + void loadUserDefaults( KConfigBase* ); + void saveUserDefaults( KConfigBase* ); + void loadK3bDefaults(); + + K3bWriterSelectionWidget* m_writerSelectionWidget; + K3bWritingModeWidget* m_writingModeWidget; + QCheckBox* m_checkForce; + QCheckBox* m_checkQuickFormat; +}; + +#endif diff --git a/src/misc/k3bisoimagewritingdialog.cpp b/src/misc/k3bisoimagewritingdialog.cpp new file mode 100644 index 0000000..1832ee5 --- /dev/null +++ b/src/misc/k3bisoimagewritingdialog.cpp @@ -0,0 +1,580 @@ +/* + * + * $Id$ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bisoimagewritingdialog.h" +#include "k3biso9660imagewritingjob.h" + +#include <k3bdevicemanager.h> +#include <k3bdevice.h> +#include <k3bwriterselectionwidget.h> +#include <k3bburnprogressdialog.h> +#include <kcutlabel.h> +#include <k3bstdguiitems.h> +#include <k3bmd5job.h> +#include <k3bglobals.h> +#include <k3bwritingmodewidget.h> +#include <k3bcore.h> +#include <k3blistview.h> +#include <k3biso9660.h> +#include <k3bapplication.h> +#include <k3bmediacache.h> + +#include <kapplication.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kurlrequester.h> +#include <kfiledialog.h> +#include <kstdguiitem.h> +#include <kguiitem.h> +#include <kiconloader.h> +#include <kconfig.h> +#include <kio/global.h> +#include <kurl.h> +#include <kinputdialog.h> +#include <kurldrag.h> +#include <klineedit.h> + +#include <qheader.h> +#include <qgroupbox.h> +#include <qcheckbox.h> +#include <qlabel.h> +#include <qcombobox.h> +#include <qlayout.h> +#include <qfile.h> +#include <qfileinfo.h> +#include <qpushbutton.h> +#include <qtabwidget.h> +#include <qtooltip.h> +#include <qwhatsthis.h> +#include <qspinbox.h> +#include <qevent.h> +#include <qpopupmenu.h> +#include <qclipboard.h> + + +class K3bIsoImageWritingDialog::Private +{ +public: + Private() + : md5SumItem(0), + haveMd5Sum( false ), + imageForced( false ) { + } + + K3bListViewItem* md5SumItem; + bool haveMd5Sum; + QString lastCheckedFile; + bool isIsoImage; + + bool imageForced; +}; + + +K3bIsoImageWritingDialog::K3bIsoImageWritingDialog( QWidget* parent, const char* name, bool modal ) + : K3bInteractionDialog( parent, name, + i18n("Burn Iso9660 Image"), + i18n("to DVD"), + START_BUTTON|CANCEL_BUTTON, + START_BUTTON, + "DVD image writing", + modal ) +{ + d = new Private(); + + setAcceptDrops(true); + setupGui(); + + m_writerSelectionWidget->setWantedMediumType( K3bDevice::MEDIA_WRITABLE_DVD ); + m_writerSelectionWidget->setWantedMediumState( K3bDevice::STATE_EMPTY ); + m_writerSelectionWidget->setSupportedWritingApps( K3b::GROWISOFS ); + m_writingModeWidget->setSupportedModes( K3b::DAO|K3b::WRITING_MODE_INCR_SEQ|K3b::WRITING_MODE_RES_OVWR ); + + m_md5Job = new K3bMd5Job( 0, this ); + connect( m_md5Job, SIGNAL(finished(bool)), + this, SLOT(slotMd5JobFinished(bool)) ); + connect( m_md5Job, SIGNAL(percent(int)), + this, SLOT(slotMd5JobPercent(int)) ); + + updateImageSize( imagePath() ); + + connect( m_writerSelectionWidget, SIGNAL(writerChanged()), + this, SLOT(slotWriterChanged()) ); + connect( m_writerSelectionWidget, SIGNAL(writingAppChanged(int)), + this, SLOT(slotWriterChanged()) ); + connect( m_writingModeWidget, SIGNAL(writingModeChanged(int)), + this, SLOT(slotWriterChanged()) ); + connect( m_editImagePath, SIGNAL(textChanged(const QString&)), + this, SLOT(updateImageSize(const QString&)) ); + connect( m_checkDummy, SIGNAL(toggled(bool)), + this, SLOT(slotWriterChanged()) ); +} + + +K3bIsoImageWritingDialog::~K3bIsoImageWritingDialog() +{ + delete d; +} + + +void K3bIsoImageWritingDialog::init() +{ + if( !d->imageForced ) { + // when opening the dialog first the default settings are loaded and afterwards we set the + // last written image because that's what most users want + KConfig* c = k3bcore->config(); + c->setGroup( configGroup() ); + QString image = c->readPathEntry( "last written image" ); + if( QFile::exists( image ) ) + m_editImagePath->setURL( image ); + } +} + + +void K3bIsoImageWritingDialog::setupGui() +{ + QWidget* frame = mainWidget(); + + // image + // ----------------------------------------------------------------------- + QGroupBox* groupImageUrl = new QGroupBox( 1, Qt::Horizontal, i18n("Image to Burn"), frame ); + m_editImagePath = new KURLRequester( groupImageUrl ); + m_editImagePath->setMode( KFile::File|KFile::ExistingOnly ); + m_editImagePath->setCaption( i18n("Choose Image File") ); + m_editImagePath->setFilter( i18n("*.iso *.ISO|ISO9660 Image Files") + "\n" + + i18n("*|All Files") ); + + connect( m_editImagePath->lineEdit(), SIGNAL( textChanged ( const QString & ) ), this, SLOT( slotWriterChanged() ) ); + + // image info + // ----------------------------------------------------------------------- + m_infoView = new K3bListView( frame ); + m_infoView->addColumn( "key" ); + m_infoView->addColumn( "value" ); + m_infoView->header()->hide(); + m_infoView->setNoItemText( i18n("No image file selected") ); + m_infoView->setSorting( -1 ); + m_infoView->setAlternateBackground( QColor() ); + m_infoView->setFullWidth(true); + m_infoView->setSelectionMode( QListView::NoSelection ); + + connect( m_infoView, SIGNAL(contextMenu(KListView*, QListViewItem*, const QPoint&)), + this, SLOT(slotContextMenu(KListView*, QListViewItem*, const QPoint&)) ); + + m_writerSelectionWidget = new K3bWriterSelectionWidget( frame ); + + // options + // ----------------------------------------------------------------------- + QTabWidget* optionTabbed = new QTabWidget( frame ); + + QWidget* optionTab = new QWidget( optionTabbed ); + QGridLayout* optionTabLayout = new QGridLayout( optionTab ); + optionTabLayout->setAlignment( Qt::AlignTop ); + optionTabLayout->setSpacing( spacingHint() ); + optionTabLayout->setMargin( marginHint() ); + + QGroupBox* writingModeGroup = new QGroupBox( 1, Vertical, i18n("Writing Mode"), optionTab ); + writingModeGroup->setInsideMargin( marginHint() ); + m_writingModeWidget = new K3bWritingModeWidget( writingModeGroup ); + + + // copies -------- + QGroupBox* groupCopies = new QGroupBox( 2, Qt::Horizontal, i18n("Copies"), optionTab ); + groupCopies->setInsideSpacing( spacingHint() ); + groupCopies->setInsideMargin( marginHint() ); + QLabel* pixLabel = new QLabel( groupCopies ); + pixLabel->setPixmap( SmallIcon( "cdcopy", KIcon::SizeMedium ) ); + pixLabel->setScaledContents( false ); + m_spinCopies = new QSpinBox( groupCopies ); + m_spinCopies->setMinValue( 1 ); + m_spinCopies->setMaxValue( 999 ); + // -------- copies + + QGroupBox* optionGroup = new QGroupBox( 3, Vertical, i18n("Settings"), optionTab ); + optionGroup->setInsideMargin( marginHint() ); + optionGroup->setInsideSpacing( spacingHint() ); + m_checkDummy = K3bStdGuiItems::simulateCheckbox( optionGroup ); + m_checkVerify = K3bStdGuiItems::verifyCheckBox( optionGroup ); + + + optionTabLayout->addWidget( writingModeGroup, 0, 0 ); + optionTabLayout->addWidget( groupCopies, 1, 0 ); + optionTabLayout->addMultiCellWidget( optionGroup, 0, 1, 1, 1 ); + optionTabLayout->setRowStretch( 1, 1 ); + optionTabLayout->setColStretch( 1, 1 ); + + optionTabbed->addTab( optionTab, i18n("Settings") ); + + + QGridLayout* grid = new QGridLayout( frame ); + grid->setSpacing( spacingHint() ); + grid->setMargin( 0 ); + + grid->addWidget( groupImageUrl, 0, 0 ); + grid->addWidget( m_infoView, 1, 0 ); + grid->addWidget( m_writerSelectionWidget, 2, 0 ); + grid->addWidget( optionTabbed, 3, 0 ); + + grid->setRowStretch( 1, 1 ); +} + + +void K3bIsoImageWritingDialog::slotStartClicked() +{ + if( !d->isIsoImage ) { + if( KMessageBox::warningContinueCancel( this, + i18n("The image you selected is not a valid ISO9660 image. " + "Are you sure you want to burn it anyway? " + "(There may exist other valid image types that are not detected by K3b but " + "will work fine.)"), i18n("Burn") ) == KMessageBox::Cancel ) + return; + } + + K3bIso9660 isoFs( imagePath() ); + if( isoFs.open() ) { + if( K3b::imageFilesize( KURL::fromPathOrURL( imagePath() ) ) < (KIO::filesize_t)(isoFs.primaryDescriptor().volumeSpaceSize*2048) ) { + if( KMessageBox::questionYesNo( this, + i18n("<p>This image has an invalid file size." + "If it has been downloaded make sure the download is complete." + "<p>Only continue if you know what you are doing."), + i18n("Warning"), + i18n("Continue"), + i18n("Cancel") ) == KMessageBox::No ) + return; + } + } + + m_md5Job->cancel(); + + // save the path + KConfig* c = k3bcore->config(); + c->setGroup( configGroup() ); + if( c->readPathEntry( "last written image" ).isEmpty() ) + c->writePathEntry( "last written image", imagePath() ); + + // create a progresswidget + K3bBurnProgressDialog dlg( kapp->mainWidget(), "burnProgress", true ); + + // create the job + K3bIso9660ImageWritingJob* job = new K3bIso9660ImageWritingJob( &dlg ); + + job->setBurnDevice( m_writerSelectionWidget->writerDevice() ); + job->setSpeed( m_writerSelectionWidget->writerSpeed() ); + job->setSimulate( m_checkDummy->isChecked() ); + job->setWritingMode( m_writingModeWidget->writingMode() ); + job->setVerifyData( m_checkVerify->isChecked() ); + job->setCopies( m_checkDummy->isChecked() ? 1 : m_spinCopies->value() ); + job->setImagePath( imagePath() ); + + // HACK (needed since if the medium is forced the stupid K3bIso9660ImageWritingJob defaults to cd writing) + job->setWritingApp( K3b::GROWISOFS ); + + if( !exitLoopOnHide() ) + hide(); + + dlg.startJob( job ); + + delete job; + + if( KConfigGroup( k3bcore->config(), "General Options" ).readBoolEntry( "keep action dialogs open", false ) && + !exitLoopOnHide() ) + show(); + else + close(); +} + + +void K3bIsoImageWritingDialog::updateImageSize( const QString& path ) +{ + m_md5Job->cancel(); + m_infoView->clear(); + d->md5SumItem = 0; + d->haveMd5Sum = false; + d->isIsoImage = false; + + QFileInfo info( path ); + if( info.isFile() ) { + + KIO::filesize_t imageSize = K3b::filesize( KURL::fromPathOrURL(path) ); + + // ------------------------------------------------ + // Test for iso9660 image + // ------------------------------------------------ + K3bIso9660 isoF( path ); + if( isoF.open() ) { + + d->isIsoImage = true; + + K3bListViewItem* isoRootItem = new K3bListViewItem( m_infoView, m_infoView->lastItem(), + i18n("Iso9660 image") ); + isoRootItem->setForegroundColor( 0, palette().disabled().foreground() ); + isoRootItem->setPixmap( 0, SmallIcon( "cdimage") ); + + K3bListViewItem* item = new K3bListViewItem( isoRootItem, m_infoView->lastItem(), + i18n("Filesize:"), KIO::convertSize( imageSize ) ); + item->setForegroundColor( 0, palette().disabled().foreground() ); + + item = new K3bListViewItem( isoRootItem, + m_infoView->lastItem(), + i18n("System Id:"), + isoF.primaryDescriptor().systemId.isEmpty() + ? QString("-") + : isoF.primaryDescriptor().systemId ); + item->setForegroundColor( 0, palette().disabled().foreground() ); + + item = new K3bListViewItem( isoRootItem, + m_infoView->lastItem(), + i18n("Volume Id:"), + isoF.primaryDescriptor().volumeId.isEmpty() + ? QString("-") + : isoF.primaryDescriptor().volumeId ); + item->setForegroundColor( 0, palette().disabled().foreground() ); + + item = new K3bListViewItem( isoRootItem, + m_infoView->lastItem(), + i18n("Volume Set Id:"), + isoF.primaryDescriptor().volumeSetId.isEmpty() + ? QString("-") + : isoF.primaryDescriptor().volumeSetId ); + item->setForegroundColor( 0, palette().disabled().foreground() ); + + item = new K3bListViewItem( isoRootItem, + m_infoView->lastItem(), + i18n("Publisher Id:"), + isoF.primaryDescriptor().publisherId.isEmpty() + ? QString("-") + : isoF.primaryDescriptor().publisherId ); + item->setForegroundColor( 0, palette().disabled().foreground() ); + + item = new K3bListViewItem( isoRootItem, + m_infoView->lastItem(), + i18n("Preparer Id:"), + isoF.primaryDescriptor().preparerId.isEmpty() + ? QString("-") : isoF.primaryDescriptor().preparerId ); + item->setForegroundColor( 0, palette().disabled().foreground() ); + + item = new K3bListViewItem( isoRootItem, + m_infoView->lastItem(), + i18n("Application Id:"), + isoF.primaryDescriptor().applicationId.isEmpty() + ? QString("-") + : isoF.primaryDescriptor().applicationId ); + item->setForegroundColor( 0, palette().disabled().foreground() ); + + isoRootItem->setOpen( true ); + + isoF.close(); + } + else { + K3bListViewItem* item = new K3bListViewItem( m_infoView, m_infoView->lastItem(), + i18n("Not an Iso9660 image") ); + item->setForegroundColor( 0, Qt::red ); + item->setPixmap( 0, SmallIcon( "stop") ); + } + + calculateMd5Sum( path ); + } + + slotWriterChanged(); +} + + +void K3bIsoImageWritingDialog::slotWriterChanged() +{ + K3bDevice::Device* dev = m_writerSelectionWidget->writerDevice(); + if( dev ) { + K3bMedium medium = k3bappcore->mediaCache()->medium( dev ); + if( medium.diskInfo().mediaType() & K3bDevice::MEDIA_DVD_PLUS_ALL ) { + // no simulation support for DVD+R(W) media + m_checkDummy->setChecked(false); + m_checkDummy->setEnabled(false); + } + else { + m_checkDummy->setDisabled( false ); + } + + m_writingModeWidget->determineSupportedModesFromMedium( dev ); + + if( m_checkDummy->isChecked() ) { + m_checkVerify->setEnabled( false ); + m_checkVerify->setChecked( false ); + } + else + m_checkVerify->setEnabled( true ); + + m_spinCopies->setEnabled( !m_checkDummy->isChecked() ); + } + + setButtonEnabled( START_BUTTON, + dev && !m_editImagePath->lineEdit()->text().isEmpty() ); +} + + +void K3bIsoImageWritingDialog::setImage( const KURL& url ) +{ + d->imageForced = true; +#if KDE_IS_VERSION(3,4,0) + m_editImagePath->setKURL( url ); +#else + m_editImagePath->setURL( url.path() ); +#endif +} + + +void K3bIsoImageWritingDialog::calculateMd5Sum( const QString& file ) +{ + d->haveMd5Sum = false; + + if( !d->md5SumItem ) + d->md5SumItem = new K3bListViewItem( m_infoView, m_infoView->firstChild() ); + + d->md5SumItem->setText( 0, i18n("Md5 Sum:") ); + d->md5SumItem->setForegroundColor( 0, palette().disabled().foreground() ); + d->md5SumItem->setProgress( 1, 0 ); + d->md5SumItem->setPixmap( 0, SmallIcon( "exec") ); + + if( file != d->lastCheckedFile ) { + d->lastCheckedFile = file; + m_md5Job->setFile( file ); + m_md5Job->start(); + } + else + slotMd5JobFinished( true ); +} + + +void K3bIsoImageWritingDialog::slotMd5JobPercent( int p ) +{ + d->md5SumItem->setProgress( 1, p ); +} + + +void K3bIsoImageWritingDialog::slotMd5JobFinished( bool success ) +{ + if( success ) { + d->md5SumItem->setText( 1, m_md5Job->hexDigest() ); + d->haveMd5Sum = true; + } + else { + d->md5SumItem->setForegroundColor( 1, Qt::red ); + if( m_md5Job->hasBeenCanceled() ) + d->md5SumItem->setText( 1, i18n("Calculation cancelled") ); + else + d->md5SumItem->setText( 1, i18n("Calculation failed") ); + d->md5SumItem->setPixmap( 0, SmallIcon( "stop") ); + d->lastCheckedFile.truncate(0); + } + + d->md5SumItem->setDisplayProgressBar( 1, false ); +} + + +void K3bIsoImageWritingDialog::slotContextMenu( KListView*, QListViewItem*, const QPoint& pos ) +{ + if( !d->haveMd5Sum ) + return; + + QPopupMenu popup; + int copyItem = popup.insertItem( i18n("Copy checksum to clipboard") ); + int compareItem = popup.insertItem( i18n("Compare checksum...") ); + + int r = popup.exec( pos ); + + if( r == compareItem ) { + bool ok; + QString md5sumToCompare = KInputDialog::getText( i18n("MD5 Sum Check"), + i18n("Please insert the MD5 Sum to compare:"), + QString::null, + &ok, + this ); + if( ok ) { + if( md5sumToCompare.lower().utf8() == m_md5Job->hexDigest().lower() ) + KMessageBox::information( this, i18n("The MD5 Sum of %1 equals the specified.").arg(imagePath()), + i18n("MD5 Sums Equal") ); + else + KMessageBox::sorry( this, i18n("The MD5 Sum of %1 differs from the specified.").arg(imagePath()), + i18n("MD5 Sums Differ") ); + } + } + else if( r == copyItem ) { + QApplication::clipboard()->setText( m_md5Job->hexDigest().lower(), QClipboard::Clipboard ); + } +} + + +void K3bIsoImageWritingDialog::loadUserDefaults( KConfigBase* c ) +{ + m_writingModeWidget->loadConfig( c ); + m_checkDummy->setChecked( c->readBoolEntry("simulate", false ) ); + m_checkVerify->setChecked( c->readBoolEntry( "verify_data", false ) ); + m_spinCopies->setValue( c->readNumEntry( "copies", 1 ) ); + + m_writerSelectionWidget->loadConfig( c ); + + if( !d->imageForced ) { + QString image = c->readPathEntry( "image path", c->readPathEntry( "last written image" ) ); + if( QFile::exists( image ) ) + m_editImagePath->setURL( image ); + } +} + + +void K3bIsoImageWritingDialog::saveUserDefaults( KConfigBase* c ) +{ + m_writingModeWidget->saveConfig( c ), + c->writeEntry( "simulate", m_checkDummy->isChecked() ); + c->writeEntry( "verify_data", m_checkVerify->isChecked() ); + c->writeEntry( "copies", m_spinCopies->value() ); + + m_writerSelectionWidget->saveConfig( c ); + + c->writePathEntry( "image path", imagePath() ); +} + + +void K3bIsoImageWritingDialog::loadK3bDefaults() +{ + m_writerSelectionWidget->loadDefaults(); + m_writingModeWidget->setWritingMode( K3b::WRITING_MODE_AUTO ); + m_checkDummy->setChecked( false ); + m_checkVerify->setChecked( false ); + m_spinCopies->setValue( 1 ); +} + + +QString K3bIsoImageWritingDialog::imagePath() const +{ + return K3b::convertToLocalUrl( KURL::fromPathOrURL( m_editImagePath->url() ) ).path(); +} + + +void K3bIsoImageWritingDialog::dragEnterEvent( QDragEnterEvent* e ) +{ + e->accept( KURLDrag::canDecode(e) ); +} + + +void K3bIsoImageWritingDialog::dropEvent( QDropEvent* e ) +{ + KURL::List urls; + KURLDrag::decode( e, urls ); +#if KDE_IS_VERSION(3,4,0) + m_editImagePath->setKURL( urls.first() ); +#else + m_editImagePath->setURL( urls.first().path() ); +#endif +} + +#include "k3bisoimagewritingdialog.moc" diff --git a/src/misc/k3bisoimagewritingdialog.h b/src/misc/k3bisoimagewritingdialog.h new file mode 100644 index 0000000..caf0f4f --- /dev/null +++ b/src/misc/k3bisoimagewritingdialog.h @@ -0,0 +1,90 @@ +/* + * + * $Id$ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BISOIMAGEWRITINGDIALOG_H +#define K3BISOIMAGEWRITINGDIALOG_H + +#include <k3binteractiondialog.h> + + +class QCheckBox; +class K3bWriterSelectionWidget; +class QLabel; +class KURL; +class K3bMd5Job; +class K3bWritingModeWidget; +class KURLRequester; +class K3bListView; +class QSpinBox; +class QDragEnterEvent; +class QDropEvent; +class KListView; +class QListViewItem; +class QPoint; + + +/** + *@author Sebastian Trueg + */ +class K3bIsoImageWritingDialog : public K3bInteractionDialog +{ + Q_OBJECT + + public: + K3bIsoImageWritingDialog( QWidget* = 0, const char* = 0, bool = true ); + ~K3bIsoImageWritingDialog(); + + void setImage( const KURL& url ); + + protected slots: + void slotStartClicked(); + void updateImageSize( const QString& ); + void slotWriterChanged(); + void slotMd5JobPercent( int ); + void slotMd5JobFinished( bool ); + void slotContextMenu( KListView*, QListViewItem*, const QPoint& pos ); + + protected: + void loadUserDefaults( KConfigBase* ); + void saveUserDefaults( KConfigBase* ); + void loadK3bDefaults(); + + void calculateMd5Sum( const QString& ); + void dragEnterEvent( QDragEnterEvent* ); + void dropEvent( QDropEvent* ); + + void init(); + + private: + void setupGui(); + QString imagePath() const; + + K3bMd5Job* m_md5Job; + + K3bWriterSelectionWidget* m_writerSelectionWidget; + QCheckBox* m_checkDummy; + QCheckBox* m_checkVerify; + QSpinBox* m_spinCopies; + K3bWritingModeWidget* m_writingModeWidget; + + KURLRequester* m_editImagePath; + K3bListView* m_infoView; + + class Private; + Private* d; +}; + +#endif diff --git a/src/option/Makefile.am b/src/option/Makefile.am new file mode 100644 index 0000000..7b99dd3 --- /dev/null +++ b/src/option/Makefile.am @@ -0,0 +1,20 @@ +AM_CPPFLAGS = -I$(srcdir)/../../libk3b/core \ + -I$(srcdir)/../../libk3bdevice \ + -I$(srcdir)/../../libk3b/plugin \ + -I$(srcdir)/../../libk3b/tools \ + -I$(srcdir)/.. \ + $(all_includes) + +METASOURCES = AUTO + +noinst_LTLIBRARIES = liboption.la + +liboption_la_SOURCES = base_k3bcddboptiontab.ui base_k3bmiscoptiontab.ui \ + base_k3bpluginoptiontab.ui \ + base_k3bthemeoptiontab.ui k3bmiscoptiontab.cpp \ + k3bexternalbinoptiontab.cpp k3bcddboptiontab.cpp \ + k3bburningoptiontab.cpp k3boptiondialog.cpp \ + k3bdeviceoptiontab.cpp k3bnotifyoptiontab.cpp \ + k3bpluginoptiontab.cpp \ + k3bthemeoptiontab.cpp k3bdevicewidget.cpp \ + k3bexternalbinwidget.cpp diff --git a/src/option/base_k3bcddboptiontab.ui b/src/option/base_k3bcddboptiontab.ui new file mode 100644 index 0000000..f46e970 --- /dev/null +++ b/src/option/base_k3bcddboptiontab.ui @@ -0,0 +1,560 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>base_K3bCddbOptionTab</class> +<author>Sebastian Trueg</author> +<widget class="QWidget"> + <property name="name"> + <cstring>base_K3bCddbOptionTab</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>648</width> + <height>553</height> + </rect> + </property> + <property name="caption"> + <string>CDDB Options</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QTabWidget"> + <property name="name"> + <cstring>m_mainTabbed</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <widget class="QWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string>Local</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox" row="0" column="0"> + <property name="name"> + <cstring>m_checkUseLocalCddb</cstring> + </property> + <property name="text"> + <string>Use local CDDB directory</string> + </property> + </widget> + <widget class="QCheckBox" row="1" column="0"> + <property name="name"> + <cstring>m_checkSaveLocalEntries</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Save entries in local directory (the first directory in the list)</string> + </property> + </widget> + <widget class="QFrame" row="2" column="0"> + <property name="name"> + <cstring>m_boxLocalDirectory</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="frameShape"> + <enum>NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>Raised</enum> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>TextLabel1_4</cstring> + </property> + <property name="text"> + <string>Directory:</string> + </property> + </widget> + <widget class="KListView" row="1" column="0" rowspan="4" colspan="2"> + <column> + <property name="text"> + <string>Directory</string> + </property> + <property name="clickable"> + <bool>false</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <property name="name"> + <cstring>m_viewLocalDir</cstring> + </property> + <property name="fullWidth"> + <bool>true</bool> + </property> + </widget> + <widget class="QToolButton" row="3" column="2"> + <property name="name"> + <cstring>m_buttonLocalDirDown</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="autoRaise"> + <bool>true</bool> + </property> + <property name="toolTip" stdset="0"> + <string>Move directory down</string> + </property> + </widget> + <widget class="QToolButton" row="0" column="2"> + <property name="name"> + <cstring>m_buttonAddLocalDir</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="autoRaise"> + <bool>true</bool> + </property> + <property name="toolTip" stdset="0"> + <string>Add directory</string> + </property> + </widget> + <widget class="KLineEdit" row="0" column="1"> + <property name="name"> + <cstring>m_editLocalDir</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="QToolButton" row="1" column="2"> + <property name="name"> + <cstring>m_buttonRemoveLocalDir</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="autoRaise"> + <bool>true</bool> + </property> + <property name="toolTip" stdset="0"> + <string>Remove directory</string> + </property> + </widget> + <widget class="QToolButton" row="2" column="2"> + <property name="name"> + <cstring>m_buttonLocalDirUp</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="autoRaise"> + <bool>true</bool> + </property> + <property name="toolTip" stdset="0"> + <string>Move directory up</string> + </property> + </widget> + <spacer row="4" column="2"> + <property name="name"> + <cstring>Spacer11_2</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>51</height> + </size> + </property> + </spacer> + </grid> + </widget> + </grid> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string>Remote</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QFrame" row="1" column="0"> + <property name="name"> + <cstring>m_boxCddbServer</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="frameShape"> + <enum>NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>Raised</enum> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>TextLabel1</cstring> + </property> + <property name="text"> + <string>Server:</string> + </property> + </widget> + <widget class="QComboBox" row="0" column="1"> + <property name="name"> + <cstring>m_comboCddbType</cstring> + </property> + </widget> + <widget class="KListView" row="1" column="0" rowspan="4" colspan="4"> + <column> + <property name="text"> + <string>Type</string> + </property> + <property name="clickable"> + <bool>false</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Server</string> + </property> + <property name="clickable"> + <bool>false</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Port</string> + </property> + <property name="clickable"> + <bool>false</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <property name="name"> + <cstring>m_viewCddbServer</cstring> + </property> + <property name="allColumnsShowFocus"> + <bool>true</bool> + </property> + <property name="fullWidth"> + <bool>true</bool> + </property> + </widget> + <widget class="KLineEdit" row="0" column="2"> + <property name="name"> + <cstring>m_editCddbServer</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="KIntNumInput" row="0" column="3"> + <property name="name"> + <cstring>m_editCddbPort</cstring> + </property> + <property name="label"> + <string></string> + </property> + <property name="value"> + <number>80</number> + </property> + <property name="minValue"> + <number>0</number> + </property> + <property name="maxValue"> + <number>64000</number> + </property> + <property name="prefix"> + <string>Port </string> + </property> + </widget> + <widget class="QToolButton" row="0" column="4"> + <property name="name"> + <cstring>m_buttonAddCddbServer</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="autoRaise"> + <bool>true</bool> + </property> + <property name="toolTip" stdset="0"> + <string>Add server</string> + </property> + </widget> + <widget class="QToolButton" row="1" column="4"> + <property name="name"> + <cstring>m_buttonRemoveCddbServer</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="autoRaise"> + <bool>true</bool> + </property> + <property name="toolTip" stdset="0"> + <string>Remove server</string> + </property> + </widget> + <widget class="QToolButton" row="2" column="4"> + <property name="name"> + <cstring>m_buttonCddbServerUp</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="autoRaise"> + <bool>true</bool> + </property> + <property name="toolTip" stdset="0"> + <string>Move server up</string> + </property> + </widget> + <widget class="QToolButton" row="3" column="4"> + <property name="name"> + <cstring>m_buttonCddbServerDown</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="autoRaise"> + <bool>true</bool> + </property> + <property name="toolTip" stdset="0"> + <string>Move server down</string> + </property> + </widget> + <spacer row="4" column="4"> + <property name="name"> + <cstring>Spacer10</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>30</height> + </size> + </property> + </spacer> + </grid> + </widget> + <widget class="QCheckBox" row="0" column="0"> + <property name="name"> + <cstring>m_checkRemoteCddb</cstring> + </property> + <property name="text"> + <string>Enable remote CDDB queries</string> + </property> + </widget> + </grid> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string>Advanced</string> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>m_groupCgi</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>CGI Path</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="KLineEdit" row="2" column="1"> + <property name="name"> + <cstring>m_editManualCgiPath</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>~/cddb/cddb.cgi</string> + </property> + </widget> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>TextLabel3</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Path:</string> + </property> + </widget> + <widget class="QCheckBox" row="1" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>m_checkManualCgiPath</cstring> + </property> + <property name="text"> + <string>Manual CGI path</string> + </property> + </widget> + </grid> + </widget> + <spacer> + <property name="name"> + <cstring>spacer5</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>31</width> + <height>151</height> + </size> + </property> + </spacer> + </vbox> + </widget> + </widget> + </vbox> +</widget> +<customwidgets> +</customwidgets> +<connections> + <connection> + <sender>m_checkManualCgiPath</sender> + <signal>toggled(bool)</signal> + <receiver>m_editManualCgiPath</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>m_checkManualCgiPath</sender> + <signal>toggled(bool)</signal> + <receiver>TextLabel3</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>m_checkUseLocalCddb</sender> + <signal>toggled(bool)</signal> + <receiver>m_boxLocalDirectory</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>m_checkUseLocalCddb</sender> + <signal>toggled(bool)</signal> + <receiver>m_checkSaveLocalEntries</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>m_checkRemoteCddb</sender> + <signal>toggled(bool)</signal> + <receiver>m_boxCddbServer</receiver> + <slot>setEnabled(bool)</slot> + </connection> +</connections> +<tabstops> + <tabstop>m_mainTabbed</tabstop> + <tabstop>m_checkUseLocalCddb</tabstop> + <tabstop>m_checkSaveLocalEntries</tabstop> + <tabstop>m_editLocalDir</tabstop> + <tabstop>m_viewLocalDir</tabstop> + <tabstop>m_checkRemoteCddb</tabstop> + <tabstop>m_comboCddbType</tabstop> + <tabstop>m_editCddbServer</tabstop> + <tabstop>m_editCddbPort</tabstop> + <tabstop>m_viewCddbServer</tabstop> + <tabstop>m_checkManualCgiPath</tabstop> + <tabstop>m_editManualCgiPath</tabstop> +</tabstops> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>klistview.h</includehint> + <includehint>klistview.h</includehint> + <includehint>knuminput.h</includehint> +</includehints> +</UI> diff --git a/src/option/base_k3bmiscoptiontab.ui b/src/option/base_k3bmiscoptiontab.ui new file mode 100644 index 0000000..364e91f --- /dev/null +++ b/src/option/base_k3bmiscoptiontab.ui @@ -0,0 +1,284 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>base_K3bMiscOptionTab</class> +<widget class="QWidget"> + <property name="name"> + <cstring>base_K3bMiscOptionTab</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox1</cstring> + </property> + <property name="title"> + <string>Misc</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_checkSaveOnExit</cstring> + </property> + <property name="text"> + <string>&Ask to save projects on exit</string> + </property> + <property name="toolTip" stdset="0"> + <string>Ask to save modified projects on exit</string> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout2</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1_2</cstring> + </property> + <property name="text"> + <string>Default Temporary Directory:</string> + </property> + </widget> + <widget class="KURLRequester"> + <property name="name"> + <cstring>m_editTempDir</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>The directory where K3b stores temporary files</string> + </property> + <property name="whatsThis" stdset="0"> + <string><p>This is the default temporary directory. This is where K3b will store temporary files like iso images or decoded audio files. +<p>Be aware that the temporary directory may also be changed in every project burn dialog.</string> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox3</cstring> + </property> + <property name="title"> + <string>System</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_checkSystemConfig</cstring> + </property> + <property name="text"> + <string>&Check system configuration</string> + </property> + <property name="toolTip" stdset="0"> + <string>Check system Configuration</string> + </property> + <property name="whatsThis" stdset="0"> + <string><p>If this option is checked K3b will check the system configuration for any problems on startup and when the the user changes the settings.</string> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout1</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Used audio output system:</string> + </property> + </widget> + <widget class="KComboBox"> + <property name="name"> + <cstring>m_comboAudioOutputSystem</cstring> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_buttonConfigureAudioOutput</cstring> + </property> + <property name="text"> + <string>Confi&gure...</string> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox2</cstring> + </property> + <property name="title"> + <string>GUI Settings</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_checkShowProgressOSD</cstring> + </property> + <property name="text"> + <string>Show progress &OSD</string> + </property> + <property name="whatsThis" stdset="0"> + <string><p>If this option is checked K3b will display the progress in an OSD which always stays on top of all other windows.</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_checkHideMainWindowWhileWriting</cstring> + </property> + <property name="text"> + <string>Hide &main window while writing</string> + </property> + <property name="toolTip" stdset="0"> + <string>Hide the main window while displaying the progress window</string> + </property> + <property name="whatsThis" stdset="0"> + <string><p>If this option is checked K3b will hide the main window while displaying the progress dialog.</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_checkShowSplash</cstring> + </property> + <property name="text"> + <string>Show splash screen</string> + </property> + <property name="toolTip" stdset="0"> + <string>Show the splash screen when K3b starts</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_checkKonqiIntegration</cstring> + </property> + <property name="text"> + <string>E&nable Konqueror integration</string> + </property> + <property name="toolTip" stdset="0"> + <string>Enable integration of K3b actions into Konqueror menus</string> + </property> + <property name="whatsThis" stdset="0"> + <string><p>K3b can integrate itself into Konqueror. This integration allows to start K3b from the context menu in the file manager. +<p>A typical example is: in order to burn a folder to a data CD one clicks on the folder using the right mouse button. In the appearing context menu one selects "Create Data CD with K3b..." and a new K3b project containing the folder is created. +<p><em>Konqueror integration is not enabled by default to prevent unwanted cluttering of the Konqueror menus.</em></string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_checkKeepDialogsOpen</cstring> + </property> + <property name="text"> + <string>&Keep action dialogs open</string> + </property> + <property name="toolTip" stdset="0"> + <string>Do not close action dialogs after finishing the process</string> + </property> + <property name="whatsThis" stdset="0"> + <string><p>If this option is checked K3b will not close action dialogs such as the CD Copy dialog after the process has been finished. It will be kept open to start a new process like copying another CD.</string> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout4</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1_3</cstring> + </property> + <property name="text"> + <string>&Default action dialog settings:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>m_comboActionDialogSettings</cstring> + </property> + </widget> + <widget class="K3bIntMapComboBox"> + <property name="name"> + <cstring>m_comboActionDialogSettings</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>Settings to load when opening an action dialog</string> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + <spacer> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>31</width> + <height>0</height> + </size> + </property> + </spacer> + </vbox> +</widget> +<customwidgets> + <customwidget> + <class>K3bIntMapComboBox</class> + <header location="global">k3bintmapcombobox.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>0</container> + <sizepolicy> + <hordata>5</hordata> + <verdata>5</verdata> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + <pixmap>image0</pixmap> + </customwidget> +</customwidgets> +<images> + <image name="image0"> + <data format="PNG" length="1125">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000042c49444154388db5954f6c14551cc73fefcd7476b65bdaae4bb78bb5502a14d404e4801c88182d1c4c2c693da847400f9c24c68b878684238660e2b1e01f12c19493012ef2478c814412d354a46017a8a564bb6da5bbedccee767776e63d0ffb073751d483bfe49799974c3eeffb7ebf37df9fd05a530b2184040cc0042420aaf9a4d0d554800f045a6b256ae0e1e1e1d6bebebe838ee31c48a7d39b5cd7fd075e251cc7617272f2ded8d8d819cff33e0316819259537aead4a9839d5dd6d1784f91f55b0a94830242088404d304292bef68a89f520802a598fecddaa04f1a876f5c250c7c0a64cdeac686e33807e23d45e6b297c8b877f1831542614550b6599835c83c2a81b6786a75134faf2f1169f12997350881d9021d0903e06de0745d3160a6d3e94dbd5b0a64dcbb94b5831d0e3375ab892b1772dcf9790528543f8dd0d367b36768153b5e31503a0f1aecb004580b44ffac58baae8b1714f0833c7638cc8dab303a320f4822ab4c7a37c69196203de3319d5ce1c4d13c733331dedc67a129a154fd128401ab0616d55a130ac3d42d93d1913940d13fd0c9ee0183685c60da01c5421bd72f7a8c8efccef9afd374267ad93d642365be0636a0d28ec7600941d9e6f23917f0e97f23ce5bef35d19ec863da0ed9059b2be70bec196c66dfa10ec0e49b338f7017258651bf95021035c595429bb0903248fe52a2b5b595dd7b4d945cc2340cdca536be389ee3f67886c5798f773fe8e0dac508c989659277a2180da4ca4ff07821058b8b251445d63d6b13ed1098a6417e39cac85197dbe31962ab9bd9f1f22a226d45366f6d0620fdb08c900d281af6110284b20085b414861d905d88f2e52739ee8cbb8022143259d3dd84691730aa2d52da441a8de0c6958068870022a41e9629ad3473fd3b8fdbe319dadb9b4924da994d2d716c7896fbe35152f78b48245d6b2da4507faf582be8eaf159b721cc837b05ae7debb1f79d08cb8b515edad942a22bc4b1c33eb3d34b1c797f06af90a72d16e2f96d9a74aa11dca8586b222d01af0fb60070f6c402d72f15d97f28c6f6d7027a5f5ce6c3233dc4e2ede496b278be4fff608cee8d3e1add806aeca51094cbb06397c1ecc328e746537c7e3ccdb5cb1136bf60635882d4d41c6ec6836ab37efa214f72208ed9f4d7cdd38ee310280542e38b1c43fb6de26b3672e1ec3cc99bcb246f66a938a3241ab3e91f7c861fbf77710b1e5e49915bae974203ba0e9e9c9cbc373d6d6d305a040a89c2a77f50b27d5782bbbf7acccf28349235dd16cf6dd374f7295e1de8a45c02d37499182b01cc0201a085d61a2144d8b2ac8fb6ed340e77240c4261890e04c250185262546d534a032154b59e0ad394e41c98182bf268ce6721ed9f064e0253356f6da2e24c1f030f783c15fe6da680af8021602bd051532ca9b8521488559f61aa86c29343578fbf0264a94c906c7d3409214c20043457a116ff6de6795578012889ff6b98fe016ea0ce1c6a2573410000000049454e44ae426082</data> + </image> +</images> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kurlrequester.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kcombobox.h</includehint> + <includehint>k3bintmapcombobox.h</includehint> +</includehints> +</UI> diff --git a/src/option/base_k3bpluginoptiontab.ui b/src/option/base_k3bpluginoptiontab.ui new file mode 100644 index 0000000..18321ee --- /dev/null +++ b/src/option/base_k3bpluginoptiontab.ui @@ -0,0 +1,90 @@ +<!DOCTYPE UI><UI version="3.1" stdsetdef="1"> +<class>base_K3bPluginOptionTab</class> +<author>Sebastian Trueg</author> +<widget class="QWidget"> + <property name="name"> + <cstring>Form1</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>600</width> + <height>480</height> + </rect> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QPushButton" row="2" column="1"> + <property name="name"> + <cstring>m_buttonConfigure</cstring> + </property> + <property name="text"> + <string>Configure...</string> + </property> + </widget> + <spacer row="2" column="0"> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>411</width> + <height>21</height> + </size> + </property> + </spacer> + <widget class="K3bListView" row="1" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>m_viewPlugins</cstring> + </property> + </widget> + <widget class="QLabel" row="0" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string><p>Here all <em>K3b Plugins</em> may be configured. Be aware that this does not include the <em>KPart Plugins</em> which embed themselves in the K3b menu structure.</p></string> + </property> + </widget> + </grid> +</widget> +<customwidgets> + <customwidget> + <class>K3bListView</class> + <header location="global">k3blistview.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>0</container> + <sizepolicy> + <hordata>5</hordata> + <verdata>5</verdata> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + <pixmap>image0</pixmap> + </customwidget> +</customwidgets> +<images> + <image name="image0"> + <data format="PNG" length="1125">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000042c49444154388db5954f6c14551cc73fefcd7476b65bdaae4bb78bb5502a14d404e4801c88182d1c4c2c693da847400f9c24c68b878684238660e2b1e01f12c19493012ef2478c814412d354a46017a8a564bb6da5bbedccee767776e63d0ffb073751d483bfe49799974c3eeffb7ebf37df9fd05a530b2184040cc0042420aaf9a4d0d554800f045a6b256ae0e1e1e1d6bebebe838ee31c48a7d39b5cd7fd075e251cc7617272f2ded8d8d819cff33e0316819259537aead4a9839d5dd6d1784f91f55b0a94830242088404d304292bef68a89f520802a598fecddaa04f1a876f5c250c7c0a64cdeac686e33807e23d45e6b297c8b877f1831542614550b6599835c83c2a81b6786a75134faf2f1169f12997350881d9021d0903e06de0745d3160a6d3e94dbd5b0a64dcbb94b5831d0e3375ab892b1772dcf9790528543f8dd0d367b36768153b5e31503a0f1aecb004580b44ffac58baae8b1714f0833c7638cc8dab303a320f4822ab4c7a37c69196203de3319d5ce1c4d13c733331dedc67a129a154fd128401ab0616d55a130ac3d42d93d1913940d13fd0c9ee0183685c60da01c5421bd72f7a8c8efccef9afd374267ad93d642365be0636a0d28ec7600941d9e6f23917f0e97f23ce5bef35d19ec863da0ed9059b2be70bec196c66dfa10ec0e49b338f7017258651bf95021035c595429bb0903248fe52a2b5b595dd7b4d945cc2340cdca536be389ee3f67886c5798f773fe8e0dac508c989659277a2180da4ca4ff07821058b8b251445d63d6b13ed1098a6417e39cac85197dbe31962ab9bd9f1f22a226d45366f6d0620fdb08c900d281af6110284b20085b414861d905d88f2e52739ee8cbb8022143259d3dd84691730aa2d52da441a8de0c6958068870022a41e9629ad3473fd3b8fdbe319dadb9b4924da994d2d716c7896fbe35152f78b48245d6b2da4507faf582be8eaf159b721cc837b05ae7debb1f79d08cb8b515edad942a22bc4b1c33eb3d34b1c797f06af90a72d16e2f96d9a74aa11dca8586b222d01af0fb60070f6c402d72f15d97f28c6f6d7027a5f5ce6c3233dc4e2ede496b278be4fff608cee8d3e1add806aeca51094cbb06397c1ecc328e746537c7e3ccdb5cb1136bf60635882d4d41c6ec6836ab37efa214f72208ed9f4d7cdd38ee310280542e38b1c43fb6de26b3672e1ec3cc99bcb246f66a938a3241ab3e91f7c861fbf77710b1e5e49915bae974203ba0e9e9c9cbc373d6d6d305a040a89c2a77f50b27d5782bbbf7acccf28349235dd16cf6dd374f7295e1de8a45c02d37499182b01cc0201a085d61a2144d8b2ac8fb6ed340e77240c4261890e04c250185262546d534a032154b59e0ad394e41c98182bf268ce6721ed9f064e0253356f6da2e24c1f030f783c15fe6da680af8021602bd051532ca9b8521488559f61aa86c29343578fbf0264a94c906c7d3409214c20043457a116ff6de6795578012889ff6b98fe016ea0ce1c6a2573410000000049454e44ae426082</data> + </image> +</images> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>k3blistview.h</includehint> +</includehints> +</UI> diff --git a/src/option/base_k3bthemeoptiontab.ui b/src/option/base_k3bthemeoptiontab.ui new file mode 100644 index 0000000..47a48b4 --- /dev/null +++ b/src/option/base_k3bthemeoptiontab.ui @@ -0,0 +1,208 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>base_K3bThemeOptionTab</class> +<author>Sebastian Trueg</author> +<widget class="QWidget"> + <property name="name"> + <cstring>base_K3bThemeOptionTab</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>661</width> + <height>499</height> + </rect> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox4</cstring> + </property> + <property name="title"> + <string>Theme Selection</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KListView"> + <column> + <property name="text"> + <string>Theme</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Author</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Version</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Comment</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <property name="name"> + <cstring>m_viewTheme</cstring> + </property> + <property name="allColumnsShowFocus"> + <bool>true</bool> + </property> + </widget> + </vbox> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox5</cstring> + </property> + <property name="title"> + <string>Preview</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout1</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="spacing"> + <number>0</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>m_leftPreviewLabel</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>m_centerPreviewLabel</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>1</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="font"> + <font> + <bold>1</bold> + </font> + </property> + <property name="text"> + <string>no Theme selected</string> + </property> + <property name="alignment"> + <set>AlignCenter</set> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>m_rightPreviewLabel</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + </hbox> + </widget> + </hbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout5</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <spacer> + <property name="name"> + <cstring>spacer3</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>161</width> + <height>2</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_buttonInstallTheme</cstring> + </property> + <property name="text"> + <string>Install New Theme...</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_buttonRemoveTheme</cstring> + </property> + <property name="text"> + <string>Remove Theme</string> + </property> + </widget> + </hbox> + </widget> + </vbox> +</widget> +<customwidgets> +</customwidgets> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>klistview.h</includehint> +</includehints> +</UI> diff --git a/src/option/k3bburningoptiontab.cpp b/src/option/k3bburningoptiontab.cpp new file mode 100644 index 0000000..21485cb --- /dev/null +++ b/src/option/k3bburningoptiontab.cpp @@ -0,0 +1,198 @@ +/* + * + * $Id: k3bburningoptiontab.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bburningoptiontab.h" +#include <k3bmsfedit.h> +#include <k3bcore.h> +#include <k3bstdguiitems.h> +#include <k3bglobalsettings.h> + +#include <qlabel.h> +#include <qcombobox.h> +#include <qcheckbox.h> +#include <qlayout.h> +#include <qgroupbox.h> +#include <qtabwidget.h> +#include <qradiobutton.h> +#include <qvalidator.h> +#include <qbuttongroup.h> +#include <qspinbox.h> +#include <qtooltip.h> +#include <qwhatsthis.h> + +#include <knuminput.h> +#include <kconfig.h> +#include <kdialog.h> +#include <klocale.h> +#include <klineedit.h> + + +K3bBurningOptionTab::K3bBurningOptionTab( QWidget* parent, const char* name ) + : QWidget( parent, name ) +{ + setupGui(); +} + + +K3bBurningOptionTab::~K3bBurningOptionTab() +{ +} + + +void K3bBurningOptionTab::setupGui() +{ + QGridLayout* groupAdvancedLayout = new QGridLayout( this ); + groupAdvancedLayout->setAlignment( Qt::AlignTop ); + groupAdvancedLayout->setSpacing( KDialog::spacingHint() ); + groupAdvancedLayout->setMargin( 0 ); + + + QGroupBox* groupWritingApp = new QGroupBox( 0, Qt::Vertical, i18n("Burning"), this ); + groupWritingApp->layout()->setMargin( 0 ); + QGridLayout* bufferLayout = new QGridLayout( groupWritingApp->layout() ); + bufferLayout->setMargin( KDialog::marginHint() ); + bufferLayout->setSpacing( KDialog::spacingHint() ); + + m_checkBurnfree = K3bStdGuiItems::burnproofCheckbox( groupWritingApp ); + m_checkOverburn = new QCheckBox( i18n("Allow overburning (¬ supported by cdrecord <= 1.10)"), groupWritingApp ); + m_checkForceUnsafeOperations = new QCheckBox( i18n("Force unsafe operations"), groupWritingApp ); + m_checkManualWritingBufferSize = new QCheckBox( i18n("&Manual writing buffer size") + ":", groupWritingApp ); + m_editWritingBufferSize = new KIntNumInput( 4, groupWritingApp ); + m_editWritingBufferSize->setSuffix( " " + i18n("MB") ); + m_checkAllowWritingAppSelection = new QCheckBox( i18n("Manual writing application &selection"), groupWritingApp ); + bufferLayout->addMultiCellWidget( m_checkBurnfree, 0, 0, 0, 2 ); + bufferLayout->addMultiCellWidget( m_checkOverburn, 1, 1, 0, 2 ); + bufferLayout->addMultiCellWidget( m_checkForceUnsafeOperations, 2, 2, 0, 2 ); + bufferLayout->addWidget( m_checkManualWritingBufferSize, 3, 0 ); + bufferLayout->addWidget( m_editWritingBufferSize, 3, 1 ); + bufferLayout->addMultiCellWidget( m_checkAllowWritingAppSelection, 4, 4, 0, 2 ); + bufferLayout->setColStretch( 2, 1 ); + + QGroupBox* groupMisc = new QGroupBox( 2, Qt::Vertical, i18n("Miscellaneous"), this ); + m_checkEject = new QCheckBox( i18n("Do not &eject medium after write process"), groupMisc ); + m_checkAutoErasingRewritable = new QCheckBox( i18n("Automatically erase CD-RWs and DVD-RWs"), groupMisc ); + + groupAdvancedLayout->addWidget( groupWritingApp, 0, 0 ); + groupAdvancedLayout->addWidget( groupMisc, 1, 0 ); + groupAdvancedLayout->setRowStretch( 2, 1 ); + + + connect( m_checkManualWritingBufferSize, SIGNAL(toggled(bool)), + m_editWritingBufferSize, SLOT(setEnabled(bool)) ); + connect( m_checkManualWritingBufferSize, SIGNAL(toggled(bool)), + this, SLOT(slotSetDefaultBufferSizes(bool)) ); + + + m_editWritingBufferSize->setDisabled( true ); + // ----------------------------------------------------------------------- + + + QToolTip::add( m_checkOverburn, i18n("Allow burning more than the official media capacity") ); + QToolTip::add( m_checkAllowWritingAppSelection, i18n("Allow to choose between cdrecord and cdrdao") ); + QToolTip::add( m_checkAutoErasingRewritable, i18n("Automatically erase CD-RWs and DVD-RWs without asking") ); + QToolTip::add( m_checkEject, i18n("Do not eject the burn medium after a completed burn process") ); + QToolTip::add( m_checkForceUnsafeOperations, i18n("Force K3b to continue some operations otherwise deemed as unsafe") ); + + QWhatsThis::add( m_checkAllowWritingAppSelection, i18n("<p>If this option is checked K3b gives " + "the possibility to choose between cdrecord " + "and cdrdao when writing a cd." + "<p>This may be useful if one of the programs " + "does not support the used writer." + "<p><b>Be aware that K3b does not support both " + "programs in all project types.</b>") ); + + QWhatsThis::add( m_checkOverburn, i18n("<p>Each medium has an official maximum capacity which is stored in a read-only " + "area of the medium and is guaranteed by the vendor. However, this official " + "maximum is not always the actual maximum. Many media have an " + "actual total capacity that is slightly larger than the official amount." + "<p>If this option is checked K3b will disable a safety check that prevents " + "burning beyond the offical capacity." + "<p><b>Caution:</b> Enabling this option can cause failures in the end of the " + "burning process if K3b attempts to write beyond the official capacity. It " + "makes sense to first determine the actual maximum capacity of the media brand " + "with a simulated burn.") ); + + QWhatsThis::add( m_checkAutoErasingRewritable, i18n("<p>If this option is checked K3b will automatically " + "erase CD-RWs and format DVD-RWs if one is found instead " + "of an empty media before writing.") ); + + QWhatsThis::add( m_checkManualWritingBufferSize, i18n("<p>K3b uses a software buffer during the burning process to " + "avoid gaps in the data stream due to high system load. The default " + "sizes used are %1 MB for CD and %2 MB for DVD burning." + "<p>If this option is checked the value specified will be used for both " + "CD and DVD burning.").arg(4).arg(32) ); + + QWhatsThis::add( m_checkEject, i18n("<p>If this option is checked K3b will not eject the medium once the burn process " + "finishes. This can be helpful in case one leaves the computer after starting the " + "burning and does not want the tray to be open all the time." + "<p>However, on Linux systems a freshly burned medium has to be reloaded. Otherwise " + "the system will not detect the changes and still treat it as an empty medium.") ); + + QWhatsThis::add( m_checkForceUnsafeOperations, i18n("<p>If this option is checked K3b will continue in some situations " + "which would otherwise be deemed as unsafe." + "<p>This setting for example disables the check for medium speed " + "verification. Thus, one can force K3b to burn a high speed medium on " + "a low speed writer." + "<p><b>Caution:</b> Enabling this option may result in damaged media.") ); +} + + +void K3bBurningOptionTab::readSettings() +{ + KConfig* c = k3bcore->config(); + + c->setGroup( "General Options" ); + m_checkAutoErasingRewritable->setChecked( c->readBoolEntry( "auto rewritable erasing", false ) ); + m_checkAllowWritingAppSelection->setChecked( c->readBoolEntry( "Manual writing app selection", false ) ); + + m_checkBurnfree->setChecked( k3bcore->globalSettings()->burnfree() ); + m_checkEject->setChecked( !k3bcore->globalSettings()->ejectMedia() ); + m_checkOverburn->setChecked( k3bcore->globalSettings()->overburn() ); + m_checkForceUnsafeOperations->setChecked( k3bcore->globalSettings()->force() ); + m_checkManualWritingBufferSize->setChecked( k3bcore->globalSettings()->useManualBufferSize() ); + if( k3bcore->globalSettings()->useManualBufferSize() ) + m_editWritingBufferSize->setValue( k3bcore->globalSettings()->bufferSize() ); +} + + +void K3bBurningOptionTab::saveSettings() +{ + KConfig* c = k3bcore->config(); + + c->setGroup( "General Options" ); + c->writeEntry( "auto rewritable erasing", m_checkAutoErasingRewritable->isChecked() ); + c->writeEntry( "Manual writing app selection", m_checkAllowWritingAppSelection->isChecked() ); + + k3bcore->globalSettings()->setEjectMedia( !m_checkEject->isChecked() ); + k3bcore->globalSettings()->setOverburn( m_checkOverburn->isChecked() ); + k3bcore->globalSettings()->setBurnfree( m_checkBurnfree->isChecked() ); + k3bcore->globalSettings()->setUseManualBufferSize( m_checkManualWritingBufferSize->isChecked() ); + k3bcore->globalSettings()->setBufferSize( m_editWritingBufferSize->value() ); + k3bcore->globalSettings()->setForce( m_checkForceUnsafeOperations->isChecked() ); + + // FIXME: remove this once libk3b does not use KConfig anymore for these values + k3bcore->globalSettings()->saveSettings( c ); +} + + +void K3bBurningOptionTab::slotSetDefaultBufferSizes( bool b ) +{ + if( !b ) { + m_editWritingBufferSize->setValue( 4 ); + } +} + + +#include "k3bburningoptiontab.moc" diff --git a/src/option/k3bburningoptiontab.h b/src/option/k3bburningoptiontab.h new file mode 100644 index 0000000..8b71e06 --- /dev/null +++ b/src/option/k3bburningoptiontab.h @@ -0,0 +1,61 @@ +/* + * + * $Id: k3bburningoptiontab.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3B_BURNING_OPTION_TAB_H +#define K3B_BURNING_OPTION_TAB_H + +#include <qwidget.h> + +class QCheckBox; +class QLabel; +class QGroupBox; +class QComboBox; +class QString; +class QSpinBox; +class KIntNumInput; +class QRadioButton; + + + +class K3bBurningOptionTab : public QWidget +{ +Q_OBJECT + + public: + K3bBurningOptionTab( QWidget* parent = 0, const char* name = 0 ); + ~K3bBurningOptionTab(); + + void saveSettings(); + void readSettings(); + + private slots: + void slotSetDefaultBufferSizes( bool ); + + private: + void setupGui(); + + QCheckBox* m_checkBurnfree; + QCheckBox* m_checkEject; + QCheckBox* m_checkAutoErasingRewritable; + QCheckBox* m_checkOverburn; + QCheckBox* m_checkManualWritingBufferSize; + KIntNumInput* m_editWritingBufferSize; + QCheckBox* m_checkAllowWritingAppSelection; + QCheckBox* m_checkForceUnsafeOperations; +}; + + +#endif diff --git a/src/option/k3bcddboptiontab.cpp b/src/option/k3bcddboptiontab.cpp new file mode 100644 index 0000000..33b2349 --- /dev/null +++ b/src/option/k3bcddboptiontab.cpp @@ -0,0 +1,338 @@ +/* + * + * $Id$ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bcddboptiontab.h" + +#include <qvariant.h> +#include <qbuttongroup.h> +#include <qcheckbox.h> +#include <qlistbox.h> +#include <qpushbutton.h> +#include <qradiobutton.h> +#include <qtabwidget.h> +#include <qlayout.h> +#include <qtooltip.h> +#include <qwhatsthis.h> +#include <qstringlist.h> +#include <qcombobox.h> +#include <qtoolbutton.h> + +#include <kdialog.h> +#include <kiconloader.h> +#include <krun.h> +#include <klistview.h> +#include <klineedit.h> +#include <klocale.h> +#include <knuminput.h> +#include <kconfig.h> +#include <kapplication.h> +#include <kdeversion.h> + + +K3bCddbOptionTab::K3bCddbOptionTab( QWidget* parent, const char* name ) + : base_K3bCddbOptionTab( parent, name ) +{ + // fix all the margins and spacings that have been corrupted by QDesigner ;-) + // ----------------------------------------------------------------------------- + + base_K3bCddbOptionTabLayout->setMargin( 0 ); + base_K3bCddbOptionTabLayout->setSpacing( KDialog::spacingHint() ); + + m_mainTabbed->page(0)->layout()->setMargin( KDialog::marginHint() ); + m_mainTabbed->page(0)->layout()->setSpacing( KDialog::spacingHint() ); + m_mainTabbed->page(1)->layout()->setMargin( KDialog::marginHint() ); + m_mainTabbed->page(1)->layout()->setSpacing( KDialog::spacingHint() ); + +// m_groupLocalDir->layout()->setMargin( 0 ); +// m_groupLocalDirLayout->setMargin( KDialog::marginHint() ); +// m_groupLocalDirLayout->setSpacing( KDialog::spacingHint() ); + +// m_groupCddbServer->layout()->setMargin( 0 ); +// m_groupCddbServerLayout->setMargin( KDialog::marginHint() ); +// m_groupCddbServerLayout->setSpacing( KDialog::spacingHint() ); + + m_groupCgi->layout()->setMargin( 0 ); + m_groupCgiLayout->setMargin( KDialog::marginHint() ); + m_groupCgiLayout->setSpacing( KDialog::spacingHint() ); + + m_boxLocalDirectoryLayout->setSpacing( KDialog::spacingHint() ); + m_boxCddbServerLayout->setSpacing( KDialog::spacingHint() ); + // ----------------------------------------------------------------------------- + + + m_viewLocalDir->setSorting(-1); + m_viewLocalDir->setAcceptDrops( true ); + m_viewLocalDir->setDragEnabled( true ); + m_viewLocalDir->setDropVisualizer( true ); + + m_viewCddbServer->setSorting(-1); + m_viewCddbServer->setAcceptDrops( true ); + m_viewCddbServer->setDragEnabled( true ); + m_viewCddbServer->setDropVisualizer( true ); + + m_comboCddbType->insertItem( "Http" ); + m_comboCddbType->insertItem( "Cddbp" ); + + + // set icons for the buttons + m_buttonAddLocalDir->setPixmap( SmallIcon("ok") ); + m_buttonRemoveLocalDir->setPixmap( SmallIcon("stop") ); + m_buttonLocalDirUp->setPixmap( SmallIcon("up") ); + m_buttonLocalDirDown->setPixmap( SmallIcon("down") ); + m_buttonAddCddbServer->setPixmap( SmallIcon("ok") ); + m_buttonRemoveCddbServer->setPixmap( SmallIcon("stop") ); + m_buttonCddbServerUp->setPixmap( SmallIcon("up") ); + m_buttonCddbServerDown->setPixmap( SmallIcon("down") ); + + + // setup connections + // ----------------------------------------------------------------------------- + connect( m_buttonAddLocalDir, SIGNAL(clicked()), this, SLOT(slotLocalDirAdd()) ); + connect( m_buttonRemoveLocalDir, SIGNAL(clicked()), this, SLOT(slotLocalDirRemove()) ); + connect( m_buttonLocalDirUp, SIGNAL(clicked()), this, SLOT(slotLocalDirUp()) ); + connect( m_buttonLocalDirDown, SIGNAL(clicked()), this, SLOT(slotLocalDirDown()) ); + + connect( m_buttonAddCddbServer, SIGNAL(clicked()), this, SLOT(slotCddbServerAdd()) ); + connect( m_buttonRemoveCddbServer, SIGNAL(clicked()), this, SLOT(slotCddbServerRemove()) ); + connect( m_buttonCddbServerUp, SIGNAL(clicked()), this, SLOT(slotCddbServerUp()) ); + connect( m_buttonCddbServerDown, SIGNAL(clicked()), this, SLOT(slotCddbServerDown()) ); + + connect( m_editLocalDir, SIGNAL(textChanged(const QString&)), this, SLOT(enDisableButtons()) ); + connect( m_editCddbServer, SIGNAL(textChanged(const QString&)), this, SLOT(enDisableButtons()) ); + connect( m_viewLocalDir, SIGNAL(selectionChanged()), this, SLOT(enDisableButtons()) ); + connect( m_viewCddbServer, SIGNAL(selectionChanged()), this, SLOT(enDisableButtons()) ); + connect( m_comboCddbType, SIGNAL(highlighted(int)), + this, SLOT(slotServerTypeChanged()) ); + connect( m_comboCddbType, SIGNAL(activated(int)), + this, SLOT(slotServerTypeChanged()) ); + // ----------------------------------------------------------------------------- + + enDisableButtons(); +} + + +K3bCddbOptionTab::~K3bCddbOptionTab() +{ +} + + +void K3bCddbOptionTab::readSettings() +{ + KConfig* c = kapp->config(); + + c->setGroup( "Cddb" ); + + // old config <= 0.7.3 + QStringList cddbpServer = c->readListEntry( "cddbp server" ); + QStringList httpServer = c->readListEntry( "http server" ); + + // new config + QStringList cddbServer = c->readListEntry( "cddb server" ); + + QStringList localCddbDirs = c->readPathListEntry( "local cddb dirs" ); + + m_checkRemoteCddb->setChecked( c->readBoolEntry( "use remote cddb", true ) ); + m_checkUseLocalCddb->setChecked( c->readBoolEntry( "use local cddb query", true ) ); + m_checkSaveLocalEntries->setChecked( c->readBoolEntry( "save cddb entries locally", true ) ); + m_checkManualCgiPath->setChecked( c->readBoolEntry( "use manual cgi path", false ) ); + m_editManualCgiPath->setText( c->readEntry( "cgi path", "/~cddb/cddb.cgi" ) ); + + if( localCddbDirs.isEmpty() ) + localCddbDirs.append( "~/.cddb/" ); + + for( QStringList::const_iterator it = localCddbDirs.begin(); it != localCddbDirs.end(); ++it ) + (void)new KListViewItem( m_viewLocalDir, m_viewLocalDir->lastItem(), *it ); + + + // old config <= 0.7.3 + if( !httpServer.isEmpty() ) { + for( QStringList::iterator it = httpServer.begin(); it != httpServer.end(); ++it ) { + cddbServer.append( "Http " + *it ); + } + } + if( !cddbpServer.isEmpty() ) { + for( QStringList::iterator it = cddbpServer.begin(); it != cddbpServer.end(); ++it ) { + cddbServer.append( "Cddbp " + *it ); + } + } + + if( cddbServer.isEmpty() ) + cddbServer.append( "Http freedb2.org:80" ); + + for( QStringList::const_iterator it = cddbServer.begin(); it != cddbServer.end(); ++it ) { + const QString& s = *it; + QStringList buf = QStringList::split( ":", s.mid( s.find(" ")+1 ) ); + QString server = buf[0]; + int port = buf[1].toInt(); + if( s.startsWith("Http") ) + (void)new KListViewItem( m_viewCddbServer, m_viewCddbServer->lastItem(), "Http", server, QString::number(port) ); + else + (void)new KListViewItem( m_viewCddbServer, m_viewCddbServer->lastItem(), "Cddbp", server, QString::number(port) ); + } + + enDisableButtons(); +} + + +void K3bCddbOptionTab::apply() +{ + KConfig* c = kapp->config(); + + c->setGroup( "Cddb" ); + + c->writeEntry( "use remote cddb", m_checkRemoteCddb->isChecked() ); + c->writeEntry( "use local cddb query", m_checkUseLocalCddb->isChecked() ); + c->writeEntry( "save cddb entries locally", m_checkSaveLocalEntries->isChecked() ); + c->writeEntry( "use manual cgi path", m_checkManualCgiPath->isChecked() ); + c->writeEntry( "cgi path", m_editManualCgiPath->text() ); + + QStringList cddbServer; + QStringList localCddbDirs; + + QListViewItemIterator it( m_viewLocalDir ); + while( it.current() ) { + localCddbDirs.append( it.current()->text(0) ); + ++it; + } + + QListViewItemIterator it1( m_viewCddbServer ); + while( it1.current() ) { + cddbServer.append( it1.current()->text(0) + " " + it1.current()->text(1) + ":" + it1.current()->text(2) ); + ++it1; + } + + // new config + c->writeEntry( "cddb server", cddbServer ); + + // old config <= 0.7.3 + if( c->hasKey( "http server" ) ) + c->deleteEntry( "http server" ); + if( c->hasKey( "cddbp server" ) ) + c->deleteEntry( "cddbp server" ); + + c->writePathEntry( "local cddb dirs", localCddbDirs ); +} + + +void K3bCddbOptionTab::slotLocalDirAdd() +{ + if( !m_editLocalDir->text().isEmpty() ) { + QString localDir( m_editLocalDir->text() ); + QListViewItemIterator it( m_viewLocalDir ); + while( it.current() ) { + if ( it.current()->text(0) == localDir ) + return; + ++it; + } + (void)new KListViewItem( m_viewLocalDir, m_viewLocalDir->lastItem(), + localDir ); + + enDisableButtons(); + } +} + + +void K3bCddbOptionTab::slotLocalDirRemove() +{ + if( QListViewItem* item = m_viewLocalDir->selectedItem() ) + delete item; + + enDisableButtons(); +} + + +void K3bCddbOptionTab::slotCddbServerAdd() +{ + if( !m_editCddbServer->text().isEmpty() ) { + (void)new KListViewItem( m_viewCddbServer, m_viewCddbServer->lastItem(), + m_comboCddbType->currentText(), + m_editCddbServer->text(), + QString::number( m_editCddbPort->value() ) ); + + enDisableButtons(); + } +} + + +void K3bCddbOptionTab::slotCddbServerRemove() +{ + if( QListViewItem* item = m_viewCddbServer->selectedItem() ) + delete item; + + enDisableButtons(); +} + + +void K3bCddbOptionTab::enDisableButtons() +{ + m_buttonAddLocalDir->setDisabled( m_editLocalDir->text().isEmpty() ); + m_buttonRemoveLocalDir->setDisabled( m_viewLocalDir->selectedItem() == 0 ); + m_buttonLocalDirUp->setDisabled( m_viewLocalDir->selectedItem() == 0 || + m_viewLocalDir->selectedItem() == m_viewLocalDir->firstChild() ); + m_buttonLocalDirDown->setDisabled( m_viewLocalDir->selectedItem() == 0 || + m_viewLocalDir->selectedItem() == m_viewLocalDir->lastItem() ); + + m_buttonAddCddbServer->setDisabled( m_editCddbServer->text().isEmpty() ); + m_buttonRemoveCddbServer->setDisabled( m_viewCddbServer->selectedItem() == 0 ); + m_buttonCddbServerUp->setDisabled( m_viewCddbServer->selectedItem() == 0 || + m_viewCddbServer->selectedItem() == m_viewCddbServer->firstChild() ); + m_buttonCddbServerDown->setDisabled( m_viewCddbServer->selectedItem() == 0 || + m_viewCddbServer->selectedItem() == m_viewCddbServer->lastItem() ); + + if( m_viewLocalDir->childCount() <= 0 ) { + m_checkSaveLocalEntries->setChecked(false); + } + m_checkSaveLocalEntries->setDisabled( m_viewLocalDir->childCount() <= 0 ); +} + + +void K3bCddbOptionTab::slotServerTypeChanged() +{ + m_editCddbPort->setValue( m_comboCddbType->currentText() == "Http" ? 80 : 8880 ); +} + + +void K3bCddbOptionTab::slotLocalDirDown() +{ + QListViewItem* sel = m_viewLocalDir->selectedItem(); + m_viewLocalDir->moveItem( sel, 0, sel->nextSibling() ); + m_viewLocalDir->setSelected( sel, true ); +} + + +void K3bCddbOptionTab::slotLocalDirUp() +{ + QListViewItem* sel = m_viewLocalDir->selectedItem(); + m_viewLocalDir->moveItem( sel, 0, sel->itemAbove()->itemAbove() ); + m_viewLocalDir->setSelected( sel, true ); +} + + +void K3bCddbOptionTab::slotCddbServerDown() +{ + QListViewItem* sel = m_viewCddbServer->selectedItem(); + m_viewCddbServer->moveItem( sel, 0, sel->nextSibling() ); + m_viewCddbServer->setSelected( sel, true ); +} + + +void K3bCddbOptionTab::slotCddbServerUp() +{ + QListViewItem* sel = m_viewCddbServer->selectedItem(); + m_viewCddbServer->moveItem( sel, 0, sel->itemAbove()->itemAbove() ); + m_viewCddbServer->setSelected( sel, true ); +} + +#include "k3bcddboptiontab.moc" diff --git a/src/option/k3bcddboptiontab.h b/src/option/k3bcddboptiontab.h new file mode 100644 index 0000000..bc89259 --- /dev/null +++ b/src/option/k3bcddboptiontab.h @@ -0,0 +1,50 @@ +/* + * + * $Id$ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef K3B_CDDB_OPTIONTAB_H +#define K3B_CDDB_OPTIONTAB_H + +#include "base_k3bcddboptiontab.h" + + +class K3bCddbOptionTab : public base_K3bCddbOptionTab +{ + Q_OBJECT + + public: + K3bCddbOptionTab( QWidget* parent = 0, const char* name = 0 ); + ~K3bCddbOptionTab(); + + public slots: + void readSettings(); + void apply(); + + private slots: + void slotLocalDirAdd(); + void slotLocalDirRemove(); + void slotLocalDirDown(); + void slotLocalDirUp(); + + void slotCddbServerAdd(); + void slotCddbServerRemove(); + void slotCddbServerDown(); + void slotCddbServerUp(); + + void slotServerTypeChanged(); + + void enDisableButtons(); +}; + +#endif diff --git a/src/option/k3bdeviceoptiontab.cpp b/src/option/k3bdeviceoptiontab.cpp new file mode 100644 index 0000000..65607c6 --- /dev/null +++ b/src/option/k3bdeviceoptiontab.cpp @@ -0,0 +1,94 @@ +/* + * + * $Id: k3bdeviceoptiontab.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bdeviceoptiontab.h" +#include <k3bdevicemanager.h> +#include "k3bdevicewidget.h" +#include <k3bglobals.h> +#include <k3bcore.h> + +#include <qlabel.h> +#include <qstring.h> +#include <qlayout.h> +#include <qcursor.h> +#include <qapplication.h> + +#include <kapplication.h> +#include <kdialog.h> +#include <klocale.h> +#include <kconfig.h> +#include <kstandarddirs.h> + + +K3bDeviceOptionTab::K3bDeviceOptionTab( QWidget* parent, const char* name ) + : QWidget( parent, name ) +{ + QGridLayout* frameLayout = new QGridLayout( this ); + frameLayout->setSpacing( KDialog::spacingHint() ); + frameLayout->setMargin( 0 ); + + + // Info Label + // ------------------------------------------------ + m_labelDevicesInfo = new QLabel( this, "m_labelDevicesInfo" ); + m_labelDevicesInfo->setAlignment( int( QLabel::WordBreak | QLabel::AlignVCenter | QLabel::AlignLeft ) ); + m_labelDevicesInfo->setText( i18n( "K3b tries to detect all your devices properly. " + "You can add devices that have not been detected and change " + "the black values by clicking in the list. If K3b is unable " + "to detect your drive, you need to modify their permissions " + "to give K3b write access to all devices." ) ); + // ------------------------------------------------ + + m_deviceWidget = new K3bDeviceWidget( k3bcore->deviceManager(), this ); + + frameLayout->addWidget( m_labelDevicesInfo, 0, 0 ); + frameLayout->addWidget( m_deviceWidget, 1, 0 ); + + connect( m_deviceWidget, SIGNAL(refreshButtonClicked()), this, SLOT(slotRefreshButtonClicked()) ); +} + + +K3bDeviceOptionTab::~K3bDeviceOptionTab() +{ +} + + +void K3bDeviceOptionTab::readDevices() +{ + m_deviceWidget->init(); +} + + + +void K3bDeviceOptionTab::saveDevices() +{ + // save changes to deviceManager + m_deviceWidget->apply(); + + // save the config + k3bcore->deviceManager()->saveConfig( kapp->config() ); +} + + +void K3bDeviceOptionTab::slotRefreshButtonClicked() +{ + QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); + k3bcore->deviceManager()->clear(); + k3bcore->deviceManager()->scanBus(); + m_deviceWidget->init(); + QApplication::restoreOverrideCursor(); +} + +#include "k3bdeviceoptiontab.moc" diff --git a/src/option/k3bdeviceoptiontab.h b/src/option/k3bdeviceoptiontab.h new file mode 100644 index 0000000..492b421 --- /dev/null +++ b/src/option/k3bdeviceoptiontab.h @@ -0,0 +1,47 @@ +/* + * + * $Id: k3bdeviceoptiontab.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3B_DEVICE_OPTIONTAB_H +#define K3B_DEVICE_OPTIONTAB_H + +#include <qwidget.h> + +class QLabel; +class K3bDeviceWidget; + + +class K3bDeviceOptionTab : public QWidget +{ +Q_OBJECT + + public: + K3bDeviceOptionTab( QWidget*, const char* name = 0 ); + ~K3bDeviceOptionTab(); + + void readDevices(); + void saveDevices(); + + private slots: + void slotRefreshButtonClicked(); + + private: + QLabel* m_labelDevicesInfo; + K3bDeviceWidget* m_deviceWidget; +}; + + + +#endif diff --git a/src/option/k3bdevicewidget.cpp b/src/option/k3bdevicewidget.cpp new file mode 100644 index 0000000..d7d1e36 --- /dev/null +++ b/src/option/k3bdevicewidget.cpp @@ -0,0 +1,404 @@ +/* + * + * $Id$ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bdevicewidget.h" +#include "k3bdevicemanager.h" +#include "k3bdevice.h" +#include "k3bdeviceglobals.h" +#include <k3blistview.h> + +#include <kinputdialog.h> +#include <kmessagebox.h> +#include <knuminput.h> +#include <kdialog.h> +#include <klocale.h> +#include <kconfig.h> +#include <ksimpleconfig.h> +#include <kiconloader.h> +#include <kstandarddirs.h> +#include <kio/global.h> + +#include <qgroupbox.h> +#include <qpushbutton.h> +#include <qlayout.h> +#include <qvariant.h> +#include <qtooltip.h> +#include <qwhatsthis.h> +#include <qheader.h> +#include <qstring.h> +#include <qcolor.h> +#include <qptrlist.h> + + +class K3bDeviceWidget::PrivateTempDevice +{ +public: + PrivateTempDevice( K3bDevice::Device* d ) { + device = d; + cdrdaoDriver = d->cdrdaoDriver(); + cdTextCapable = ( d->cdTextCapable() != 2 ); + writer = d->burner(); + } + + K3bDevice::Device* device; + QString cdrdaoDriver; + bool cdTextCapable; + bool writer; +}; + + +class K3bDeviceWidget::PrivateDeviceViewItem1 : public K3bListViewItem +{ +public: + PrivateDeviceViewItem1( int type, PrivateTempDevice* dev, QListView* view, QListViewItem* after ) + : K3bListViewItem( view, after ), + m_type(type) { + this->dev = dev; + init(); + } + + PrivateDeviceViewItem1( int type, PrivateTempDevice* dev, QListViewItem* item, QListViewItem* after ) + : K3bListViewItem( item, after ), + m_type(type) { + this->dev = dev; + init(); + } + + void setText(int col, const QString& text) { + if( col == 1 ) { + switch(m_type) { + case t_cdrdaoDriver: + dev->cdrdaoDriver = text; + break; + case t_cdTextCapable: + if( dev->cdrdaoDriver != "auto" ) + dev->cdTextCapable = ( text == i18n("yes") ); + break; + } + } + } + + QString text( int col ) const { + switch(m_type) { + case t_cdrdaoDriver: + return (col == 0 ? i18n("Cdrdao driver:") : dev->cdrdaoDriver ); + break; + case t_cdTextCapable: + if( col == 0 ) + return i18n("CD-Text capable:"); + else { + if( dev->cdrdaoDriver == "auto" ) + return "auto"; + else return ( dev->cdTextCapable ? i18n("yes") : i18n("no") ); + } + } + return "???"; + } + + enum itemType { t_cdrdaoDriver, t_cdTextCapable }; + + PrivateTempDevice* dev; + +private: + void init() { + static QStringList l; + static QStringList l2; + + switch(m_type) { + case t_cdrdaoDriver: + if( l.isEmpty() ) + for( int i = 0; i < 13; i++ ) + l.append(K3bDevice::Device::cdrdao_drivers[i]); + + setEditor( 1, COMBO, l ); + break; + case t_cdTextCapable: + if( l2.isEmpty() ) { + l2.append(i18n("auto")); + l2.append(i18n("yes")); + l2.append(i18n("no")); + } + + setEditor( 1, COMBO, l2 ); + } + } + + int m_type; +}; + + + + + + +K3bDeviceWidget::K3bDeviceWidget( K3bDevice::DeviceManager* manager, QWidget *parent, const char *name ) + : QWidget( parent, name ), m_deviceManager( manager ) +{ + QGridLayout* frameLayout = new QGridLayout( this ); + frameLayout->setSpacing( KDialog::spacingHint() ); + frameLayout->setMargin( 0 ); + + + // buttons + // ------------------------------------------------ + QGridLayout* refreshButtonGrid = new QGridLayout; + refreshButtonGrid->setSpacing( KDialog::spacingHint() ); + refreshButtonGrid->setMargin(0); + m_buttonRefreshDevices = new QPushButton( i18n( "Refresh" ), this, "m_buttonRefreshDevices" ); + m_buttonAddDevice = new QPushButton( i18n( "Add Device..." ), this, "m_buttonAddDevice" ); + QToolTip::add( m_buttonRefreshDevices, i18n( "Rescan the devices" ) ); + QSpacerItem* spacer = new QSpacerItem( 20, 20, QSizePolicy::Expanding, QSizePolicy::Minimum ); + refreshButtonGrid->addItem( spacer, 0, 0 ); + refreshButtonGrid->addWidget( m_buttonRefreshDevices, 0, 2 ); + refreshButtonGrid->addWidget( m_buttonAddDevice, 0, 1 ); + // ------------------------------------------------ + + + // Devices Box + // ------------------------------------------------ + QGroupBox* groupDevices = new QGroupBox( 1, Qt::Vertical, i18n( "CD/DVD Drives" ), this ); + groupDevices->layout()->setSpacing( KDialog::spacingHint() ); + groupDevices->layout()->setMargin( KDialog::marginHint() ); + + m_viewDevices = new K3bListView( groupDevices, "m_viewDevicesReader" ); + m_viewDevices->addColumn( "V" ); + m_viewDevices->addColumn( "D" ); + m_viewDevices->setAllColumnsShowFocus( true ); + m_viewDevices->header()->hide(); + m_viewDevices->setSorting( -1 ); + m_viewDevices->setDoubleClickForEdit(false); + m_viewDevices->setAlternateBackground( QColor() ); + m_viewDevices->setSelectionMode( QListView::NoSelection ); + m_viewDevices->setFullWidth(true); + // ------------------------------------------------ + + + frameLayout->addWidget( groupDevices, 0, 0 ); + frameLayout->addLayout( refreshButtonGrid, 1, 0 ); + // ------------------------------------------------ + + // temporary device lists settings + // ------------------------------------------------ + m_tempDevices.setAutoDelete( true ); + // ------------------------------------------------ + + + // connections + // ------------------------------------------------ + // connect( m_buttonRefreshDevices, SIGNAL(clicked()), this, SLOT(slotRefreshDevices()) ); + connect( m_buttonRefreshDevices, SIGNAL(clicked()), this, SIGNAL(refreshButtonClicked()) ); + connect( m_buttonAddDevice, SIGNAL(clicked()), this, SLOT(slotNewDevice()) ); + connect( m_deviceManager, SIGNAL(changed()), this, SLOT(init()) ); + // ------------------------------------------------ +} + + +K3bDeviceWidget::~K3bDeviceWidget() +{ + m_tempDevices.clear(); +} + + +void K3bDeviceWidget::init() +{ + // fill the temporary lists + m_tempDevices.clear(); + + // add the reading devices + for( QPtrListIterator<K3bDevice::Device> it( m_deviceManager->allDevices() ); *it; ++it ) + m_tempDevices.append( new PrivateTempDevice( *it ) ); + + updateDeviceListViews(); +} + + +void K3bDeviceWidget::updateDeviceListViews() +{ + m_viewDevices->clear(); + + // create the parent view items + // ----------------------------------------- + m_writerParentViewItem = new QListViewItem( m_viewDevices, i18n("Writer Drives") ); + m_writerParentViewItem->setPixmap( 0, SmallIcon( "cdwriter_unmount" ) ); + // spacer item + (void)new QListViewItem( m_viewDevices ); + m_readerParentViewItem = new QListViewItem( m_viewDevices, i18n("Readonly Drives") ); + m_readerParentViewItem->setPixmap( 0, SmallIcon( "cdrom_unmount" ) ); + // ----------------------------------------- + + QFont fBold( m_viewDevices->font() ); + fBold.setBold(true); + QFont fItalic( m_viewDevices->font() ); + fItalic.setItalic(true); + + PrivateTempDevice* dev = m_tempDevices.first(); + while( dev ) { + // create the root device item + K3bListViewItem* devRoot = new K3bListViewItem( (dev->writer ? m_writerParentViewItem : m_readerParentViewItem), + dev->device->vendor() + " " + dev->device->description() ); + devRoot->setFont( 0, fBold ); + + // create the read-only info items + K3bListViewItem* systemDeviceItem = new K3bListViewItem( devRoot, i18n("System device name:") ); + if( dev->device->interfaceType() == K3bDevice::SCSI ) + systemDeviceItem->setText( 1, QString("%1 (%2)").arg(dev->device->devicename()).arg(dev->device->busTargetLun()) ); + else + systemDeviceItem->setText( 1, dev->device->devicename() ); + systemDeviceItem->setForegroundColor( 1, palette().disabled().foreground() ); + + K3bListViewItem* interfaceItem = new K3bListViewItem( devRoot, systemDeviceItem, + i18n("Interface type:"), + ( dev->device->interfaceType() == K3bDevice::SCSI ? + i18n("Generic SCSI") : + i18n("ATAPI") ) ); + interfaceItem->setForegroundColor( 1, palette().disabled().foreground() ); + + K3bListViewItem* vendorItem = new K3bListViewItem( devRoot, interfaceItem, + i18n("Vendor:"), + dev->device->vendor() ); + vendorItem->setForegroundColor( 1, palette().disabled().foreground() ); + K3bListViewItem* modelItem = new K3bListViewItem( devRoot, vendorItem, + i18n("Description:"), + dev->device->description() ); + modelItem->setForegroundColor( 1, palette().disabled().foreground() ); + K3bListViewItem* versionItem = new K3bListViewItem( devRoot, modelItem, + i18n("Firmware:"), + dev->device->version() ); + versionItem->setForegroundColor( 1, palette().disabled().foreground() ); + + + // drive type + // -------------------------------- + K3bListViewItem* typeItem = new K3bListViewItem( devRoot, versionItem, + i18n("Writes CD-R:"), + dev->device->writesCd() ? i18n("yes") : i18n("no") ); + typeItem->setForegroundColor( 1, palette().disabled().foreground() ); + typeItem = new K3bListViewItem( devRoot, typeItem, + i18n("Writes CD-RW:"), + dev->device->writesCdrw() ? i18n("yes") : i18n("no") ); + typeItem->setForegroundColor( 1, palette().disabled().foreground() ); + typeItem = new K3bListViewItem( devRoot, typeItem, + i18n("Reads DVD:"), + dev->device->readsDvd() ? i18n("yes") : i18n("no") ); + typeItem->setForegroundColor( 1, palette().disabled().foreground() ); + typeItem = new K3bListViewItem( devRoot, typeItem, + i18n("Writes DVD-R(W):"), + dev->device->writesDvdMinus() ? i18n("yes") : i18n("no") ); + typeItem->setForegroundColor( 1, palette().disabled().foreground() ); + typeItem = new K3bListViewItem( devRoot, typeItem, + i18n("Writes DVD-R Dual Layer:"), + (dev->device->type() & K3bDevice::DEVICE_DVD_R_DL) + ? i18n("yes") : i18n("no") ); + typeItem->setForegroundColor( 1, palette().disabled().foreground() ); + typeItem = new K3bListViewItem( devRoot, typeItem, + i18n("Writes DVD+R(W):"), + dev->device->writesDvdPlus() ? i18n("yes") : i18n("no") ); + typeItem->setForegroundColor( 1, palette().disabled().foreground() ); + typeItem = new K3bListViewItem( devRoot, typeItem, + i18n("Writes DVD+R Double Layer:"), + (dev->device->type() & K3bDevice::DEVICE_DVD_PLUS_R_DL) + ? i18n("yes") : i18n("no") ); + typeItem->setForegroundColor( 1, palette().disabled().foreground() ); + // -------------------------------- + + + // now add the reader (both interfaces) items + if( dev->device->bufferSize() > 0 ) { + typeItem = new K3bListViewItem( devRoot, typeItem, + i18n("Buffer Size:"), + KIO::convertSizeFromKB(dev->device->bufferSize()) ); + typeItem->setForegroundColor( 1, palette().disabled().foreground() ); + } + + PrivateDeviceViewItem1* cdrdaoDriverItem = new PrivateDeviceViewItem1( PrivateDeviceViewItem1::t_cdrdaoDriver, + dev, + devRoot, + typeItem ); + + + // now add the writer specific items + if( dev->writer ) { + PrivateDeviceViewItem1* cdTextItem = new PrivateDeviceViewItem1( PrivateDeviceViewItem1::t_cdTextCapable, + dev, + devRoot, + cdrdaoDriverItem ); + + typeItem = new K3bListViewItem( devRoot, cdTextItem, + i18n("Supports Burnfree:"), + dev->device->burnfree() ? i18n("yes") : i18n("no") ); + typeItem->setForegroundColor( 1, palette().disabled().foreground() ); + + + // and at last the write modes + (new K3bListViewItem( devRoot, + typeItem, + i18n("Write modes:"), + K3bDevice::writingModeString(dev->device->writingModes()) ))->setForegroundColor( 1, palette().disabled().foreground() ); + } + + devRoot->setOpen(true); + + dev = m_tempDevices.next(); + } + + // create empty items + if( m_writerParentViewItem->childCount() == 0 ) { + K3bListViewItem* item = new K3bListViewItem( m_writerParentViewItem, i18n("none") ); + item->setFont( 0, fItalic ); + } + if( m_readerParentViewItem->childCount() == 0 ) { + K3bListViewItem* item = new K3bListViewItem( m_readerParentViewItem, i18n("none") ); + item->setFont( 0, fItalic ); + } + + m_writerParentViewItem->setOpen( true ); + m_readerParentViewItem->setOpen( true ); +} + + +void K3bDeviceWidget::slotNewDevice() +{ + bool ok; + QString newDevicename = KInputDialog::getText( i18n("Location of New Drive"), + i18n("Please enter the device name where K3b should search\nfor a new drive (example: /dev/cdrom):"), + "/dev/", &ok, this ); + + if( ok ) { + if( K3bDevice::Device* dev = m_deviceManager->addDevice( newDevicename ) ) { + m_tempDevices.append( new PrivateTempDevice( dev ) ); + + updateDeviceListViews(); + } + else + KMessageBox::error( this, i18n("Could not find an additional device at\n%1").arg(newDevicename), i18n("Error"), false ); + } +} + + +void K3bDeviceWidget::apply() +{ + // update the devices + PrivateTempDevice* tempDev = m_tempDevices.first(); + while( tempDev != 0 ) { + tempDev->device->setCdrdaoDriver( tempDev->cdrdaoDriver ); + tempDev->device->setCdTextCapability( tempDev->cdTextCapable ); + + tempDev = m_tempDevices.next(); + } +} + + +#include "k3bdevicewidget.moc" diff --git a/src/option/k3bdevicewidget.h b/src/option/k3bdevicewidget.h new file mode 100644 index 0000000..a874c94 --- /dev/null +++ b/src/option/k3bdevicewidget.h @@ -0,0 +1,78 @@ +/* + * + * $Id: k3bdevicewidget.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BDEVICEWIDGET_H +#define K3BDEVICEWIDGET_H + +#include <qwidget.h> +#include <qptrlist.h> +#include "k3bdevice.h" +#include "k3bdevicemanager.h" + +class QComboBox; +class QLabel; +class QGroupBox; +class QPushButton; +class QCheckBox; +class K3bListView; +class QString; +class KIntNumInput; +class QFrame; +class QListViewItem; +class QString; +class QLineEdit; + + +/** + *@author Sebastian Trueg + */ +class K3bDeviceWidget : public QWidget +{ + Q_OBJECT + + public: + K3bDeviceWidget( K3bDevice::DeviceManager*, QWidget *parent = 0, const char *name = 0 ); + ~K3bDeviceWidget(); + + public slots: + void init(); + void apply(); + + signals: + void refreshButtonClicked(); + + private slots: + void slotNewDevice(); + void updateDeviceListViews(); + + private: + class PrivateTempDevice; + class PrivateDeviceViewItem1; + + /** list to save changes to the devices before applying */ + QPtrList<PrivateTempDevice> m_tempDevices; + + QListViewItem* m_writerParentViewItem; + QListViewItem* m_readerParentViewItem; + + K3bDevice::DeviceManager* m_deviceManager; + + K3bListView* m_viewDevices; + QPushButton* m_buttonRefreshDevices; + QPushButton* m_buttonAddDevice; +}; + +#endif diff --git a/src/option/k3bexternalbinoptiontab.cpp b/src/option/k3bexternalbinoptiontab.cpp new file mode 100644 index 0000000..d5c78bc --- /dev/null +++ b/src/option/k3bexternalbinoptiontab.cpp @@ -0,0 +1,78 @@ +/* + * + * $Id: k3bexternalbinoptiontab.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bexternalbinoptiontab.h" +#include <k3bexternalbinmanager.h> +#include "k3bexternalbinwidget.h" + +#include <kmessagebox.h> +#include <kdialog.h> +#include <klocale.h> +#include <kiconloader.h> +#include <klistview.h> + +#include <qgroupbox.h> +#include <qlabel.h> +#include <qpushbutton.h> +#include <qlayout.h> +#include <qvariant.h> +#include <qtooltip.h> +#include <qwhatsthis.h> +#include <qfile.h> +#include <qptrlist.h> + + + +K3bExternalBinOptionTab::K3bExternalBinOptionTab( K3bExternalBinManager* manager, QWidget* parent, const char* name ) + : QWidget( parent, name ) +{ + m_manager = manager; + + QGridLayout* frameLayout = new QGridLayout( this ); + frameLayout->setSpacing( KDialog::spacingHint() ); + frameLayout->setMargin( 0 ); + + m_externalBinWidget = new K3bExternalBinWidget( manager, this ); + frameLayout->addWidget( m_externalBinWidget, 1, 0 ); + + QLabel* m_labelInfo = new QLabel( this, "m_labelInfo" ); + m_labelInfo->setText( i18n( "Specify the paths to the external programs that K3b needs to work properly, " + "or press \"Search\" to let K3b search for the programs." ) ); + m_labelInfo->setScaledContents( false ); + m_labelInfo->setAlignment( int( QLabel::WordBreak | QLabel::AlignVCenter | QLabel::AlignLeft ) ); + + frameLayout->addWidget( m_labelInfo, 0, 0 ); +} + + +K3bExternalBinOptionTab::~K3bExternalBinOptionTab() +{ +} + + +void K3bExternalBinOptionTab::readSettings() +{ + m_externalBinWidget->load(); +} + + +void K3bExternalBinOptionTab::saveSettings() +{ + m_externalBinWidget->save(); +} + + +#include "k3bexternalbinoptiontab.moc" diff --git a/src/option/k3bexternalbinoptiontab.h b/src/option/k3bexternalbinoptiontab.h new file mode 100644 index 0000000..8622579 --- /dev/null +++ b/src/option/k3bexternalbinoptiontab.h @@ -0,0 +1,50 @@ +/* + * + * $Id: k3bexternalbinoptiontab.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3B_EXTERNALBIN_OPTIONTAB_H +#define K3B_EXTERNALBIN_OPTIONTAB_H + +#include <qwidget.h> + + + +class QPushButton; +class QListViewItem; +class KListView; +class K3bExternalBinManager; +class K3bExternalBinWidget; + + +class K3bExternalBinOptionTab : public QWidget +{ +Q_OBJECT + + public: + K3bExternalBinOptionTab( K3bExternalBinManager*, QWidget*, const char* name = 0 ); + ~K3bExternalBinOptionTab(); + + void readSettings(); + void saveSettings(); + + private: + K3bExternalBinManager* m_manager; + + K3bExternalBinWidget* m_externalBinWidget; +}; + + + +#endif diff --git a/src/option/k3bexternalbinwidget.cpp b/src/option/k3bexternalbinwidget.cpp new file mode 100644 index 0000000..e1c62bb --- /dev/null +++ b/src/option/k3bexternalbinwidget.cpp @@ -0,0 +1,318 @@ +/* + * + * $Id: k3bexternalbinwidget.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bexternalbinwidget.h" +#include "k3bexternalbinmanager.h" + +#include <qpushbutton.h> +#include <kdebug.h> +#include <qtabwidget.h> +#include <qlayout.h> +#include <qheader.h> +#include <qlabel.h> +#include <qstringlist.h> +#include <qmap.h> +#include <qregexp.h> +#include <qfont.h> +#include <qpainter.h> +#include <qtooltip.h> +#include <qwhatsthis.h> +#include <qcursor.h> +#include <qapplication.h> +#include <qbitmap.h> + +#include <kdialog.h> +#include <kiconloader.h> +#include <klocale.h> +#include <keditlistbox.h> +#include <klistview.h> +#include <kglobalsettings.h> +#include <kdeversion.h> + + + +K3bExternalBinWidget::K3bExternalProgramViewItem::K3bExternalProgramViewItem( K3bExternalProgram* p, QListView* parent ) + : K3bListViewItem( parent ), m_program(p) +{ + QFont f( listView()->font() ); + f.setBold(true); + setFont( 0, f ); + setBackgroundColor( 0, KGlobalSettings::alternateBackgroundColor() ); + setBackgroundColor( 1, KGlobalSettings::alternateBackgroundColor() ); + setBackgroundColor( 2, KGlobalSettings::alternateBackgroundColor() ); + setText( 0, p->name() ); + setSelectable( false ); +} + + +K3bExternalBinWidget::K3bExternalBinViewItem::K3bExternalBinViewItem( K3bExternalBin* bin, K3bExternalProgramViewItem* parent ) + : K3bListViewItem( parent ), m_bin( bin ), m_parent( parent ) +{ + setText( 0, bin->path ); + setText( 1, bin->version ); + setText( 2, bin->features().join(", ") ); + + setDefault(false); +} + + +void K3bExternalBinWidget::K3bExternalBinViewItem::setDefault( bool b ) +{ + static QPixmap s_emptyPix( (int)KIcon::SizeSmall, (int)KIcon::SizeSmall ); + static bool s_emptyPixInitialized = false; + if( !s_emptyPixInitialized ) { + s_emptyPix.setMask( QBitmap( (int)KIcon::SizeSmall, (int)KIcon::SizeSmall, true ) ); + s_emptyPixInitialized = true; + } + + m_default = b; + if( b ) + setPixmap( 0, SmallIcon( "ok" ) ); + else + setPixmap( 0, s_emptyPix ); +} + + + + + +// /////////////////////////////////////////////////////////// +// +// K3BEXTERNALBINWIDGET +// +// ////////////////////////////////////////////////////////// + + +K3bExternalBinWidget::K3bExternalBinWidget( K3bExternalBinManager* manager, QWidget* parent, const char* name ) + : QWidget( parent, name ), m_manager( manager ) +{ + QGridLayout* mainGrid = new QGridLayout( this ); + mainGrid->setMargin( 0 ); + mainGrid->setSpacing( KDialog::spacingHint() ); + + m_mainTabWidget = new QTabWidget( this ); + m_rescanButton = new QPushButton( i18n("&Search"), this ); + mainGrid->addMultiCellWidget( m_mainTabWidget, 0, 0, 0, 1 ); + mainGrid->addWidget( m_rescanButton, 1, 1 ); + mainGrid->setColStretch( 0, 1 ); + mainGrid->setRowStretch( 0, 1 ); + + + // setup program tab + // ------------------------------------------------------------ + QWidget* programTab = new QWidget( m_mainTabWidget ); + QGridLayout* programTabLayout = new QGridLayout( programTab ); + programTabLayout->setMargin( KDialog::marginHint() ); + programTabLayout->setSpacing( KDialog::spacingHint() ); + m_programView = new K3bListView( programTab ); + m_defaultButton = new QPushButton( i18n("Set Default"), programTab ); + QToolTip::add( m_defaultButton, i18n("Change the versions K3b should use.") ); + QWhatsThis::add( m_defaultButton, i18n("<p>If K3b found more than one installed version of a program " + "it will choose one as the <em>default</em> which will be used " + "to do the work. If you want to change the default select the " + "wanted version and press this button.") ); + programTabLayout->addMultiCellWidget( m_programView, 1, 1, 0, 1 ); + programTabLayout->addWidget( m_defaultButton, 0, 1 ); + programTabLayout->addWidget( new QLabel( i18n("Use the 'Default' button to change the versions K3b should use."), + programTab ), 0, 0 ); + programTabLayout->setColStretch( 0, 1 ); + programTabLayout->setRowStretch( 1, 1 ); + + m_programView->addColumn( i18n("Path") ); + m_programView->addColumn( i18n("Version") ); + m_programView->addColumn( i18n("Features") ); + m_programView->setAllColumnsShowFocus(true); + m_programView->setFullWidth(true); + m_programView->setAlternateBackground( QColor() ); +#if KDE_IS_VERSION(3,4,0) + m_programView->setShadeSortColumn( false ); +#endif + m_mainTabWidget->addTab( programTab, i18n("Programs") ); + + + // setup parameters tab + // ------------------------------------------------------------ + QWidget* parametersTab = new QWidget( m_mainTabWidget ); + QGridLayout* parametersTabLayout = new QGridLayout( parametersTab ); + parametersTabLayout->setMargin( KDialog::marginHint() ); + parametersTabLayout->setSpacing( KDialog::spacingHint() ); + m_parameterView = new K3bListView( parametersTab ); + parametersTabLayout->addWidget( m_parameterView, 1, 0 ); + parametersTabLayout->addWidget( new QLabel( i18n("User parameters have to be separated by space."), parametersTab ), 0, 0 ); + + parametersTabLayout->setRowStretch( 1, 1 ); + + m_parameterView->addColumn( i18n("Program") ); + m_parameterView->addColumn( i18n("Parameters") ); + m_parameterView->setAllColumnsShowFocus(true); + m_parameterView->setFullWidth(true); + m_parameterView->setDefaultRenameAction( QListView::Accept ); + m_parameterView->setDoubleClickForEdit( false ); + + m_mainTabWidget->addTab( parametersTab, i18n("User Parameters") ); + + + // setup search path tab + // ------------------------------------------------------------ + QWidget* searchPathTab = new QWidget( m_mainTabWidget ); + QGridLayout* searchPathTabLayout = new QGridLayout( searchPathTab ); + searchPathTabLayout->setMargin( KDialog::marginHint() ); + searchPathTabLayout->setSpacing( KDialog::spacingHint() ); + m_searchPathBox = new KEditListBox( i18n("Search Path"), searchPathTab, "searchPathBox", true ); + searchPathTabLayout->addWidget( m_searchPathBox, 0, 0 ); + searchPathTabLayout->addWidget( new QLabel( i18n("<qt><b>Hint:</b> to force K3b to use another than the " + "default name for the executable specify it in the search path.</qt>"), + searchPathTab ), 1, 0 ); + + searchPathTabLayout->setRowStretch( 0, 1 ); + + m_mainTabWidget->addTab( searchPathTab, i18n("Search Path") ); + + + m_programRootItems.setAutoDelete( true ); + + + connect( m_rescanButton, SIGNAL(clicked()), this, SLOT(rescan()) ); + connect( m_defaultButton, SIGNAL(clicked()), this, SLOT(slotSetDefaultButtonClicked()) ); + connect( m_programView, SIGNAL(selectionChanged(QListViewItem*)), this, SLOT(slotProgramSelectionChanged(QListViewItem*)) ); + + slotProgramSelectionChanged( 0 ); +} + + +K3bExternalBinWidget::~K3bExternalBinWidget() +{ +} + +void K3bExternalBinWidget::rescan() +{ + QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); + saveSearchPath(); + m_manager->search(); + load(); + QApplication::restoreOverrideCursor(); +} + + +void K3bExternalBinWidget::load() +{ + m_programRootItems.clear(); + m_parameterView->clear(); + + // load programs + const QMap<QString, K3bExternalProgram*>& map = m_manager->programs(); + for( QMap<QString, K3bExternalProgram*>::const_iterator it = map.begin(); it != map.end(); ++it ) { + K3bExternalProgram* p = it.data(); + + K3bExternalProgramViewItem* pV = new K3bExternalProgramViewItem( p, m_programView ); + m_programRootItems.append( pV ); + // populate it + QPtrListIterator<K3bExternalBin> binIt( p->bins() ); + for( ; binIt.current(); ++binIt ) { + K3bExternalBin* b = *binIt; + + K3bExternalBinViewItem* bV = new K3bExternalBinViewItem( b, pV ); + if( b == p->defaultBin() ) + bV->setDefault(true); + + pV->setOpen(true); + } + + if( p->bins().isEmpty() ) + pV->setText( 0, p->name() + i18n(" (not found)") ); + + // load user parameters + if( p->supportsUserParameters() ) { + K3bExternalProgramViewItem* paraV = new K3bExternalProgramViewItem( p, m_parameterView ); + paraV->setText( 1, p->userParameters().join( " " ) ); + paraV->setEditor( 1, K3bListViewItem::LINE ); + } + } + + + + // load search path + m_searchPathBox->clear(); + m_searchPathBox->insertStringList( m_manager->searchPath() ); +} + + +void K3bExternalBinWidget::save() +{ + saveSearchPath(); + + + // save the default programs + QListViewItemIterator progIt( m_programView ); + while( progIt.current() ) { + if( K3bExternalBinViewItem* bV = dynamic_cast<K3bExternalBinViewItem*>( progIt.current() ) ) { + if( bV->isDefault() ) + bV->parentProgramItem()->program()->setDefault( bV->bin() ); + } + + ++progIt; + } + + + // save the user parameters + QListViewItemIterator paraIt( m_parameterView ); + QRegExp reSpace( "\\s" ); + while( paraIt.current() ) { + K3bExternalProgramViewItem* pV = (K3bExternalProgramViewItem*)paraIt.current(); + pV->program()->setUserParameters( QStringList::split( reSpace, pV->text(1) ) ); + + ++paraIt; + } +} + + +void K3bExternalBinWidget::saveSearchPath() +{ + m_manager->setSearchPath( m_searchPathBox->items() ); +} + + +void K3bExternalBinWidget::slotSetDefaultButtonClicked() +{ + // check if we are on a binItem + K3bExternalBinViewItem* item = dynamic_cast<K3bExternalBinViewItem*>( m_programView->selectedItem() ); + if( item ) { + // remove all default flags + K3bExternalBinViewItem* bi = (K3bExternalBinViewItem*)item->parentProgramItem()->firstChild(); + QListViewItemIterator it( bi ); + while( it.current() && it.current()->parent() == item->parentProgramItem() ) { + ((K3bExternalBinViewItem*)it.current())->setDefault(false); + ++it; + } + + item->setDefault(true); + } +} + + +void K3bExternalBinWidget::slotProgramSelectionChanged( QListViewItem* item ) +{ + K3bExternalBinViewItem* bV = dynamic_cast<K3bExternalBinViewItem*>( item ); + if( bV ) { + if( bV->isDefault() ) + m_defaultButton->setEnabled(false); + else + m_defaultButton->setEnabled(true); + } + else + m_defaultButton->setEnabled(false); +} + +#include "k3bexternalbinwidget.moc" diff --git a/src/option/k3bexternalbinwidget.h b/src/option/k3bexternalbinwidget.h new file mode 100644 index 0000000..fe2e163 --- /dev/null +++ b/src/option/k3bexternalbinwidget.h @@ -0,0 +1,103 @@ +/* + * + * $Id: k3bexternalbinwidget.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3B_EXTERNAL_BIN_WIDGET_H +#define K3B_EXTERNAL_BIN_WIDGET_H + + +#include <qwidget.h> +#include <qptrlist.h> + +#include <k3blistview.h> + + +class K3bExternalBinManager; +class QPushButton; +class QTabWidget; +class KEditListBox; +class K3bExternalProgram; +class K3bExternalBin; + + +class K3bExternalBinWidget : public QWidget +{ + Q_OBJECT + + public: + K3bExternalBinWidget( K3bExternalBinManager*, QWidget* parent = 0, const char* name = 0 ); + ~K3bExternalBinWidget(); + + class K3bExternalBinViewItem; + class K3bExternalProgramViewItem; + + public slots: + void rescan(); + void load(); + void save(); + + private slots: + void slotSetDefaultButtonClicked(); + void slotProgramSelectionChanged( QListViewItem* ); + void saveSearchPath(); + + private: + K3bExternalBinManager* m_manager; + + QTabWidget* m_mainTabWidget; + K3bListView* m_programView; + K3bListView* m_parameterView; + KEditListBox* m_searchPathBox; + + QPushButton* m_defaultButton; + QPushButton* m_rescanButton; + + QPtrList<K3bExternalProgramViewItem> m_programRootItems; +}; + + +class K3bExternalBinWidget::K3bExternalProgramViewItem : public K3bListViewItem +{ + public: + K3bExternalProgramViewItem( K3bExternalProgram* p, QListView* parent ); + + K3bExternalProgram* program() const { return m_program; } + + private: + K3bExternalProgram* m_program; +}; + + + +class K3bExternalBinWidget::K3bExternalBinViewItem : public K3bListViewItem +{ + public: + K3bExternalBinViewItem( K3bExternalBin* bin, K3bExternalProgramViewItem* parent ); + + K3bExternalBin* bin() const { return m_bin; } + K3bExternalProgramViewItem* parentProgramItem() const { return m_parent; } + + bool isDefault() const { return m_default; } + void setDefault( bool b ); + + private: + K3bExternalBin* m_bin; + K3bExternalProgramViewItem* m_parent; + + bool m_default; +}; + + +#endif diff --git a/src/option/k3bmiscoptiontab.cpp b/src/option/k3bmiscoptiontab.cpp new file mode 100644 index 0000000..d81e565 --- /dev/null +++ b/src/option/k3bmiscoptiontab.cpp @@ -0,0 +1,187 @@ +/* + * + * $Id: k3bmiscoptiontab.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bmiscoptiontab.h" + +#include <k3bpluginmanager.h> +#include <k3baudiooutputplugin.h> +#include <k3baudioserver.h> +#include <k3bcore.h> +#include <k3bservicemenuinstaller.h> +#include <k3binteractiondialog.h> +#include <k3bintmapcombobox.h> + +#include <qcheckbox.h> +#include <qfileinfo.h> +#include <qradiobutton.h> + +#include <kapplication.h> +#include <klocale.h> +#include <kconfig.h> +#include <kdialog.h> +#include <kstandarddirs.h> +#include <kmessagebox.h> +#include <kurlrequester.h> +#include <kcombobox.h> + + +K3bMiscOptionTab::K3bMiscOptionTab(QWidget *parent, const char *name ) + : base_K3bMiscOptionTab(parent,name) +{ + m_editTempDir->setMode( KFile::Directory ); + connect( m_buttonConfigureAudioOutput, SIGNAL(clicked()), + this, SLOT(slotConfigureAudioOutput()) ); + + m_comboActionDialogSettings->insertItem( K3bInteractionDialog::LOAD_K3B_DEFAULTS, + i18n("Default Settings"), + i18n("Load the K3b Defaults at dialog startup.") ); + m_comboActionDialogSettings->insertItem( K3bInteractionDialog::LOAD_SAVED_SETTINGS, + i18n("Saved Settings"), + i18n("Load the settings saved by the user at dialog startup.") ); + m_comboActionDialogSettings->insertItem( K3bInteractionDialog::LOAD_LAST_SETTINGS, + i18n("Last Used Settings"), + i18n("Load the last used settings at dialog startup.") ); + m_comboActionDialogSettings->addGlobalWhatsThisText( i18n("K3b handles three sets of settings in action dialogs " + "(action dialogs include the CD Copy dialog or the Audio CD " + "project dialog):"), + i18n("One of these sets is loaded once an action dialog is opened. " + "This setting defines which set it will be.") ); +} + + +K3bMiscOptionTab::~K3bMiscOptionTab() +{ +} + + +void K3bMiscOptionTab::readSettings() +{ + KConfig* c = kapp->config(); + c->setGroup( "General Options" ); + m_checkSaveOnExit->setChecked( c->readBoolEntry( "ask_for_saving_changes_on_exit", true ) ); + m_checkShowSplash->setChecked( c->readBoolEntry("Show splash", true) ); + m_checkShowProgressOSD->setChecked( c->readBoolEntry( "Show progress OSD", true ) ); + m_checkHideMainWindowWhileWriting->setChecked( c->readBoolEntry( "hide main window while writing", false ) ); + m_checkKeepDialogsOpen->setChecked( c->readBoolEntry( "keep action dialogs open", false ) ); + m_comboActionDialogSettings->setSelectedValue( c->readNumEntry( "action dialog startup settings", + K3bInteractionDialog::LOAD_SAVED_SETTINGS ) ); + m_checkSystemConfig->setChecked( c->readBoolEntry( "check system config", true ) ); + + QString tempdir = c->readPathEntry( "Temp Dir", KGlobal::dirs()->resourceDirs( "tmp" ).first() ); + m_editTempDir->setURL( tempdir ); + +// if( c->readEntry( "Multiple Instances", "smart" ) == "smart" ) +// m_radioMultipleInstancesSmart->setChecked(true); +// else +// m_radioMultipleInstancesNew->setChecked(true); + + // Audio Output + m_comboAudioOutputSystem->clear(); + QPtrList<K3bPlugin> fl = k3bcore->pluginManager()->plugins( "AudioOutput" ); + for( QPtrListIterator<K3bPlugin> it( fl ); it.current(); ++it ) { + K3bAudioOutputPlugin* f = static_cast<K3bAudioOutputPlugin*>( it.current() ); + m_comboAudioOutputSystem->insertItem( QString::fromLocal8Bit(f->soundSystem()) ); + } + + m_comboAudioOutputSystem->setCurrentItem( c->readEntry( "Audio Output System", "arts" ), false ); + m_buttonConfigureAudioOutput->setEnabled( m_comboAudioOutputSystem->count() > 0 ); + + K3bServiceInstaller si; + m_checkKonqiIntegration->setChecked( si.allInstalled() ); +} + + +bool K3bMiscOptionTab::saveSettings() +{ + KConfig* c = kapp->config(); + c->setGroup( "General Options" ); + c->writeEntry( "ask_for_saving_changes_on_exit", m_checkSaveOnExit->isChecked() ); + c->writeEntry( "Show splash", m_checkShowSplash->isChecked() ); + c->writeEntry( "Show progress OSD", m_checkShowProgressOSD->isChecked() ); + c->writeEntry( "hide main window while writing", m_checkHideMainWindowWhileWriting->isChecked() ); + c->writeEntry( "keep action dialogs open", m_checkKeepDialogsOpen->isChecked() ); + c->writeEntry( "check system config", m_checkSystemConfig->isChecked() ); + c->writeEntry( "action dialog startup settings", m_comboActionDialogSettings->selectedValue() ); + + QString tempDir = m_editTempDir->url(); + QFileInfo fi( tempDir ); + + if( fi.isRelative() ) { + fi.setFile( fi.absFilePath() ); + } + + if( !fi.exists() ) { + if( KMessageBox::questionYesNo( this, i18n("Directory (%1) does not exist. Create?").arg(tempDir), + i18n("Create Directory"), i18n("Create"), KStdGuiItem::cancel() ) == KMessageBox::Yes ) { + if( !KStandardDirs::makeDir( fi.absFilePath() ) ) { + KMessageBox::error( this, i18n("Unable to create directory %1").arg(tempDir) ); + return false; + } + } + else { + // the dir does not exist and the user doesn't want to create it + return false; + } + } + + if( fi.isFile() ) { + KMessageBox::information( this, i18n("You specified a file for the temporary directory. " + "K3b will use its base path as the temporary directory."), + i18n("Warning"), + "temp file only using base path" ); + fi.setFile( fi.dirPath() ); + } + + // check for writing permission + if( !fi.isWritable() ) { + KMessageBox::error( this, i18n("You do not have permission to write to %1.").arg(fi.absFilePath()) ); + return false; + } + + m_editTempDir->setURL( fi.absFilePath() ); + + c->writePathEntry( "Temp Dir", m_editTempDir->url() ); + +// if( m_radioMultipleInstancesSmart->isChecked() ) +// c->writeEntry( "Multiple Instances", "smart" ); +// else +// c->writeEntry( "Multiple Instances", "always_new" ); + + // Audio Output System + if( m_comboAudioOutputSystem->count() > 0 ) { + c->writeEntry( "Audio Output System", m_comboAudioOutputSystem->currentText() ); + K3bAudioServer::instance()->setOutputMethod( m_comboAudioOutputSystem->currentText().local8Bit() ); + } + + K3bServiceInstaller si; + if( m_checkKonqiIntegration->isChecked() ) + si.install( this ); + else + si.remove( this ); + + return true; +} + + +void K3bMiscOptionTab::slotConfigureAudioOutput() +{ + QString system = m_comboAudioOutputSystem->currentText(); + if( K3bAudioOutputPlugin* plugin = K3bAudioServer::findOutputPlugin( system.local8Bit() ) ) { + k3bcore->pluginManager()->execPluginDialog( plugin, this ); + } +} + +#include "k3bmiscoptiontab.moc" diff --git a/src/option/k3bmiscoptiontab.h b/src/option/k3bmiscoptiontab.h new file mode 100644 index 0000000..6e5ded6 --- /dev/null +++ b/src/option/k3bmiscoptiontab.h @@ -0,0 +1,43 @@ +/* + * + * $Id: k3bmiscoptiontab.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BMISCOPTIONTAB_H +#define K3BMISCOPTIONTAB_H + +#include "base_k3bmiscoptiontab.h" + +class QCheckBox; +class KURLRequester; + +/** + *@author Sebastian Trueg + */ +class K3bMiscOptionTab : public base_K3bMiscOptionTab +{ + Q_OBJECT + + public: + K3bMiscOptionTab(QWidget *parent=0, const char *name=0); + ~K3bMiscOptionTab(); + + void readSettings(); + bool saveSettings(); + + private slots: + void slotConfigureAudioOutput(); +}; + +#endif diff --git a/src/option/k3bnotifyoptiontab.cpp b/src/option/k3bnotifyoptiontab.cpp new file mode 100644 index 0000000..60ddc7c --- /dev/null +++ b/src/option/k3bnotifyoptiontab.cpp @@ -0,0 +1,61 @@ +/* + * + * $Id: k3bnotifyoptiontab.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include <kdeversion.h> + +#include "k3bnotifyoptiontab.h" + +#include <knotifydialog.h> +#include <kdebug.h> + +#include <qlayout.h> + + + +K3bNotifyOptionTab::K3bNotifyOptionTab( QWidget* parent, const char* name ) + : QWidget( parent, name ) +{ + m_notifyWidget = new KNotify::KNotifyWidget( this ); + + QHBoxLayout* box = new QHBoxLayout( this ); + box->addWidget( m_notifyWidget ); +} + + +K3bNotifyOptionTab::~K3bNotifyOptionTab() +{ +} + + +void K3bNotifyOptionTab::readSettings() +{ + m_notifyWidget->clear(); + KNotify::Application* app = m_notifyWidget->addApplicationEvents( "k3b/eventsrc" ); + if( app ) + m_notifyWidget->addVisibleApp(app); + else + kdDebug() << "(K3bNotifyOptionTab) could not find K3b eventsrc." << endl; +} + + +bool K3bNotifyOptionTab::saveSettings() +{ + m_notifyWidget->save(); + + return true; +} + +#include "k3bnotifyoptiontab.moc" diff --git a/src/option/k3bnotifyoptiontab.h b/src/option/k3bnotifyoptiontab.h new file mode 100644 index 0000000..03314dc --- /dev/null +++ b/src/option/k3bnotifyoptiontab.h @@ -0,0 +1,43 @@ +/* + * + * $Id: k3bnotifyoptiontab.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + + +#ifndef _K3B_NOTIFY_OPTIONTAB_H_ +#define _K3B_NOTIFY_OPTIONTAB_H_ + +#include <qwidget.h> + +namespace KNotify { + class KNotifyWidget; +} + + +class K3bNotifyOptionTab : public QWidget +{ + Q_OBJECT + + public: + K3bNotifyOptionTab( QWidget* parent = 0, const char* name = 0 ); + ~K3bNotifyOptionTab(); + + void readSettings(); + bool saveSettings(); + + private: + KNotify::KNotifyWidget* m_notifyWidget; +}; + +#endif diff --git a/src/option/k3boptiondialog.cpp b/src/option/k3boptiondialog.cpp new file mode 100644 index 0000000..d0ba7ce --- /dev/null +++ b/src/option/k3boptiondialog.cpp @@ -0,0 +1,258 @@ +/* + * + * $Id$ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3boptiondialog.h" +#include <k3bcore.h> +#include "k3bcddboptiontab.h" +#include "k3bdeviceoptiontab.h" +#include "k3bburningoptiontab.h" +#include "k3bexternalbinoptiontab.h" +#include "k3bmiscoptiontab.h" +#include "k3bthemeoptiontab.h" +#include "k3bpluginoptiontab.h" +#include <k3bsystemproblemdialog.h> + + +#include <qlayout.h> +#include <qtooltip.h> +#include <qwhatsthis.h> +#include <qtabwidget.h> + +#include <klocale.h> +#include <kiconloader.h> +#include <kconfig.h> +#include <kdeversion.h> +#include "k3bnotifyoptiontab.h" + + +// TODO: handle the default-settings + +K3bOptionDialog::K3bOptionDialog(QWidget *parent, const char *name, bool modal ) + : KDialogBase( IconList, i18n("Settings"), Apply|Ok|Cancel, Ok, parent,name, modal, true) +{ + setupMiscPage(); + setupDevicePage(); + setupProgramsPage(); + setupCddbPage(); + setupNotifyPage(); + setupPluginPage(); + setupThemePage(); + setupBurningPage(); + + m_externalBinOptionTab->readSettings(); + m_cddbOptionTab->readSettings(); + m_deviceOptionTab->readDevices(); + m_burningOptionTab->readSettings(); + m_miscOptionTab->readSettings(); + m_notifyOptionTab->readSettings(); + m_pluginOptionTab->readSettings(); + m_themeOptionTab->readSettings(); + + // if we don't do this the dialog start really huge + // because of the label in the device-tab + resize( 700, 500 ); + + showPage( 0 ); +} + + +K3bOptionDialog::~K3bOptionDialog() +{ +} + + +void K3bOptionDialog::slotOk() +{ + if( saveSettings() ) { + accept(); + + k3bcore->config()->setGroup( "General Options" ); + if( k3bcore->config()->readBoolEntry( "check system config", true ) ) + K3bSystemProblemDialog::checkSystem(); + } +} + +void K3bOptionDialog::slotApply() +{ + saveSettings(); +} + + +bool K3bOptionDialog::saveSettings() +{ + // save all the shit! + m_cddbOptionTab->apply(); + m_deviceOptionTab->saveDevices(); + m_burningOptionTab->saveSettings(); + m_externalBinOptionTab->saveSettings(); + m_notifyOptionTab->saveSettings(); + + m_themeOptionTab->saveSettings(); + + if( !m_miscOptionTab->saveSettings() ) + return false; + + return true; +} + + +void K3bOptionDialog::slotDefault() +{ + switch( activePageIndex() ) + { + case 0: // device page + + break; + case 1: // programs page + break; + default: + break; + } +} + + +void K3bOptionDialog::setupBurningPage() +{ + QFrame* frame = addPage( i18n("Advanced"), i18n("Advanced Settings"), + KGlobal::instance()->iconLoader()->loadIcon( "cdwriter_unmount", KIcon::NoGroup, KIcon::SizeMedium ) ); + + QGridLayout* _frameLayout = new QGridLayout( frame ); + _frameLayout->setSpacing( 0 ); + _frameLayout->setMargin( 0 ); + + m_burningOptionTab = new K3bBurningOptionTab( frame ); + _frameLayout->addWidget( m_burningOptionTab, 0, 0 ); +} + + +void K3bOptionDialog::setupProgramsPage() +{ + QFrame* frame = addPage( i18n("Programs"), i18n("Setup External Programs"), + KGlobal::instance()->iconLoader()->loadIcon( "exec", KIcon::NoGroup, KIcon::SizeMedium ) ); + + QGridLayout* _frameLayout = new QGridLayout( frame ); + _frameLayout->setSpacing( 0 ); + _frameLayout->setMargin( 0 ); + + m_externalBinOptionTab = new K3bExternalBinOptionTab( k3bcore->externalBinManager(), frame ); + _frameLayout->addWidget( m_externalBinOptionTab, 0, 0 ); +} + + +void K3bOptionDialog::setupCddbPage() +{ + QFrame* frame = addPage( i18n("CDDB"), i18n("Setup the CDDB Server"), + KGlobal::instance()->iconLoader()->loadIcon( "connect_established", KIcon::NoGroup, KIcon::SizeMedium ) ); + + QGridLayout* mainGrid = new QGridLayout( frame ); + mainGrid->setSpacing(0); + mainGrid->setMargin(0); + // QTabWidget *_tab = new QTabWidget( frame ); + m_cddbOptionTab = new K3bCddbOptionTab( frame, "cddbremotepage"); + // m_cddbLocalTab = new K3bCddbLocalDBTab( frame, "cddblocalpage"); +// _tab->addTab( m_cddbOptionTab, i18n("Remote") ); +// _tab->addTab( m_cddbLocalTab, i18n("Local") ); + //mainGrid->addWidget( m_cddbOptionTab, 0, 0 ); + mainGrid->addWidget( m_cddbOptionTab, 0, 0 ); +} + + +void K3bOptionDialog::setupDevicePage() +{ + QFrame* frame = addPage( i18n("Devices"), i18n("Setup Devices"), + KGlobal::instance()->iconLoader()->loadIcon( "blockdevice", KIcon::NoGroup, KIcon::SizeMedium ) ); + + QHBoxLayout* box = new QHBoxLayout( frame ); + box->setSpacing(0); + box->setMargin(0); + m_deviceOptionTab = new K3bDeviceOptionTab( frame, "deviceOptionTab" ); + box->addWidget( m_deviceOptionTab ); +} + + +void K3bOptionDialog::setupMiscPage() +{ + QFrame* frame = addPage( i18n("Misc"), i18n("Miscellaneous Settings"), + KGlobal::instance()->iconLoader()->loadIcon( "misc", KIcon::NoGroup, KIcon::SizeMedium ) ); + + QVBoxLayout* box = new QVBoxLayout( frame ); + box->setSpacing( 0 ); + box->setMargin( 0 ); + + m_miscOptionTab = new K3bMiscOptionTab( frame ); + box->addWidget( m_miscOptionTab ); +} + + +void K3bOptionDialog::setupNotifyPage() +{ + QFrame* frame = addPage( i18n("Notifications"), i18n("System Notifications"), + KGlobal::instance()->iconLoader()->loadIcon( "knotify", + KIcon::NoGroup, KIcon::SizeMedium ) ); + QVBoxLayout* box = new QVBoxLayout( frame ); + box->setSpacing( 0 ); + box->setMargin( 0 ); + + m_notifyOptionTab = new K3bNotifyOptionTab( frame ); + box->addWidget( m_notifyOptionTab ); +} + + +void K3bOptionDialog::setupPluginPage() +{ + QFrame* frame = addPage( i18n("Plugins"), i18n("K3b Plugin Configuration"), + KGlobal::instance()->iconLoader()->loadIcon( "gear", + KIcon::NoGroup, KIcon::SizeMedium ) ); + QVBoxLayout* box = new QVBoxLayout( frame ); + box->setSpacing( 0 ); + box->setMargin( 0 ); + + m_pluginOptionTab = new K3bPluginOptionTab( frame ); + box->addWidget( m_pluginOptionTab ); +} + + +void K3bOptionDialog::setupThemePage() +{ + QFrame* frame = addPage( i18n("Themes"), i18n("K3b GUI Themes"), + KGlobal::instance()->iconLoader()->loadIcon( "style", + KIcon::NoGroup, KIcon::SizeMedium ) ); + QVBoxLayout* box = new QVBoxLayout( frame ); + box->setSpacing( 0 ); + box->setMargin( 0 ); + + m_themeOptionTab = new K3bThemeOptionTab( frame ); + box->addWidget( m_themeOptionTab ); +} + + +// void K3bOptionDialog::addOptionPage( QWidget* widget, +// const QString& name, +// const QString& header, +// const QPixmap& icon ) +// { +// QFrame* frame = addPage( name, header, icon ); + +// QVBoxLayout* box = new QVBoxLayout( frame ); +// box->setSpacing( 0 ); +// box->setMargin( 0 ); + +// widget->reparent( frame ); +// box->addWidget( widget ); +// } + + +#include "k3boptiondialog.moc" diff --git a/src/option/k3boptiondialog.h b/src/option/k3boptiondialog.h new file mode 100644 index 0000000..1f417b6 --- /dev/null +++ b/src/option/k3boptiondialog.h @@ -0,0 +1,91 @@ +/* + * + * $Id$ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BOPTIONDIALOG_H +#define K3BOPTIONDIALOG_H + +#include <kdialogbase.h> + +class K3bCddbOptionTab; +class K3bDeviceOptionTab; +class K3bBurningOptionTab; +class K3bExternalBinOptionTab; +class K3bMiscOptionTab; +class K3bNotifyOptionTab; +class K3bPluginOptionTab; +class K3bThemeOptionTab; + + +/** + *@author Sebastian Trueg + */ +class K3bOptionDialog : public KDialogBase +{ + Q_OBJECT + + public: + K3bOptionDialog(QWidget *parent=0, const char *name=0, bool modal = true); + ~K3bOptionDialog(); + + enum m_configPageIndex { Burning = 0, Devices = 1, Programs = 2, Cddb = 3 }; + +/* void addOptionPage( QWidget* widget, */ +/* const QString& name, */ +/* const QString& header, */ +/* const QPixmap& icon ); */ + + protected slots: + void slotOk(); + void slotApply(); + void slotDefault(); + + private: + bool saveSettings(); + + // programs tab + K3bExternalBinOptionTab* m_externalBinOptionTab; + void setupProgramsPage(); + + // device tab + K3bDeviceOptionTab* m_deviceOptionTab; + void setupDevicePage(); + + // burning tab + void setupBurningPage(); + K3bBurningOptionTab* m_burningOptionTab; + + // cddb tabs + K3bCddbOptionTab *m_cddbOptionTab; + void setupCddbPage(); + + // misc options + K3bMiscOptionTab* m_miscOptionTab; + void setupMiscPage(); + + // notify options + K3bNotifyOptionTab* m_notifyOptionTab; + void setupNotifyPage(); + + // plugin options + K3bPluginOptionTab* m_pluginOptionTab; + void setupPluginPage(); + + // theme options + K3bThemeOptionTab* m_themeOptionTab; + void setupThemePage(); +}; + +#endif diff --git a/src/option/k3bpluginoptiontab.cpp b/src/option/k3bpluginoptiontab.cpp new file mode 100644 index 0000000..59d7b74 --- /dev/null +++ b/src/option/k3bpluginoptiontab.cpp @@ -0,0 +1,137 @@ +/* + * + * $Id: k3bpluginoptiontab.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bpluginoptiontab.h" + + +#include <k3bpluginmanager.h> +#include <k3bplugin.h> +#include <k3bpluginconfigwidget.h> +#include <k3blistview.h> +#include <k3bcore.h> + +#include <klocale.h> +#include <kmessagebox.h> +#include <kdebug.h> +#include <kdialogbase.h> +#include <kconfig.h> +#include <kglobalsettings.h> +#include <kdeversion.h> + +#include <qstringlist.h> +#include <qpushbutton.h> + + +class K3bPluginOptionTab::PluginViewItem : public K3bListViewItem +{ +public: + PluginViewItem( K3bPlugin* p, KListViewItem* parent ) + : K3bListViewItem( parent ), + plugin(p) { + const K3bPluginInfo& info = p->pluginInfo(); + setText( 0, info.name() ); + if( !info.author().isEmpty() ) { + if( info.email().isEmpty() ) + setText( 1, info.author() ); + else + setText( 1, info.author() + " <" + info.email() + ">" ); + } + setText( 2, info.version() ); + setText( 3, info.comment() ); + setText( 4, info.licence() ); + } + + K3bPlugin* plugin; +}; + + + +K3bPluginOptionTab::K3bPluginOptionTab( QWidget* parent, const char* name ) + : base_K3bPluginOptionTab( parent, name ) +{ +#if KDE_IS_VERSION(3,4,0) + m_viewPlugins->setShadeSortColumn( false ); +#endif + m_viewPlugins->addColumn( i18n("Name") ); + m_viewPlugins->addColumn( i18n("Author") ); + m_viewPlugins->addColumn( i18n("Version") ); + m_viewPlugins->addColumn( i18n("Description") ); + m_viewPlugins->addColumn( i18n("License") ); + m_viewPlugins->setAlternateBackground( QColor() ); + m_viewPlugins->setAllColumnsShowFocus(true); + + connect( m_viewPlugins, SIGNAL(doubleClicked(QListViewItem*, const QPoint&, int)), this, SLOT(slotConfigureButtonClicked()) ); + connect( m_buttonConfigure, SIGNAL(clicked()), this, SLOT(slotConfigureButtonClicked()) ); + connect( m_viewPlugins, SIGNAL(selectionChanged()), this, SLOT(slotSelectionChanged()) ); +} + + +K3bPluginOptionTab::~K3bPluginOptionTab() +{ +} + + +void K3bPluginOptionTab::readSettings() +{ + m_viewPlugins->clear(); + QStringList groups = k3bcore->pluginManager()->groups(); + for( QStringList::const_iterator it = groups.begin(); + it != groups.end(); ++it ) { + const QString& group = *it; + + K3bListViewItem* groupViewItem = new K3bListViewItem( m_viewPlugins, + m_viewPlugins->lastChild(), + group ); + QFont f( font() ); + f.setBold(true); + groupViewItem->setFont( 0, f ); + groupViewItem->setBackgroundColor( 0, KGlobalSettings::alternateBackgroundColor() ); + groupViewItem->setBackgroundColor( 1, KGlobalSettings::alternateBackgroundColor() ); + groupViewItem->setBackgroundColor( 2, KGlobalSettings::alternateBackgroundColor() ); + groupViewItem->setBackgroundColor( 3, KGlobalSettings::alternateBackgroundColor() ); + groupViewItem->setBackgroundColor( 4, KGlobalSettings::alternateBackgroundColor() ); + groupViewItem->setSelectable( false ); + + QPtrList<K3bPlugin> fl = k3bcore->pluginManager()->plugins( group ); + for( QPtrListIterator<K3bPlugin> fit( fl ); fit.current(); ++fit ) + (void)new PluginViewItem( fit.current(), groupViewItem ); + + groupViewItem->setOpen(true); + } + + slotSelectionChanged(); +} + + +bool K3bPluginOptionTab::saveSettings() +{ + return true; +} + + +void K3bPluginOptionTab::slotConfigureButtonClicked() +{ + QListViewItem* item = m_viewPlugins->selectedItem(); + if( PluginViewItem* pi = dynamic_cast<PluginViewItem*>( item ) ) + k3bcore->pluginManager()->execPluginDialog( pi->plugin, this ); +} + + +void K3bPluginOptionTab::slotSelectionChanged() +{ + m_buttonConfigure->setEnabled( dynamic_cast<PluginViewItem*>( m_viewPlugins->selectedItem() ) != 0 ); +} + +#include "k3bpluginoptiontab.moc" diff --git a/src/option/k3bpluginoptiontab.h b/src/option/k3bpluginoptiontab.h new file mode 100644 index 0000000..1fb1821 --- /dev/null +++ b/src/option/k3bpluginoptiontab.h @@ -0,0 +1,43 @@ +/* + * + * $Id: k3bpluginoptiontab.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_PLUGIN_OPTION_TAB_H_ +#define _K3B_PLUGIN_OPTION_TAB_H_ + +#include "base_k3bpluginoptiontab.h" + + + +class K3bPluginOptionTab : public base_K3bPluginOptionTab +{ + Q_OBJECT + + public: + K3bPluginOptionTab( QWidget* parent = 0, const char* name = 0 ); + ~K3bPluginOptionTab(); + + public slots: + void readSettings(); + bool saveSettings(); + + private slots: + void slotConfigureButtonClicked(); + void slotSelectionChanged(); + + private: + class PluginViewItem; +}; + +#endif diff --git a/src/option/k3bthemeoptiontab.cpp b/src/option/k3bthemeoptiontab.cpp new file mode 100644 index 0000000..4fd3f61 --- /dev/null +++ b/src/option/k3bthemeoptiontab.cpp @@ -0,0 +1,234 @@ +/* + * + * $Id: k3bthemeoptiontab.cpp 642063 2007-03-13 09:40:13Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bthemeoptiontab.h" + +#include "k3bthememanager.h" + +#include <k3bapplication.h> +#include <klocale.h> +#include <kconfig.h> +#include <kmessagebox.h> +#include <kurlrequester.h> +#include <klistview.h> +#include <kio/global.h> +#include <kio/netaccess.h> +#include <kio/job.h> +#include <kstandarddirs.h> +#include <ktar.h> +#include <kurlrequesterdlg.h> +#include <kdeversion.h> + +#include <qlabel.h> +#include <qfile.h> +#include <qfileinfo.h> + + +class K3bThemeOptionTab::Private +{ +public: +}; + + +class ThemeViewItem : public KListViewItem +{ +public: + ThemeViewItem( K3bTheme* theme_, QListView* parent, QListViewItem* after ) + : KListViewItem( parent, after ), + theme(theme_) { + setText( 0, theme->name() ); + setText( 1, theme->author() ); + setText( 2, theme->version() ); + setText( 3, theme->comment() ); + } + + K3bTheme* theme; +}; + +K3bThemeOptionTab::K3bThemeOptionTab(QWidget *parent, const char *name ) + : base_K3bThemeOptionTab(parent,name) +{ + d = new Private(); + +#if KDE_IS_VERSION(3,4,0) + m_viewTheme->setShadeSortColumn( false ); +#endif + + connect( m_viewTheme, SIGNAL(selectionChanged()), + this, SLOT(selectionChanged()) ); + connect( kapp, SIGNAL(appearanceChanged()), + this, SLOT(selectionChanged()) ); + connect( m_buttonInstallTheme, SIGNAL(clicked()), + this, SLOT(slotInstallTheme()) ); + connect( m_buttonRemoveTheme, SIGNAL(clicked()), + this, SLOT(slotRemoveTheme()) ); +} + + +K3bThemeOptionTab::~K3bThemeOptionTab() +{ + delete d; +} + + +void K3bThemeOptionTab::readSettings() +{ + m_viewTheme->clear(); + + k3bappcore->themeManager()->loadThemes(); + + QValueList<K3bTheme*> themes = k3bappcore->themeManager()->themes(); + for( QValueList<K3bTheme*>::const_iterator it = themes.constBegin(); it != themes.constEnd(); ++it ) { + K3bTheme* theme = *it; + ThemeViewItem* item = new ThemeViewItem( theme, m_viewTheme, m_viewTheme->lastItem() ); + if( theme == k3bappcore->themeManager()->currentTheme() ) + m_viewTheme->setSelected( item, true ); + } +} + + +bool K3bThemeOptionTab::saveSettings() +{ + ThemeViewItem* item = (ThemeViewItem*)m_viewTheme->selectedItem(); + if( item ) + k3bappcore->themeManager()->setCurrentTheme( item->theme ); + + return true; +} + + +void K3bThemeOptionTab::selectionChanged() +{ + ThemeViewItem* item = (ThemeViewItem*)m_viewTheme->selectedItem(); + if( item ) { + m_centerPreviewLabel->setText( i18n("K3b - The CD/DVD Kreator") ); + m_centerPreviewLabel->setPaletteBackgroundColor( item->theme->backgroundColor() ); + m_centerPreviewLabel->setPaletteForegroundColor( item->theme->foregroundColor() ); + m_leftPreviewLabel->setPaletteBackgroundColor( item->theme->backgroundColor() ); + m_leftPreviewLabel->setPaletteForegroundColor( item->theme->foregroundColor() ); + m_rightPreviewLabel->setPaletteBackgroundColor( item->theme->backgroundColor() ); + m_rightPreviewLabel->setPaletteForegroundColor( item->theme->foregroundColor() ); + m_leftPreviewLabel->setPixmap( item->theme->pixmap( K3bTheme::PROJECT_LEFT ) ); + m_rightPreviewLabel->setPixmap( item->theme->pixmap( K3bTheme::PROJECT_RIGHT ) ); + + m_buttonRemoveTheme->setEnabled( item->theme->local() ); + } +} + + +void K3bThemeOptionTab::slotInstallTheme() +{ + KURL themeURL = KURLRequesterDlg::getURL( QString::null, this, + i18n("Drag or Type Theme URL") ); + + if( themeURL.url().isEmpty() ) + return; + + QString themeTmpFile; + // themeTmpFile contains the name of the downloaded file + + if( !KIO::NetAccess::download( themeURL, themeTmpFile, this ) ) { + QString sorryText; + if (themeURL.isLocalFile()) + sorryText = i18n("Unable to find the icon theme archive %1."); + else + sorryText = i18n("Unable to download the icon theme archive.\n" + "Please check that address %1 is correct."); + KMessageBox::sorry( this, sorryText.arg(themeURL.prettyURL()) ); + return; + } + + // check if the archive contains a dir with a k3b.theme file + QString themeName; + KTar archive( themeTmpFile ); + archive.open(IO_ReadOnly); + const KArchiveDirectory* themeDir = archive.directory(); + QStringList entries = themeDir->entries(); + bool validThemeArchive = false; + if( entries.count() > 0 ) { + if( themeDir->entry(entries.first())->isDirectory() ) { + const KArchiveDirectory* subDir = dynamic_cast<const KArchiveDirectory*>( themeDir->entry(entries.first()) ); + themeName = subDir->name(); + if( subDir && subDir->entry( "k3b.theme" ) ) { + validThemeArchive = true; + + // check for all nessessary pixmaps (this is a little evil hacking) + for( int i = 0; i <= K3bTheme::WELCOME_BG; ++i ) { + if( !subDir->entry( K3bTheme::filenameForPixmapType( (K3bTheme::PixmapType)i ) ) ) { + validThemeArchive = false; + break; + } + } + } + } + } + + if( !validThemeArchive ) { + KMessageBox::error( this, i18n("The file is not a valid K3b theme archive.") ); + } + else { + QString themeBasePath = locateLocal( "data", "k3b/pics/" ); + + // check if there already is a theme by that name + if( !QFile::exists( themeBasePath + '/' + themeName ) || + KMessageBox::warningYesNo( this, + i18n("A theme with the name '%1' already exists. Do you want to " + "overwrite it?"), + i18n("Theme exists"), + i18n("Overwrite"), + i18n("Cancel") ) == KMessageBox::Yes ) { + // install the theme + archive.directory()->copyTo( themeBasePath ); + } + } + + archive.close(); + KIO::NetAccess::removeTempFile(themeTmpFile); + + readSettings(); +} + + +void K3bThemeOptionTab::slotRemoveTheme() +{ + ThemeViewItem* item = (ThemeViewItem*)m_viewTheme->selectedItem(); + if( item ) { + QString question=i18n("<qt>Are you sure you want to remove the " + "<strong>%1</strong> icon theme?<br>" + "<br>" + "This will delete the files installed by this theme.</qt>"). + arg(item->text(0)); + + if( KMessageBox::warningContinueCancel( this, question, i18n("Delete") ) != KMessageBox::Continue ) + return; + + K3bTheme* theme = item->theme; + delete item; + QString path = theme->path(); + + // delete k3b.theme file to avoid it to get loaded + QFile::remove( path + "/k3b.theme" ); + + // reread the themes (this will also set the default theme in case we delete the + // selected one) + readSettings(); + + // delete the theme data itself + KIO::del( path, false, false ); + } +} + +#include "k3bthemeoptiontab.moc" diff --git a/src/option/k3bthemeoptiontab.h b/src/option/k3bthemeoptiontab.h new file mode 100644 index 0000000..bfb1d72 --- /dev/null +++ b/src/option/k3bthemeoptiontab.h @@ -0,0 +1,47 @@ +/* + * + * $Id: k3bthemeoptiontab.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3BTHEMEOPTIONTAB_H_ +#define _K3BTHEMEOPTIONTAB_H_ + +#include "base_k3bthemeoptiontab.h" + + +/** + *@author Sebastian Trueg + */ +class K3bThemeOptionTab : public base_K3bThemeOptionTab +{ + Q_OBJECT + + public: + K3bThemeOptionTab( QWidget* parent = 0, const char* name = 0 ); + ~K3bThemeOptionTab(); + + void readSettings(); + bool saveSettings(); + + private slots: + void selectionChanged(); + void slotInstallTheme(); + void slotRemoveTheme(); + + private: + class Private; + Private* d; +}; + +#endif diff --git a/src/pics/73lab/Makefile.am b/src/pics/73lab/Makefile.am new file mode 100644 index 0000000..50c69a4 --- /dev/null +++ b/src/pics/73lab/Makefile.am @@ -0,0 +1,23 @@ +picsdir = $(kde_datadir)/k3b/pics/73lab + +pics_DATA = splash.png \ + project_left.png \ + project_right.png \ + probing.png \ + media_audio.png \ + media_data.png \ + media_video.png \ + media_empty.png \ + media_left.png \ + media_mixed.png \ + media_none.png \ + progress_working.png \ + progress_fail.png \ + progress_success.png \ + progress_right.png \ + dialog_left.png \ + dialog_right.png \ + welcome_bg.png \ + k3b.theme + +EXTRA_DIST = $(pics_DATA) diff --git a/src/pics/73lab/dialog_left.png b/src/pics/73lab/dialog_left.png new file mode 100644 index 0000000..98b69c0 Binary files /dev/null and b/src/pics/73lab/dialog_left.png differ diff --git a/src/pics/73lab/dialog_right.png b/src/pics/73lab/dialog_right.png new file mode 100644 index 0000000..f7fef0e Binary files /dev/null and b/src/pics/73lab/dialog_right.png differ diff --git a/src/pics/73lab/k3b.theme b/src/pics/73lab/k3b.theme new file mode 100644 index 0000000..ad17706 --- /dev/null +++ b/src/pics/73lab/k3b.theme @@ -0,0 +1,5 @@ +Author=Ayo +Backgroundcolor=205,210,255 +Foregroundcolor=0,0,0 +Comment=Ayo's original K3b theme +Version=2.0 diff --git a/src/pics/73lab/media_audio.png b/src/pics/73lab/media_audio.png new file mode 100644 index 0000000..e12f591 Binary files /dev/null and b/src/pics/73lab/media_audio.png differ diff --git a/src/pics/73lab/media_data.png b/src/pics/73lab/media_data.png new file mode 100644 index 0000000..dd0cbce Binary files /dev/null and b/src/pics/73lab/media_data.png differ diff --git a/src/pics/73lab/media_empty.png b/src/pics/73lab/media_empty.png new file mode 100644 index 0000000..9e9f05b Binary files /dev/null and b/src/pics/73lab/media_empty.png differ diff --git a/src/pics/73lab/media_left.png b/src/pics/73lab/media_left.png new file mode 100644 index 0000000..98b69c0 Binary files /dev/null and b/src/pics/73lab/media_left.png differ diff --git a/src/pics/73lab/media_mixed.png b/src/pics/73lab/media_mixed.png new file mode 100644 index 0000000..a9404ab Binary files /dev/null and b/src/pics/73lab/media_mixed.png differ diff --git a/src/pics/73lab/media_none.png b/src/pics/73lab/media_none.png new file mode 100644 index 0000000..f7fef0e Binary files /dev/null and b/src/pics/73lab/media_none.png differ diff --git a/src/pics/73lab/media_video.png b/src/pics/73lab/media_video.png new file mode 100644 index 0000000..a5e6709 Binary files /dev/null and b/src/pics/73lab/media_video.png differ diff --git a/src/pics/73lab/probing.png b/src/pics/73lab/probing.png new file mode 100644 index 0000000..4a03574 Binary files /dev/null and b/src/pics/73lab/probing.png differ diff --git a/src/pics/73lab/progress_fail.png b/src/pics/73lab/progress_fail.png new file mode 100644 index 0000000..73b65d6 Binary files /dev/null and b/src/pics/73lab/progress_fail.png differ diff --git a/src/pics/73lab/progress_right.png b/src/pics/73lab/progress_right.png new file mode 100644 index 0000000..f4126f6 Binary files /dev/null and b/src/pics/73lab/progress_right.png differ diff --git a/src/pics/73lab/progress_success.png b/src/pics/73lab/progress_success.png new file mode 100644 index 0000000..abcdab6 Binary files /dev/null and b/src/pics/73lab/progress_success.png differ diff --git a/src/pics/73lab/progress_working.png b/src/pics/73lab/progress_working.png new file mode 100644 index 0000000..4a6f479 Binary files /dev/null and b/src/pics/73lab/progress_working.png differ diff --git a/src/pics/73lab/project_left.png b/src/pics/73lab/project_left.png new file mode 100644 index 0000000..9906ac6 Binary files /dev/null and b/src/pics/73lab/project_left.png differ diff --git a/src/pics/73lab/project_right.png b/src/pics/73lab/project_right.png new file mode 100644 index 0000000..f4126f6 Binary files /dev/null and b/src/pics/73lab/project_right.png differ diff --git a/src/pics/73lab/splash.png b/src/pics/73lab/splash.png new file mode 100644 index 0000000..f36348c Binary files /dev/null and b/src/pics/73lab/splash.png differ diff --git a/src/pics/73lab/welcome_bg.png b/src/pics/73lab/welcome_bg.png new file mode 100644 index 0000000..e4f8879 Binary files /dev/null and b/src/pics/73lab/welcome_bg.png differ diff --git a/src/pics/Makefile.am b/src/pics/Makefile.am new file mode 100644 index 0000000..5c1832f --- /dev/null +++ b/src/pics/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = 73lab crystal quant RobsTheme diff --git a/src/pics/RobsTheme/Makefile.am b/src/pics/RobsTheme/Makefile.am new file mode 100644 index 0000000..01890be --- /dev/null +++ b/src/pics/RobsTheme/Makefile.am @@ -0,0 +1,23 @@ + +picsdir = $(kde_datadir)/k3b/pics/RobsTheme + +pics_DATA = splash.png \ + project_left.png \ + project_right.png \ + media_audio.png \ + media_data.png \ + media_video.png \ + media_empty.png \ + media_left.png \ + media_mixed.png \ + media_none.png \ + progress_working.png \ + progress_fail.png \ + progress_success.png \ + progress_right.png \ + dialog_left.png \ + dialog_right.png \ + welcome_bg.png \ + k3b.theme + +EXTRA_DIST = $(pics_DATA) diff --git a/src/pics/RobsTheme/dialog_left.png b/src/pics/RobsTheme/dialog_left.png new file mode 100644 index 0000000..ee0f896 Binary files /dev/null and b/src/pics/RobsTheme/dialog_left.png differ diff --git a/src/pics/RobsTheme/dialog_right.png b/src/pics/RobsTheme/dialog_right.png new file mode 100644 index 0000000..b1013c1 Binary files /dev/null and b/src/pics/RobsTheme/dialog_right.png differ diff --git a/src/pics/RobsTheme/k3b.theme b/src/pics/RobsTheme/k3b.theme new file mode 100644 index 0000000..64b1494 --- /dev/null +++ b/src/pics/RobsTheme/k3b.theme @@ -0,0 +1,5 @@ +Author=Robert Wadley +Backgroundcolor=Window +Foregroundcolor=WindowText +Comment=A semitransparent theme that uses your system colors. +Version=1.0 diff --git a/src/pics/RobsTheme/media_audio.png b/src/pics/RobsTheme/media_audio.png new file mode 100644 index 0000000..e4aa6e6 Binary files /dev/null and b/src/pics/RobsTheme/media_audio.png differ diff --git a/src/pics/RobsTheme/media_data.png b/src/pics/RobsTheme/media_data.png new file mode 100644 index 0000000..0810113 Binary files /dev/null and b/src/pics/RobsTheme/media_data.png differ diff --git a/src/pics/RobsTheme/media_empty.png b/src/pics/RobsTheme/media_empty.png new file mode 100644 index 0000000..776eb5e Binary files /dev/null and b/src/pics/RobsTheme/media_empty.png differ diff --git a/src/pics/RobsTheme/media_left.png b/src/pics/RobsTheme/media_left.png new file mode 100644 index 0000000..ee0f896 Binary files /dev/null and b/src/pics/RobsTheme/media_left.png differ diff --git a/src/pics/RobsTheme/media_mixed.png b/src/pics/RobsTheme/media_mixed.png new file mode 100644 index 0000000..c17b91b Binary files /dev/null and b/src/pics/RobsTheme/media_mixed.png differ diff --git a/src/pics/RobsTheme/media_none.png b/src/pics/RobsTheme/media_none.png new file mode 100644 index 0000000..4035080 Binary files /dev/null and b/src/pics/RobsTheme/media_none.png differ diff --git a/src/pics/RobsTheme/media_video.png b/src/pics/RobsTheme/media_video.png new file mode 100644 index 0000000..4ffb8d9 Binary files /dev/null and b/src/pics/RobsTheme/media_video.png differ diff --git a/src/pics/RobsTheme/progress_fail.png b/src/pics/RobsTheme/progress_fail.png new file mode 100644 index 0000000..761da82 Binary files /dev/null and b/src/pics/RobsTheme/progress_fail.png differ diff --git a/src/pics/RobsTheme/progress_right.png b/src/pics/RobsTheme/progress_right.png new file mode 100644 index 0000000..973e81a Binary files /dev/null and b/src/pics/RobsTheme/progress_right.png differ diff --git a/src/pics/RobsTheme/progress_success.png b/src/pics/RobsTheme/progress_success.png new file mode 100644 index 0000000..b61daef Binary files /dev/null and b/src/pics/RobsTheme/progress_success.png differ diff --git a/src/pics/RobsTheme/progress_working.png b/src/pics/RobsTheme/progress_working.png new file mode 100644 index 0000000..dd59dce Binary files /dev/null and b/src/pics/RobsTheme/progress_working.png differ diff --git a/src/pics/RobsTheme/project_left.png b/src/pics/RobsTheme/project_left.png new file mode 100644 index 0000000..e114f5e Binary files /dev/null and b/src/pics/RobsTheme/project_left.png differ diff --git a/src/pics/RobsTheme/project_right.png b/src/pics/RobsTheme/project_right.png new file mode 100644 index 0000000..c061b4f Binary files /dev/null and b/src/pics/RobsTheme/project_right.png differ diff --git a/src/pics/RobsTheme/splash.png b/src/pics/RobsTheme/splash.png new file mode 100644 index 0000000..752b51b Binary files /dev/null and b/src/pics/RobsTheme/splash.png differ diff --git a/src/pics/RobsTheme/welcome_bg.png b/src/pics/RobsTheme/welcome_bg.png new file mode 100644 index 0000000..b54c4cd Binary files /dev/null and b/src/pics/RobsTheme/welcome_bg.png differ diff --git a/src/pics/crystal/Makefile.am b/src/pics/crystal/Makefile.am new file mode 100644 index 0000000..a7d58eb --- /dev/null +++ b/src/pics/crystal/Makefile.am @@ -0,0 +1,24 @@ + +picsdir = $(kde_datadir)/k3b/pics/crystal + +pics_DATA = splash.png \ + project_left.png \ + project_right.png \ + probing.png \ + media_audio.png \ + media_data.png \ + media_video.png \ + media_empty.png \ + media_left.png \ + media_mixed.png \ + media_none.png \ + progress_working.png \ + progress_fail.png \ + progress_success.png \ + progress_right.png \ + dialog_left.png \ + dialog_right.png \ + welcome_bg.png \ + k3b.theme + +EXTRA_DIST = $(pics_DATA) diff --git a/src/pics/crystal/dialog_left.png b/src/pics/crystal/dialog_left.png new file mode 100644 index 0000000..f2e1a08 Binary files /dev/null and b/src/pics/crystal/dialog_left.png differ diff --git a/src/pics/crystal/dialog_right.png b/src/pics/crystal/dialog_right.png new file mode 100644 index 0000000..2efac87 Binary files /dev/null and b/src/pics/crystal/dialog_right.png differ diff --git a/src/pics/crystal/k3b.theme b/src/pics/crystal/k3b.theme new file mode 100644 index 0000000..1bf94fb --- /dev/null +++ b/src/pics/crystal/k3b.theme @@ -0,0 +1,5 @@ +Author=Everaldo +Backgroundcolor=139,153,222 +Foregroundcolor=255,255,255 +Comment=The cool crystal theme +Version=2.0 diff --git a/src/pics/crystal/media_audio.png b/src/pics/crystal/media_audio.png new file mode 100644 index 0000000..6ce1348 Binary files /dev/null and b/src/pics/crystal/media_audio.png differ diff --git a/src/pics/crystal/media_data.png b/src/pics/crystal/media_data.png new file mode 100644 index 0000000..877f7db Binary files /dev/null and b/src/pics/crystal/media_data.png differ diff --git a/src/pics/crystal/media_empty.png b/src/pics/crystal/media_empty.png new file mode 100644 index 0000000..7664557 Binary files /dev/null and b/src/pics/crystal/media_empty.png differ diff --git a/src/pics/crystal/media_left.png b/src/pics/crystal/media_left.png new file mode 100644 index 0000000..f2e1a08 Binary files /dev/null and b/src/pics/crystal/media_left.png differ diff --git a/src/pics/crystal/media_mixed.png b/src/pics/crystal/media_mixed.png new file mode 100644 index 0000000..6bc8140 Binary files /dev/null and b/src/pics/crystal/media_mixed.png differ diff --git a/src/pics/crystal/media_none.png b/src/pics/crystal/media_none.png new file mode 100644 index 0000000..2efac87 Binary files /dev/null and b/src/pics/crystal/media_none.png differ diff --git a/src/pics/crystal/media_video.png b/src/pics/crystal/media_video.png new file mode 100644 index 0000000..ca46c9f Binary files /dev/null and b/src/pics/crystal/media_video.png differ diff --git a/src/pics/crystal/probing.png b/src/pics/crystal/probing.png new file mode 100644 index 0000000..fb23fce Binary files /dev/null and b/src/pics/crystal/probing.png differ diff --git a/src/pics/crystal/progress_fail.png b/src/pics/crystal/progress_fail.png new file mode 100644 index 0000000..726e381 Binary files /dev/null and b/src/pics/crystal/progress_fail.png differ diff --git a/src/pics/crystal/progress_right.png b/src/pics/crystal/progress_right.png new file mode 100644 index 0000000..dfbd28a Binary files /dev/null and b/src/pics/crystal/progress_right.png differ diff --git a/src/pics/crystal/progress_success.png b/src/pics/crystal/progress_success.png new file mode 100644 index 0000000..f6d174f Binary files /dev/null and b/src/pics/crystal/progress_success.png differ diff --git a/src/pics/crystal/progress_working.png b/src/pics/crystal/progress_working.png new file mode 100644 index 0000000..9990d37 Binary files /dev/null and b/src/pics/crystal/progress_working.png differ diff --git a/src/pics/crystal/project_left.png b/src/pics/crystal/project_left.png new file mode 100644 index 0000000..e3b3e3e Binary files /dev/null and b/src/pics/crystal/project_left.png differ diff --git a/src/pics/crystal/project_right.png b/src/pics/crystal/project_right.png new file mode 100644 index 0000000..dfbd28a Binary files /dev/null and b/src/pics/crystal/project_right.png differ diff --git a/src/pics/crystal/splash.png b/src/pics/crystal/splash.png new file mode 100644 index 0000000..699424f Binary files /dev/null and b/src/pics/crystal/splash.png differ diff --git a/src/pics/crystal/welcome_bg.png b/src/pics/crystal/welcome_bg.png new file mode 100644 index 0000000..4224f61 Binary files /dev/null and b/src/pics/crystal/welcome_bg.png differ diff --git a/src/pics/quant/Makefile.am b/src/pics/quant/Makefile.am new file mode 100644 index 0000000..1b5ca07 --- /dev/null +++ b/src/pics/quant/Makefile.am @@ -0,0 +1,23 @@ + +picsdir = $(kde_datadir)/k3b/pics/quant + +pics_DATA = splash.png \ + project_left.png \ + project_right.png \ + media_audio.png \ + media_data.png \ + media_video.png \ + media_empty.png \ + media_left.png \ + media_mixed.png \ + media_none.png \ + progress_working.png \ + progress_fail.png \ + progress_success.png \ + progress_right.png \ + dialog_left.png \ + dialog_right.png \ + welcome_bg.png \ + k3b.theme + +EXTRA_DIST = $(pics_DATA) diff --git a/src/pics/quant/dialog_left.png b/src/pics/quant/dialog_left.png new file mode 100644 index 0000000..ea5173e Binary files /dev/null and b/src/pics/quant/dialog_left.png differ diff --git a/src/pics/quant/dialog_right.png b/src/pics/quant/dialog_right.png new file mode 100644 index 0000000..cbf12a8 Binary files /dev/null and b/src/pics/quant/dialog_right.png differ diff --git a/src/pics/quant/k3b.theme b/src/pics/quant/k3b.theme new file mode 100644 index 0000000..c5c173e --- /dev/null +++ b/src/pics/quant/k3b.theme @@ -0,0 +1,6 @@ +Author=Dmitry Novikov (quant@trktvs.ru) +Backgroundcolor=Window +Foregroundcolor=WindowText +Comment=New official theme for K3b. Enjoy! +Version=0.1 +BackgroundMode=Scaled diff --git a/src/pics/quant/media_audio.png b/src/pics/quant/media_audio.png new file mode 100644 index 0000000..c2a068a Binary files /dev/null and b/src/pics/quant/media_audio.png differ diff --git a/src/pics/quant/media_data.png b/src/pics/quant/media_data.png new file mode 100644 index 0000000..4e4876b Binary files /dev/null and b/src/pics/quant/media_data.png differ diff --git a/src/pics/quant/media_empty.png b/src/pics/quant/media_empty.png new file mode 100644 index 0000000..d4c2e70 Binary files /dev/null and b/src/pics/quant/media_empty.png differ diff --git a/src/pics/quant/media_left.png b/src/pics/quant/media_left.png new file mode 100644 index 0000000..c0211f8 Binary files /dev/null and b/src/pics/quant/media_left.png differ diff --git a/src/pics/quant/media_mixed.png b/src/pics/quant/media_mixed.png new file mode 100644 index 0000000..1f04083 Binary files /dev/null and b/src/pics/quant/media_mixed.png differ diff --git a/src/pics/quant/media_none.png b/src/pics/quant/media_none.png new file mode 100644 index 0000000..8f47198 Binary files /dev/null and b/src/pics/quant/media_none.png differ diff --git a/src/pics/quant/media_video.png b/src/pics/quant/media_video.png new file mode 100644 index 0000000..93e8a20 Binary files /dev/null and b/src/pics/quant/media_video.png differ diff --git a/src/pics/quant/progress_fail.png b/src/pics/quant/progress_fail.png new file mode 100644 index 0000000..b8c1276 Binary files /dev/null and b/src/pics/quant/progress_fail.png differ diff --git a/src/pics/quant/progress_right.png b/src/pics/quant/progress_right.png new file mode 100644 index 0000000..2dfa665 Binary files /dev/null and b/src/pics/quant/progress_right.png differ diff --git a/src/pics/quant/progress_success.png b/src/pics/quant/progress_success.png new file mode 100644 index 0000000..36145f1 Binary files /dev/null and b/src/pics/quant/progress_success.png differ diff --git a/src/pics/quant/progress_working.png b/src/pics/quant/progress_working.png new file mode 100644 index 0000000..6215897 Binary files /dev/null and b/src/pics/quant/progress_working.png differ diff --git a/src/pics/quant/project_left.png b/src/pics/quant/project_left.png new file mode 100644 index 0000000..bcc7ff2 Binary files /dev/null and b/src/pics/quant/project_left.png differ diff --git a/src/pics/quant/project_right.png b/src/pics/quant/project_right.png new file mode 100644 index 0000000..0db8e25 Binary files /dev/null and b/src/pics/quant/project_right.png differ diff --git a/src/pics/quant/splash.png b/src/pics/quant/splash.png new file mode 100644 index 0000000..25a7c4c Binary files /dev/null and b/src/pics/quant/splash.png differ diff --git a/src/pics/quant/welcome_bg.png b/src/pics/quant/welcome_bg.png new file mode 100644 index 0000000..a53e597 Binary files /dev/null and b/src/pics/quant/welcome_bg.png differ diff --git a/src/projects/Makefile.am b/src/projects/Makefile.am new file mode 100644 index 0000000..751eb71 --- /dev/null +++ b/src/projects/Makefile.am @@ -0,0 +1,86 @@ +AM_CPPFLAGS= -I$(srcdir)/../../libk3b/core \ + -I$(srcdir)/../../libk3bdevice \ + -I$(srcdir)/../../libk3b/projects \ + -I$(srcdir)/../../libk3b/projects/audiocd \ + -I$(srcdir)/../../libk3b/projects/datacd \ + -I$(srcdir)/../../libk3b/projects/mixedcd \ + -I$(srcdir)/../../libk3b/projects/movixcd \ + -I$(srcdir)/../../libk3b/projects/datadvd \ + -I$(srcdir)/../../libk3b/projects/videocd \ + -I$(srcdir)/../../libk3b/projects/videodvd \ + -I$(srcdir)/../../libk3b/projects/movixdvd \ + -I$(srcdir)/../../libk3b/cddb \ + -I$(srcdir)/../../libk3b/tools \ + -I$(srcdir)/../../libk3b/plugin \ + -I$(srcdir)/../rip \ + -I$(srcdir)/.. \ + $(all_includes) + +METASOURCES = AUTO + +SUBDIRS = kostore + +noinst_LTLIBRARIES = libprojects.la + +libprojects_la_LIBADD = ../rip/librip.la ./kostore/libkostore.la + +libprojects_la_SOURCES = k3baudioburndialog.cpp \ + k3baudiocdtextwidget.cpp \ + k3baudiodatasourceviewitem.cpp \ + k3baudioeditorwidget.cpp \ + k3baudiotrackdialog.cpp \ + k3baudiotrackwidget.cpp \ + k3baudiotrackplayer.cpp \ + k3baudiotracksplitdialog.cpp \ + k3baudiotrackview.cpp \ + k3baudiotrackviewitem.cpp \ + k3baudioview.cpp \ + base_k3baudiocdtextwidget.ui \ + base_k3baudiocdtextallfieldswidget.ui \ + base_k3baudiotrackwidget.ui \ + k3bmixedburndialog.cpp \ + k3bmixeddirtreeview.cpp \ + k3bmixedview.cpp \ + base_k3badvanceddataimagesettings.ui \ + base_k3bbootimageview.ui \ + base_k3bdataimagesettings.ui \ + base_k3bdatavolumedescwidget.ui \ + k3bdataadvancedimagesettingswidget.cpp \ + k3bdatadirtreeview.cpp \ + k3bdatafileview.cpp \ + k3bdataimagesettingswidget.cpp \ + k3bdatapropertiesdialog.cpp \ + k3bdataview.cpp \ + k3bdataviewitem.cpp \ + k3bdatavolumedescwidget.cpp \ + k3bdataburndialog.cpp \ + k3bbootimagedialog.cpp \ + k3bbootimageview.cpp \ + k3bdvdburndialog.cpp \ + k3bdvdview.cpp \ + base_k3bmovixoptionswidget.ui \ + k3bmovixburndialog.cpp \ + k3bmovixlistview.cpp \ + k3bmovixoptionswidget.cpp \ + k3bmovixview.cpp \ + k3bmovixdvdburndialog.cpp \ + k3bmovixdvdview.cpp \ + k3bvideodvdburndialog.cpp \ + k3bvideodvdview.cpp \ + k3bvcdburndialog.cpp \ + k3bvcdlistview.cpp \ + k3bvcdlistviewitem.cpp \ + k3bvcdtrackdialog.cpp \ + k3bvcdview.cpp \ + k3bfillstatusdisplay.cpp \ + k3bview.cpp \ + k3bprojectburndialog.cpp \ + k3bprojectplugindialog.cpp \ + k3baudiotracktrmlookupdialog.cpp \ + k3bdatamultisessioncombobox.cpp \ + k3bmusicbrainzjob.cpp \ + k3bdataurladdingdialog.cpp \ + k3bdatasessionimportdialog.cpp \ + k3baudiodatasourceeditwidget.cpp \ + k3baudiotrackaddingdialog.cpp \ + k3bencodingconverter.cpp \ No newline at end of file diff --git a/src/projects/base_k3badvanceddataimagesettings.ui b/src/projects/base_k3badvanceddataimagesettings.ui new file mode 100644 index 0000000..593b404 --- /dev/null +++ b/src/projects/base_k3badvanceddataimagesettings.ui @@ -0,0 +1,193 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>base_K3bAdvancedDataImageSettings</class> +<author>Sebastian Trueg</author> +<widget class="QWidget"> + <property name="name"> + <cstring>base_K3bDataCustomFilesystemsWidget</cstring> + </property> + <property name="caption"> + <string>Custom Data Filesystems</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QGroupBox" row="1" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>groupIsoSettings</cstring> + </property> + <property name="title"> + <string>File System Settings</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KListView"> + <column> + <property name="text"> + <string>ISO9660 Filesystem</string> + </property> + <property name="clickable"> + <bool>false</bool> + </property> + <property name="resizable"> + <bool>false</bool> + </property> + </column> + <property name="name"> + <cstring>m_viewIsoSettings</cstring> + </property> + <property name="fullWidth"> + <bool>true</bool> + </property> + </widget> + </vbox> + </widget> + <widget class="QGroupBox" row="0" column="0"> + <property name="name"> + <cstring>groupBox3</cstring> + </property> + <property name="title"> + <string>File Systems</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_checkRockRidge</cstring> + </property> + <property name="text"> + <string>&Generate Rock Ridge extensions</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + <property name="toolTip" stdset="0"> + <string>Add Rock Ridge extensions to the file system</string> + </property> + <property name="whatsThis" stdset="0"> + <string><p>If this option is checked, K3b will generate the System Use Sharing Protocol records (SUSP) specified by the Rock Ridge Interchange Protocol (IEEE-P1282). +<p>Rock Ridge extends the ISO-9660 filesystem by features equal to the UNIX filesystems (permissions, symbolic links, very long filenames, ...). It uses ISO-8859 or UTF-16 based characters and allows 255 octets. +<p>Rock Ridge extensions are located at the end of each ISO-9660 directory record. This makes the Rock Ridge tree closely coupled to the ISO-9660 tree. +<p><b>It is highly recommended to use Rock Ridge extensions on every data CD or DVD.</b></string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_checkJoliet</cstring> + </property> + <property name="text"> + <string>Generate &Joliet extensions</string> + </property> + <property name="toolTip" stdset="0"> + <string>Add Joliet extensions to the file system</string> + </property> + <property name="whatsThis" stdset="0"> + <string><p>If this option is checked, K3b will add additional Joliet extensions to the ISO-9660 file system. +<p>Joliet is not an accepted independent international standard like ISO-9660 or Rock Ridge. It is mainly used on Windows systems. +<p>Joliet does not allow all characters, so the Joliet filenames are not identical to the filenames on disk (as compared to Rock Ridge). Joliet has a filename length limitation of 64 chars (independent from the character coding and type e.g. European vs. Japanese). This is annoying, as modern file systems all allow 255 characters per path name component. +<p>Joliet uses UTF-16 coding. +<p><b>Caution:</b> With the exception of Linux and FreeBSD, there is no POSIX-like OS that supports Joliet. So <b>never create Joliet-only CDs or DVDs</b> for that reason.</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_checkUdf</cstring> + </property> + <property name="text"> + <string>Generate &UDF structures</string> + </property> + <property name="toolTip" stdset="0"> + <string>Add UDF structures to the file system</string> + </property> + <property name="whatsThis" stdset="0"> + <string><p>If this option is checked K3b will create UDF filesystem structures in addition to the ISO9660 filesystem. +<p>The UDF (<em><b>U</b>niversal <b>D</b>isk <b>F</b>ormat</em>) is mainly used for DVDs.</string> + </property> + </widget> + </vbox> + </widget> + <widget class="QGroupBox" row="0" column="1"> + <property name="name"> + <cstring>groupBox5</cstring> + </property> + <property name="title"> + <string>Other Settings</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout1</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_checkForceInputCharset</cstring> + </property> + <property name="text"> + <string>F&orce input charset:</string> + </property> + </widget> + <widget class="KComboBox"> + <property name="name"> + <cstring>m_comboInputCharset</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="editable"> + <bool>true</bool> + </property> + </widget> + </hbox> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_checkPreservePermissions</cstring> + </property> + <property name="text"> + <string>Preserve file permissions (bac&kup)</string> + </property> + <property name="whatsThis" stdset="0"> + <string><p>If this option is checked, all files in the resulting file system will have exactly the same permissions as the source files. (Otherwise, all files will have equal permissions and be owned by root). +<p>This is mainly useful for backups.<p><b>Caution:</b> The permissions may not make much sense on other file systems; for example, if a user that owns a file on the CD or DVD does not exist.</string> + </property> + </widget> + </vbox> + </widget> + </grid> +</widget> +<connections> + <connection> + <sender>m_checkForceInputCharset</sender> + <signal>toggled(bool)</signal> + <receiver>m_comboInputCharset</receiver> + <slot>setEnabled(bool)</slot> + </connection> +</connections> +<tabstops> + <tabstop>m_checkRockRidge</tabstop> + <tabstop>m_checkJoliet</tabstop> +</tabstops> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>klistview.h</includehint> + <includehint>kcombobox.h</includehint> + <includehint>klineedit.h</includehint> +</includehints> +</UI> diff --git a/src/projects/base_k3baudiocdtextallfieldswidget.ui b/src/projects/base_k3baudiocdtextallfieldswidget.ui new file mode 100644 index 0000000..e178d1f --- /dev/null +++ b/src/projects/base_k3baudiocdtextallfieldswidget.ui @@ -0,0 +1,275 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>base_K3bAudioCdTextAllFieldsWidget</class> +<author>Sebastian Trueg</author> +<widget class="QWidget"> + <property name="name"> + <cstring>base_K3bAudioCdTextAllFieldsWidget</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QLabel" row="8" column="0"> + <property name="name"> + <cstring>textLabel8</cstring> + </property> + <property name="text"> + <string>Messa&ge:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>m_editMessage</cstring> + </property> + </widget> + <widget class="QLayoutWidget" row="4" column="1"> + <property name="name"> + <cstring>layout2</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KLineEdit"> + <property name="name"> + <cstring>m_editSongwriter</cstring> + </property> + </widget> + <widget class="QToolButton"> + <property name="name"> + <cstring>m_buttonCopySongwriter</cstring> + </property> + <property name="text"> + <string>...</string> + </property> + <property name="toolTip" stdset="0"> + <string>Copy to all tracks</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QLabel" row="6" column="0"> + <property name="name"> + <cstring>textLabel6</cstring> + </property> + <property name="text"> + <string>&UPC EAN:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>m_editUpc_ean</cstring> + </property> + </widget> + <widget class="QLayoutWidget" row="5" column="1"> + <property name="name"> + <cstring>layout1</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KLineEdit"> + <property name="name"> + <cstring>m_editComposer</cstring> + </property> + </widget> + <widget class="QToolButton"> + <property name="name"> + <cstring>m_buttonCopyComposer</cstring> + </property> + <property name="text"> + <string>...</string> + </property> + <property name="toolTip" stdset="0"> + <string>Copy to all tracks</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QLabel" row="4" column="0"> + <property name="name"> + <cstring>textLabel4</cstring> + </property> + <property name="text"> + <string>So&ngwriter:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>m_editSongwriter</cstring> + </property> + </widget> + <widget class="QLabel" row="5" column="0"> + <property name="name"> + <cstring>textLabel5</cstring> + </property> + <property name="text"> + <string>&Composer:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>m_editComposer</cstring> + </property> + </widget> + <widget class="QLabel" row="7" column="0"> + <property name="name"> + <cstring>textLabel7</cstring> + </property> + <property name="text"> + <string>&Disk id:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>m_editDisc_id</cstring> + </property> + </widget> + <widget class="QLayoutWidget" row="3" column="1"> + <property name="name"> + <cstring>layout3</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KLineEdit"> + <property name="name"> + <cstring>m_editArranger</cstring> + </property> + </widget> + <widget class="QToolButton"> + <property name="name"> + <cstring>m_buttonCopyArranger</cstring> + </property> + <property name="text"> + <string>...</string> + </property> + <property name="toolTip" stdset="0"> + <string>Copy to all tracks</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QLabel" row="3" column="0"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>&Arranger:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>m_editArranger</cstring> + </property> + </widget> + <widget class="KLineEdit" row="6" column="1"> + <property name="name"> + <cstring>m_editUpc_ean</cstring> + </property> + </widget> + <widget class="KLineEdit" row="7" column="1"> + <property name="name"> + <cstring>m_editDisc_id</cstring> + </property> + </widget> + <widget class="KLineEdit" row="8" column="1"> + <property name="name"> + <cstring>m_editMessage</cstring> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>&Performer:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>m_editPerformer</cstring> + </property> + </widget> + <widget class="QLayoutWidget" row="0" column="1"> + <property name="name"> + <cstring>layout5</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KLineEdit"> + <property name="name"> + <cstring>m_editTitle</cstring> + </property> + </widget> + <widget class="QToolButton"> + <property name="name"> + <cstring>m_buttonCopyTitle</cstring> + </property> + <property name="text"> + <string>...</string> + </property> + <property name="toolTip" stdset="0"> + <string>Copy to all tracks</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>&Title:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>m_editTitle</cstring> + </property> + </widget> + <widget class="Line" row="2" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>line4</cstring> + </property> + <property name="frameShape"> + <enum>HLine</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + </widget> + <widget class="QLayoutWidget" row="1" column="1"> + <property name="name"> + <cstring>layout4</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KLineEdit"> + <property name="name"> + <cstring>m_editPerformer</cstring> + </property> + </widget> + <widget class="QToolButton"> + <property name="name"> + <cstring>m_buttonCopyPerformer</cstring> + </property> + <property name="text"> + <string>...</string> + </property> + <property name="toolTip" stdset="0"> + <string>Copy to all tracks</string> + </property> + </widget> + </hbox> + </widget> + </grid> +</widget> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>klineedit.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>klineedit.h</includehint> +</includehints> +</UI> diff --git a/src/projects/base_k3baudiocdtextwidget.ui b/src/projects/base_k3baudiocdtextwidget.ui new file mode 100644 index 0000000..50daff2 --- /dev/null +++ b/src/projects/base_k3baudiocdtextwidget.ui @@ -0,0 +1,222 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>base_K3bAudioCdTextWidget</class> +<comment>Widget to edit the global CD-Text in a K3b audio project.</comment> +<author>Sebastian Trueg</author> +<widget class="QWidget"> + <property name="name"> + <cstring>K3bAudioCDTextWidget</cstring> + </property> + <property name="caption"> + <string>K3bAudioCDTextWidget</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>m_groupCdText</cstring> + </property> + <property name="title"> + <string>Write CD-Text</string> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="checked"> + <bool>false</bool> + </property> + <property name="toolTip" stdset="0"> + <string></string> + </property> + <property name="whatsThis" stdset="0"> + <string><p><b>CD-Text</b> +<p>If this option is checked K3b uses some otherwise unused space on the Audio CD to store additional information, like the artist or the CD title. +<p>CD-Text is an extension to the audio CD standard introduced by Sony. +<p>CD-Text will only be usable on CD players that support this extension (mostly car CD players) and software like K3b, of course. +<p>Since a CD-Text-enhanced Audio CD will work in any Hifi CD or DVD player even if the player does not support CD-Text explicitly, enabling it is never a bad idea (just remember to fill in the CD-Text information).</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QFrame"> + <property name="name"> + <cstring>frame3</cstring> + </property> + <property name="frameShape"> + <enum>NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>Raised</enum> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Perf&ormer:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>m_editPerformer</cstring> + </property> + </widget> + <widget class="QLayoutWidget" row="2" column="1"> + <property name="name"> + <cstring>layout4</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KLineEdit"> + <property name="name"> + <cstring>m_editPerformer</cstring> + </property> + </widget> + <widget class="QToolButton"> + <property name="name"> + <cstring>m_buttonCopyPerformer</cstring> + </property> + <property name="text"> + <string>...</string> + </property> + <property name="toolTip" stdset="0"> + <string>Copy to all tracks</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QLayoutWidget" row="1" column="1"> + <property name="name"> + <cstring>layout5</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KLineEdit"> + <property name="name"> + <cstring>m_editTitle</cstring> + </property> + </widget> + <widget class="QToolButton"> + <property name="name"> + <cstring>m_buttonCopyTitle</cstring> + </property> + <property name="text"> + <string>...</string> + </property> + <property name="toolTip" stdset="0"> + <string>Copy to all tracks</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>&Title:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>m_editTitle</cstring> + </property> + </widget> + </grid> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout15</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer3</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_buttonMoreFields</cstring> + </property> + <property name="text"> + <string>More Fiel&ds...</string> + </property> + </widget> + </hbox> + </widget> + <spacer> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>21</width> + <height>0</height> + </size> + </property> + </spacer> + </vbox> + </widget> + </vbox> +</widget> +<connections> + <connection> + <sender>m_buttonCopyTitle</sender> + <signal>clicked()</signal> + <receiver>K3bAudioCDTextWidget</receiver> + <slot>slotCopyTitle()</slot> + </connection> + <connection> + <sender>m_buttonCopyPerformer</sender> + <signal>clicked()</signal> + <receiver>K3bAudioCDTextWidget</receiver> + <slot>slotCopyPerformer()</slot> + </connection> +</connections> +<tabstops> + <tabstop>m_editTitle</tabstop> + <tabstop>m_editPerformer</tabstop> +</tabstops> +<slots> + <slot access="protected" specifier="pure virtual">slotCopyTitle()</slot> + <slot access="protected" specifier="pure virtual">slotCopyPerformer()</slot> + <slot access="protected" specifier="pure virtual">slotCopyArranger()</slot> + <slot access="protected" specifier="pure virtual">slotCopyComposer()</slot> + <slot access="protected" specifier="pure virtual">slotCopySongwriter()</slot> +</slots> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>klineedit.h</includehint> + <includehint>klineedit.h</includehint> +</includehints> +</UI> diff --git a/src/projects/base_k3baudiotrackwidget.ui b/src/projects/base_k3baudiotrackwidget.ui new file mode 100644 index 0000000..813b042 --- /dev/null +++ b/src/projects/base_k3baudiotrackwidget.ui @@ -0,0 +1,336 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>base_K3bAudioTrackWidget</class> +<author>Sebastian Trueg</author> +<widget class="QWidget"> + <property name="name"> + <cstring>K3bAudioTrackWidget</cstring> + </property> + <property name="caption"> + <string>K3bAudioTrackWidget</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QTabWidget"> + <property name="name"> + <cstring>m_mainTab</cstring> + </property> + <widget class="QWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string>C&D-Text</string> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout9</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KLineEdit" row="4" column="1"> + <property name="name"> + <cstring>m_editSongwriter</cstring> + </property> + </widget> + <widget class="QLabel" row="4" column="0"> + <property name="name"> + <cstring>textLabel4</cstring> + </property> + <property name="text"> + <string>So&ngwriter:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>m_editSongwriter</cstring> + </property> + </widget> + <widget class="KLineEdit" row="3" column="1"> + <property name="name"> + <cstring>m_editArranger</cstring> + </property> + </widget> + <widget class="KLineEdit" row="3" column="3"> + <property name="name"> + <cstring>m_editComposer</cstring> + </property> + </widget> + <widget class="KLineEdit" row="5" column="1" rowspan="1" colspan="3"> + <property name="name"> + <cstring>m_editMessage</cstring> + </property> + </widget> + <widget class="Line" row="1" column="0" rowspan="1" colspan="4"> + <property name="name"> + <cstring>line2</cstring> + </property> + <property name="frameShape"> + <enum>HLine</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + </widget> + <widget class="QLabel" row="2" column="0" rowspan="2" colspan="1"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>&Arranger:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>m_editArranger</cstring> + </property> + </widget> + <widget class="QLabel" row="2" column="2" rowspan="2" colspan="1"> + <property name="name"> + <cstring>textLabel5</cstring> + </property> + <property name="text"> + <string>&Composer:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>m_editComposer</cstring> + </property> + </widget> + <widget class="QLabel" row="5" column="0"> + <property name="name"> + <cstring>textLabel8</cstring> + </property> + <property name="text"> + <string>&Message:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>m_editMessage</cstring> + </property> + </widget> + <widget class="KLineEdit" row="0" column="1"> + <property name="name"> + <cstring>m_editTitle</cstring> + </property> + </widget> + <widget class="QLabel" row="0" column="2"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>&Performer:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>m_editPerformer</cstring> + </property> + </widget> + <widget class="QLabel" row="4" column="2"> + <property name="name"> + <cstring>textLabel6</cstring> + </property> + <property name="text"> + <string>&ISRC:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>m_editIsrc</cstring> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>&Title:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>m_editTitle</cstring> + </property> + </widget> + <widget class="KLineEdit" row="4" column="3"> + <property name="name"> + <cstring>m_editIsrc</cstring> + </property> + </widget> + <widget class="KLineEdit" row="0" column="3"> + <property name="name"> + <cstring>m_editPerformer</cstring> + </property> + </widget> + </grid> + </widget> + <spacer> + <property name="name"> + <cstring>spacer4</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>350</width> + <height>50</height> + </size> + </property> + </spacer> + </vbox> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string>&Options</string> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_checkPreemphasis</cstring> + </property> + <property name="text"> + <string>Preemph&asis</string> + </property> + <property name="whatsThis" stdset="0"> + <string><p>Preemphasis is mainly used in audio processing. Higher frequencies in audio signals usually have lower amplitudes. This can lead to bad signal quality on noisy transmission because the high frequencies might become too weak. To avoid this effect, high frequencies are amplified before transmission (preemphasis); the receiver will then weaken them accordingly for playback.</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_checkCopyPermitted</cstring> + </property> + <property name="text"> + <string>&Copy permitted</string> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout6</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>m_labelPostGap</cstring> + </property> + <property name="text"> + <string>Post-Gap:</string> + </property> + </widget> + <widget class="K3bMsfEdit"> + <property name="name"> + <cstring>m_editPostGap</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>Set the length of the track's post-gap</string> + </property> + <property name="whatsThis" stdset="0"> + <string><p>On an audio CD each track (except for the last) can have a post-gap. +This does not mean that K3b adds an additional gap of silence to the track. This setting simply influences the display on a Hifi audio CD player. The part of an audio track that is marked as post-gap is counted backwards. +<p>This setting is irrelevant for most users as todays CD burners can put arbitrary audio data in the post-gap when burning in DAO mode. +<p><i>In other CD-burning applications the post-gap might be called the pre-gap. The pre-gap of track 2 is the same as the post-gap of track 1. +<p><b>Changing the post-gap does not change the length of the track!</b> +<p><b>When writing in TAO writing mode (not recommended for Audio CDs) the post-gap will most likely be muted and on some burners forced to 2 seconds.</b></string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer7</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>161</width> + <height>20</height> + </size> + </property> + </spacer> + </hbox> + </widget> + <spacer> + <property name="name"> + <cstring>spacer3</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>41</width> + <height>80</height> + </size> + </property> + </spacer> + </vbox> + </widget> + </widget> + </hbox> +</widget> +<customwidgets> + <customwidget> + <class>K3bMsfEdit</class> + <header location="global">k3bmsfedit.h</header> + <sizehint> + <width>100</width> + <height>-1</height> + </sizehint> + <container>0</container> + <sizepolicy> + <hordata>7</hordata> + <verdata>5</verdata> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + <pixmap>image0</pixmap> + </customwidget> +</customwidgets> +<images> + <image name="image0"> + <data format="XBM.GZ" length="79">789c534e494dcbcc4b554829cdcdad8c2fcf4c29c95030e0524611cd48cd4ccf28010a1797249664262b2467241641a592324b8aa363156c15aab914146aadb90067111b1f</data> + </image> +</images> +<tabstops> + <tabstop>m_editTitle</tabstop> + <tabstop>m_editPerformer</tabstop> + <tabstop>m_editArranger</tabstop> + <tabstop>m_editComposer</tabstop> + <tabstop>m_editSongwriter</tabstop> + <tabstop>m_editIsrc</tabstop> + <tabstop>m_editMessage</tabstop> + <tabstop>m_checkPreemphasis</tabstop> + <tabstop>m_checkCopyPermitted</tabstop> +</tabstops> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>klineedit.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>k3bmsfedit.h</includehint> +</includehints> +</UI> diff --git a/src/projects/base_k3bbootimageview.ui b/src/projects/base_k3bbootimageview.ui new file mode 100644 index 0000000..6ba21f6 --- /dev/null +++ b/src/projects/base_k3bbootimageview.ui @@ -0,0 +1,394 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>base_K3bBootImageView</class> +<author>Sebastian Trueg</author> +<widget class="QWidget"> + <property name="name"> + <cstring>base_K3bBootImageView</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout17</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>label</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>1</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Boot images:</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_buttonNew</cstring> + </property> + <property name="text"> + <string>&New...</string> + </property> + <property name="toolTip" stdset="0"> + <string>Add new boot image</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_buttonDelete</cstring> + </property> + <property name="text"> + <string>&Delete</string> + </property> + <property name="toolTip" stdset="0"> + <string>Remove selected boot image</string> + </property> + </widget> + </hbox> + </widget> + <widget class="KListView"> + <column> + <property name="text"> + <string>Emulation Type</string> + </property> + <property name="clickable"> + <bool>false</bool> + </property> + <property name="resizable"> + <bool>false</bool> + </property> + </column> + <column> + <property name="text"> + <string>Size</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Local Path</string> + </property> + <property name="clickable"> + <bool>false</bool> + </property> + <property name="resizable"> + <bool>false</bool> + </property> + </column> + <property name="name"> + <cstring>m_viewImages</cstring> + </property> + <property name="allColumnsShowFocus"> + <bool>true</bool> + </property> + <property name="fullWidth"> + <bool>true</bool> + </property> + </widget> + <widget class="QButtonGroup"> + <property name="name"> + <cstring>m_groupImageType</cstring> + </property> + <property name="title"> + <string>Emulation Type</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QRadioButton"> + <property name="name"> + <cstring>m_radioFloppy</cstring> + </property> + <property name="text"> + <string>Flopp&y</string> + </property> + <property name="toolTip" stdset="0"> + <string>Emulate a 1440/2880 kb floppy</string> + </property> + </widget> + <widget class="QRadioButton"> + <property name="name"> + <cstring>m_radioHarddisk</cstring> + </property> + <property name="text"> + <string>Harddisk</string> + </property> + <property name="toolTip" stdset="0"> + <string>Emulate a harddisk</string> + </property> + </widget> + <widget class="QRadioButton"> + <property name="name"> + <cstring>m_radioNoEmulation</cstring> + </property> + <property name="text"> + <string>None</string> + </property> + <property name="toolTip" stdset="0"> + <string>No emulation at all</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>m_groupOptions</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>Settings</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_checkNoBoot</cstring> + </property> + <property name="text"> + <string>No boot image</string> + </property> + <property name="toolTip" stdset="0"> + <string>Do not boot from the emulated floppy/harddisk</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_checkInfoTable</cstring> + </property> + <property name="text"> + <string>Boot-info-table</string> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout10</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLineEdit" row="0" column="1"> + <property name="name"> + <cstring>m_editLoadSegment</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>0</string> + </property> + </widget> + <widget class="QLineEdit" row="1" column="1"> + <property name="name"> + <cstring>m_editLoadSize</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>0</string> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel2_2</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Boot load segment:</string> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Boot load size:</string> + </property> + </widget> + </grid> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout16</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_buttonToggleOptions</cstring> + </property> + <property name="text"> + <string>Show Advanced Op&tions</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer16</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>261</width> + <height>21</height> + </size> + </property> + </spacer> + </hbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout18</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Boot catalog:</string> + </property> + </widget> + <widget class="QLineEdit"> + <property name="name"> + <cstring>m_editBootCataloge</cstring> + </property> + <property name="text"> + <string>boot/boot.catalog</string> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </hbox> + </widget> + </vbox> +</widget> +<connections> + <connection> + <sender>m_radioFloppy</sender> + <signal>toggled(bool)</signal> + <receiver>base_K3bBootImageView</receiver> + <slot>slotOptionsChanged()</slot> + </connection> + <connection> + <sender>m_radioHarddisk</sender> + <signal>toggled(bool)</signal> + <receiver>base_K3bBootImageView</receiver> + <slot>slotOptionsChanged()</slot> + </connection> + <connection> + <sender>m_checkNoBoot</sender> + <signal>toggled(bool)</signal> + <receiver>base_K3bBootImageView</receiver> + <slot>slotOptionsChanged()</slot> + </connection> + <connection> + <sender>m_checkInfoTable</sender> + <signal>toggled(bool)</signal> + <receiver>base_K3bBootImageView</receiver> + <slot>slotOptionsChanged()</slot> + </connection> + <connection> + <sender>m_editLoadSegment</sender> + <signal>textChanged(const QString&)</signal> + <receiver>base_K3bBootImageView</receiver> + <slot>slotOptionsChanged()</slot> + </connection> + <connection> + <sender>m_editLoadSize</sender> + <signal>textChanged(const QString&)</signal> + <receiver>base_K3bBootImageView</receiver> + <slot>slotOptionsChanged()</slot> + </connection> + <connection> + <sender>m_radioNoEmulation</sender> + <signal>toggled(bool)</signal> + <receiver>textLabel2_2</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>m_radioNoEmulation</sender> + <signal>toggled(bool)</signal> + <receiver>textLabel3</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>m_radioNoEmulation</sender> + <signal>toggled(bool)</signal> + <receiver>m_editLoadSegment</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>m_radioNoEmulation</sender> + <signal>toggled(bool)</signal> + <receiver>m_editLoadSize</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>m_radioNoEmulation</sender> + <signal>toggled(bool)</signal> + <receiver>m_checkNoBoot</receiver> + <slot>setDisabled(bool)</slot> + </connection> + <connection> + <sender>m_radioNoEmulation</sender> + <signal>toggled(bool)</signal> + <receiver>base_K3bBootImageView</receiver> + <slot>slotOptionsChanged()</slot> + </connection> +</connections> +<slots> + <slot access="protected">slotOptionsChanged()</slot> +</slots> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>klistview.h</includehint> +</includehints> +</UI> diff --git a/src/projects/base_k3bdataimagesettings.ui b/src/projects/base_k3bdataimagesettings.ui new file mode 100644 index 0000000..3427ab7 --- /dev/null +++ b/src/projects/base_k3bdataimagesettings.ui @@ -0,0 +1,274 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>base_K3bDataImageSettings</class> +<author>Sebastian Trueg</author> +<widget class="QWidget"> + <property name="name"> + <cstring>base_K3bDataImageSetings</cstring> + </property> + <property name="caption"> + <string>Data Image Settings</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>m_groupVolumeName</cstring> + </property> + <property name="title"> + <string>Volume Name</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLineEdit"> + <property name="name"> + <cstring>m_editVolumeName</cstring> + </property> + <property name="maxLength"> + <number>32</number> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_buttonMoreVolDescFields</cstring> + </property> + <property name="text"> + <string>&More fields...</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>m_groupFileSystem</cstring> + </property> + <property name="title"> + <string>File System</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QComboBox"> + <property name="name"> + <cstring>m_comboFilesystems</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>1</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip" stdset="0"> + <string>File system presets</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_buttonCustomFilesystems</cstring> + </property> + <property name="text"> + <string>&Custom...</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout4</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>m_groupSymlinks</cstring> + </property> + <property name="title"> + <string>Symbolic Links</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QComboBox"> + <item> + <property name="text"> + <string>No Change</string> + </property> + </item> + <item> + <property name="text"> + <string>Discard broken symlinks</string> + </property> + </item> + <item> + <property name="text"> + <string>Discard all symlinks</string> + </property> + </item> + <item> + <property name="text"> + <string>Follow symlinks</string> + </property> + </item> + <property name="name"> + <cstring>m_comboSymlinkHandling</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>1</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip" stdset="0"> + <string>Symbolic link handling in the project</string> + </property> + <property name="whatsThis" stdset="0"> + <string><p>K3b can create ISO9660 filesystems that contain symlinks if the Rock Ridge extensions are enabled (they are by default). You can change the way symlinks are handled in a K3b project. + +<p><b>No Change</b><br> +Symlinks are used as they have been added to the project. + +<p><b>Discard broken symlinks</b><br> +K3b will discard all symbolic links that do not point to a file inside the project. That includes all links to absolute paths like '/home/myhome/testfile'. + +<p><b>Discard all symlinks</b><br> +K3b will discard all symbolic links that have been added to the project; meaning that the resulting file system will have no links at all. + +<p><b>Follow symlinks</b><br> +Each symbolic link in the project will be replaced with the contents of the file it is pointing to. Thus, the resulting filesystem will not contain any symbolic links.<br> +Be aware that in case Rock Ridge extensions are disabled (which is not recommended) symbolic links are always followed because ISO9660 does not support symbolic links. + +<p><b>Caution:</b> Symbolic links require Rock Ridge extensions.</string> + </property> + </widget> + </vbox> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>m_groupWhitespace</cstring> + </property> + <property name="title"> + <string>White space handling</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QComboBox"> + <item> + <property name="text"> + <string>No Change</string> + </property> + </item> + <item> + <property name="text"> + <string>Strip</string> + </property> + </item> + <item> + <property name="text"> + <string>Extended Strip</string> + </property> + </item> + <item> + <property name="text"> + <string>Replace</string> + </property> + </item> + <property name="name"> + <cstring>m_comboSpaceHandling</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>1</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip" stdset="0"> + <string>Handling of spaces in filenames</string> + </property> + <property name="whatsThis" stdset="0"> + <string><p><b>No Change</b><br> +If this option is checked, K3b will leave all spaces in filenames as they are. +<p><b>Strip</b><br> +If this option is checked, K3b will remove all spaces from all filenames.<br> +Example: 'my good file.ext' becomes 'mygoodfile.ext' +<p><b>Extended Strip</b><br> +If this option is checked K3b will remove all spaces in all filenames and capitalize all letters following a space.<br> +Example: 'my good file.ext' becomes 'myGoodFile.ext' +<p><b>Replace</b><br> +If this option is checked, K3b will replace all spaces in all filenames with the specified characters.<br> +Example: 'my good file.ext' becomes 'my_good_file.ext'</string> + </property> + </widget> + <widget class="QLineEdit"> + <property name="name"> + <cstring>m_editReplace</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>_</string> + </property> + <property name="toolTip" stdset="0"> + <string>The string to replace spaces with</string> + </property> + </widget> + </hbox> + </widget> + </hbox> + </widget> + <spacer> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>21</width> + <height>0</height> + </size> + </property> + </spacer> + </vbox> +</widget> +<tabstops> + <tabstop>m_editReplace</tabstop> +</tabstops> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/src/projects/base_k3bdatavolumedescwidget.ui b/src/projects/base_k3bdatavolumedescwidget.ui new file mode 100644 index 0000000..ce31be9 --- /dev/null +++ b/src/projects/base_k3bdatavolumedescwidget.ui @@ -0,0 +1,370 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>base_K3bDataVolumeDescWidget</class> +<author>Sebastian Trueg</author> +<widget class="QWidget"> + <property name="name"> + <cstring>base_K3bDataVolumeDescWidget</cstring> + </property> + <property name="caption"> + <string>Volume Descriptor</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QLineEdit" row="0" column="1"> + <property name="name"> + <cstring>m_editVolumeName</cstring> + </property> + <property name="maxLength"> + <number>32</number> + </property> + </widget> + <widget class="QLineEdit" row="1" column="1"> + <property name="name"> + <cstring>m_editVolumeSetName</cstring> + </property> + <property name="maxLength"> + <number>128</number> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>TextLabel2</cstring> + </property> + <property name="text"> + <string>V&olume set name:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>m_editVolumeSetName</cstring> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>TextLabel1</cstring> + </property> + <property name="text"> + <string>&Volume name:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>m_editVolumeName</cstring> + </property> + </widget> + <widget class="QLineEdit" row="3" column="1"> + <property name="name"> + <cstring>m_editPublisher</cstring> + </property> + <property name="maxLength"> + <number>128</number> + </property> + </widget> + <widget class="QLineEdit" row="4" column="1"> + <property name="name"> + <cstring>m_editPreparer</cstring> + </property> + <property name="maxLength"> + <number>128</number> + </property> + </widget> + <widget class="QLabel" row="4" column="0"> + <property name="name"> + <cstring>TextLabel4</cstring> + </property> + <property name="text"> + <string>P&reparer:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>m_editPreparer</cstring> + </property> + </widget> + <widget class="QLabel" row="3" column="0"> + <property name="name"> + <cstring>TextLabel3</cstring> + </property> + <property name="text"> + <string>P&ublisher:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>m_editPublisher</cstring> + </property> + </widget> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Volu&me set size:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>m_spinVolumeSetSize</cstring> + </property> + </widget> + <widget class="QLayoutWidget" row="2" column="1"> + <property name="name"> + <cstring>layout1</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QSpinBox"> + <property name="name"> + <cstring>m_spinVolumeSetSize</cstring> + </property> + <property name="specialValueText"> + <string></string> + </property> + <property name="minValue"> + <number>1</number> + </property> + <property name="value"> + <number>1</number> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Volume set &number:</string> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + <property name="buddy" stdset="0"> + <cstring>m_spinVolumeSetNumber</cstring> + </property> + </widget> + <widget class="QSpinBox"> + <property name="name"> + <cstring>m_spinVolumeSetNumber</cstring> + </property> + <property name="specialValueText"> + <string></string> + </property> + <property name="maxValue"> + <number>2</number> + </property> + <property name="minValue"> + <number>1</number> + </property> + <property name="value"> + <number>1</number> + </property> + </widget> + </hbox> + </widget> + <widget class="QLabel" row="6" column="0"> + <property name="name"> + <cstring>TextLabel5</cstring> + </property> + <property name="text"> + <string>S&ystem:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>m_editSystem</cstring> + </property> + </widget> + <widget class="QLineEdit" row="6" column="1"> + <property name="name"> + <cstring>m_editSystem</cstring> + </property> + <property name="maxLength"> + <number>32</number> + </property> + </widget> + <widget class="QLabel" row="7" column="0"> + <property name="name"> + <cstring>TextLabel6</cstring> + </property> + <property name="text"> + <string>&Application:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>m_editApplication</cstring> + </property> + </widget> + <spacer row="12" column="1"> + <property name="name"> + <cstring>Spacer1</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>0</height> + </size> + </property> + </spacer> + <widget class="Line" row="5" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>line1</cstring> + </property> + <property name="frameShape"> + <enum>HLine</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + </widget> + <widget class="QLineEdit" row="7" column="1"> + <property name="name"> + <cstring>m_editApplication</cstring> + </property> + <property name="maxLength"> + <number>128</number> + </property> + </widget> + <widget class="QLayoutWidget" row="11" column="1"> + <property name="name"> + <cstring>layout4</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLineEdit"> + <property name="name"> + <cstring>m_editBiblio</cstring> + </property> + <property name="maxLength"> + <number>37</number> + </property> + </widget> + <widget class="QToolButton"> + <property name="name"> + <cstring>m_buttonFindBiblio</cstring> + </property> + <property name="text"> + <string>...</string> + </property> + <property name="toolTip" stdset="0"> + <string>Select a bibliographic file from the project</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QLayoutWidget" row="9" column="1"> + <property name="name"> + <cstring>layout2</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLineEdit"> + <property name="name"> + <cstring>m_editAbstract</cstring> + </property> + <property name="maxLength"> + <number>37</number> + </property> + </widget> + <widget class="QToolButton"> + <property name="name"> + <cstring>m_buttonFindAbstract</cstring> + </property> + <property name="text"> + <string>...</string> + </property> + <property name="toolTip" stdset="0"> + <string>Select an abstract file from the project</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QLayoutWidget" row="10" column="1"> + <property name="name"> + <cstring>layout3</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLineEdit"> + <property name="name"> + <cstring>m_editCopyright</cstring> + </property> + <property name="maxLength"> + <number>37</number> + </property> + </widget> + <widget class="QToolButton"> + <property name="name"> + <cstring>m_buttonFindCopyright</cstring> + </property> + <property name="text"> + <string>...</string> + </property> + <property name="toolTip" stdset="0"> + <string>Select a copyright file from the project</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QLabel" row="9" column="0"> + <property name="name"> + <cstring>textLabel1_2</cstring> + </property> + <property name="text"> + <string>Abstract file:</string> + </property> + </widget> + <widget class="QLabel" row="10" column="0"> + <property name="name"> + <cstring>textLabel2_2</cstring> + </property> + <property name="text"> + <string>Copyright file:</string> + </property> + </widget> + <widget class="QLabel" row="11" column="0"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>Bibliographic file:</string> + </property> + </widget> + <widget class="Line" row="8" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>line1_2</cstring> + </property> + <property name="frameShape"> + <enum>HLine</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + </widget> + </grid> +</widget> +<tabstops> + <tabstop>m_editVolumeName</tabstop> + <tabstop>m_editVolumeSetName</tabstop> + <tabstop>m_spinVolumeSetSize</tabstop> + <tabstop>m_spinVolumeSetNumber</tabstop> + <tabstop>m_editPublisher</tabstop> + <tabstop>m_editPreparer</tabstop> + <tabstop>m_editSystem</tabstop> + <tabstop>m_editApplication</tabstop> +</tabstops> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/src/projects/base_k3bmovixoptionswidget.ui b/src/projects/base_k3bmovixoptionswidget.ui new file mode 100644 index 0000000..973dd11 --- /dev/null +++ b/src/projects/base_k3bmovixoptionswidget.ui @@ -0,0 +1,337 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>base_K3bMovixOptionsWidget</class> +<author>Sebastian trueg</author> +<widget class="QWidget"> + <property name="name"> + <cstring>Form1</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox2</cstring> + </property> + <property name="frameShape"> + <enum>GroupBoxPanel</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="title"> + <string>Playback Settings</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>MPlayer subtitle fontset:</string> + </property> + </widget> + <widget class="KComboBox" row="0" column="1"> + <property name="name"> + <cstring>m_comboSubtitleFontset</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>Select the font to be used to render subtitles</string> + </property> + </widget> + <widget class="QLabel" row="5" column="0"> + <property name="name"> + <cstring>textLabel7</cstring> + </property> + <property name="text"> + <string>Unwanted MPlayer options:</string> + </property> + <property name="whatsThis" stdset="0"> + <string></string> + </property> + </widget> + <widget class="QLayoutWidget" row="3" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>layout1</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_checkRandomPlay</cstring> + </property> + <property name="text"> + <string>Pla&y files randomly</string> + </property> + <property name="toolTip" stdset="0"> + <string>The files are played in random order</string> + </property> + <property name="whatsThis" stdset="0"> + <string><p>If this option is checked the order in which the files are played is determined randomly every time it is played.</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_checkNoDma</cstring> + </property> + <property name="text"> + <string>&Do not use DMA</string> + </property> + <property name="toolTip" stdset="0"> + <string>Do not use DMA for media access</string> + </property> + <property name="whatsThis" stdset="0"> + <string><p>If this option is checked the resulting eMovix CD/DVD will not use DMA for accessing the drive. This will slow down reading from the CD/DVD but may be necessary on some systems that do not support DMA.</p></string> + </property> + </widget> + </hbox> + </widget> + <widget class="QLineEdit" row="5" column="1"> + <property name="name"> + <cstring>m_editUnwantedMplayerOptions</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>MPlayer options you want to be sure MPlayer will not use</string> + </property> + <property name="whatsThis" stdset="0"> + <string><p>Here one can specify MPlayer options that should never be used. +<p>They have to be separated by spaces: +<pre>opt1 opt2 opt3</pre></string> + </property> + </widget> + <widget class="QLineEdit" row="4" column="1"> + <property name="name"> + <cstring>m_editAdditionalMplayerOptions</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>Additional MPlayer options</string> + </property> + <property name="whatsThis" stdset="0"> + <string><p>MPlayer options that should be used in any case. +<p>They have to be separated by spaces: +<pre>opt1 opt2 opt3</pre></string> + </property> + </widget> + <widget class="QLabel" row="4" column="0"> + <property name="name"> + <cstring>textLabel6</cstring> + </property> + <property name="text"> + <string>Additional MPlayer options:</string> + </property> + </widget> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>Loop playlist:</string> + </property> + </widget> + <widget class="QSpinBox" row="2" column="1"> + <property name="name"> + <cstring>m_spinLoop</cstring> + </property> + <property name="suffix"> + <string> time(s)</string> + </property> + <property name="specialValueText"> + <string>infinity</string> + </property> + <property name="value"> + <number>1</number> + </property> + <property name="toolTip" stdset="0"> + <string>How many times should the playlist be looped</string> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>m_labelAudioBackground</cstring> + </property> + <property name="text"> + <string>Audio Player Background:</string> + </property> + </widget> + <widget class="KComboBox" row="1" column="1"> + <property name="name"> + <cstring>m_comboAudioBackground</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>Background video to show during audio playback</string> + </property> + <property name="whatsThis" stdset="0"> + <string><p><b>Audio Player Background</b> +<p>During audio playback normally the screen would be black. However, if a background movie has been selected, eMovix will display it during playback. +<p>Additional background movies can be installed. However, this is not as simple as a few mouse clicks. The background movies are stored in the emovix shared data folder (mostly <i>/usr/share/emovix</i> or <i>/usr/local/share/emovix</i>) under <em>backgrounds</em>. So to add a background one has to copy the file to that folder.</string> + </property> + </widget> + </grid> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox3</cstring> + </property> + <property name="title"> + <string>Startup Behavior</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>m_labelKeyboardLayout</cstring> + </property> + <property name="text"> + <string>Keyboard Layout:</string> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>eMovix boot messages language:</string> + </property> + </widget> + <widget class="KComboBox" row="0" column="1"> + <property name="name"> + <cstring>m_comboBootMessageLanguage</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>Select the language of the eMovix help screens</string> + </property> + </widget> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>textLabel5</cstring> + </property> + <property name="text"> + <string>Default boot label:</string> + </property> + </widget> + <widget class="KComboBox" row="2" column="1"> + <property name="name"> + <cstring>m_comboDefaultBootLabel</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>Select the default Linux kernel configuration</string> + </property> + <property name="whatsThis" stdset="0"> + <string><p><b>eMovix Boot Labels</b> +<p>eMovix provides are variety or different boot configurations which can be selected at boot time via a boot label (compare Lilo or Grub). The many different boot configurations mainly influence the Video output. +<p>The <b>default</b>, <b>movix</b>, or <b>MoviX</b> labels start a general Vesa video driver. +<p>The <b>TV</b> labels can be used to direct video to the TV output of the graphic board. eMovix provides TVout drivers for different brands of graphic boards. +<p>The <b>FB</b> labels refer to configurations that start a Frame Buffer driver in different screen resolutions. +<p>The <b>AA</b> labels make eMovix output the video through the Ascii-Art library which displays the picture in text mode through the usage of simple Acsii characters. +<p>The <b>hd</b> label makes eMovix boot from the local harddisk instead of the medium. This can be used to prevent accidental starting of an eMovix medium. +<p>The <b>floppy</b> label makes eMovix boot from the local floppy drive instead of the medium.</string> + </property> + </widget> + <widget class="KComboBox" row="1" column="1"> + <property name="name"> + <cstring>m_comboKeyboardLayout</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>Select the layout of the keyboard</string> + </property> + <property name="whatsThis" stdset="0"> + <string><p>The keyboard layout selected here will be used for the eMovix commands like controlling the media player.</string> + </property> + </widget> + </grid> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox1</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>1</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>Behavior After Playing</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_checkEject</cstring> + </property> + <property name="text"> + <string>E&ject disk</string> + </property> + <property name="toolTip" stdset="0"> + <string>Eject the disk after playing has finished</string> + </property> + <property name="whatsThis" stdset="0"> + <string><p>If this option is checked the disk will be ejected after MPlayer has finished.</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_checkShutdown</cstring> + </property> + <property name="text"> + <string>Sh&utdown</string> + </property> + <property name="toolTip" stdset="0"> + <string>Shutdown after playing has finished</string> + </property> + <property name="whatsThis" stdset="0"> + <string><p>If this option is checked the PC will be shut down after MPlayer has finished playing.</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_checkReboot</cstring> + </property> + <property name="text"> + <string>Re&boot</string> + </property> + <property name="toolTip" stdset="0"> + <string>Reboot after playing has finished</string> + </property> + <property name="whatsThis" stdset="0"> + <string><p>If this option is checked the PC will be rebooted after MPlayer has finished playing.</string> + </property> + </widget> + </hbox> + </widget> + </vbox> +</widget> +<connections> + <connection> + <sender>m_checkShutdown</sender> + <signal>toggled(bool)</signal> + <receiver>m_checkReboot</receiver> + <slot>setDisabled(bool)</slot> + </connection> + <connection> + <sender>m_checkReboot</sender> + <signal>toggled(bool)</signal> + <receiver>m_checkShutdown</receiver> + <slot>setDisabled(bool)</slot> + </connection> +</connections> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kcombobox.h</includehint> + <includehint>kcombobox.h</includehint> + <includehint>kcombobox.h</includehint> + <includehint>kcombobox.h</includehint> + <includehint>kcombobox.h</includehint> +</includehints> +</UI> diff --git a/src/projects/k3baudioburndialog.cpp b/src/projects/k3baudioburndialog.cpp new file mode 100644 index 0000000..97bf318 --- /dev/null +++ b/src/projects/k3baudioburndialog.cpp @@ -0,0 +1,341 @@ +/* + * + * $Id: k3baudioburndialog.cpp 623768 2007-01-15 13:33:55Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3baudioburndialog.h" +#include "k3baudioview.h" +#include "k3baudiotrackplayer.h" +#include "k3baudiotrack.h" +#include "k3baudiocdtracksource.h" +#include <k3bcore.h> +#include "k3baudiodoc.h" +#include <k3bdevice.h> +#include <k3bwriterselectionwidget.h> +#include <k3btempdirselectionwidget.h> +#include "k3baudiocdtextwidget.h" +#include <k3bglobals.h> +#include <k3bstdguiitems.h> +#include <k3bwritingmodewidget.h> +#include <k3bexternalbinmanager.h> + +#include <qcheckbox.h> +#include <qcombobox.h> +#include <qgroupbox.h> +#include <qlabel.h> +#include <qlineedit.h> +#include <qpushbutton.h> +#include <qtabwidget.h> +#include <qlayout.h> +#include <qvariant.h> +#include <qtooltip.h> +#include <qwhatsthis.h> +#include <qgrid.h> +#include <qtoolbutton.h> +#include <qptrlist.h> +#include <qstringlist.h> +#include <qpoint.h> +#include <qhbox.h> +#include <qspinbox.h> + +#include <klocale.h> +#include <kstandarddirs.h> +#include <kconfig.h> +#include <kmessagebox.h> + + +K3bAudioBurnDialog::K3bAudioBurnDialog(K3bAudioDoc* _doc, QWidget *parent, const char *name, bool modal ) + : K3bProjectBurnDialog( _doc, parent, name, modal ), + m_doc(_doc) +{ + prepareGui(); + + setTitle( i18n("Audio Project"), + i18n("1 track (%1 minutes)", "%n tracks (%1 minutes)", + m_doc->numOfTracks() ).arg(m_doc->length().toString()) ); + + QSpacerItem* spacer = new QSpacerItem( 20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding ); + m_optionGroupLayout->addItem( spacer ); + + // create cd-text page + m_cdtextWidget = new K3bAudioCdTextWidget( this ); + addPage( m_cdtextWidget, i18n("CD-Text") ); + + // create advanced tab + // ---------------------------------------------------------- + QWidget* advancedTab = new QWidget( this ); + QGridLayout* advancedTabGrid = new QGridLayout( advancedTab ); + advancedTabGrid->setSpacing( spacingHint() ); + advancedTabGrid->setMargin( marginHint() ); + + QGroupBox* advancedSettingsGroup = new QGroupBox( 1, Qt::Vertical, i18n("Settings"), advancedTab ); + m_checkNormalize = K3bStdGuiItems::normalizeCheckBox( advancedSettingsGroup ); + + QGroupBox* advancedGimmickGroup = new QGroupBox( 1, Qt::Vertical, i18n("Gimmicks"), advancedTab ); + m_checkHideFirstTrack = new QCheckBox( i18n( "Hide first track" ), advancedGimmickGroup, "m_checkHideFirstTrack" ); + + m_audioRippingGroup = new QGroupBox( 3, Qt::Vertical, i18n("Audio Ripping"), advancedTab ); + QHBox* box = new QHBox( m_audioRippingGroup ); + box->setSpacing( spacingHint() ); + box->setStretchFactor(new QLabel( i18n("Paranoia mode:"), box ), 1 ); + m_comboParanoiaMode = K3bStdGuiItems::paranoiaModeComboBox( box ); + box = new QHBox( m_audioRippingGroup ); + box->setSpacing( spacingHint() ); + box->setStretchFactor( new QLabel( i18n("Read retries:"), box ), 1 ); + m_spinAudioRippingReadRetries = new QSpinBox( 1, 128, 1, box ); + m_checkAudioRippingIgnoreReadErrors = new QCheckBox( i18n("Ignore read errors"), m_audioRippingGroup ); + + advancedTabGrid->addWidget( advancedSettingsGroup, 0, 0 ); + advancedTabGrid->addWidget( advancedGimmickGroup, 1, 0 ); + advancedTabGrid->addWidget( m_audioRippingGroup, 2, 0 ); + advancedTabGrid->setRowStretch( 3, 1 ); + + addPage( advancedTab, i18n("Advanced") ); + + connect( m_writerSelectionWidget, SIGNAL(writingAppChanged(int)), this, SLOT(slotToggleAll()) ); + connect( m_checkNormalize, SIGNAL(toggled(bool)), this, SLOT(slotNormalizeToggled(bool)) ); + connect( m_checkCacheImage, SIGNAL(toggled(bool)), this, SLOT(slotCacheImageToggled(bool)) ); + connect( m_writingModeWidget, SIGNAL(writingModeChanged(int)), this, SLOT(slotToggleAll()) ); + + // ToolTips + // ------------------------------------------------------------------------- + QToolTip::add( m_checkHideFirstTrack, i18n("Hide the first track in the first pregap") ); + + // What's This info + // ------------------------------------------------------------------------- + QWhatsThis::add( m_checkHideFirstTrack, + i18n("<p>If this option is checked K3b will <em>hide</em> the first track." + "<p>The audio CD standard uses pregaps before every track on the CD. " + "By default these last for 2 seconds and are silent. In DAO mode it " + "is possible to have longer pregaps that contain some audio. In this case " + "the first pregap will contain the complete first track." + "<p>You will need to seek back from the beginning of the CD to listen to " + "the first track. Try it, it is quite amusing." + "<p><b>This feature is only available in DAO mode when writing with cdrdao.") ); +} + +K3bAudioBurnDialog::~K3bAudioBurnDialog(){ +} + + +void K3bAudioBurnDialog::slotStartClicked() +{ + static_cast<K3bAudioView*>(m_doc->view())->player()->stop(); + K3bProjectBurnDialog::slotStartClicked(); +} + + +void K3bAudioBurnDialog::saveSettings() +{ + K3bProjectBurnDialog::saveSettings(); + + m_doc->setTempDir( m_tempDirSelectionWidget->tempPath() ); + m_doc->setHideFirstTrack( m_checkHideFirstTrack->isChecked() ); + m_doc->setNormalize( m_checkNormalize->isChecked() ); + + // -- save Cd-Text ------------------------------------------------ + m_cdtextWidget->save( m_doc ); + + // audio ripping + m_doc->setAudioRippingParanoiaMode( m_comboParanoiaMode->currentText().toInt() ); + m_doc->setAudioRippingRetries( m_spinAudioRippingReadRetries->value() ); + m_doc->setAudioRippingIgnoreReadErrors( m_checkAudioRippingIgnoreReadErrors->isChecked() ); + + doc()->setTempDir( m_tempDirSelectionWidget->tempPath() ); +} + + +void K3bAudioBurnDialog::readSettings() +{ + K3bProjectBurnDialog::readSettings(); + + m_checkHideFirstTrack->setChecked( m_doc->hideFirstTrack() ); + m_checkNormalize->setChecked( m_doc->normalize() ); + + // read CD-Text ------------------------------------------------------------ + m_cdtextWidget->load( m_doc ); + + // audio ripping + m_comboParanoiaMode->setCurrentItem( m_doc->audioRippingParanoiaMode() ); + m_checkAudioRippingIgnoreReadErrors->setChecked( m_doc->audioRippingIgnoreReadErrors() ); + m_spinAudioRippingReadRetries->setValue( m_doc->audioRippingRetries() ); + + if( !doc()->tempDir().isEmpty() ) + m_tempDirSelectionWidget->setTempPath( doc()->tempDir() ); + + toggleAll(); +} + + +void K3bAudioBurnDialog::loadK3bDefaults() +{ + K3bProjectBurnDialog::loadK3bDefaults(); + + m_cdtextWidget->setChecked( true ); + m_checkHideFirstTrack->setChecked( false ); + m_checkNormalize->setChecked(false); + + m_comboParanoiaMode->setCurrentItem( 0 ); + m_checkAudioRippingIgnoreReadErrors->setChecked( true ); + m_spinAudioRippingReadRetries->setValue( 5 ); + + toggleAll(); +} + + +void K3bAudioBurnDialog::loadUserDefaults( KConfigBase* c ) +{ + K3bProjectBurnDialog::loadUserDefaults( c ); + + m_cdtextWidget->setChecked( c->readBoolEntry( "cd_text", true ) ); + m_checkHideFirstTrack->setChecked( c->readBoolEntry( "hide_first_track", false ) ); + m_checkNormalize->setChecked( c->readBoolEntry( "normalize", false ) ); + + m_comboParanoiaMode->setCurrentItem( c->readNumEntry( "paranoia mode", 0 ) ); + m_checkAudioRippingIgnoreReadErrors->setChecked( c->readBoolEntry( "ignore read errors", true ) ); + m_spinAudioRippingReadRetries->setValue( c->readNumEntry( "read retries", 5 ) ); + + toggleAll(); +} + + +void K3bAudioBurnDialog::saveUserDefaults( KConfigBase* c ) +{ + K3bProjectBurnDialog::saveUserDefaults( c ); + + c->writeEntry( "cd_text", m_cdtextWidget->isChecked() ); + c->writeEntry( "hide_first_track", m_checkHideFirstTrack->isChecked() ); + c->writeEntry( "normalize", m_checkNormalize->isChecked() ); + + c->writeEntry( "paranoia mode", m_comboParanoiaMode->currentText() ); + c->writeEntry( "ignore read errors", m_checkAudioRippingIgnoreReadErrors->isChecked() ); + c->writeEntry( "read retries", m_spinAudioRippingReadRetries->value() ); +} + +void K3bAudioBurnDialog::toggleAll() +{ + K3bProjectBurnDialog::toggleAll(); + + bool cdrecordOnTheFly = false; + bool cdrecordCdText = false; + if ( k3bcore->externalBinManager()->binObject("cdrecord") ) { + cdrecordOnTheFly = k3bcore->externalBinManager()->binObject("cdrecord")->hasFeature( "audio-stdin" ); + cdrecordCdText = k3bcore->externalBinManager()->binObject("cdrecord")->hasFeature( "cdtext" ); + } + + // cdrdao always knows onthefly and cdtext + bool onTheFly = true; + bool cdText = true; + if( m_writingModeWidget->writingMode() == K3b::TAO || + m_writingModeWidget->writingMode() == K3b::RAW || + m_writerSelectionWidget->writingApp() == K3b::CDRECORD ) { + onTheFly = cdrecordOnTheFly; + cdText = cdrecordCdText; + m_checkHideFirstTrack->setChecked(false); + m_checkHideFirstTrack->setEnabled(false); + } + else { + m_checkHideFirstTrack->setEnabled( !m_checkOnlyCreateImage->isChecked() ); + m_cdtextWidget->setEnabled( !m_checkOnlyCreateImage->isChecked() ); + } + + m_checkCacheImage->setEnabled( !m_checkOnlyCreateImage->isChecked() && + onTheFly ); + if( !onTheFly ) + m_checkCacheImage->setChecked( true ); + m_cdtextWidget->setEnabled( !m_checkOnlyCreateImage->isChecked() && + cdText && + m_writingModeWidget->writingMode() != K3b::TAO ); + if( !cdText || m_writingModeWidget->writingMode() == K3b::TAO ) + m_cdtextWidget->setChecked(false); +} + + +void K3bAudioBurnDialog::showEvent( QShowEvent* e ) +{ + // we only show the audio ripping options when there are audio cd track sources + bool showRipOptions = false; + if( m_doc->firstTrack() ) { + K3bAudioTrack* track = m_doc->firstTrack(); + K3bAudioDataSource* source = track->firstSource(); + + while( source ) { + + if( dynamic_cast<K3bAudioCdTrackSource*>(source) ) { + showRipOptions = true; + break; + } + + // next source + source = source->next(); + if( !source ) { + track = track->next(); + if( track ) + source = track->firstSource(); + } + } + } + + m_audioRippingGroup->setShown( showRipOptions ); + + K3bProjectBurnDialog::showEvent(e); +} + + +void K3bAudioBurnDialog::slotNormalizeToggled( bool on ) +{ + if( on ) { + // we are not able to normalize in on-the-fly mode + if( !k3bcore->externalBinManager()->foundBin( "normalize-audio" ) ) { + KMessageBox::sorry( this, i18n("<p><b>External program <em>normalize-audio</em> is not installed.</b>" + "<p>K3b uses <em>normalize-audio</em> (http://www1.cs.columbia.edu/~cvaill/normalize/) " + "to normalize audio tracks. In order to " + "use this functionality, please install it first. (sudo apt-get install normalize-audio)") ); + m_checkNormalize->setChecked( false ); + } + else if( !m_checkCacheImage->isChecked() && !m_checkOnlyCreateImage->isChecked() ) { + if( KMessageBox::warningYesNo( this, i18n("<p>K3b is not able to normalize audio tracks when burning on-the-fly. " + "The external program used for this task only supports normalizing a set " + "of audio files."), + QString::null, + i18n("Disable normalization"), + i18n("Disable on-the-fly burning"), + "audioProjectNormalizeOrOnTheFly" ) == KMessageBox::Yes ) + m_checkNormalize->setChecked( false ); + else + m_checkCacheImage->setChecked( true ); + } + } +} + + +void K3bAudioBurnDialog::slotCacheImageToggled( bool on ) +{ + if( !on ) { + if( m_checkNormalize->isChecked() ) { + if( KMessageBox::warningYesNo( this, i18n("<p>K3b is not able to normalize audio tracks when burning on-the-fly. " + "The external program used for this task only supports normalizing a set " + "of audio files."), + QString::null, + i18n("Disable normalization"), + i18n("Disable on-the-fly burning"), + "audioProjectNormalizeOrOnTheFly" ) == KMessageBox::Yes ) + m_checkNormalize->setChecked( false ); + else + m_checkCacheImage->setChecked( true ); + } + } +} + +#include "k3baudioburndialog.moc" diff --git a/src/projects/k3baudioburndialog.h b/src/projects/k3baudioburndialog.h new file mode 100644 index 0000000..47be09f --- /dev/null +++ b/src/projects/k3baudioburndialog.h @@ -0,0 +1,81 @@ +/* + * + * $Id: k3baudioburndialog.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BAUDIOBURNDIALOG_H +#define K3BAUDIOBURNDIALOG_H + + +#include "k3bprojectburndialog.h" + +#include <qvariant.h> +#include <qwidget.h> + +class QCheckBox; +class QComboBox; +class QGroupBox; +class QLabel; +class QLineEdit; +class QSpinBox; +class K3bWriterSelectionWidget; +class K3bTempDirSelectionWidget; +class K3bAudioDoc; +class K3bAudioCdTextWidget; +class QShowEvent; + + +/** + *@author Sebastian Trueg + */ +class K3bAudioBurnDialog : public K3bProjectBurnDialog +{ + Q_OBJECT + + public: + K3bAudioBurnDialog(K3bAudioDoc* doc, QWidget *parent=0, const char *name=0, bool modal = true ); + ~K3bAudioBurnDialog(); + + protected: + void saveSettings(); + void readSettings(); + void loadK3bDefaults(); + void loadUserDefaults( KConfigBase* ); + void saveUserDefaults( KConfigBase* ); + void showEvent( QShowEvent* ); + void toggleAll(); + + protected slots: + /** + * Reimplemented for internal reasons (shut down the audio player) + */ + void slotStartClicked(); + void slotCacheImageToggled( bool on ); + void slotNormalizeToggled( bool on ); + + private: + /** + * We need this here to be able to hide/show the group + */ + QGroupBox* m_audioRippingGroup; + QCheckBox* m_checkHideFirstTrack; + QCheckBox* m_checkNormalize; + QCheckBox* m_checkAudioRippingIgnoreReadErrors; + QSpinBox* m_spinAudioRippingReadRetries; + QComboBox* m_comboParanoiaMode; + K3bAudioCdTextWidget* m_cdtextWidget; + K3bAudioDoc* m_doc; +}; + +#endif diff --git a/src/projects/k3baudiocdtextwidget.cpp b/src/projects/k3baudiocdtextwidget.cpp new file mode 100644 index 0000000..8ee5543 --- /dev/null +++ b/src/projects/k3baudiocdtextwidget.cpp @@ -0,0 +1,236 @@ +/* + * + * $Id: k3baudiocdtextwidget.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3baudiocdtextwidget.h" +#include "base_k3baudiocdtextallfieldswidget.h" + +#include "k3baudiodoc.h" +#include "k3baudiotrack.h" +#include <k3bcdtextvalidator.h> + +#include <qcheckbox.h> +#include <qtoolbutton.h> +#include <qpushbutton.h> +#include <qptrlist.h> +#include <qlayout.h> +#include <qgroupbox.h> + +#include <klineedit.h> +#include <klocale.h> +#include <kdialogbase.h> +#include <kiconloader.h> + + +class K3bAudioCdTextWidget::AllFieldsDialog : public KDialogBase +{ +public: + AllFieldsDialog( QWidget* parent ) + : KDialogBase( parent, + "cdtext_allfields_dialog", + true, + i18n("CD-Text"), + Ok|Cancel, + Ok, + true ) { + w = new base_K3bAudioCdTextAllFieldsWidget( this ); + setMainWidget( w ); + } + + base_K3bAudioCdTextAllFieldsWidget* w; +}; + + +K3bAudioCdTextWidget::K3bAudioCdTextWidget( QWidget* parent, const char* name ) + : base_K3bAudioCdTextWidget( parent, name ), + m_doc(0) +{ + m_allFieldsDlg = new AllFieldsDialog( this ); + + m_buttonCopyTitle->setPixmap( SmallIcon( "editcopy" ) ); + m_buttonCopyPerformer->setPixmap( SmallIcon( "editcopy" ) ); + + m_allFieldsDlg->w->m_buttonCopyTitle->setPixmap( SmallIcon( "editcopy" ) ); + m_allFieldsDlg->w->m_buttonCopyPerformer->setPixmap( SmallIcon( "editcopy" ) ); + m_allFieldsDlg->w->m_buttonCopySongwriter->setPixmap( SmallIcon( "editcopy" ) ); + m_allFieldsDlg->w->m_buttonCopyComposer->setPixmap( SmallIcon( "editcopy" ) ); + m_allFieldsDlg->w->m_buttonCopyArranger->setPixmap( SmallIcon( "editcopy" ) ); + + QValidator* cdTextVal = new K3bCdTextValidator( this ); + m_editTitle->setValidator( cdTextVal ); + m_editPerformer->setValidator( cdTextVal ); + + m_allFieldsDlg->w->m_editTitle->setValidator( cdTextVal ); + m_allFieldsDlg->w->m_editPerformer->setValidator( cdTextVal ); + m_allFieldsDlg->w->m_editDisc_id->setValidator( cdTextVal ); + m_allFieldsDlg->w->m_editUpc_ean->setValidator( cdTextVal ); + m_allFieldsDlg->w->m_editMessage->setValidator( cdTextVal ); + m_allFieldsDlg->w->m_editArranger->setValidator( cdTextVal ); + m_allFieldsDlg->w->m_editSongwriter->setValidator( cdTextVal ); + m_allFieldsDlg->w->m_editComposer->setValidator( cdTextVal ); + + connect( m_allFieldsDlg->w->m_buttonCopyTitle, SIGNAL(clicked()), + this, SLOT(slotCopyTitle()) ); + connect( m_allFieldsDlg->w->m_buttonCopyPerformer, SIGNAL(clicked()), + this, SLOT(slotCopyPerformer()) ); + connect( m_allFieldsDlg->w->m_buttonCopyArranger, SIGNAL(clicked()), + this, SLOT(slotCopyArranger()) ); + connect( m_allFieldsDlg->w->m_buttonCopySongwriter, SIGNAL(clicked()), + this, SLOT(slotCopySongwriter()) ); + connect( m_allFieldsDlg->w->m_buttonCopyComposer, SIGNAL(clicked()), + this, SLOT(slotCopyComposer()) ); + + connect( m_buttonMoreFields, SIGNAL(clicked()), + this, SLOT(slotMoreFields()) ); +} + + +K3bAudioCdTextWidget::~K3bAudioCdTextWidget() +{ +} + +void K3bAudioCdTextWidget::load( K3bAudioDoc* doc ) +{ + m_doc = doc; + m_groupCdText->setChecked( doc->cdText() ); + + m_editTitle->setText( doc->title() ); + m_editPerformer->setText( doc->artist() ); + + m_allFieldsDlg->w->m_editTitle->setText( doc->title() ); + m_allFieldsDlg->w->m_editPerformer->setText( doc->artist() ); + m_allFieldsDlg->w->m_editDisc_id->setText( doc->disc_id() ); + m_allFieldsDlg->w->m_editUpc_ean->setText( doc->upc_ean() ); + m_allFieldsDlg->w->m_editArranger->setText( doc->arranger() ); + m_allFieldsDlg->w->m_editSongwriter->setText( doc->songwriter() ); + m_allFieldsDlg->w->m_editComposer->setText( doc->composer() ); + m_allFieldsDlg->w->m_editMessage->setText( doc->cdTextMessage() ); +} + +void K3bAudioCdTextWidget::save( K3bAudioDoc* doc ) +{ + m_doc = doc; + doc->writeCdText( m_groupCdText->isChecked() ); + + // we save the title and artist values from the main view since + // the dialog is only updated before it is shown + doc->setTitle( m_editTitle->text() ); + doc->setArtist( m_editPerformer->text() ); + doc->setDisc_id( m_allFieldsDlg->w->m_editDisc_id->text() ); + doc->setUpc_ean( m_allFieldsDlg->w->m_editUpc_ean->text() ); + doc->setArranger( m_allFieldsDlg->w->m_editArranger->text() ); + doc->setSongwriter( m_allFieldsDlg->w->m_editSongwriter->text() ); + doc->setComposer( m_allFieldsDlg->w->m_editComposer->text() ); + doc->setCdTextMessage( m_allFieldsDlg->w->m_editMessage->text() ); +} + + +void K3bAudioCdTextWidget::slotMoreFields() +{ + // update dlg to current state + m_allFieldsDlg->w->m_editTitle->setText( m_editTitle->text() ); + m_allFieldsDlg->w->m_editPerformer->setText( m_editPerformer->text() ); + + // save old settings + QString title = m_allFieldsDlg->w->m_editTitle->text(); + QString performer = m_allFieldsDlg->w->m_editPerformer->text(); + QString disc_id = m_allFieldsDlg->w->m_editDisc_id->text(); + QString upc_ean = m_allFieldsDlg->w->m_editUpc_ean->text(); + QString arranger = m_allFieldsDlg->w->m_editArranger->text(); + QString songwriter = m_allFieldsDlg->w->m_editSongwriter->text(); + QString composer = m_allFieldsDlg->w->m_editComposer->text(); + QString message = m_allFieldsDlg->w->m_editMessage->text(); + + // exec dlg + if( m_allFieldsDlg->exec() == QDialog::Accepted ) { + // accept new entries + m_editTitle->setText( m_allFieldsDlg->w->m_editTitle->text() ); + m_editPerformer->setText( m_allFieldsDlg->w->m_editPerformer->text() ); + } + else { + // reset + m_allFieldsDlg->w->m_editTitle->setText( title ); + m_allFieldsDlg->w->m_editPerformer->setText( performer ); + m_allFieldsDlg->w->m_editDisc_id->setText( disc_id ); + m_allFieldsDlg->w->m_editUpc_ean->setText( upc_ean ); + m_allFieldsDlg->w->m_editArranger->setText( arranger ); + m_allFieldsDlg->w->m_editSongwriter->setText( songwriter ); + m_allFieldsDlg->w->m_editComposer->setText( composer ); + m_allFieldsDlg->w->m_editMessage->setText( message ); + } +} + + +void K3bAudioCdTextWidget::setChecked( bool b ) +{ + m_groupCdText->setChecked( b ); +} + +bool K3bAudioCdTextWidget::isChecked() const +{ + return m_groupCdText->isChecked(); +} + + +void K3bAudioCdTextWidget::slotCopyTitle() +{ + K3bAudioTrack* track = m_doc->firstTrack(); + while( track ) { + track->setTitle( m_allFieldsDlg->isVisible() + ? m_allFieldsDlg->w->m_editTitle->text() + : m_editTitle->text() ); + track = track->next(); + } +} + +void K3bAudioCdTextWidget::slotCopyPerformer() +{ + K3bAudioTrack* track = m_doc->firstTrack(); + while( track ) { + track->setPerformer( m_allFieldsDlg->isVisible() + ? m_allFieldsDlg->w->m_editPerformer->text() + : m_editPerformer->text() ); + track = track->next(); + } +} + +void K3bAudioCdTextWidget::slotCopyArranger() +{ + K3bAudioTrack* track = m_doc->firstTrack(); + while( track ) { + track->setArranger( m_allFieldsDlg->w->m_editArranger->text() ); + track = track->next(); + } +} + +void K3bAudioCdTextWidget::slotCopySongwriter() +{ + K3bAudioTrack* track = m_doc->firstTrack(); + while( track ) { + track->setSongwriter( m_allFieldsDlg->w->m_editSongwriter->text() ); + track = track->next(); + } +} + +void K3bAudioCdTextWidget::slotCopyComposer() +{ + K3bAudioTrack* track = m_doc->firstTrack(); + while( track ) { + track->setComposer( m_allFieldsDlg->w->m_editComposer->text() ); + track = track->next(); + } +} + + +#include "k3baudiocdtextwidget.moc" diff --git a/src/projects/k3baudiocdtextwidget.h b/src/projects/k3baudiocdtextwidget.h new file mode 100644 index 0000000..49b579f --- /dev/null +++ b/src/projects/k3baudiocdtextwidget.h @@ -0,0 +1,55 @@ +/* + * + * $Id: k3baudiocdtextwidget.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef K3B_AUDIO_CDTEXT_WIDGET_H +#define K3B_AUDIO_CDTEXT_WIDGET_H + +#include "base_k3baudiocdtextwidget.h" + + +class K3bAudioDoc; + + +class K3bAudioCdTextWidget : public base_K3bAudioCdTextWidget +{ + Q_OBJECT + + public: + K3bAudioCdTextWidget( QWidget* parent = 0, const char* name = 0 ); + ~K3bAudioCdTextWidget(); + + bool isChecked() const; + + public slots: + void setChecked( bool ); + void load( K3bAudioDoc* ); + void save( K3bAudioDoc* ); + + private slots: + void slotCopyTitle(); + void slotCopyPerformer(); + void slotCopyArranger(); + void slotCopySongwriter(); + void slotCopyComposer(); + void slotMoreFields(); + + private: + K3bAudioDoc* m_doc; + + class AllFieldsDialog; + AllFieldsDialog* m_allFieldsDlg; +}; + +#endif diff --git a/src/projects/k3baudiodatasourceeditwidget.cpp b/src/projects/k3baudiodatasourceeditwidget.cpp new file mode 100644 index 0000000..d54bb5d --- /dev/null +++ b/src/projects/k3baudiodatasourceeditwidget.cpp @@ -0,0 +1,166 @@ +/* + * + * $Id: sourceheader 380067 2005-01-19 13:03:46Z trueg $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3baudiodatasourceeditwidget.h" +#include "k3baudioeditorwidget.h" +#include <k3bmsfedit.h> + +#include <k3baudiodatasource.h> + +#include <qlayout.h> +#include <qlabel.h> +#include <qtooltip.h> + +#include <klocale.h> +#include <kdialog.h> + + +K3bAudioDataSourceEditWidget::K3bAudioDataSourceEditWidget( QWidget* parent, const char* name ) + : QWidget( parent, name ), + m_source(0) +{ + m_editor = new K3bAudioEditorWidget( this ); + m_editStartOffset = new K3bMsfEdit( this ); + m_editEndOffset = new K3bMsfEdit( this ); + + QLabel* startLabel = new QLabel( i18n("Start Offset") + ":", this ); + QLabel* endLabel = new QLabel( i18n("End Offset") + ":", this ); + endLabel->setAlignment( Qt::AlignRight ); + + QGridLayout* grid = new QGridLayout( this ); + grid->setMargin( 0 ); + grid->setSpacing( KDialog::spacingHint() ); + + grid->addWidget( startLabel, 0, 0 ); + grid->addWidget( m_editStartOffset, 1, 0 ); + grid->addMultiCellWidget( m_editor, 0, 1, 1, 1 ); + grid->addWidget( endLabel, 0, 2 ); + grid->addWidget( m_editEndOffset, 1, 2 ); + grid->setColStretch( 1, 1 ); + + // setup connections between the msfedits and the editor + connect( m_editor, SIGNAL(rangeChanged(int, const K3b::Msf&, const K3b::Msf&)), + this, SLOT(slotRangeModified(int, const K3b::Msf&, const K3b::Msf&)) ); + + connect( m_editStartOffset, SIGNAL(valueChanged(const K3b::Msf&)), + this, SLOT(slotStartOffsetEdited(const K3b::Msf&)) ); + + connect( m_editEndOffset, SIGNAL(valueChanged(const K3b::Msf&)), + this, SLOT(slotEndOffsetEdited(const K3b::Msf&)) ); + + QToolTip::add( m_editor, i18n("Drag the edges of the highlighted area to define the portion of the " + "audio source you want to include in the Audio CD track. " + "You can also use the input windows to fine-tune your selection.") ); +} + + +K3bAudioDataSourceEditWidget::~K3bAudioDataSourceEditWidget() +{ +} + + +K3b::Msf K3bAudioDataSourceEditWidget::startOffset() const +{ + return m_editor->rangeStart( m_rangeId ); +} + + +K3b::Msf K3bAudioDataSourceEditWidget::endOffset() const +{ + return m_editor->rangeEnd( m_rangeId ); +} + + +void K3bAudioDataSourceEditWidget::loadSource( K3bAudioDataSource* source ) +{ + m_source = source; + + // remove old range + m_editor->removeRange( m_rangeId ); + + // and add the proper new range + // the source's end offset points after the last sector while + // the editor widget returns the last used sector + m_editor->setLength( source->originalLength() ); + m_rangeId = m_editor->addRange( source->startOffset(), + source->endOffset() == 0 + ? source->originalLength()-1 + : source->endOffset()-1, + false, + false, + i18n("Used part of the audio source"), + colorGroup().highlight() ); + + m_editStartOffset->setMaxValue( source->originalLength().lba() ); + m_editEndOffset->setMaxValue( source->originalLength().lba() ); + + m_editStartOffset->setMsfValue( startOffset() ); + m_editEndOffset->setMsfValue( endOffset() ); +} + + +void K3bAudioDataSourceEditWidget::saveSource() +{ + if( m_source ) { + m_source->setStartOffset( startOffset() ); + // the source's end offset points after the last sector while + // the editor widget returns the last used sector + m_source->setEndOffset( endOffset()+1 ); + } +} + + +void K3bAudioDataSourceEditWidget::setStartOffset( const K3b::Msf& msf ) +{ + if( m_source ) { + m_editor->modifyRange( m_rangeId, + msf, + endOffset() ); + } +} + + +void K3bAudioDataSourceEditWidget::setEndOffset( const K3b::Msf& msf ) +{ + if( m_source ) { + m_editor->modifyRange( m_rangeId, + startOffset(), + msf ); + } +} + + +void K3bAudioDataSourceEditWidget::slotRangeModified( int, const K3b::Msf& start, const K3b::Msf& end ) +{ + m_editStartOffset->setMsfValue( start ); + m_editEndOffset->setMsfValue( end ); +} + +void K3bAudioDataSourceEditWidget::slotStartOffsetEdited( const K3b::Msf& msf ) +{ + if( m_source ) { + m_editor->modifyRange( m_rangeId, msf, endOffset() ); + } +} + + +void K3bAudioDataSourceEditWidget::slotEndOffsetEdited( const K3b::Msf& msf ) +{ + if( m_source ) { + m_editor->modifyRange( m_rangeId, startOffset(), msf ); + } +} + +#include "k3baudiodatasourceeditwidget.moc" diff --git a/src/projects/k3baudiodatasourceeditwidget.h b/src/projects/k3baudiodatasourceeditwidget.h new file mode 100644 index 0000000..4c9d1cb --- /dev/null +++ b/src/projects/k3baudiodatasourceeditwidget.h @@ -0,0 +1,70 @@ +/* + * + * $Id: sourceheader 380067 2005-01-19 13:03:46Z trueg $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_AUDIODATASOURCE_EDITWIDGET_H_ +#define _K3B_AUDIODATASOURCE_EDITWIDGET_H_ + +#include <qwidget.h> +#include <k3bmsf.h> + +class K3bAudioDataSource; +class K3bAudioEditorWidget; +class K3bMsfEdit; + +/** + * Widget to modify the start and end offset of a source or simply change + * the length of a silence source. + */ +class K3bAudioDataSourceEditWidget : public QWidget +{ + Q_OBJECT + + public: + K3bAudioDataSourceEditWidget( QWidget* parent = 0, const char* name = 0 ); + ~K3bAudioDataSourceEditWidget(); + + K3b::Msf startOffset() const; + + /** + * Highest value (mening to use all the data up to the end of the source) + * is source::originalLength(). + * + * Be aware that this differs from K3bAudioDataSource::endOffset() which + * points after the last used sector for internal reasons. + */ + K3b::Msf endOffset() const; + + public slots: + void loadSource( K3bAudioDataSource* ); + void saveSource(); + + void setStartOffset( const K3b::Msf& ); + void setEndOffset( const K3b::Msf& ); + + private slots: + void slotRangeModified( int, const K3b::Msf&, const K3b::Msf& ); + void slotStartOffsetEdited( const K3b::Msf& ); + void slotEndOffsetEdited( const K3b::Msf& ); + + private: + K3bAudioDataSource* m_source; + int m_rangeId; + + K3bAudioEditorWidget* m_editor; + K3bMsfEdit* m_editStartOffset; + K3bMsfEdit* m_editEndOffset; +}; + +#endif diff --git a/src/projects/k3baudiodatasourceviewitem.cpp b/src/projects/k3baudiodatasourceviewitem.cpp new file mode 100644 index 0000000..6cf3004 --- /dev/null +++ b/src/projects/k3baudiodatasourceviewitem.cpp @@ -0,0 +1,111 @@ +/* + * + * $Id: k3baudiodatasourceviewitem.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3baudiodatasourceviewitem.h" +#include "k3baudiodatasource.h" +#include "k3baudiotrackviewitem.h" +#include "k3baudiozerodata.h" + +#include <k3bmsf.h> + +#include <kiconloader.h> + + +K3bAudioDataSourceViewItem::K3bAudioDataSourceViewItem( K3bAudioTrackViewItem* parent, + K3bAudioDataSourceViewItem* after, + K3bAudioDataSource* source ) + : K3bListViewItem( parent, after ), + m_trackViewItem( parent ), + m_source( source ), + m_animationCounter(1) +{ + // italic type + QFont f(listView()->font()); + f.setItalic( true ); + setFont( 3, f ); + + // setMarginVertical( 2 ); + + // gray out filename + setForegroundColor( 5, listView()->palette().disabled().foreground() ); + + // smaller filename + f = listView()->font(); + f.setPointSize( f.pointSize() - 2 ); + setFont( 5, f ); + + // for zero items we make the length editable + if( dynamic_cast<K3bAudioZeroData*>( source ) ) + setEditor( 4, MSF ); +} + + +QString K3bAudioDataSourceViewItem::text( int i ) const +{ + switch( i ) { + case 3: + return m_source->type(); + case 4: + return m_source->length().toString(); + case 5: + return m_source->sourceComment(); + default: + return QString::null; + } +} + + +void K3bAudioDataSourceViewItem::setText( int col, const QString& text ) +{ + // + // See K3bAudioTrackViewItem::setText for an explanation why we have to check if + // the value really changed + // + if( col == 4 ) { + if( K3bAudioZeroData* zero = dynamic_cast<K3bAudioZeroData*>( source() ) ) { + bool ok; + K3b::Msf f = K3b::Msf::fromString( text, &ok ); + if( ok && f != zero->length() ) + zero->setLength( f ); + } + } + else + KListViewItem::setText( col, text ); +} + + +bool K3bAudioDataSourceViewItem::animate() +{ + if( source()->length() == 0 && source()->isValid() ) { + QString icon = QString( "kde%1" ).arg( m_animationCounter ); + setPixmap( 4, SmallIcon( icon ) ); + m_animationCounter++; + if ( m_animationCounter > 6 ) + m_animationCounter = 1; + return true; + } + else { + // set status icon + setPixmap( 4, ( source()->isValid() ? SmallIcon( "greenled" ) : SmallIcon( "redled" ) ) ); + return false; + } +} + + +void K3bAudioDataSourceViewItem::setSelected( bool s ) +{ + if( s || !m_trackViewItem->isSelected() ) + K3bListViewItem::setSelected(s); +} diff --git a/src/projects/k3baudiodatasourceviewitem.h b/src/projects/k3baudiodatasourceviewitem.h new file mode 100644 index 0000000..14da1de --- /dev/null +++ b/src/projects/k3baudiodatasourceviewitem.h @@ -0,0 +1,54 @@ +/* + * + * $Id: k3baudiodatasourceviewitem.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_AUDIO_DATA_SOURCE_VIEWITEM_H_ +#define _K3B_AUDIO_DATA_SOURCE_VIEWITEM_H_ + +#include <k3blistview.h> + +class K3bAudioTrack; +class K3bAudioDataSource; +class K3bAudioTrackViewItem; + +class K3bAudioDataSourceViewItem : public K3bListViewItem +{ + public: + K3bAudioDataSourceViewItem( K3bAudioTrackViewItem* parent, + K3bAudioDataSourceViewItem* after, + K3bAudioDataSource* ); + + K3bAudioDataSource* source() const { return m_source; } + K3bAudioTrackViewItem* trackViewItem() const { return m_trackViewItem; } + + QString text( int i ) const; + void setText( int col, const QString& text ); + + bool animate(); + + void setSelected( bool s ); + + /** + * Does nothing becasue we don't want no branches here. + */ + void paintBranches( QPainter*, const QColorGroup &, + int, int, int ) {} + + private: + K3bAudioTrackViewItem* m_trackViewItem; + K3bAudioDataSource* m_source; + int m_animationCounter; +}; + +#endif diff --git a/src/projects/k3baudioeditorwidget.cpp b/src/projects/k3baudioeditorwidget.cpp new file mode 100644 index 0000000..453f76f --- /dev/null +++ b/src/projects/k3baudioeditorwidget.cpp @@ -0,0 +1,877 @@ +/* + * + * $Id: k3baudioeditorwidget.cpp 630444 2007-02-05 12:43:19Z trueg $ + * Copyright (C) 2004-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3baudioeditorwidget.h" + +#include <qpainter.h> +#include <qcolor.h> +#include <qpixmap.h> +#include <qcursor.h> +#include <qapplication.h> +#include <qdesktopwidget.h> +#include <qtooltip.h> + + + +class K3bAudioEditorWidget::Range +{ +public: + Range( int i, + const K3b::Msf& s, + const K3b::Msf& e, + bool sf, + bool ef, + const QString& t, + const QBrush& b ) + : id(i), + start(s), + end(e), + startFixed(sf), + endFixed(ef), + brush(b), + toolTip(t) { + } + + int id; + K3b::Msf start; + K3b::Msf end; + bool startFixed; + bool endFixed; + QBrush brush; + QString toolTip; + + bool operator<( const K3bAudioEditorWidget::Range& r ) { + return start < r.start; + } + bool operator>( const K3bAudioEditorWidget::Range& r ) { + return start > r.start; + } + bool operator==( const K3bAudioEditorWidget::Range& r ) { + return start == r.start; + } +}; + + +class K3bAudioEditorWidget::Marker +{ +public: + Marker( int i, + const K3b::Msf& msf, + bool f, + const QColor& c, + const QString& t ) + : id(i), + pos(msf), + fixed(f), + color(c), + toolTip(t) { + } + + int id; + K3b::Msf pos; + bool fixed; + QColor color; + QString toolTip; + + operator K3b::Msf& () { return pos; } +}; + + +class K3bAudioEditorWidget::RangeList : public QPtrList<K3bAudioEditorWidget::Range> +{ +public: + RangeList() + : QPtrList<Range>() { + } + + RangeList( const RangeList& l ) + : QPtrList<Range>( l ) { + } + + int compareItems( QPtrCollection::Item item1, QPtrCollection::Item item2 ) { + if( *static_cast<Range*>(item1) > *static_cast<Range*>(item2) ) + return 1; + else if( *static_cast<Range*>(item1) < *static_cast<Range*>(item2) ) + return -1; + else + return 0; + } +}; + +class K3bAudioEditorWidget::ToolTip : public QToolTip +{ +public: + ToolTip( K3bAudioEditorWidget* w ) + : QToolTip( w ), + m_editorWidget( w ) { + } + +protected: + void maybeTip( const QPoint& p ) { + QRect r = m_editorWidget->contentsRect(); + Marker* m = m_editorWidget->findMarker( p ); + if( m ) { + r.setLeft( p.x() - 1 ); + r.setRight( p.x() + 1 ); + tip( r, m->toolTip.isEmpty() ? m->pos.toString() : QString("%1 (%2)").arg(m->toolTip).arg(m->pos.toString()) ); + } + else { + Range* range = m_editorWidget->findRange( p ); + if( range ) { + r.setLeft( m_editorWidget->msfToPos( range->start ) ); + r.setRight( m_editorWidget->msfToPos( range->end ) ); + tip( r, + range->toolTip.isEmpty() + ? QString("%1 - %2").arg(range->start.toString()).arg(range->end.toString()) + : QString("%1 (%2 - %3)").arg(range->toolTip).arg(range->start.toString()).arg(range->end.toString()) ); + } + } + } + +private: + K3bAudioEditorWidget* m_editorWidget; +}; + + +class K3bAudioEditorWidget::Private +{ +public: + Private() + : allowOverlappingRanges(true), + rangeSelectionEnabled(false), + selectedRange(0), + movedRange(0) { + } + + QBrush selectedRangeBrush; + + bool allowOverlappingRanges; + bool rangeSelectionEnabled; + + Range* selectedRange; + Range* movedRange; + K3b::Msf lastMovePosition; + + RangeList ranges; +}; + + +K3bAudioEditorWidget::K3bAudioEditorWidget( QWidget* parent, const char* name ) + : QFrame( parent, name, Qt::WNoAutoErase ), + m_maxMarkers(1), + m_idCnt(1), + m_mouseAt(true), + m_draggedRange(0), + m_draggedMarker(0) +{ + d = new Private; + d->selectedRangeBrush = colorGroup().highlight(); + + setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Minimum ); + setFrameStyle( StyledPanel|Sunken ); + setMouseTracking(true); + setCursor( Qt::PointingHandCursor ); + + m_margin = 5; + + m_toolTip = new ToolTip( this ); +} + + +K3bAudioEditorWidget::~K3bAudioEditorWidget() +{ + d->ranges.setAutoDelete(true); + m_markers.setAutoDelete(true); + d->ranges.clear(); + m_markers.clear(); + + delete d; +} + + +QSize K3bAudioEditorWidget::minimumSizeHint() const +{ + constPolish(); + // some fixed height minimum and enough space for a tickmark every minute + // But never exceed 2/3 of the the screen width, otherwise it just looks ugly + // FIXME: this is still bad for long sources and there might be 60 minutes sources! + + int maxWidth = QApplication::desktop()->width()*2/3; + int wantedWidth = 2*m_margin + 2*frameWidth() + (m_length.totalFrames()/75/60 + 1) * fontMetrics().width( "000" ); + return QSize( QMIN( maxWidth, wantedWidth ), + 2*m_margin + 12 + 6 /*12 for the tickmarks and 6 for the markers */ + fontMetrics().height() + 2*frameWidth() ); +} + + +QSize K3bAudioEditorWidget::sizeHint() const +{ + return minimumSizeHint(); +} + + +void K3bAudioEditorWidget::setLength( const K3b::Msf& length ) +{ + m_length = length; + // TODO: remove markers beyond length + // TODO: shorten ranges if nesseccary + update(); +} + + +const K3b::Msf K3bAudioEditorWidget::length() const +{ + return m_length; +} + + +void K3bAudioEditorWidget::setSelectedRangeBrush( const QBrush& b ) +{ + d->selectedRangeBrush = b; +} + + +const QBrush& K3bAudioEditorWidget::selectedRangeBrush() const +{ + return d->selectedRangeBrush; +} + + +void K3bAudioEditorWidget::setAllowOverlappingRanges( bool b ) +{ + d->allowOverlappingRanges = b; +} + + +bool K3bAudioEditorWidget::allowOverlappingRanges() const +{ + return d->allowOverlappingRanges; +} + + +void K3bAudioEditorWidget::enableRangeSelection( bool b ) +{ + d->rangeSelectionEnabled = b; + repaint( false ); +} + + +bool K3bAudioEditorWidget::rangeSelectedEnabled() const +{ + return d->selectedRange; +} + + +void K3bAudioEditorWidget::setSelectedRange( int id ) +{ + setSelectedRange( getRange( id ) ); +} + + +void K3bAudioEditorWidget::setSelectedRange( K3bAudioEditorWidget::Range* r ) +{ + d->selectedRange = r; + if( rangeSelectedEnabled() ) { + repaint( false ); + emit selectedRangeChanged( d->selectedRange ? d->selectedRange->id : 0 ); + } +} + + +int K3bAudioEditorWidget::selectedRange() const +{ + if( d->selectedRange ) + return d->selectedRange->id; + else + return 0; +} + + +int K3bAudioEditorWidget::addRange( const K3b::Msf& start, const K3b::Msf& end, + bool startFixed, bool endFixed, + const QString& toolTip, + const QBrush& brush ) +{ + if( start > end || end > m_length-1 ) + return -1; + + Range* r = new Range( m_idCnt++, start, end, startFixed, endFixed, toolTip, + brush.style() != QBrush::NoBrush ? brush : QBrush(colorGroup().background()) ); + d->ranges.inSort( r ); + + // only update the changed range + QRect rect = contentsRect(); + rect.setLeft( msfToPos( start ) ); + rect.setRight( msfToPos( end ) ); + update( rect ); + + return r->id; +} + + +int K3bAudioEditorWidget::findRange( int pos ) const +{ + Range* r = findRange( QPoint( pos, 0 ) ); + if( r ) + return r->id; + else + return 0; +} + + +int K3bAudioEditorWidget::findRangeEdge( int pos, bool* end ) const +{ + Range* r = findRangeEdge( QPoint( pos, 0 ), end ); + if( r ) + return r->id; + else + return 0; +} + + +bool K3bAudioEditorWidget::modifyRange( int identifier, const K3b::Msf& start, const K3b::Msf& end ) +{ + Range* range = getRange( identifier ); + if( range ) { + if( start > end ) + return false; + + if( end > m_length ) + return false; + + range->start = start; + range->end = end; + + if( !d->allowOverlappingRanges ) + fixupOverlappingRanges( range ); + + repaint( false ); + + return true; + } + else + return false; +} + + +bool K3bAudioEditorWidget::removeRange( int identifier ) +{ + if( Range* range = getRange( identifier ) ) { + d->ranges.removeRef( range ); + + emit rangeRemoved( identifier ); + + // repaint only the part of the range + QRect rect = contentsRect(); + rect.setLeft( msfToPos( range->start ) ); + rect.setRight( msfToPos( range->end ) ); + + if( d->selectedRange == range ) + setSelectedRange( 0 ); + + delete range; + + update( rect ); + + return true; + } + else + return false; +} + + +K3b::Msf K3bAudioEditorWidget::rangeStart( int identifier ) const +{ + if( Range* range = getRange( identifier ) ) + return range->start; + else + return 0; +} + + +K3b::Msf K3bAudioEditorWidget::rangeEnd( int identifier ) const +{ + if( Range* range = getRange( identifier ) ) + return range->end; + else + return 0; +} + + +QValueList<int> K3bAudioEditorWidget::allRanges() const +{ + QValueList<int> l; + d->ranges.sort(); + for( QPtrListIterator<Range> it( d->ranges ); *it; ++it ) + l.append( (*it)->id ); + return l; +} + + +void K3bAudioEditorWidget::setMaxNumberOfMarkers( int i ) +{ + m_maxMarkers = i; + + // remove last markers + while( m_markers.count() > QMAX( 1, m_maxMarkers ) ) { + removeMarker( m_markers.getLast()->id ); + } +} + + +int K3bAudioEditorWidget::addMarker( const K3b::Msf& pos, bool fixed, const QString& toolTip, const QColor& color ) +{ + if( pos < m_length ) { + Marker* m = new Marker( m_idCnt++, pos, fixed, color.isValid() ? color : colorGroup().foreground(), toolTip ); + m_markers.inSort( m ); + return m->id; + } + else + return -1; +} + + +bool K3bAudioEditorWidget::removeMarker( int identifier ) +{ + if( Marker* m = getMarker( identifier ) ) { + m_markers.removeRef( m ); + + emit markerRemoved( identifier ); + + // TODO: in case a marker is bigger than one pixel this needs to be changed + QRect rect = contentsRect(); + rect.setLeft( msfToPos( m->pos ) ); + rect.setRight( msfToPos( m->pos ) ); + delete m; + + update( rect ); + + return true; + } + else + return false; +} + + +bool K3bAudioEditorWidget::moveMarker( int identifier, const K3b::Msf& pos ) +{ + if( pos < m_length ) + if( Marker* m = getMarker( identifier ) ) { + QRect rect = contentsRect(); + rect.setLeft( QMIN( msfToPos( pos ), msfToPos( m->pos ) ) ); + rect.setRight( QMAX( msfToPos( pos ), msfToPos( m->pos ) ) ); + + m->pos = pos; + + // TODO: in case a marker is bigger than one pixel this needs to be changed + update( rect ); + + return true; + } + + return false; +} + + +void K3bAudioEditorWidget::drawContents( QPainter* p ) +{ + // double buffering + QPixmap pix( contentsRect().size() ); + pix.fill( colorGroup().base() ); + + QPainter pixP; + pixP.begin( &pix, this ); + + QRect drawRect( contentsRect() ); + drawRect.setLeft( drawRect.left() + m_margin ); + drawRect.setRight( drawRect.right() - m_margin ); + + // from minimumSizeHint() +// int neededHeight = fontMetrics().height() + 12 + 6; + +// drawRect.setTop( drawRect.top() + (drawRect.height() - neededHeight)/2 ); +// drawRect.setHeight( neededHeight ); + + drawRect.setTop( drawRect.top() + m_margin ); + drawRect.setBottom( drawRect.bottom() - m_margin ); + + drawAll( &pixP, drawRect ); + + pixP.end(); + + QRect rect = p->clipRegion().boundingRect(); + QRect pixRect = rect; + pixRect.moveBy( -1*frameWidth(), -1*frameWidth() ); + bitBlt( this, rect.topLeft(), &pix, pixRect ); +} + + +void K3bAudioEditorWidget::drawAll( QPainter* p, const QRect& drawRect ) +{ + // we simply draw the ranges one after the other. + for( QPtrListIterator<Range> it( d->ranges ); *it; ++it ) + drawRange( p, drawRect, *it ); + + // Hack to make sure the currently selected range is always on top + if( d->selectedRange ) + drawRange( p, drawRect, d->selectedRange ); + + for( QPtrListIterator<Marker> it( m_markers ); *it; ++it ) + drawMarker( p, drawRect, *it ); + + + // left vline + p->drawLine( drawRect.left(), drawRect.top(), + drawRect.left(), drawRect.bottom() ); + + // timeline + p->drawLine( drawRect.left(), drawRect.bottom(), + drawRect.right(), drawRect.bottom() ); + + // right vline + p->drawLine( drawRect.right(), drawRect.top(), + drawRect.right(), drawRect.bottom() ); + + // draw minute markers every minute + int minute = 1; + int minuteStep = 1; + int markerVPos = drawRect.bottom(); + int maxMarkerWidth = fontMetrics().width( QString::number(m_length.minutes()) ); + int minNeededSpace = maxMarkerWidth + 1; + int x = 0; + while( minute*60*75 < m_length ) { + int newX = msfToPos( minute*60*75 ); + + // only draw the mark if we have anough space + if( newX - x >= minNeededSpace ) { + p->drawLine( newX, markerVPos, newX, markerVPos-5 ); + QRect txtRect( newX-(maxMarkerWidth/2), + markerVPos - 6 - fontMetrics().height(), + maxMarkerWidth, + fontMetrics().height() ); + p->drawText( txtRect, Qt::AlignCenter, QString::number(minute) ); + + // FIXME: draw second markers if we have enough space + + x = newX; + } + else { + minute -= minuteStep; + if( minuteStep == 1 ) + minuteStep = 5; + else + minuteStep *= 2; + } + + minute += minuteStep; + } +} + + +void K3bAudioEditorWidget::drawRange( QPainter* p, const QRect& drawRect, K3bAudioEditorWidget::Range* r ) +{ + p->save(); + + int start = msfToPos( r->start ); + int end = msfToPos( r->end ); + + if( rangeSelectedEnabled() && r == d->selectedRange ) + p->fillRect( start, drawRect.top() + 6 , end-start+1, drawRect.height() - 6, selectedRangeBrush() ); + else + p->fillRect( start, drawRect.top() + 6 , end-start+1, drawRect.height() - 6, r->brush ); + + p->drawRect( start, drawRect.top() + 6 , end-start+1, drawRect.height() - 6 ); + + p->restore(); +} + + +void K3bAudioEditorWidget::drawMarker( QPainter* p, const QRect& drawRect, K3bAudioEditorWidget::Marker* m ) +{ + p->save(); + + p->setPen( m->color ); + p->setBrush( m->color ); + + int x = msfToPos( m->pos ); + p->drawLine( x, drawRect.bottom(), x, drawRect.top() ); + + QPointArray points( 3 ); + points.setPoint( 0, x, drawRect.top() + 6 ); + points.setPoint( 1, x-3, drawRect.top() ); + points.setPoint( 2, x+3, drawRect.top() ); + p->drawPolygon( points ); + + p->restore(); +} + + +void K3bAudioEditorWidget::fixupOverlappingRanges( Range* r ) +{ + // copy the list to avoid problems with the iterator + RangeList ranges( d->ranges ); + for( QPtrListIterator<Range> it( ranges ); *it; ++it ) { + Range* range = *it; + if( range != r ) { + // remove the range if it is covered completely + if( range->start >= r->start && + range->end <= r->end ) { + d->ranges.removeRef( range ); + emit rangeRemoved( range->id ); + if( d->selectedRange == range ) + setSelectedRange( 0 ); + delete range; + } + // split the range if it contains r completely + else if( r->start >= range->start && + r->end <= range->end ) { + // create a new range that spans the part after r + addRange( r->end+1, range->end, + range->startFixed, range->endFixed, + range->toolTip, + range->brush ); + + // modify the old range to only span the part before r + range->end = r->start-1; + emit rangeChanged( range->id, range->start, range->end ); + } + else if( range->start >= r->start && range->start <= r->end ) { + range->start = r->end+1; + emit rangeChanged( range->id, range->start, range->end ); + } + else if( range->end >= r->start && range->end <= r->end ) { + range->end = r->start-1; + emit rangeChanged( range->id, range->start, range->end ); + } + } + } +} + + +void K3bAudioEditorWidget::mousePressEvent( QMouseEvent* e ) +{ + m_draggedRange = 0; + m_draggedMarker = 0; + + bool end; + if( Range* r = findRangeEdge( e->pos(), &end ) ) { + m_draggedRange = r; + m_draggingRangeEnd = end; + setSelectedRange( r ); + } + else { + Range* r = findRange( e->pos() ); + d->movedRange = r; + d->lastMovePosition = posToMsf( e->pos().x() ); + setSelectedRange( r ); + m_draggedMarker = findMarker( e->pos() ); + } + + QFrame::mousePressEvent(e); +} + + +void K3bAudioEditorWidget::mouseReleaseEvent( QMouseEvent* e ) +{ + if( !d->allowOverlappingRanges ) { + // + // modify and even delete ranges that we touched + // + if( m_draggedRange ) { + fixupOverlappingRanges( m_draggedRange ); + repaint( false ); + } + else if( d->movedRange ) { + fixupOverlappingRanges( d->movedRange ); + repaint( false ); + } + } + + m_draggedRange = 0; + m_draggedMarker = 0; + d->movedRange = 0; + + QFrame::mouseReleaseEvent(e); +} + + +void K3bAudioEditorWidget::mouseDoubleClickEvent( QMouseEvent* e ) +{ + QFrame::mouseDoubleClickEvent(e); +} + + +void K3bAudioEditorWidget::mouseMoveEvent( QMouseEvent* e ) +{ + if( m_mouseAt ) + emit mouseAt( posToMsf( e->pos().x() ) ); + + if( e->state() & Qt::LeftButton ) { + if( m_draggedRange ) { + // determine the position the range's end was dragged to and its other end + K3b::Msf msfPos = QMAX( 0, QMIN( posToMsf( e->pos().x() ), m_length-1 ) ); + K3b::Msf otherEnd = ( m_draggingRangeEnd ? m_draggedRange->start : m_draggedRange->end ); + + // move it to the new pos + if( m_draggingRangeEnd ) + m_draggedRange->end = msfPos; + else + m_draggedRange->start = msfPos; + + // if we pass the other end switch them + if( m_draggedRange->start > m_draggedRange->end ) { + K3b::Msf buf = m_draggedRange->start; + m_draggedRange->start = m_draggedRange->end; + m_draggedRange->end = buf; + m_draggingRangeEnd = !m_draggingRangeEnd; + } + + emit rangeChanged( m_draggedRange->id, m_draggedRange->start, m_draggedRange->end ); + + repaint( false ); + } + else if( m_draggedMarker ) { + m_draggedMarker->pos = posToMsf( e->pos().x() ); + emit markerMoved( m_draggedMarker->id, m_draggedMarker->pos ); + + repaint( false ); + } + else if( d->movedRange ) { + int diff = posToMsf( e->pos().x() ).lba() - d->lastMovePosition.lba(); + if( d->movedRange->end + diff >= m_length ) + diff = m_length.lba() - d->movedRange->end.lba() - 1; + else if( d->movedRange->start - diff < 0 ) + diff = -1 * d->movedRange->start.lba(); + d->movedRange->start += diff; + d->movedRange->end += diff; + +// if( !d->allowOverlappingRanges ) +// fixupOverlappingRanges( d->movedRange ); + + d->lastMovePosition = posToMsf( e->pos().x() ); + + emit rangeChanged( d->movedRange->id, d->movedRange->start, d->movedRange->end ); + + repaint( false ); + } + } + else if( findRangeEdge( e->pos() ) || findMarker( e->pos() ) ) + setCursor( Qt::SizeHorCursor ); + else + setCursor( Qt::PointingHandCursor ); + + QFrame::mouseMoveEvent(e); +} + + +K3bAudioEditorWidget::Range* K3bAudioEditorWidget::getRange( int i ) const +{ + for( QPtrListIterator<Range> it( d->ranges ); *it; ++it ) + if( (*it)->id == i ) + return *it; + + return 0; +} + + +K3bAudioEditorWidget::Range* K3bAudioEditorWidget::findRange( const QPoint& p ) const +{ + // TODO: binary search; maybe store start and end positions in sorted lists for quick searching + // this might be a stupid approach but we do not have many ranges anyway + for( QPtrListIterator<Range> it( d->ranges ); *it; ++it ) { + Range* range = *it; + int start = msfToPos( range->start ); + int end = msfToPos( range->end ); + + if( p.x() >= start && p.x() <= end ) { + return range; + } + } + return 0; +} + + +K3bAudioEditorWidget::Range* K3bAudioEditorWidget::findRangeEdge( const QPoint& p, bool* isEnd ) const +{ + // TODO: binary search + // this might be a stupid approach but we do not have many ranges anyway + for( QPtrListIterator<Range> it( d->ranges ); *it; ++it ) { + Range* range = *it; + int start = msfToPos( range->start ); + int end = msfToPos( range->end ); + + // + // In case two ranges meet at one point moving the mouse cursor deeper into one + // range allows for grabbing that end + // + + if( p.x() - 3 <= start && p.x() >= start && !range->startFixed ) { + if( isEnd ) + *isEnd = false; + return range; + } + else if( p.x() <= end && p.x() + 3 >= end && !range->endFixed ) { + if( isEnd ) + *isEnd = true; + return range; + } + } + return 0; +} + + +K3bAudioEditorWidget::Marker* K3bAudioEditorWidget::getMarker( int i ) const +{ + for( QPtrListIterator<Marker> it( m_markers ); *it; ++it ) + if( (*it)->id == i ) + return *it; + + return 0; +} + + +K3bAudioEditorWidget::Marker* K3bAudioEditorWidget::findMarker( const QPoint& p ) const +{ + // TODO: binary search + for( QPtrListIterator<Marker> it( m_markers ); *it; ++it ) { + Marker* marker = *it; + int start = msfToPos( marker->pos ); + + if( p.x() - 1 <= start && p.x() + 1 >= start && !marker->fixed ) + return marker; + } + + return 0; +} + + +// p is in widget coordinates +K3b::Msf K3bAudioEditorWidget::posToMsf( int p ) const +{ + int w = contentsRect().width() - 2*m_margin; + int x = QMIN( p-frameWidth()-m_margin, w ); + return ( (int)((double)(m_length.lba()-1) / (double)w * (double)x) ); +} + + +// returns widget coordinates +int K3bAudioEditorWidget::msfToPos( const K3b::Msf& msf ) const +{ + int w = contentsRect().width() - 2*m_margin; + int pos = (int)((double)w / (double)(m_length.lba()-1) * (double)msf.lba()); + return frameWidth() + m_margin + QMIN( pos, w-1 ); +} + + +#include "k3baudioeditorwidget.moc" diff --git a/src/projects/k3baudioeditorwidget.h b/src/projects/k3baudioeditorwidget.h new file mode 100644 index 0000000..6e939d7 --- /dev/null +++ b/src/projects/k3baudioeditorwidget.h @@ -0,0 +1,220 @@ +/* + * + * $Id: k3baudioeditorwidget.h 620140 2007-01-05 12:02:29Z trueg $ + * Copyright (C) 2004-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_AUDIO_EDITOR_WIDGET_H_ +#define _K3B_AUDIO_EDITOR_WIDGET_H_ + +#include <qframe.h> +#include <qptrlist.h> + +#include <k3bmsf.h> + + +class QPainter; + + +class K3bAudioEditorWidget : public QFrame +{ + Q_OBJECT + + public: + K3bAudioEditorWidget( QWidget* parent = 0, const char* name = 0 ); + ~K3bAudioEditorWidget(); + + QSize sizeHint() const; + QSize minimumSizeHint() const; + + /** + * For now the Editor has only one parameter: the length data. + */ + void setLength( const K3b::Msf& length ); + + const K3b::Msf length() const; + + /** + * Add a user editable range. + * @param startFixed if true the range's start cannot be changed by the user, only with modifyRange + * @param endFixed if true the range's end cannot be changed by the user, only with modifyRange + * @param brush if not specified or it has the NoBrush style one is chosen automatically. + * + * @return -1 on error or an identifier on success (be aware that the highest value for end is length-1) + */ + int addRange( const K3b::Msf& start, const K3b::Msf& end, + bool startFixed = false, bool endFixed = false, + const QString& toolTip = QString::null, + const QBrush& brush = QBrush() ); + + /** + * \returns the identifier of the range which spans over x position \a pos or + * 0 if no range is defined in this region. + */ + int findRange( int pos ) const; + + /** + * Searches for a range edge at x position \a pos. + * \return The ranges identifier if an edge could be found or 0 if there is no + * range edge at the position. + */ + int findRangeEdge( int pos, bool* end = 0 ) const; + + /** + * @returns false if the range does not exist or end was bigger than start. + */ + bool modifyRange( int identifier, const K3b::Msf& start, const K3b::Msf& end ); + + /** + * @returns false if the range does not exist. + */ + bool removeRange( int identifier ); + + K3b::Msf rangeStart( int identifier ) const; + K3b::Msf rangeEnd( int identifier ) const; + + /** + * \return A list of all ranges' identifiers sorted ascending by start + * offset + */ + QValueList<int> allRanges() const; + + void setMaxNumberOfMarkers( int ); + + /** + * @param fixed if true the marker cannot be changed by the user, only with moveMarker + * @return -1 on error or an identifier on success. + */ + int addMarker( const K3b::Msf& pos, bool fixed = false, + const QString& toolTip = QString::null, const QColor& color = QColor() ); + + /** + * @return false if the marker does not exist. + */ + bool removeMarker( int identifier ); + + /** + * @return false if the marker does not exist. + */ + bool moveMarker( int identifier, const K3b::Msf& ); + + void enableMouseAtSignal( bool b ) { m_mouseAt = b; } + + /** + * By default ranges can overlap. If overlapping ranges are not allowed + * the editor widget will modify and delete ranges accordingly. + * + * Caution: So far setting this will not check if ranges already overlap. + */ + void setAllowOverlappingRanges( bool b ); + + /** + * Range selection is by default disabled. If it is enabled the editor visually + * highlights the last clicked range. + * + * \sa setSelectedRange + */ + void enableRangeSelection( bool b ); + + bool allowOverlappingRanges() const; + bool rangeSelectedEnabled() const; + + void setSelectedRange( int id ); + + /** + * \return The identifier of the currently selected range or 0 + * if none is selected. + */ + int selectedRange() const; + + K3b::Msf posToMsf( int x ) const; + int msfToPos( const K3b::Msf& msf ) const; + + /** + * Set the brush to paint the selected range. Default is QColorGroup::Highlight + */ + void setSelectedRangeBrush( const QBrush& ); + const QBrush& selectedRangeBrush() const; + + signals: + /** + * Emitted when enabled. + */ + void mouseAt( const K3b::Msf& ); + + /** + * Emitted when the user changed a range. + * This signal is not emitted when a range is changed via modifyRange. + */ + void rangeChanged( int identifier, const K3b::Msf& start, const K3b::Msf& end ); + void rangeRemoved( int ); + + void selectedRangeChanged( int ); + + /** + * Emitted when the user moves a marker. + * This signal is not emitted when a marker is changed via moveMarker. + */ + void markerMoved( int identifier, const K3b::Msf& pos ); + void markerAdded( int identifier, const K3b::Msf& pos ); + void markerRemoved( int identifier ); + + private: + class Range; + class RangeList; + class Marker; + class ToolTip; + + class Private; + Private* d; + + void mousePressEvent( QMouseEvent* e ); + void mouseReleaseEvent( QMouseEvent* e ); + void mouseDoubleClickEvent( QMouseEvent* e ); + void mouseMoveEvent( QMouseEvent* e ); + void drawContents( QPainter* ); + void drawAll( QPainter*, const QRect& ); + void drawRange( QPainter* p, const QRect&, Range* r ); + void drawMarker( QPainter* p, const QRect&, Marker* m ); + + /** + * Makes sure that \a r does not overlap any other range by modifying and + * deleting other ranges. + */ + void fixupOverlappingRanges( Range* r ); + + Range* getRange( int i ) const; + Marker* getMarker( int i ) const; + Range* findRange( const QPoint& p ) const; + Range* findRangeEdge( const QPoint& p, bool* end = 0 ) const; + Marker* findMarker( const QPoint& p ) const; + void setSelectedRange( Range* ); + + int m_maxMarkers; + K3b::Msf m_length; + QPtrList<Marker> m_markers; + int m_idCnt; + bool m_mouseAt; + + /** + * Margin around the timethingy + */ + int m_margin; + + Range* m_draggedRange; + bool m_draggingRangeEnd; + Marker* m_draggedMarker; + + ToolTip* m_toolTip; +}; + +#endif diff --git a/src/projects/k3baudiotrackaddingdialog.cpp b/src/projects/k3baudiotrackaddingdialog.cpp new file mode 100644 index 0000000..dfbcbb9 --- /dev/null +++ b/src/projects/k3baudiotrackaddingdialog.cpp @@ -0,0 +1,302 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3baudiotrackaddingdialog.h" + +#include <k3baudiodoc.h> +#include <k3baudiotrack.h> +#include <k3baudiofile.h> +#include <k3baudiodecoder.h> +#include <k3bbusywidget.h> +#include <k3bglobals.h> +#include <k3bthread.h> +#include <k3bthreadjob.h> +#include <k3bcuefileparser.h> + +#include <klocale.h> +#include <kdebug.h> +#include <kmessagebox.h> + +#include <qlabel.h> +#include <qlayout.h> +#include <qfileinfo.h> +#include <qtimer.h> +#include <qdir.h> + + +class K3bAudioTrackAddingDialog::AnalyserThread : public K3bThread +{ +public: + AnalyserThread() + : K3bThread(), + m_decoder(0) { + } + + void run() { + emitStarted(); + m_decoder->analyseFile(); + emitFinished( m_decoder->isValid() ); + } + + K3bAudioDecoder* m_decoder; +}; + + +K3bAudioTrackAddingDialog::K3bAudioTrackAddingDialog( QWidget* parent, const char* name ) + : KDialogBase( Plain, + i18n("Please be patient..."), + Cancel, + Cancel, + parent, + name, + true, + true ), + m_bCanceled(false) +{ + QWidget* page = plainPage(); + QGridLayout* grid = new QGridLayout( page ); + grid->setSpacing( spacingHint() ); + grid->setMargin( marginHint() ); + + m_infoLabel = new QLabel( page ); + m_busyWidget = new K3bBusyWidget( page ); + + grid->addWidget( m_infoLabel, 0, 0 ); + grid->addWidget( m_busyWidget, 1, 0 ); + + m_analyserThread = new AnalyserThread(); + m_analyserJob = new K3bThreadJob( m_analyserThread, this, this ); + connect( m_analyserJob, SIGNAL(finished(bool)), this, SLOT(slotAnalysingFinished(bool)) ); +} + + +K3bAudioTrackAddingDialog::~K3bAudioTrackAddingDialog() +{ + delete m_analyserThread; +} + + +int K3bAudioTrackAddingDialog::addUrls( const KURL::List& urls, + K3bAudioDoc* doc, + K3bAudioTrack* afterTrack, + K3bAudioTrack* parentTrack, + K3bAudioDataSource* afterSource, + QWidget* parent ) +{ + if( urls.isEmpty() ) + return 0; + + K3bAudioTrackAddingDialog dlg( parent ); + dlg.m_urls = extractUrlList( urls ); + dlg.m_doc = doc; + dlg.m_trackAfter = afterTrack; + dlg.m_parentTrack = parentTrack; + dlg.m_sourceAfter = afterSource; + dlg.m_infoLabel->setText( i18n("Adding files to project \"%1\"...").arg(doc->URL().fileName()) ); + + dlg.m_busyWidget->showBusy(true); + QTimer::singleShot( 0, &dlg, SLOT(slotAddUrls()) ); + int ret = dlg.exec(); + + QString message; + if( !dlg.m_unreadableFiles.isEmpty() ) + message += QString("<p><b>%1:</b><br>%2") + .arg( i18n("Insufficient permissions to read the following files") ) + .arg( dlg.m_unreadableFiles.join( "<br>" ) ); + if( !dlg.m_notFoundFiles.isEmpty() ) + message += QString("<p><b>%1:</b><br>%2") + .arg( i18n("Unable to find the following files") ) + .arg( dlg.m_notFoundFiles.join( "<br>" ) ); + if( !dlg.m_nonLocalFiles.isEmpty() ) + message += QString("<p><b>%1:</b><br>%2") + .arg( i18n("No non-local files supported") ) + .arg( dlg.m_unreadableFiles.join( "<br>" ) ); + if( !dlg.m_unsupportedFiles.isEmpty() ) + message += QString("<p><b>%1:</b><br><i>%2</i><br>%3") + .arg( i18n("Unable to handle the following files due to an unsupported format" ) ) + .arg( i18n("You may manually convert these audio files to wave using another " + "application supporting the audio format and then add the wave files " + "to the K3b project.") ) + .arg( dlg.m_unsupportedFiles.join( "<br>" ) ); + + if( !message.isEmpty() ) + KMessageBox::detailedSorry( parent, i18n("Problems while adding files to the project."), message ); + + return ret; +} + + + +void K3bAudioTrackAddingDialog::slotAddUrls() +{ + if( m_bCanceled ) + return; + + if( m_urls.isEmpty() ) { + accept(); + return; + } + + KURL url = m_urls.first(); + bool valid = true; + + if( url.path().right(3).lower() == "cue" ) { + // see if its a cue file + K3bCueFileParser parser( url.path() ); + if( parser.isValid() && parser.toc().contentType() == K3bDevice::AUDIO ) { + // remember cue url and set the new audio file url + m_cueUrl = url; + url = m_urls[0] = KURL::fromPathOrURL( parser.imageFilename() ); + } + } + + m_infoLabel->setText( i18n("Analysing file '%1'...").arg( url.fileName() ) ); + + if( !url.isLocalFile() ) { + valid = false; + m_nonLocalFiles.append( url.path() ); + } + else { + QFileInfo fi( url.path() ); + if( !fi.exists() ) { + valid = false; + m_notFoundFiles.append( url.path() ); + } + else if( !fi.isReadable() ) { + valid = false; + m_unreadableFiles.append( url.path() ); + } + } + + if( valid ) { + bool reused; + K3bAudioDecoder* dec = m_doc->getDecoderForUrl( url, &reused ); + if( dec ) { + m_analyserThread->m_decoder = dec; + if( reused ) + slotAnalysingFinished( true ); + else + m_analyserJob->start(); + } + else { + valid = false; + m_unsupportedFiles.append( url.path() ); + } + } + + // invalid file, next url + if( !valid ) { + m_urls.remove( m_urls.begin() ); + QTimer::singleShot( 0, this, SLOT(slotAddUrls()) ); + } +} + + +void K3bAudioTrackAddingDialog::slotAnalysingFinished( bool /*success*/ ) +{ + if( m_bCanceled ) { + // We only started the analyser thread in case the decoder was new + // thus, we can safely delete it since no other source needs it. + delete m_analyserThread->m_decoder; + return; + } + + KURL url = m_urls.first(); + m_urls.remove( m_urls.begin() ); + + if( m_cueUrl.isValid() ) { + // import the cue file + m_doc->importCueFile( m_cueUrl.path(), m_trackAfter, m_analyserThread->m_decoder ); + m_cueUrl = KURL(); + } + else { + // create the track and source items + K3bAudioDecoder* dec = m_analyserThread->m_decoder; + K3bAudioFile* file = new K3bAudioFile( dec, m_doc ); + if( m_parentTrack ) { + if( m_sourceAfter ) + file->moveAfter( m_sourceAfter ); + else + file->moveAhead( m_parentTrack->firstSource() ); + m_sourceAfter = file; + } + else { + K3bAudioTrack* track = new K3bAudioTrack( m_doc ); + track->setFirstSource( file ); + + track->setTitle( dec->metaInfo( K3bAudioDecoder::META_TITLE ) ); + track->setArtist( dec->metaInfo( K3bAudioDecoder::META_ARTIST ) ); + track->setSongwriter( dec->metaInfo( K3bAudioDecoder::META_SONGWRITER ) ); + track->setComposer( dec->metaInfo( K3bAudioDecoder::META_COMPOSER ) ); + track->setCdTextMessage( dec->metaInfo( K3bAudioDecoder::META_COMMENT ) ); + + if( m_trackAfter ) + track->moveAfter( m_trackAfter ); + else + track->moveAfter( m_doc->lastTrack() ); + + m_trackAfter = track; + } + } + + QTimer::singleShot( 0, this, SLOT(slotAddUrls()) ); +} + + +void K3bAudioTrackAddingDialog::slotCancel() +{ + m_bCanceled = true; + m_analyserJob->cancel(); + KDialogBase::slotCancel(); +} + + +KURL::List K3bAudioTrackAddingDialog::extractUrlList( const KURL::List& urls ) +{ + KURL::List allUrls = urls; + KURL::List urlsFromPlaylist; + KURL::List::iterator it = allUrls.begin(); + while( it != allUrls.end() ) { + + const KURL& url = *it; + QFileInfo fi( url.path() ); + + if( fi.isDir() ) { + it = allUrls.remove( it ); + // add all files in the dir + QDir dir(fi.filePath()); + QStringList entries = dir.entryList( QDir::Files ); + KURL::List::iterator oldIt = it; + // add all files into the list after the current item + for( QStringList::iterator dirIt = entries.begin(); + dirIt != entries.end(); ++dirIt ) + it = allUrls.insert( oldIt, KURL::fromPathOrURL( dir.absPath() + "/" + *dirIt ) ); + } + else if( K3bAudioDoc::readPlaylistFile( url, urlsFromPlaylist ) ) { + it = allUrls.remove( it ); + KURL::List::iterator oldIt = it; + // add all files into the list after the current item + for( KURL::List::iterator dirIt = urlsFromPlaylist.begin(); + dirIt != urlsFromPlaylist.end(); ++dirIt ) + it = allUrls.insert( oldIt, *dirIt ); + } + else + ++it; + } + + return allUrls; +} + +#include "k3baudiotrackaddingdialog.moc" diff --git a/src/projects/k3baudiotrackaddingdialog.h b/src/projects/k3baudiotrackaddingdialog.h new file mode 100644 index 0000000..4590e95 --- /dev/null +++ b/src/projects/k3baudiotrackaddingdialog.h @@ -0,0 +1,106 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_AUDIO_TRACK_ADDING_DIALOG_H_ +#define _K3B_AUDIO_TRACK_ADDING_DIALOG_H_ + +#include <k3bjobhandler.h> +#include <kdialogbase.h> +#include <kurl.h> +#include <qstringlist.h> + + +class K3bBusyWidget; +class QLabel; +class K3bAudioTrack; +class K3bAudioDataSource; +class K3bThreadJob; +class K3bAudioDoc; + + +class K3bAudioTrackAddingDialog : public KDialogBase, public K3bJobHandler +{ + Q_OBJECT + + public: + ~K3bAudioTrackAddingDialog(); + + /** + * @reimplemented from K3bJobHandler + */ + int waitForMedia( K3bDevice::Device*, + int = K3bDevice::STATE_EMPTY, + int = K3bDevice::MEDIA_WRITABLE_CD, + const QString& = QString::null ) { return 0; } + + /** + * @reimplemented from K3bJobHandler + */ + bool questionYesNo( const QString&, + const QString& = QString::null, + const QString& = QString::null, + const QString& = QString::null ) { return false; } + + /** + * reimplemented from K3bJobHandler + */ + void blockingInformation( const QString&, + const QString& = QString::null ) {} + + /** + * \return \see QDialog::exec() + */ + static int addUrls( const KURL::List& urls, + K3bAudioDoc* doc, + K3bAudioTrack* afterTrack = 0, + K3bAudioTrack* parentTrack = 0, + K3bAudioDataSource* afterSource = 0, + QWidget* parent = 0 ); + + private slots: + void slotAddUrls(); + void slotAnalysingFinished( bool ); + void slotCancel(); + + private: + K3bAudioTrackAddingDialog( QWidget* parent = 0, const char* name = 0 ); + + static KURL::List extractUrlList( const KURL::List& urls ); + + K3bBusyWidget* m_busyWidget; + QLabel* m_infoLabel; + + QStringList m_unreadableFiles; + QStringList m_notFoundFiles; + QStringList m_nonLocalFiles; + QStringList m_unsupportedFiles; + + KURL::List m_urls; + + K3bAudioDoc* m_doc; + K3bAudioTrack* m_trackAfter; + K3bAudioTrack* m_parentTrack; + K3bAudioDataSource* m_sourceAfter; + + KURL m_cueUrl; + + bool m_bCanceled; + + class AnalyserThread; + AnalyserThread* m_analyserThread; + K3bThreadJob* m_analyserJob; +}; + +#endif diff --git a/src/projects/k3baudiotrackdialog.cpp b/src/projects/k3baudiotrackdialog.cpp new file mode 100644 index 0000000..ecb7796 --- /dev/null +++ b/src/projects/k3baudiotrackdialog.cpp @@ -0,0 +1,113 @@ +/* + * + * $Id: k3baudiotrackdialog.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include <qtextedit.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qgroupbox.h> +#include <qframe.h> +#include <qcheckbox.h> +#include <qcombobox.h> +#include <qhbox.h> +#include <qwhatsthis.h> + +#include <kiconloader.h> +#include <klocale.h> +#include <knuminput.h> +#include <kmimetype.h> +#include <kurl.h> +#include <kio/global.h> +#include <klineedit.h> + +#include "k3baudiotrackdialog.h" +#include "k3baudioeditorwidget.h" +#include "k3baudiotrackwidget.h" +#include "k3baudiotrack.h" +#include <k3bvalidators.h> +#include <kcutlabel.h> +#include <k3bmsf.h> +#include <k3bcdtextvalidator.h> +#include <k3baudiodecoder.h> +#include <k3bmsfedit.h> + + +// TODO: three modes: +// 1. Only one track with only one source +// show decoder tech info, cdtext, options and the track editor without showing anything +// about sources +// 2. Only one track with multible sources +// like the above but with the possiblity to edit the sources +// 3. multible tracks +// do only show cd-text and options (eventuelle index0) + + +K3bAudioTrackDialog::K3bAudioTrackDialog( QPtrList<K3bAudioTrack>& tracks, QWidget *parent, const char *name ) + : KDialogBase( KDialogBase::Plain, i18n("Audio Track Properties"), + KDialogBase::Ok|KDialogBase::Cancel|KDialogBase::Apply, + KDialogBase::Ok, parent, name ) +{ + m_tracks = tracks; + + setupGui(); + setupConnections(); +} + +K3bAudioTrackDialog::~K3bAudioTrackDialog() +{ +} + + +void K3bAudioTrackDialog::slotOk() +{ + slotApply(); + done(0); +} + + +void K3bAudioTrackDialog::slotApply() +{ + m_audioTrackWidget->save(); + +} + + +void K3bAudioTrackDialog::setupGui() +{ + QFrame* frame = plainPage(); + + QGridLayout* mainLayout = new QGridLayout( frame ); + mainLayout->setSpacing( spacingHint() ); + mainLayout->setMargin( 0 ); + + m_audioTrackWidget = new K3bAudioTrackWidget( m_tracks, frame ); + mainLayout->addWidget( m_audioTrackWidget, 0, 0 ); +} + +void K3bAudioTrackDialog::setupConnections() +{ +} + + +void K3bAudioTrackDialog::updateTrackLengthDisplay() +{ +// K3b::Msf len = m_editTrackEnd->msfValue() - m_editTrackStart->msfValue(); +// m_displayLength->setText( len.toString() ); +// m_displaySize->setText( KIO::convertSize(len.audioBytes()) ); +} + + + +#include "k3baudiotrackdialog.moc" diff --git a/src/projects/k3baudiotrackdialog.h b/src/projects/k3baudiotrackdialog.h new file mode 100644 index 0000000..53edc1c --- /dev/null +++ b/src/projects/k3baudiotrackdialog.h @@ -0,0 +1,57 @@ +/* + * + * $Id: k3baudiotrackdialog.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BAUDIOTRACKDIALOG_H +#define K3BAUDIOTRACKDIALOG_H + + +#include <kdialogbase.h> + +#include <k3bmsf.h> + +#include <qptrlist.h> + +class K3bAudioTrack; +class K3bAudioTrackWidget; + +/** + *@author Sebastian Trueg + */ + +class K3bAudioTrackDialog : public KDialogBase +{ + Q_OBJECT + + public: + K3bAudioTrackDialog( QPtrList<K3bAudioTrack>&, QWidget *parent=0, const char *name=0); + ~K3bAudioTrackDialog(); + + protected slots: + void slotOk(); + void slotApply(); + + void updateTrackLengthDisplay(); + + private: + QPtrList<K3bAudioTrack> m_tracks; + + K3bAudioTrackWidget* m_audioTrackWidget; + + void setupGui(); + void setupConnections(); +}; + +#endif diff --git a/src/projects/k3baudiotrackplayer.cpp b/src/projects/k3baudiotrackplayer.cpp new file mode 100644 index 0000000..cac2e7a --- /dev/null +++ b/src/projects/k3baudiotrackplayer.cpp @@ -0,0 +1,365 @@ +/* + * + * $Id: k3baudiotrackplayer.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3baudiotrackplayer.h" +#include <k3baudiodoc.h> +#include <k3baudiotrack.h> +#include <k3baudioserver.h> + +#include <kactionclasses.h> +#include <klocale.h> + +#include <qslider.h> +#include <qtimer.h> +#include <qmutex.h> +#include <qtooltip.h> + + +class K3bAudioTrackPlayer::Private +{ +public: + KAction* actionPlay; + KAction* actionPause; + KAction* actionPlayPause; + KAction* actionStop; + KAction* actionNext; + KAction* actionPrev; + KAction* actionSeek; + + // just to handle them easily; + KActionCollection* actionCollection; + + QSlider* seekSlider; + QTimer sliderTimer; + + // used to make sure that no seek and read operation occur in parallel + QMutex mutex; + + bool playing; + bool paused; +}; + + +K3bAudioTrackPlayer::K3bAudioTrackPlayer( K3bAudioDoc* doc, QObject* parent, const char* name ) + : QObject( parent, name ), + K3bAudioClient(), + m_doc( doc ), + m_currentTrack( 0 ) +{ + d = new Private; + d->paused = false; + d->playing = false; + + // TODO: handle the shortcuts: pass a widget to the action collection (perhaps the trackview?) + d->actionCollection = new KActionCollection( 0, this ); + + // create the actions + // TODO: create shortcuts (is there a way to let the user change them?) + d->actionPlay = new KAction( i18n("Play"), + "player_play", + KShortcut(), + this, SLOT(playPause()), + d->actionCollection, + "play" ); + d->actionPause = new KAction( i18n("Pause"), + "player_pause", + KShortcut(), + this, SLOT(playPause()), + d->actionCollection, + "pause" ); + d->actionPlayPause = new KAction( i18n("Play/Pause"), + "player_play", + KShortcut(), + this, SLOT(playPause()), + d->actionCollection, + "play_pause" ); + + d->actionStop = new KAction( i18n("Stop"), + "player_stop", + KShortcut(), + this, SLOT(stop()), + d->actionCollection, + "stop" ); + d->actionNext = new KAction( i18n("Next"), + "player_end", + KShortcut(), + this, SLOT(next()), + d->actionCollection, + "next" ); + d->actionPrev = new KAction( i18n("Prev"), + "player_start", + KShortcut(), + this, SLOT(prev()), + d->actionCollection, + "prev" ); + + d->seekSlider = new QSlider( 0, 100, 1, 0, Qt::Horizontal, 0, "audiotrackplayerslider" ); + connect( d->seekSlider, SIGNAL(sliderMoved(int)), this, SLOT(slotSeek(int)) ); + // FIXME: maybe it's not such a good idea to use a KWidgetAction here since this way the player + // can only be used once in one widget. If the action would always create a new slider we could plug + // the action into several toolboxes and also use it in some resizing or track splitting dialogs. + d->actionSeek = new KWidgetAction( d->seekSlider, + i18n("Seek"), + KShortcut(), + 0, + 0, + d->actionCollection, + "seek" ); + // this should be done in KWidgetAction but is not yet + connect( d->actionSeek, SIGNAL(enabled(bool)), d->seekSlider, SLOT(setEnabled(bool)) ); + + d->actionStop->setEnabled(false); + d->actionPause->setEnabled(false); + d->actionNext->setEnabled(false); + d->actionPrev->setEnabled(false); + d->actionSeek->setEnabled(false); + + connect( m_doc, SIGNAL(changed()), + this, SLOT(slotDocChanged()) ); + connect( m_doc, SIGNAL(trackChanged(K3bAudioTrack*)), + this, SLOT(slotTrackChanged(K3bAudioTrack*)) ); + connect( m_doc, SIGNAL(trackRemoved(K3bAudioTrack*)), + this, SLOT(slotTrackRemoved(K3bAudioTrack*)) ); + connect( &d->sliderTimer, SIGNAL(timeout()), + this, SLOT(slotUpdateSlider()) ); + + // we just stop the player if the audio server has an error. K3bMainWindow will show the error message + // This is all very hacky and has to be improved for K3b 2.0. But then we will probably use Phonon anyway... + connect( K3bAudioServer::instance(), SIGNAL(error(const QString&)), this, SLOT(stop()) ); + + // tooltips + d->actionPlay->setToolTip( i18n("Play") ); + d->actionStop->setToolTip( i18n("Stop") ); + d->actionPause->setToolTip( i18n("Pause") ); + d->actionNext->setToolTip( i18n("Next") ); + d->actionPrev->setToolTip( i18n("Previous") ); +} + + +K3bAudioTrackPlayer::~K3bAudioTrackPlayer() +{ + stop(); + delete d->seekSlider; + delete d; +} + + +KAction* K3bAudioTrackPlayer::action( int action ) const +{ + switch( action ) { + case ACTION_PLAY: + return d->actionPlay; + case ACTION_PAUSE: + return d->actionPause; + case ACTION_PLAY_PAUSE: + return d->actionPlayPause; + case ACTION_STOP: + return d->actionStop; + case ACTION_NEXT: + return d->actionNext; + case ACTION_PREV: + return d->actionPrev; + case ACTION_SEEK: + return d->actionSeek; + default: + return 0; + } +} + + +void K3bAudioTrackPlayer::playTrack( K3bAudioTrack* track ) +{ + if( track ) { + // we show the currently playing track as a tooltip on the slider + QToolTip::remove( d->seekSlider ); + QToolTip::add( d->seekSlider, i18n("Playing track %1: %2 - %3") + .arg(track->trackNumber()) + .arg(track->artist()) + .arg(track->title()) ); + d->seekSlider->setMaxValue( track->length().totalFrames() ); + m_currentTrack = track; + d->paused = true; + + d->actionNext->setEnabled( m_currentTrack->next() != 0 ); + d->actionPrev->setEnabled( m_currentTrack->prev() != 0 ); + + seek(0); + playPause(); + + emit playingTrack( track ); + } +} + + +void K3bAudioTrackPlayer::playPause() +{ + if( !m_currentTrack ) { + playTrack( m_doc->firstTrack() ); + } + else { + if( !d->playing ) { + seek( m_currentPosition ); + d->playing = true; + d->actionPlayPause->setIcon( "player_pause" ); + d->actionPause->setEnabled(true); + d->actionPlay->setEnabled(false); + d->actionSeek->setEnabled(true); + startStreaming(); + d->sliderTimer.start(1000); + } + else if( d->paused ) { + d->paused = false; + d->actionPlayPause->setIcon( "player_pause" ); + d->actionPause->setEnabled(true); + d->actionPlay->setEnabled(false); + startStreaming(); + d->sliderTimer.start(1000); + + emit paused( false ); + } + else { + d->paused = true; + d->actionPlayPause->setIcon( "player_play" ); + d->actionPause->setEnabled(false); + d->actionPlay->setEnabled(true); + stopStreaming(); + d->sliderTimer.stop(); + + emit paused( true ); + } + + d->actionStop->setEnabled(true); + } +} + + +void K3bAudioTrackPlayer::stop() +{ + m_currentTrack = 0; + m_currentPosition = 0; + stopStreaming(); + d->paused = false; + d->playing = false; + d->actionStop->setEnabled(false); + d->actionPause->setEnabled(false); + d->actionPlay->setEnabled(true); + d->actionSeek->setEnabled(false); + d->actionNext->setEnabled(false); + d->actionPrev->setEnabled(false); + + d->actionPlayPause->setIcon( "player_play" ); + + emit stopped(); +} + + +void K3bAudioTrackPlayer::next() +{ + if( m_currentTrack && m_currentTrack->next() ) { + playTrack( m_currentTrack->next() ); + } +} + + +void K3bAudioTrackPlayer::prev() +{ + if( m_currentTrack && m_currentTrack->prev() ) { + playTrack( m_currentTrack->prev() ); + } +} + + +void K3bAudioTrackPlayer::seek( const K3b::Msf& msf ) +{ + if( m_currentTrack ) { + if( msf < m_currentTrack->length() ) { + d->mutex.lock(); + m_currentTrack->seek( msf ); + m_currentPosition = msf; + slotUpdateSlider(); + d->mutex.unlock(); + } + else + next(); + } +} + + +void K3bAudioTrackPlayer::slotSeek( int frames ) +{ + seek( K3b::Msf( frames ) ); +} + + +int K3bAudioTrackPlayer::read( char* data, int maxlen ) +{ + if( m_currentTrack ) { + d->mutex.lock(); + int len = m_currentTrack->read( data, maxlen ); + d->mutex.unlock(); + if( len > 0 ) { + m_currentPosition += (int)( (double)len / 2352.0 + 0.5 ); + } + else if( m_currentTrack->next() ) { + // play the next track + next(); + return read( data, maxlen ); + } + else { + stop(); + return -1; // no more tracks + } + + return len; + } + else + return -1; +} + + +void K3bAudioTrackPlayer::slotTrackRemoved( K3bAudioTrack* track ) +{ + if( m_currentTrack == track ) { + stop(); + m_currentTrack = 0; + } +} + + +void K3bAudioTrackPlayer::slotTrackChanged( K3bAudioTrack* track ) +{ + if( m_currentTrack == track ) { + d->seekSlider->setMaxValue( track->length().totalFrames() ); + } +} + + +void K3bAudioTrackPlayer::slotUpdateSlider() +{ + d->seekSlider->setValue( m_currentPosition.totalFrames() ); +} + + +void K3bAudioTrackPlayer::slotDocChanged() +{ + // update the controls in case a new track has been added before or after + // the current one and it has been the first or last track + if( m_currentTrack ) { + d->actionNext->setEnabled( m_currentTrack->next() != 0 ); + d->actionPrev->setEnabled( m_currentTrack->prev() != 0 ); + } +} + +#include "k3baudiotrackplayer.moc" diff --git a/src/projects/k3baudiotrackplayer.h b/src/projects/k3baudiotrackplayer.h new file mode 100644 index 0000000..92f4f0a --- /dev/null +++ b/src/projects/k3baudiotrackplayer.h @@ -0,0 +1,87 @@ +/* + * + * $Id: k3baudiotrackplayer.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_AUDIO_TRACK_PLAYER_H_ +#define _K3B_AUDIO_TRACK_PLAYER_H_ + +#include <qobject.h> + +#include <k3baudioclient.h> + +#include <k3bmsf.h> + +class K3bAudioDoc; +class K3bAudioTrack; +class KAction; + + +class K3bAudioTrackPlayer : public QObject, public K3bAudioClient +{ + Q_OBJECT + + public: + K3bAudioTrackPlayer( K3bAudioDoc* doc, QObject* parent = 0, const char* name = 0 ); + ~K3bAudioTrackPlayer(); + + K3bAudioTrack* currentPlayingTrack() const { return m_currentTrack; } + const K3b::Msf& currentPosition() const { return m_currentPosition; } + + enum Actions { + ACTION_PLAY, + ACTION_PAUSE, + ACTION_PLAY_PAUSE, + ACTION_STOP, + ACTION_NEXT, + ACTION_PREV, + ACTION_SEEK + }; + + KAction* action( int action ) const; + + /** + * Reimplemented from K3bAudioClient + */ + int read( char* data, int maxlen ); + + public slots: + void playTrack( K3bAudioTrack* ); + void playPause(); + void stop(); + void next(); + void prev(); + void seek( const K3b::Msf& ); + + signals: + void playingTrack( K3bAudioTrack* ); + void paused( bool paused ); + void stopped(); + + private slots: + void slotSeek( int ); + void slotTrackChanged( K3bAudioTrack* track ); + void slotTrackRemoved( K3bAudioTrack* track ); + void slotUpdateSlider(); + void slotDocChanged(); + + private: + K3bAudioDoc* m_doc; + K3bAudioTrack* m_currentTrack; + K3b::Msf m_currentPosition; + + class Private; + Private* d; +}; + +#endif diff --git a/src/projects/k3baudiotracksplitdialog.cpp b/src/projects/k3baudiotracksplitdialog.cpp new file mode 100644 index 0000000..1acd370 --- /dev/null +++ b/src/projects/k3baudiotracksplitdialog.cpp @@ -0,0 +1,232 @@ +/* + * + * $Id: k3baudiotracksplitdialog.cpp 630444 2007-02-05 12:43:19Z trueg $ + * Copyright (C) 2004-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3baudiotracksplitdialog.h" +#include "k3baudiotrack.h" +#include "k3baudioeditorwidget.h" + +#include <k3bmsf.h> +#include <k3bmsfedit.h> + +#include <klocale.h> +#include <kactioncollection.h> +#include <kaction.h> +#include <kpopupmenu.h> + +#include <qlabel.h> +#include <qframe.h> +#include <qlayout.h> + + +K3bAudioTrackSplitDialog::K3bAudioTrackSplitDialog( K3bAudioTrack* track, QWidget* parent, const char* name ) + : KDialogBase( KDialogBase::Plain, i18n("Split Audio Track"), + KDialogBase::Ok|KDialogBase::Cancel, + KDialogBase::Ok, parent, name ), + m_track(track) +{ + QFrame* frame = plainPage(); + + m_editorWidget = new K3bAudioEditorWidget( frame ); + m_msfEditStart = new K3bMsfEdit( frame ); + m_msfEditEnd = new K3bMsfEdit( frame ); + + QGridLayout* layout = new QGridLayout( frame ); + layout->setMargin( 0 ); + layout->setSpacing( spacingHint() ); + + // FIXME: After the string freeze replace the text with a better one explaning how to use this dialog + layout->addMultiCellWidget( new QLabel( i18n("Please select the position where the track should be split."), + frame ), 0, 0, 0, 3 ); + layout->addMultiCellWidget( m_editorWidget, 1, 1, 0, 3 ); + layout->addWidget( m_msfEditStart, 2, 1 ); + layout->addWidget( new QLabel( " - ", frame ), 2, 2 ); + layout->addWidget( m_msfEditEnd, 2, 3 ); + layout->addWidget( new QLabel( i18n("Split track at:"), frame ), 2, 0 ); + layout->setColStretch( 0, 1 ); + + m_editorWidget->setAllowOverlappingRanges( false ); + m_editorWidget->enableRangeSelection( true ); + m_editorWidget->installEventFilter( this ); + + connect( m_editorWidget, SIGNAL(rangeChanged(int, const K3b::Msf&, const K3b::Msf&)), + this, SLOT(slotRangeModified(int, const K3b::Msf&, const K3b::Msf&)) ); + connect( m_editorWidget, SIGNAL(selectedRangeChanged(int)), + this, SLOT(slotRangeSelectionChanged(int)) ); + connect( m_msfEditStart, SIGNAL(valueChanged(const K3b::Msf&)), + this, SLOT(slotMsfEditChanged(const K3b::Msf&)) ); + connect( m_msfEditEnd, SIGNAL(valueChanged(const K3b::Msf&)), + this, SLOT(slotMsfEditChanged(const K3b::Msf&)) ); + + setupActions(); + + // load the track + m_editorWidget->setLength( m_track->length() ); + + // default split + K3b::Msf mid = m_track->length().lba() / 2; + m_editorWidget->addRange( 0, mid-1 ); + m_editorWidget->addRange( mid, m_track->length()-1 ); + + slotRangeSelectionChanged( 0 ); +} + + +K3bAudioTrackSplitDialog::~K3bAudioTrackSplitDialog() +{ +} + + +void K3bAudioTrackSplitDialog::setupActions() +{ + m_actionCollection = new KActionCollection( this ); + m_popupMenu = new KPopupMenu( this ); + + KAction* actionSplitHere = new KAction( i18n("Split Here"), 0, + KShortcut(), this, SLOT(slotSplitHere()), + actionCollection(), "range_split" ); + // FIXME: after the message freeze give this action a proper name like "Remove track part" + KAction* actionRemoveRange = new KAction( i18n("Remove this Range"), 0, + KShortcut(), this, SLOT(slotRemoveRange()), + actionCollection(), "range_remove" ); + + actionSplitHere->plug( m_popupMenu ); + actionRemoveRange->plug( m_popupMenu ); +} + + +void K3bAudioTrackSplitDialog::slotRangeModified( int id, const K3b::Msf& start, const K3b::Msf& end ) +{ + if( id == m_editorWidget->selectedRange() ) { + m_msfEditStart->blockSignals( true ); + m_msfEditEnd->blockSignals( true ); + + m_msfEditStart->setMsfValue( start ); + m_msfEditEnd->setMsfValue( end ); + + m_msfEditStart->blockSignals( false ); + m_msfEditEnd->blockSignals( false ); + } +} + + +void K3bAudioTrackSplitDialog::slotMsfEditChanged( const K3b::Msf& ) +{ + m_editorWidget->modifyRange( m_editorWidget->selectedRange(), m_msfEditStart->msfValue(), m_msfEditEnd->msfValue() ); +} + + +void K3bAudioTrackSplitDialog::slotRangeSelectionChanged( int id ) +{ + if( id > 0 ) { + m_msfEditStart->blockSignals( true ); + m_msfEditEnd->blockSignals( true ); + + m_msfEditStart->setMsfValue( m_editorWidget->rangeStart( id ) ); + m_msfEditEnd->setMsfValue( m_editorWidget->rangeEnd( id ) ); + m_msfEditStart->setEnabled( true ); + m_msfEditEnd->setEnabled( true ); + + m_msfEditStart->blockSignals( false ); + m_msfEditEnd->blockSignals( false ); + } + else { + m_msfEditStart->setEnabled( false ); + m_msfEditEnd->setEnabled( false ); + } +} + + +void K3bAudioTrackSplitDialog::splitAt( const QPoint& p ) +{ + int id = m_editorWidget->findRange( p.x() ); + if( id ) { + K3b::Msf msf = m_editorWidget->posToMsf( p.x() ); + m_editorWidget->addRange( msf+1, m_editorWidget->rangeEnd( id ) ); + m_editorWidget->modifyRange( id, m_editorWidget->rangeStart( id ), msf ); + slotRangeSelectionChanged( m_editorWidget->selectedRange() ); + } +} + + +bool K3bAudioTrackSplitDialog::eventFilter( QObject* o, QEvent* e ) +{ + if( o == m_editorWidget ) { + if( e->type() == QEvent::MouseButtonDblClick ) { + QMouseEvent* me = static_cast<QMouseEvent*>( e ); + splitAt( me->pos() ); + } + else if( e->type() == QEvent::ContextMenu ) { + QContextMenuEvent* ce = static_cast<QContextMenuEvent*>( e ); + ce->consume(); + m_lastClickPosition = ce->pos(); + if( m_editorWidget->findRange( ce->pos().x() ) > 0 ) + m_popupMenu->popup( ce->globalPos() ); + } + } + + return KDialogBase::eventFilter( o, e ); +} + + +void K3bAudioTrackSplitDialog::slotSplitHere() +{ + splitAt( m_lastClickPosition ); +} + + +void K3bAudioTrackSplitDialog::slotRemoveRange() +{ + m_editorWidget->removeRange( m_editorWidget->findRange( m_lastClickPosition.x() ) ); +} + + +void K3bAudioTrackSplitDialog::splitTrack( K3bAudioTrack* track, + QWidget* parent, + const char* name ) +{ + K3bAudioTrackSplitDialog d( track, parent, name ); + if( d.exec() == QDialog::Accepted ) { + QValueList<int> ranges = d.m_editorWidget->allRanges(); + // we split the track at all range ends and just delete those that relate to the gaps in between + K3b::Msf pos = 0; + for( QValueList<int>::const_iterator it = ranges.constBegin(); + it != ranges.constEnd(); ++it ) { + + // delete the unwanted part + if( d.m_editorWidget->rangeStart( *it ) > pos ) { + // split so the range's start is the first frame of the new track + K3bAudioTrack* nextTrack = track->split( d.m_editorWidget->rangeStart( *it ) - pos ); + delete track; + track = nextTrack; + } + + // create a new track part for the range itself + pos = d.m_editorWidget->rangeStart( *it ); + if( d.m_editorWidget->rangeEnd( *it ) < d.m_editorWidget->length()-1 ) { + // split so the range's end is the last frame in the old track + // and thus, the range's end + 1 the first frame in the new track + track = track->split( d.m_editorWidget->rangeEnd( *it ) - pos + 1 ); + } + pos = d.m_editorWidget->rangeEnd( *it )+1; + } + + // remove the last unwanted part + if( pos < d.m_editorWidget->length() ) { + delete track; + } + } +} + +#include "k3baudiotracksplitdialog.moc" diff --git a/src/projects/k3baudiotracksplitdialog.h b/src/projects/k3baudiotracksplitdialog.h new file mode 100644 index 0000000..c4be91a --- /dev/null +++ b/src/projects/k3baudiotracksplitdialog.h @@ -0,0 +1,71 @@ +/* + * + * $Id: k3baudiotracksplitdialog.h 620140 2007-01-05 12:02:29Z trueg $ + * Copyright (C) 2004-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_AUDIO_TRACK_SPLIT_DIALOG_H_ +#define _K3B_AUDIO_TRACK_SPLIT_DIALOG_H_ + +#include <kdialogbase.h> + +namespace K3b { + class Msf; +} +class K3bAudioTrack; +class K3bAudioEditorWidget; +class K3bMsfEdit; +class KActionCollection; +class KPopupMenu; + + +/** + * Internally used by K3bAudioTrackView to get an msf value from the user. + */ +class K3bAudioTrackSplitDialog : public KDialogBase +{ + Q_OBJECT + + public: + K3bAudioTrackSplitDialog( K3bAudioTrack*, QWidget* parent = 0, const char* name = 0 ); + ~K3bAudioTrackSplitDialog(); + + bool eventFilter( QObject* o, QEvent* e ); + + KActionCollection* actionCollection() const { return m_actionCollection; } + + /** + * if this method returns true val is filled with the user selected value. + */ + static void splitTrack( K3bAudioTrack* track, QWidget* parent = 0, const char* name = 0 ); + + private slots: + void slotRangeModified( int, const K3b::Msf& start, const K3b::Msf& ); + void slotMsfEditChanged( const K3b::Msf& msf ); + void slotRangeSelectionChanged( int ); + void slotSplitHere(); + void slotRemoveRange(); + void splitAt( const QPoint& p ); + + private: + void setupActions(); + + K3bAudioEditorWidget* m_editorWidget; + K3bMsfEdit* m_msfEditStart; + K3bMsfEdit* m_msfEditEnd; + K3bAudioTrack* m_track; + KActionCollection* m_actionCollection; + KPopupMenu* m_popupMenu; + QPoint m_lastClickPosition; +}; + +#endif diff --git a/src/projects/k3baudiotracktrmlookupdialog.cpp b/src/projects/k3baudiotracktrmlookupdialog.cpp new file mode 100644 index 0000000..b537583 --- /dev/null +++ b/src/projects/k3baudiotracktrmlookupdialog.cpp @@ -0,0 +1,131 @@ +/* + * + * $Id: k3baudiotracktrmlookupdialog.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include <config.h> + +#ifdef HAVE_MUSICBRAINZ + +#include "k3baudiotracktrmlookupdialog.h" +#include "k3bmusicbrainzjob.h" + +#include <k3bbusywidget.h> +#include <k3baudiotrack.h> +#include <k3baudiofile.h> +#include <k3bpassivepopup.h> + +#include <kmessagebox.h> +#include <kinputdialog.h> +#include <klocale.h> +#include <kiconloader.h> +#include <kglobal.h> +#include <kdebug.h> + +#include <qlabel.h> +#include <qlayout.h> +#include <qtimer.h> +#include <qframe.h> +#include <qeventloop.h> +#include <qpushbutton.h> +#include <qapplication.h> + + +K3bAudioTrackTRMLookupDialog::K3bAudioTrackTRMLookupDialog( QWidget* parent, const char* name ) + : KDialogBase( KDialogBase::Plain, + i18n("MusicBrainz Query"), + KDialogBase::Cancel, + KDialogBase::Cancel, + parent, + name, + true, + true ) +{ + QGridLayout* grid = new QGridLayout( plainPage() ); + grid->setMargin( marginHint() ); + grid->setSpacing( spacingHint() ); + + m_infoLabel = new QLabel( plainPage() ); + QLabel* pixLabel = new QLabel( plainPage() ); + pixLabel->setPixmap( KGlobal::iconLoader()->loadIcon( "musicbrainz", KIcon::NoGroup, 64 ) ); + pixLabel->setScaledContents( false ); + + m_busyWidget = new K3bBusyWidget( plainPage() ); + + grid->addMultiCellWidget( pixLabel, 0, 1, 0, 0 ); + grid->addWidget( m_infoLabel, 0, 1 ); + grid->addWidget( m_busyWidget, 1, 1 ); + + m_inLoop = false; + m_mbJob = new K3bMusicBrainzJob( this ); + connect( m_mbJob, SIGNAL(infoMessage(const QString&, int)), + this, SLOT(slotMbJobInfoMessage(const QString&, int)) ); + connect( m_mbJob, SIGNAL(finished(bool)), this, SLOT(slotMbJobFinished(bool)) ); + connect( m_mbJob, SIGNAL(trackFinished(K3bAudioTrack*, bool)), + this, SLOT(slotTrackFinished(K3bAudioTrack*, bool)) ); +} + + +K3bAudioTrackTRMLookupDialog::~K3bAudioTrackTRMLookupDialog() +{ +} + + +int K3bAudioTrackTRMLookupDialog::lookup( const QPtrList<K3bAudioTrack>& tracks ) +{ + m_mbJob->setTracks( tracks ); + m_mbJob->start(); + + m_busyWidget->showBusy(true); + setModal( true ); + show(); + m_inLoop = true; + QApplication::eventLoop()->enterLoop(); + + return 0; +} + + +void K3bAudioTrackTRMLookupDialog::slotMbJobInfoMessage( const QString& message, int ) +{ + m_infoLabel->setText( message ); +} + + +void K3bAudioTrackTRMLookupDialog::slotMbJobFinished( bool ) +{ + m_busyWidget->showBusy(false); + hide(); + if( m_inLoop ) + QApplication::eventLoop()->exitLoop(); +} + + +void K3bAudioTrackTRMLookupDialog::slotCancel() +{ + actionButton( Cancel )->setEnabled( false ); + m_mbJob->cancel(); +} + + +void K3bAudioTrackTRMLookupDialog::slotTrackFinished( K3bAudioTrack* track, bool success ) +{ + if( !success ) + K3bPassivePopup::showPopup( i18n("Track %1 was not found in the MusicBrainz database.") + .arg( track->trackNumber()), + i18n("Audio Project") ); +} + +#include "k3baudiotracktrmlookupdialog.moc" + +#endif diff --git a/src/projects/k3baudiotracktrmlookupdialog.h b/src/projects/k3baudiotracktrmlookupdialog.h new file mode 100644 index 0000000..10a0f32 --- /dev/null +++ b/src/projects/k3baudiotracktrmlookupdialog.h @@ -0,0 +1,54 @@ +/* + * + * $Id: k3baudiotracktrmlookupdialog.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_AUDIOTRACK_TRM_LOOKUP_DIALOG_H_ +#define _K3B_AUDIOTRACK_TRM_LOOKUP_DIALOG_H_ + +#include <kdialogbase.h> +#include <qptrlist.h> + +class QLabel; +class K3bAudioTrack; +class K3bMusicBrainzJob; +class K3bBusyWidget; + + +class K3bAudioTrackTRMLookupDialog : public KDialogBase +{ + Q_OBJECT + + public: + K3bAudioTrackTRMLookupDialog( QWidget* parent = 0, const char* name = 0 ); + ~K3bAudioTrackTRMLookupDialog(); + + /** + * This will show the dialog and start the lookup + */ + int lookup( const QPtrList<K3bAudioTrack>& tracks ); + + private slots: + void slotMbJobFinished( bool ); + void slotMbJobInfoMessage( const QString&, int ); + void slotTrackFinished( K3bAudioTrack* track, bool success ); + void slotCancel(); + + private: + QLabel* m_infoLabel; + K3bBusyWidget* m_busyWidget; + K3bMusicBrainzJob* m_mbJob; + bool m_inLoop; +}; + +#endif diff --git a/src/projects/k3baudiotrackview.cpp b/src/projects/k3baudiotrackview.cpp new file mode 100644 index 0000000..1af6a5c --- /dev/null +++ b/src/projects/k3baudiotrackview.cpp @@ -0,0 +1,1005 @@ +/* + * + * $Id: k3baudiotrackview.cpp 689561 2007-07-18 15:19:38Z trueg $ + * Copyright (C) 2004 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include <config.h> + +#include "k3baudiotrackview.h" +#include "k3baudiotrackviewitem.h" +#include "k3baudiodatasourceviewitem.h" +#include "k3baudiotrack.h" +#include "k3baudiodatasource.h" +#include "k3baudiotrackdialog.h" +#include "k3baudiodoc.h" +#include "k3baudiozerodata.h" +#include "k3baudiotracksplitdialog.h" +#include "k3baudiofile.h" +#include "k3baudiotrackplayer.h" +#include "k3baudiocdtrackdrag.h" +#include "k3baudiocdtracksource.h" +#include "k3baudiotracktrmlookupdialog.h" +#include "k3baudiodatasourceeditwidget.h" +#include "k3baudiotrackaddingdialog.h" + +#include <k3bview.h> +#include <k3blistviewitemanimator.h> +#include <k3baudiodecoder.h> +#include <k3bmsfedit.h> + +#include <qheader.h> +#include <qtimer.h> +#include <qdragobject.h> +#include <qpoint.h> +#include <qptrlist.h> +#include <qstringlist.h> +#include <qevent.h> +#include <qpixmap.h> +#include <qpainter.h> +#include <qlayout.h> +#include <qlabel.h> +#include <qvaluelist.h> + +#include <kurl.h> +#include <kurldrag.h> +#include <klocale.h> +#include <kaction.h> +#include <kpopupmenu.h> +#include <kiconloader.h> +#include <kapplication.h> +#include <kmessagebox.h> +#include <kdialogbase.h> + + +K3bAudioTrackView::K3bAudioTrackView( K3bAudioDoc* doc, QWidget* parent, const char* name ) + : K3bListView( parent, name ), + m_doc(doc), + m_updatingColumnWidths(false), + m_currentMouseOverItem(0), + m_currentlyPlayingTrack(0) +{ + m_player = new K3bAudioTrackPlayer( m_doc, this ); + connect( m_player, SIGNAL(playingTrack(K3bAudioTrack*)), this, + SLOT(showPlayerIndicator(K3bAudioTrack*)) ); + connect( m_player, SIGNAL(paused(bool)), this, SLOT(togglePauseIndicator(bool)) ); + connect( m_player, SIGNAL(stopped()), this, SLOT(removePlayerIndicator()) ); + + setItemMargin( 5 ); + setAcceptDrops( true ); + setDropVisualizer( true ); + setAllColumnsShowFocus( true ); + setDragEnabled( true ); + // setSelectionModeExt( KListView::Konqueror ); // FileManager in KDE3 + setSelectionModeExt( KListView::Extended ); + setItemsMovable( false ); + setAlternateBackground( QColor() ); // disable alternate colors + + setNoItemText( i18n("Use drag'n'drop to add audio files to the project.") + "\n" + + i18n("After that press the burn button to write the CD." ) ); + + setupColumns(); + setupActions(); + + m_playerItemAnimator = new K3bListViewItemAnimator( this ); + + m_animationTimer = new QTimer( this ); + connect( m_animationTimer, SIGNAL(timeout()), this, SLOT(slotAnimation()) ); + + m_autoOpenTrackTimer = new QTimer( this ); + connect( m_autoOpenTrackTimer, SIGNAL(timeout()), this, SLOT(slotDragTimeout()) ); + + connect( this, SIGNAL(dropped(QDropEvent*, QListViewItem*, QListViewItem*)), + this, SLOT(slotDropped(QDropEvent*, QListViewItem*, QListViewItem*)) ); + connect( this, SIGNAL(contextMenu(KListView*, QListViewItem*, const QPoint&)), + this, SLOT(showPopupMenu(KListView*, QListViewItem*, const QPoint&)) ); + connect( this, SIGNAL(doubleClicked(QListViewItem*, const QPoint&, int)), + this, SLOT(slotProperties()) ); + + connect( doc, SIGNAL(changed()), + this, SLOT(slotChanged()) ); + connect( doc, SIGNAL(trackChanged(K3bAudioTrack*)), + this, SLOT(slotTrackChanged(K3bAudioTrack*)) ); + connect( doc, SIGNAL(trackRemoved(K3bAudioTrack*)), + this, SLOT(slotTrackRemoved(K3bAudioTrack*)) ); + + slotChanged(); + + // a little background pix hack because I am simply incapable of doing it another way. :( +// static QPixmap s_bgPix("/tmp/trueg/audio_bg.png"); +// setK3bBackgroundPixmap( s_bgPix, TOP_LEFT ); +} + + +K3bAudioTrackView::~K3bAudioTrackView() +{ +} + + +void K3bAudioTrackView::setupColumns() +{ + addColumn( i18n("No.") ); + addColumn( i18n("Artist (CD-Text)") ); + addColumn( i18n("Title (CD-Text)") ); + addColumn( i18n("Type") ); + addColumn( i18n("Length") ); + addColumn( i18n("Filename") ); + + setColumnAlignment( 3, Qt::AlignHCenter ); + setColumnAlignment( 4, Qt::AlignHCenter ); + + setColumnWidthMode( 1, Manual ); + setColumnWidthMode( 2, Manual ); + setColumnWidthMode( 3, Manual ); + setColumnWidthMode( 4, Manual ); + setColumnWidthMode( 5, Manual ); + + header()->setResizeEnabled( false ); + header()->setClickEnabled( false ); + setSorting( -1 ); +} + + +void K3bAudioTrackView::setupActions() +{ + m_actionCollection = new KActionCollection( this ); + m_popupMenu = new KPopupMenu( this ); + + m_actionProperties = new KAction( i18n("Properties"), "misc", + KShortcut(), this, SLOT(slotProperties()), + actionCollection(), "track_properties" ); + m_actionRemove = new KAction( i18n( "Remove" ), "editdelete", + Key_Delete, this, SLOT(slotRemove()), + actionCollection(), "track_remove" ); + + m_actionAddSilence = new KAction( i18n("Add Silence") + "...", "misc", + KShortcut(), this, SLOT(slotAddSilence()), + actionCollection(), "track_add_silence" ); + m_actionMergeTracks = new KAction( i18n("Merge Tracks"), "misc", + KShortcut(), this, SLOT(slotMergeTracks()), + actionCollection(), "track_merge" ); + m_actionSplitSource = new KAction( i18n("Source to Track"), "misc", + KShortcut(), this, SLOT(slotSplitSource()), + actionCollection(), "source_split" ); + m_actionSplitTrack = new KAction( i18n("Split Track..."), 0, + KShortcut(), this, SLOT(slotSplitTrack()), + actionCollection(), "track_split" ); + m_actionEditSource = new KAction( i18n("Edit Source..."), 0, + KShortcut(), this, SLOT(slotEditSource()), + actionCollection(), "source_edit" ); + m_actionPlayTrack = new KAction( i18n("Play Track"), "player_play", + KShortcut(), this, SLOT(slotPlayTrack()), + actionCollection(), "track_play" ); +#ifdef HAVE_MUSICBRAINZ + KAction* mbAction = new KAction( i18n("Musicbrainz Lookup"), "musicbrainz", 0, this, + SLOT(slotQueryMusicBrainz()), + actionCollection(), "project_audio_musicbrainz" ); + mbAction->setToolTip( i18n("Try to determine meta information over the internet") ); +#endif +} + + +bool K3bAudioTrackView::acceptDrag(QDropEvent* e) const +{ + // the first is for built-in item moving, the second for dropping urls, the third for dropping audio tracks + return ( KListView::acceptDrag(e) || KURLDrag::canDecode(e) || K3bAudioCdTrackDrag::canDecode(e) ); +} + + +QDragObject* K3bAudioTrackView::dragObject() +{ + QPtrList<QListViewItem> list = selectedItems(); + + if( list.isEmpty() ) + return 0; + + KURL::List urls; + + for( QPtrListIterator<QListViewItem> it(list); it.current(); ++it ) { + QListViewItem* item = *it; + // we simply ignore open track items to not include files twice + // we also don't want the invisible source items + QListViewItem* parentItem = K3bListView::parentItem(item); + if( !item->isOpen() && ( !parentItem || parentItem->isOpen() ) ) { + if( K3bAudioDataSourceViewItem* sourceItem = dynamic_cast<K3bAudioDataSourceViewItem*>( item ) ) { + if( K3bAudioFile* file = dynamic_cast<K3bAudioFile*>( sourceItem->source() ) ) + urls.append( KURL::fromPathOrURL(file->filename()) ); + } + else { + K3bAudioTrackViewItem* trackItem = static_cast<K3bAudioTrackViewItem*>( item ); + K3bAudioDataSource* source = trackItem->track()->firstSource(); + while( source ) { + if( K3bAudioFile* file = dynamic_cast<K3bAudioFile*>( source ) ) + urls.append( KURL::fromPathOrURL(file->filename()) ); + source = source->next(); + } + } + } + } + + return new KURLDrag( urls, viewport() ); +} + + +void K3bAudioTrackView::slotDropped( QDropEvent* e, QListViewItem* parent, QListViewItem* after ) +{ + m_autoOpenTrackTimer->stop(); + + if( !e->isAccepted() ) + return; + + m_dropTrackAfter = 0; + m_dropTrackParent = 0; + m_dropSourceAfter = 0; + if( after ) { + if( K3bAudioTrackViewItem* tv = dynamic_cast<K3bAudioTrackViewItem*>( after ) ) { + m_dropTrackAfter = tv->track(); + } + else if( K3bAudioDataSourceViewItem* sv = dynamic_cast<K3bAudioDataSourceViewItem*>( after ) ) { + m_dropSourceAfter = sv->source(); + } + } + + if( K3bAudioTrackViewItem* tv = dynamic_cast<K3bAudioTrackViewItem*>( parent ) ) { + m_dropTrackParent = tv->track(); + } + + // + // In case the sources are not shown we do not want to handle them because the average + // user would be confused otherwise + // + if( m_dropTrackParent && !m_trackItemMap[m_dropTrackParent]->showingSources() ) { + kdDebug() << "(K3bAudioTrackView) dropped after track which does not show it's sources." << endl; + m_dropTrackAfter = m_dropTrackParent; + m_dropTrackParent = 0; + } + + if( e->source() == viewport() ) { + + bool copyItems = (e->action() == QDropEvent::Copy); + + // 1. tracks (with some of their sources) -> move complete tracks around + // 2. sources (multiple sources) -> move the sources to the destination track + // 3. tracks and sources (the latter without their track) -> ignore the latter sources + QPtrList<K3bAudioTrack> tracks; + QPtrList<K3bAudioDataSource> sources; + getSelectedItems( tracks, sources ); + + // + // remove all sources which belong to one of the selected tracks since they will be + // moved along with their tracks + // + QPtrListIterator<K3bAudioDataSource> srcIt( sources ); + while( srcIt.current() ) { + if( tracks.containsRef( srcIt.current()->track() ) ) + sources.removeRef( *srcIt ); + else + ++srcIt; + } + + // + // Now move (or copy) all the tracks + // + for( QPtrListIterator<K3bAudioTrack> it( tracks ); it.current(); ++it ) { + K3bAudioTrack* track = *it; + if( m_dropTrackParent ) { + m_dropTrackParent->merge( copyItems ? track->copy() : track, m_dropSourceAfter ); + } + else if( m_dropTrackAfter ) { + if( copyItems ) + track->copy()->moveAfter( m_dropTrackAfter ); + else + track->moveAfter( m_dropTrackAfter ); + } + else { + if( copyItems ) + track->copy()->moveAhead( m_doc->firstTrack() ); + else + track->moveAhead( m_doc->firstTrack() ); + } + } + + // + // now move (or copy) the sources + // + for( QPtrListIterator<K3bAudioDataSource> it( sources ); it.current(); ++it ) { + K3bAudioDataSource* source = *it; + if( m_dropTrackParent ) { + if( m_dropSourceAfter ) { + if( copyItems ) + source->copy()->moveAfter( m_dropSourceAfter ); + else + source->moveAfter( m_dropSourceAfter ); + } + else { + if( copyItems ) + source->copy()->moveAhead( m_dropTrackParent->firstSource() ); + else + source->moveAhead( m_dropTrackParent->firstSource() ); + } + } + else { + // create a new track + K3bAudioTrack* track = new K3bAudioTrack( m_doc ); + + // special case: the source we remove from the track is the last and the track + // will be deleted. + if( !copyItems && m_dropTrackAfter == source->track() && m_dropTrackAfter->numberSources() == 1 ) + m_dropTrackAfter = m_dropTrackAfter->prev(); + + if( copyItems ) + track->addSource( source->copy() ); + else + track->addSource( source ); + + if( m_dropTrackAfter ) { + track->moveAfter( m_dropTrackAfter ); + m_dropTrackAfter = track; + } + else { + track->moveAhead( m_doc->firstTrack() ); + m_dropTrackAfter = track; + } + } + } + } + else if( K3bAudioCdTrackDrag::canDecode( e ) ) { + kdDebug() << "(K3bAudioTrackView) audiocdtrack dropped." << endl; + K3bDevice::Toc toc; + K3bDevice::Device* dev = 0; + K3bCddbResultEntry cddb; + QValueList<int> trackNumbers; + + K3bAudioCdTrackDrag::decode( e, toc, trackNumbers, cddb, &dev ); + + // for now we just create one source + for( QValueList<int>::const_iterator it = trackNumbers.begin(); + it != trackNumbers.end(); ++it ) { + int trackNumber = *it; + + K3bAudioCdTrackSource* source = new K3bAudioCdTrackSource( toc, trackNumber, cddb, dev ); + if( m_dropTrackParent ) { + source->moveAfter( m_dropSourceAfter ); + if( m_dropSourceAfter ) + m_dropSourceAfter = source; + } + else { + K3bAudioTrack* track = new K3bAudioTrack(); + track->setPerformer( cddb.artists[trackNumber-1] ); + track->setTitle( cddb.titles[trackNumber-1] ); + track->addSource( source ); + if( m_dropTrackAfter ) + track->moveAfter( m_dropTrackAfter ); + else + m_doc->addTrack( track, 0 ); + + m_dropTrackAfter = track; + } + } + } + else{ + m_dropUrls.clear(); + if( KURLDrag::decode( e, m_dropUrls ) ) { + // + // This is a small (not to ugly) hack to circumvent problems with the + // event queues: the url adding dialog will be non-modal regardless of + // the settings in case we open it directly. + // + QTimer::singleShot( 0, this, SLOT(slotAddUrls()) ); + } + } + + showAllSources(); + + // now grab that focus + setFocus(); +} + + +void K3bAudioTrackView::slotAddUrls() +{ + K3bAudioTrackAddingDialog::addUrls( m_dropUrls, m_doc, m_dropTrackAfter, m_dropTrackParent, m_dropSourceAfter, this ); +} + + +void K3bAudioTrackView::slotChanged() +{ + kdDebug() << "(K3bAudioTrackView::slotChanged)" << endl; + // we only need to add new items here. Everything else is done in the + // specific slots below + K3bAudioTrack* track = m_doc->firstTrack(); + bool newTracks = false; + while( track ) { + bool newTrack; + getTrackViewItem( track, &newTrack ); + if( newTrack ) + newTracks = true; + track = track->next(); + } + + if( newTracks ) { + m_animationTimer->start(200); + showAllSources(); + } + + header()->setShown( m_doc->numOfTracks() > 0 ); + + kdDebug() << "(K3bAudioTrackView::slotChanged) finished" << endl; +} + + +K3bAudioTrackViewItem* K3bAudioTrackView::getTrackViewItem( K3bAudioTrack* track, bool* isNewItem ) +{ + QMap<K3bAudioTrack*, K3bAudioTrackViewItem*>::iterator itemIt = m_trackItemMap.find(track); + if( itemIt == m_trackItemMap.end() ) { + kdDebug() << "(K3bAudioTrackView) new track " << track << endl; + K3bAudioTrackViewItem* prevItem = 0; + if( track->prev() && m_trackItemMap.contains( track->prev() ) ) + prevItem = m_trackItemMap[track->prev()]; + K3bAudioTrackViewItem* newItem = new K3bAudioTrackViewItem( this, prevItem, track ); + // + // disable the item until the files have been analysed + // so the user may not change the cd-text until the one from the + // file is loaded. + // + // Since for some reason QT thinks it's bad to open disabled items + // we need to open it before disabling it + // + newItem->showSources( track->numberSources() != 1 ); + newItem->setEnabled( false ); + m_trackItemMap[track] = newItem; + + if( isNewItem ) + *isNewItem = true; + return newItem; + } + else { + if( isNewItem ) + *isNewItem = false; + return *itemIt; + } +} + + +void K3bAudioTrackView::slotTrackChanged( K3bAudioTrack* track ) +{ + kdDebug() << "(K3bAudioTrackView::slotTrackChanged( " << track << " )" << endl; + + // + // There may be some tracks around that have not been added to the list yet + // (and might never). We ignore them until they are in the list and then + // we create the item in slotChanged + // + if( track->inList() ) { + K3bAudioTrackViewItem* item = getTrackViewItem(track); + item->updateSourceItems(); + + if( track->numberSources() > 1 ) + item->showSources(true); + + // the length might have changed + item->repaint(); + + // FIXME: only do this if the position really changed + // move the item if the position has changed + if( track->prev() && m_trackItemMap.contains(track->prev()) ) + item->moveItem( m_trackItemMap[track->prev()] ); + else if( !track->prev() ) { + takeItem( item ); + insertItem( item ); + } + + // start the animation in case new sources have been added + m_animationTimer->start( 200 ); + + showAllSources(); + } + kdDebug() << "(K3bAudioTrackView::slotTrackChanged( " << track << " ) finished" << endl; +} + + +void K3bAudioTrackView::slotTrackRemoved( K3bAudioTrack* track ) +{ + kdDebug() << "(K3bAudioTrackView::slotTrackRemoved( " << track << " )" << endl; + if ( m_playerItemAnimator->item() == m_trackItemMap[track] ) { + m_playerItemAnimator->stop(); + } + delete m_trackItemMap[track]; + m_trackItemMap.erase(track); +} + + +void K3bAudioTrackView::showAllSources() +{ + // TODO: add an action to show all sources + + QListViewItem* item = firstChild(); + while( item ) { + if( K3bAudioTrackViewItem* tv = dynamic_cast<K3bAudioTrackViewItem*>( item ) ) + tv->showSources( tv->track()->numberSources() != 1 ); + item = item->nextSibling(); + } +} + + +void K3bAudioTrackView::keyPressEvent( QKeyEvent* e ) +{ + // showAllSources(); + + K3bListView::keyPressEvent(e); +} + + +void K3bAudioTrackView::keyReleaseEvent( QKeyEvent* e ) +{ + // showAllSources(); + + K3bListView::keyReleaseEvent(e); +} + + +void K3bAudioTrackView::contentsMouseMoveEvent( QMouseEvent* e ) +{ + // showAllSources(); + + K3bListView::contentsMouseMoveEvent( e ); +} + + +void K3bAudioTrackView::focusOutEvent( QFocusEvent* e ) +{ + // showAllSources(); + + K3bListView::focusOutEvent( e ); +} + + +void K3bAudioTrackView::resizeEvent( QResizeEvent* e ) +{ + K3bListView::resizeEvent(e); + + resizeColumns(); +} + + +void K3bAudioTrackView::contentsDragMoveEvent( QDragMoveEvent* event ) +{ + K3bAudioTrackViewItem* item = findTrackItem( event->pos() ); + if( m_currentMouseOverItem != item ) { + showAllSources(); // hide previous sources + m_currentMouseOverItem = item; + } + if( m_currentMouseOverItem ) + m_autoOpenTrackTimer->start( 1000 ); // 1 sec + + K3bListView::contentsDragMoveEvent( event ); +} + + +void K3bAudioTrackView::contentsDragLeaveEvent( QDragLeaveEvent* e ) +{ + m_autoOpenTrackTimer->stop(); + K3bListView::contentsDragLeaveEvent( e ); +} + + +K3bAudioTrackViewItem* K3bAudioTrackView::findTrackItem( const QPoint& pos ) const +{ + QListViewItem* parent = 0; + QListViewItem* after = 0; + K3bAudioTrackView* that = const_cast<K3bAudioTrackView*>(this); + that->findDrop( pos, parent, after ); + if( parent ) + return static_cast<K3bAudioTrackViewItem*>( parent ); + else if( K3bAudioTrackViewItem* tv = dynamic_cast<K3bAudioTrackViewItem*>(after) ) + return tv; + else if( K3bAudioDataSourceViewItem* sv = dynamic_cast<K3bAudioDataSourceViewItem*>(after) ) + return sv->trackViewItem(); + else + return 0; +} + + +void K3bAudioTrackView::resizeColumns() +{ + if( m_updatingColumnWidths ) { + kdDebug() << "(K3bAudioTrackView) already updating column widths." << endl; + return; + } + + m_updatingColumnWidths = true; + + // now properly resize the columns + // minimal width for type, length, pregap + // fixed for filename + // expand for cd-text + int titleWidth = header()->fontMetrics().width( header()->label(1) ); + int artistWidth = header()->fontMetrics().width( header()->label(2) ); + int typeWidth = header()->fontMetrics().width( header()->label(3) ); + int lengthWidth = header()->fontMetrics().width( header()->label(4) ); + int filenameWidth = header()->fontMetrics().width( header()->label(5) ); + + for( QListViewItemIterator it( this ); it.current(); ++it ) { + artistWidth = QMAX( artistWidth, it.current()->width( fontMetrics(), this, 1 ) ); + titleWidth = QMAX( titleWidth, it.current()->width( fontMetrics(), this, 2 ) ); + typeWidth = QMAX( typeWidth, it.current()->width( fontMetrics(), this, 3 ) ); + lengthWidth = QMAX( lengthWidth, it.current()->width( fontMetrics(), this, 4 ) ); + filenameWidth = QMAX( filenameWidth, it.current()->width( fontMetrics(), this, 5 ) ); + } + + // add a margin + typeWidth += 10; + lengthWidth += 10; + + // these always need to be completely visible + setColumnWidth( 3, typeWidth ); + setColumnWidth( 4, lengthWidth ); + + int remaining = visibleWidth() - typeWidth - lengthWidth - columnWidth(0); + + // now let's see if there is enough space for all + if( remaining >= artistWidth + titleWidth + filenameWidth ) { + remaining -= filenameWidth; + remaining -= (titleWidth + artistWidth); + setColumnWidth( 1, artistWidth + remaining/2 ); + setColumnWidth( 2, titleWidth + remaining/2 ); + setColumnWidth( 5, filenameWidth ); + } + else if( remaining >= artistWidth + titleWidth + 20 ) { + setColumnWidth( 1, artistWidth ); + setColumnWidth( 2, titleWidth ); + setColumnWidth( 5, remaining - artistWidth - titleWidth ); + } + else { + setColumnWidth( 1, remaining/3 ); + setColumnWidth( 2, remaining/3 ); + setColumnWidth( 5, remaining/3 ); + } + + triggerUpdate(); + m_updatingColumnWidths = false; +} + + +void K3bAudioTrackView::slotAnimation() +{ + resizeColumns(); + QListViewItem* item = firstChild(); + + bool animate = false; + + while( item ) { + K3bAudioTrackViewItem* trackItem = dynamic_cast<K3bAudioTrackViewItem*>(item); + if( trackItem->animate() ) + animate = true; + else + trackItem->setEnabled( true ); // files analysed, cd-text loaded + item = item->nextSibling(); + } + + if( !animate ) { + m_animationTimer->stop(); + } +} + + +void K3bAudioTrackView::slotDragTimeout() +{ + m_autoOpenTrackTimer->stop(); + + if( m_currentMouseOverItem ) { + m_currentMouseOverItem->showSources( true ); + } +} + + +void K3bAudioTrackView::getSelectedItems( QPtrList<K3bAudioTrack>& tracks, + QPtrList<K3bAudioDataSource>& sources ) +{ + tracks.clear(); + sources.clear(); + + QPtrList<QListViewItem> items = selectedItems(); + for( QPtrListIterator<QListViewItem> it( items ); it.current(); ++it ) { + if( K3bAudioTrackViewItem* tv = dynamic_cast<K3bAudioTrackViewItem*>( *it ) ) + tracks.append( tv->track() ); + else { + K3bAudioDataSourceViewItem* sv = static_cast<K3bAudioDataSourceViewItem*>( *it ); + // do not select hidden source items or unfinished source files + if( sv->trackViewItem()->showingSources() && + !(sv->source()->isValid() && sv->source()->length() == 0) ) + sources.append( sv->source() ); + } + } +} + + +void K3bAudioTrackView::slotRemove() +{ + QPtrList<K3bAudioTrack> tracks; + QPtrList<K3bAudioDataSource> sources; + getSelectedItems( tracks, sources ); + + // + // remove all sources which belong to one of the selected tracks since they will be + // deleted along with their tracks + // + QPtrListIterator<K3bAudioDataSource> srcIt( sources ); + while( srcIt.current() ) { + if( tracks.containsRef( srcIt.current()->track() ) ) + sources.removeRef( *srcIt ); + else + ++srcIt; + } + + // + // Now delete all the tracks + // + for( QPtrListIterator<K3bAudioTrack> it( tracks ); it.current(); ++it ) + delete *it; + + // + // Now delete all the sources + // + for( QPtrListIterator<K3bAudioDataSource> it( sources ); it.current(); ++it ) + delete *it; +} + + +void K3bAudioTrackView::slotAddSilence() +{ + QListViewItem* item = selectedItems().first(); + if( item ) { + // + // create a simple dialog for asking the length of the silence + // + KDialogBase dlg( KDialogBase::Plain, + i18n("Add Silence"), + KDialogBase::Ok|KDialogBase::Cancel, + KDialogBase::Ok, + this ); + QHBoxLayout* dlgLayout = new QHBoxLayout( dlg.plainPage(), 0, KDialog::spacingHint() ); + dlgLayout->setAutoAdd( true ); + (void)new QLabel( i18n("Length of silence:"), dlg.plainPage() ); + K3bMsfEdit* msfEdit = new K3bMsfEdit( dlg.plainPage() ); + msfEdit->setValue( 150 ); // 2 seconds default + msfEdit->setFocus(); + + if( dlg.exec() == QDialog::Accepted ) { + K3bAudioZeroData* zero = new K3bAudioZeroData( msfEdit->value() ); + if( K3bAudioTrackViewItem* tv = dynamic_cast<K3bAudioTrackViewItem*>(item) ) { + tv->track()->addSource( zero ); + } + else if( K3bAudioDataSourceViewItem* sv = dynamic_cast<K3bAudioDataSourceViewItem*>(item) ) { + zero->moveAfter( sv->source() ); + } + } + } +} + + +void K3bAudioTrackView::slotMergeTracks() +{ + QPtrList<K3bAudioTrack> tracks; + QPtrList<K3bAudioDataSource> sources; + getSelectedItems( tracks, sources ); + + // we simply merge the selected tracks ignoring any eventually selected sources + K3bAudioTrack* firstTrack = tracks.first(); + tracks.remove(); + while( K3bAudioTrack* mergeTrack = tracks.first() ) { + tracks.remove(); + firstTrack->merge( mergeTrack, firstTrack->lastSource() ); + } +} + + +void K3bAudioTrackView::slotSplitSource() +{ + QListViewItem* item = selectedItems().first(); + if( K3bAudioDataSourceViewItem* sv = dynamic_cast<K3bAudioDataSourceViewItem*>(item) ) { + // create a new track + K3bAudioTrack* track = new K3bAudioTrack( m_doc ); + K3bAudioTrack* trackAfter = sv->source()->track(); + if( trackAfter->numberSources() == 1 ) + trackAfter = trackAfter->prev(); + track->addSource( sv->source()->take() ); + track->moveAfter( trackAfter ); + + // let's see if it's a file because in that case we can reuse the metainfo :) + // TODO: maybe add meta data to sources + if( K3bAudioFile* file = dynamic_cast<K3bAudioFile*>( track->firstSource() ) ) { + track->setArtist( file->decoder()->metaInfo( K3bAudioDecoder::META_ARTIST ) ); + track->setTitle( file->decoder()->metaInfo( K3bAudioDecoder::META_TITLE ) ); + track->setSongwriter( file->decoder()->metaInfo( K3bAudioDecoder::META_SONGWRITER ) ); + track->setComposer( file->decoder()->metaInfo( K3bAudioDecoder::META_COMPOSER ) ); + track->setCdTextMessage( file->decoder()->metaInfo( K3bAudioDecoder::META_COMMENT ) ); + } + } +} + + +void K3bAudioTrackView::slotSplitTrack() +{ + QListViewItem* item = selectedItems().first(); + if( K3bAudioTrackViewItem* tv = dynamic_cast<K3bAudioTrackViewItem*>(item) ) { + K3bAudioTrackSplitDialog::splitTrack( tv->track(), this ); + } +} + + +void K3bAudioTrackView::slotEditSource() +{ + QListViewItem* item = selectedItems().first(); + + K3bAudioDataSource* source = 0; + if( K3bAudioDataSourceViewItem* sv = dynamic_cast<K3bAudioDataSourceViewItem*>(item) ) + source = sv->source(); + else if( K3bAudioTrackViewItem* tv = dynamic_cast<K3bAudioTrackViewItem*>(item) ) + source = tv->track()->firstSource(); + + if( source ) { + KDialogBase dlg( KDialogBase::Plain, + i18n("Edit Audio Track Source"), + KDialogBase::Ok|KDialogBase::Cancel, + KDialogBase::Ok, + this, + 0, + true, + true ); + QVBoxLayout* lay = new QVBoxLayout( dlg.plainPage() ); + lay->setMargin( 0 ); + lay->setSpacing( KDialog::spacingHint() ); + lay->setAutoAdd( true ); + K3bAudioDataSourceEditWidget* editW = new K3bAudioDataSourceEditWidget( dlg.plainPage() ); + editW->loadSource( source ); + if( dlg.exec() == QDialog::Accepted ) + editW->saveSource(); + } +} + + +void K3bAudioTrackView::showPopupMenu( KListView*, QListViewItem* item, const QPoint& pos ) +{ + QPtrList<K3bAudioTrack> tracks; + QPtrList<K3bAudioDataSource> sources; + getSelectedItems( tracks, sources ); + + int numTracks = tracks.count(); + int numSources = sources.count(); + + // build the menu + m_popupMenu->clear(); + + if( numTracks >= 1 ) { + m_actionPlayTrack->plug( m_popupMenu ); + m_popupMenu->insertSeparator(); + } + + if( item ) + m_actionRemove->plug( m_popupMenu ); + + if( numSources + numTracks == 1 ) + m_actionAddSilence->plug( m_popupMenu ); + + if( numSources == 1 && numTracks == 0 ) { + m_popupMenu->insertSeparator(); + m_actionSplitSource->plug( m_popupMenu ); + m_actionEditSource->plug( m_popupMenu ); + } + else if( numTracks == 1 && numSources == 0 ) { + m_popupMenu->insertSeparator(); + + + + if( K3bAudioTrackViewItem* tv = dynamic_cast<K3bAudioTrackViewItem*>(item) ) + if( tv->track()->length().lba() > 60 ) + m_actionSplitTrack->plug( m_popupMenu ); + + m_actionEditSource->plug( m_popupMenu ); + + } + else if( numTracks > 1 ) { + m_popupMenu->insertSeparator(); + m_actionMergeTracks->plug( m_popupMenu ); + } + + m_actionProperties->plug( m_popupMenu ); + m_popupMenu->insertSeparator(); + static_cast<K3bView*>(m_doc->view())->actionCollection()->action( "project_burn" )->plug( m_popupMenu ); + + m_popupMenu->popup( pos ); +} + + +void K3bAudioTrackView::slotProperties() +{ + QPtrList<K3bAudioTrack> tracks; + QPtrList<K3bAudioDataSource> sources; + getSelectedItems( tracks, sources ); + + // TODO: add tracks from sources to tracks + + if( !tracks.isEmpty() ) { + K3bAudioTrackDialog d( tracks, this ); + d.exec(); + } + else { + static_cast<K3bView*>(m_doc->view())->slotProperties(); + } +} + + +void K3bAudioTrackView::slotPlayTrack() +{ + QPtrList<K3bAudioTrack> tracks; + QPtrList<K3bAudioDataSource> sources; + getSelectedItems( tracks, sources ); + if( tracks.count() > 0 ) + m_player->playTrack( tracks.first() ); +} + + +void K3bAudioTrackView::showPlayerIndicator( K3bAudioTrack* track ) +{ + removePlayerIndicator(); + m_currentlyPlayingTrack = track; + K3bAudioTrackViewItem* item = getTrackViewItem( track ); + item->setPixmap( 1, SmallIcon( "player_play" ) ); + m_playerItemAnimator->setItem( item, 1 ); +} + + +void K3bAudioTrackView::togglePauseIndicator( bool b ) +{ + if( m_currentlyPlayingTrack ) { + if( b ) + m_playerItemAnimator->setPixmap( SmallIcon( "player_pause" ) ); + else + m_playerItemAnimator->setPixmap( SmallIcon( "player_play" ) ); + } +} + + +void K3bAudioTrackView::removePlayerIndicator() +{ + if( m_currentlyPlayingTrack ) + getTrackViewItem( m_currentlyPlayingTrack )->setPixmap( 1, QPixmap() ); + m_playerItemAnimator->stop(); + m_currentlyPlayingTrack = 0; +} + + +void K3bAudioTrackView::slotQueryMusicBrainz() +{ +#ifdef HAVE_MUSICBRAINZ + QPtrList<K3bAudioTrack> tracks; + QPtrList<K3bAudioDataSource> sources; + getSelectedItems( tracks, sources ); + + if( tracks.isEmpty() ) { + KMessageBox::sorry( this, i18n("Please select an audio track.") ); + return; + } + + // only one may use the tracks at the same time + if( m_currentlyPlayingTrack && + tracks.containsRef( m_currentlyPlayingTrack ) ) + m_player->stop(); + + // now do the lookup on the files. + K3bAudioTrackTRMLookupDialog dlg( this ); + dlg.lookup( tracks ); +#endif +} + +#include "k3baudiotrackview.moc" diff --git a/src/projects/k3baudiotrackview.h b/src/projects/k3baudiotrackview.h new file mode 100644 index 0000000..07415b6 --- /dev/null +++ b/src/projects/k3baudiotrackview.h @@ -0,0 +1,142 @@ +/* + * + * $Id: k3baudiotrackview.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_AUDIO_TRACK_VIEW_H_ +#define _K3B_AUDIO_TRACK_VIEW_H_ + +#include <k3blistview.h> + +#include <qmap.h> +#include <qptrlist.h> +#include <kurl.h> + +class K3bAudioTrack; +class K3bAudioTrackViewItem; +class K3bAudioDataSource; +class K3bAudioDoc; +class KActionCollection; +class KAction; +class QDropEvent; +class QKeyEvent; +class QFocusEvent; +class QMouseEvent; +class QDragMoveEvent; +class QTimer; +class KPopupMenu; +class QPainter; +class K3bListViewItemAnimator; +class K3bAudioTrackPlayer; + + +class K3bAudioTrackView : public K3bListView +{ + Q_OBJECT + + public: + K3bAudioTrackView( K3bAudioDoc*, QWidget* parent, const char* name = 0 ); + ~K3bAudioTrackView(); + + KActionCollection* actionCollection() const { return m_actionCollection; } + + K3bAudioTrackPlayer* player() const { return m_player; } + + void getSelectedItems( QPtrList<K3bAudioTrack>& tracks, + QPtrList<K3bAudioDataSource>& sources ); + + public slots: + void showPlayerIndicator( K3bAudioTrack* ); + void togglePauseIndicator( bool b ); + void removePlayerIndicator(); + + private: + void setupColumns(); + void setupActions(); + void showAllSources(); + K3bAudioTrackViewItem* findTrackItem( const QPoint& pos ) const; + K3bAudioTrackViewItem* getTrackViewItem( K3bAudioTrack* track, bool* isNew = 0 ); + + K3bAudioDoc* m_doc; + + KAction* m_actionProperties; + KAction* m_actionRemove; + KAction* m_actionAddSilence; + KAction* m_actionMergeTracks; + KAction* m_actionSplitSource; + KAction* m_actionSplitTrack; + KAction* m_actionEditSource; + KAction* m_actionPlayTrack; + KActionCollection* m_actionCollection; + + bool m_updatingColumnWidths; + + QMap<K3bAudioTrack*, K3bAudioTrackViewItem*> m_trackItemMap; + + K3bAudioTrackViewItem* m_currentMouseOverItem; + QTimer* m_autoOpenTrackTimer; + QTimer* m_animationTimer; + + KPopupMenu* m_popupMenu; + + K3bAudioTrackPlayer* m_player; + + // used for the audiotrackplayer indicator + K3bAudioTrack* m_currentlyPlayingTrack; + + // to animate the player icon + K3bListViewItemAnimator* m_playerItemAnimator; + + // used for the drop-event hack + KURL::List m_dropUrls; + K3bAudioTrack* m_dropTrackAfter; + K3bAudioTrack* m_dropTrackParent; + K3bAudioDataSource* m_dropSourceAfter; + + private slots: + void slotAnimation(); + void slotDropped( QDropEvent* e, QListViewItem* parent, QListViewItem* after ); + void slotChanged(); + void slotTrackChanged( K3bAudioTrack* ); + void slotTrackRemoved( K3bAudioTrack* ); + void slotDragTimeout(); + + // action slots + void slotAddSilence(); + void slotRemove(); + void slotMergeTracks(); + void slotSplitSource(); + void slotSplitTrack(); + void showPopupMenu( KListView*, QListViewItem* item, const QPoint& pos ); + void slotProperties(); + void slotPlayTrack(); + void slotQueryMusicBrainz(); + void slotEditSource(); + + // drop-event hack slot + void slotAddUrls(); + + protected: + void keyPressEvent( QKeyEvent* e ); + void keyReleaseEvent( QKeyEvent* e ); + void focusOutEvent( QFocusEvent* e ); + void contentsMouseMoveEvent( QMouseEvent* e ); + void contentsDragMoveEvent( QDragMoveEvent* e ); + void contentsDragLeaveEvent( QDragLeaveEvent* e ); + void resizeEvent( QResizeEvent* e ); + void resizeColumns(); + bool acceptDrag(QDropEvent* e) const; + QDragObject* dragObject(); +}; + +#endif diff --git a/src/projects/k3baudiotrackviewitem.cpp b/src/projects/k3baudiotrackviewitem.cpp new file mode 100644 index 0000000..6918e2a --- /dev/null +++ b/src/projects/k3baudiotrackviewitem.cpp @@ -0,0 +1,229 @@ +/* + * + * $Id: k3baudiotrackviewitem.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3baudiotrackviewitem.h" +#include "k3baudiodatasourceviewitem.h" +#include "k3baudiodatasource.h" +#include "k3baudiotrackview.h" +#include "k3baudiotrack.h" +#include <k3bcdtextvalidator.h> + +#include <kiconloader.h> + +#include <qpainter.h> + + +K3bAudioTrackViewItem::K3bAudioTrackViewItem( K3bAudioTrackView* parent, + K3bAudioTrackViewItem* after, + K3bAudioTrack* track ) + : K3bListViewItem( parent, after ), + m_track( track ), + m_alreadyRemoved(false), + m_showingSources(false), + m_animationCounter(1) +{ + // columns + // 0 - No. + // 1 - Artist (CD-Text) + // 2 - Title (CD-Text) + // 3 - Type + // 4 - Pregap + // 5 - Length + // 6 - Filename + + // animationIconNumber = 1; + setEditor( 1, LINE ); + setEditor( 2, LINE ); + setValidator( 1, new K3bCdTextValidator() ); + setValidator( 2, validator(1) ); + + // setMarginVertical( 5 ); + + // italic type + QFont f(listView()->font()); + f.setItalic( true ); + setFont( 3, f ); + + // gray out filename + setForegroundColor( 5, listView()->palette().disabled().foreground() ); + + // smaller filename + f = listView()->font(); + f.setPointSize( f.pointSize() - 2 ); + setFont( 5, f ); + + updateSourceItems(); +} + + +K3bAudioTrackViewItem::~K3bAudioTrackViewItem() +{ + delete validator(1); +} + + +void K3bAudioTrackViewItem::paintCell( QPainter* p, const QColorGroup& cg, int col, int width, int align ) +{ + K3bListViewItem::paintCell( p, cg, col, width, align ); + + // draw the separator + if( listView()->firstChild() != this ) { + p->save(); + // FIXME: modify the value from palette().disabled().foreground() to be lighter (or darker, depending on the background color ) + p->setPen( Qt::lightGray ); + p->drawLine( 0, 0, width, 0 ); + p->restore(); + } +} + + +void K3bAudioTrackViewItem::paintBranches( QPainter* p, const QColorGroup& cg, int w, int, int h ) +{ + // we just want empty space + p->fillRect( QRect( 0, 0, w, h ), cg.base() ); +} + + +QString K3bAudioTrackViewItem::text(int i) const +{ + // to avoid crashes when the track has been deleted and this viewitem is still around + if( m_alreadyRemoved ) + return QString::null; + + // + // We add two spaces after all strings (except the once renameable) + // to increase readability + // + + switch( i ) + { + case 0: + return QString::number( m_track->trackNumber() ).rightJustify( 2, ' ' ); + case 1: + return m_track->performer(); + case 2: + return m_track->title(); + case 3: + if( m_showingSources ) + return QString::null; + else + return m_track->firstSource()->type(); + case 4: + return m_track->length().toString(); + case 5: + if( m_showingSources ) + return QString::null; + else + return m_track->firstSource()->sourceComment(); + default: + return KListViewItem::text(i); + } +} + +void K3bAudioTrackViewItem::setText( int col, const QString& text ) +{ + // + // Stupid QListViewItem actually calls setText in paintCell. Thus, once a new item + // is created setText is called and in turn the doc is marked as modified since + // we call setArtist or setPerformer here! :( + // + // Quick fix: check if the field actually changed + // + if( col == 1 ) { + // this is the cd-text artist field + if( text != m_track->performer() ) + m_track->setPerformer( text ); + } + else if( col == 2 ) { + // this is the cd-text title field + if( text != m_track->title() ) + m_track->setTitle( text ); + } + + KListViewItem::setText( col, text ); +} + + +void K3bAudioTrackViewItem::showSources( bool show ) +{ + setOpen(show); + m_showingSources = show; +} + + +void K3bAudioTrackViewItem::updateSourceItems() +{ + while( firstChild() ) + delete firstChild(); + + K3bAudioDataSource* source = track()->firstSource(); + K3bAudioDataSourceViewItem* sourceItem = 0; + while( source ) { + sourceItem = new K3bAudioDataSourceViewItem( this, sourceItem, source ); + sourceItem->animate(); + source = source->next(); + } +} + + +bool K3bAudioTrackViewItem::animate() +{ + // + // We animate if one of the sources have length == 0 + // otherwise we set the led + // + bool animate = false; + bool valid = true; + QListViewItem* item = firstChild(); + while( item ) { + K3bAudioDataSourceViewItem* sourceItem = dynamic_cast<K3bAudioDataSourceViewItem*>( item ); + animate = animate || sourceItem->animate(); + valid = valid && sourceItem->source()->isValid(); + item = item->nextSibling(); + } + if( animate ) { + QString icon = QString( "kde%1" ).arg( m_animationCounter ); + setPixmap( 4, SmallIcon( icon ) ); + m_animationCounter++; + if ( m_animationCounter > 6 ) + m_animationCounter = 1; + } + else { + // set status icon + setPixmap( 4, ( valid ? SmallIcon( "greenled" ) : SmallIcon( "redled" ) ) ); + } + return animate; +} + + +void K3bAudioTrackViewItem::setSelected( bool s ) +{ + K3bListViewItem::setSelected(s); + + // we also select or unselect all source items + QListViewItem* item = firstChild(); + while( item ) { + item->setSelected(s); + item = item->nextSibling(); + } +} + + +void K3bAudioTrackViewItem::insertItem( QListViewItem* item ) +{ + K3bListViewItem::insertItem( item ); + if( isSelected() ) + item->setSelected(true); +} diff --git a/src/projects/k3baudiotrackviewitem.h b/src/projects/k3baudiotrackviewitem.h new file mode 100644 index 0000000..9eb6065 --- /dev/null +++ b/src/projects/k3baudiotrackviewitem.h @@ -0,0 +1,66 @@ +/* + * + * $Id: k3baudiotrackviewitem.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_AUDIO_TRACK_VIEWITEM_H_ +#define _K3B_AUDIO_TRACK_VIEWITEM_H_ + +#include <k3blistview.h> + +class K3bAudioTrackView; +class K3bAudioTrack; + + +class K3bAudioTrackViewItem : public K3bListViewItem +{ + public: + K3bAudioTrackViewItem( K3bAudioTrackView* parent, + K3bAudioTrackViewItem* after, + K3bAudioTrack* track ); + ~K3bAudioTrackViewItem(); + + /** + * If one of the sources still have length 0 we animate. + */ + bool animate(); + + K3bAudioTrack* track() const { return m_track; } + + void updateSourceItems(); + bool showingSources() const { return m_showingSources; } + void showSources( bool show ); + void setText( int col, const QString& text ); + QString text( int i ) const; + + /** + * @reimpl + */ + void setSelected( bool s ); + /** + * @reimpl + */ + void insertItem( QListViewItem* item ); + + void paintBranches( QPainter*, const QColorGroup &, int, int, int ); + void paintCell( QPainter* p, const QColorGroup& cg, int col, int width, int align ); + + private: + K3bAudioTrack* m_track; + bool m_alreadyRemoved; + bool m_showingSources; + + int m_animationCounter; +}; + +#endif diff --git a/src/projects/k3baudiotrackwidget.cpp b/src/projects/k3baudiotrackwidget.cpp new file mode 100644 index 0000000..a5a3971 --- /dev/null +++ b/src/projects/k3baudiotrackwidget.cpp @@ -0,0 +1,162 @@ +/* + * + * $Id: k3baudiotrackwidget.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3baudiotrackwidget.h" +#include "k3baudioeditorwidget.h" +#include "k3baudiotrack.h" + +#include <k3bmsfedit.h> +#include <k3bvalidators.h> +#include <k3bcdtextvalidator.h> + +#include <qlabel.h> +#include <qcheckbox.h> +#include <qtooltip.h> +#include <qwhatsthis.h> +#include <qwidgetstack.h> +#include <qgroupbox.h> +#include <qtabwidget.h> + +#include <klineedit.h> +#include <klocale.h> +#include <kdebug.h> + + + +K3bAudioTrackWidget::K3bAudioTrackWidget( const QPtrList<K3bAudioTrack>& tracks, + QWidget* parent, const char* name ) + : base_K3bAudioTrackWidget( parent, name ), + m_tracks(tracks) +{ + m_labelPostGap->setBuddy( m_editPostGap ); + + QToolTip::add( m_labelPostGap, QToolTip::textFor( m_editPostGap ) ); + QWhatsThis::add( m_labelPostGap, QWhatsThis::textFor( m_editPostGap ) ); + + // no post-gap for the last track + m_editPostGap->setDisabled( tracks.count() == 1 && !tracks.getFirst()->next() ); + + K3bCdTextValidator* val = new K3bCdTextValidator( this ); + m_editSongwriter->setValidator( val ); + m_editArranger->setValidator( val ); + m_editComposer->setValidator( val ); + m_editMessage->setValidator( val ); + m_editTitle->setValidator( val ); + m_editPerformer->setValidator( val ); + m_editIsrc->setValidator( K3bValidators::isrcValidator( this ) ); + + load(); +} + + +K3bAudioTrackWidget::~K3bAudioTrackWidget() +{ +} + + +void K3bAudioTrackWidget::load() +{ + if( !m_tracks.isEmpty() ) { + + K3bAudioTrack* track = m_tracks.first(); + + m_editPostGap->setMsfValue( track->postGap() ); + + m_editTitle->setText( track->title() ); + m_editPerformer->setText( track->artist() ); + m_editArranger->setText( track->arranger() ); + m_editSongwriter->setText( track->songwriter() ); + m_editComposer->setText( track->composer() ); + m_editIsrc->setText( track->isrc() ); + m_editMessage->setText( track->cdTextMessage() ); + + m_checkCopyPermitted->setChecked( !track->copyProtection() ); + m_checkPreemphasis->setChecked( track->preEmp() ); + + // load CD-Text for all other tracks + for( track = m_tracks.next(); track != 0; track = m_tracks.next() ) { + + // FIXME: handle different post-gaps + // m_editPostGap->setMsfValue( track->postGap() ); + + if( track->title() != m_editTitle->text() ) + m_editTitle->setText( QString::null ); + + if( track->artist() != m_editPerformer->text() ) + m_editPerformer->setText( QString::null ); + + if( track->arranger() != m_editArranger->text() ) + m_editArranger->setText( QString::null ); + + if( track->songwriter() != m_editSongwriter->text() ) + m_editSongwriter->setText( QString::null ); + + if( track->composer() != m_editComposer->text() ) + m_editComposer->setText( QString::null ); + + if( track->isrc() != m_editIsrc->text() ) + m_editIsrc->setText( QString::null ); + + if( track->cdTextMessage() != m_editMessage->text() ) + m_editMessage->setText( QString::null ); + } + + if( m_tracks.count() > 1 ) { + m_checkCopyPermitted->setNoChange(); + m_checkPreemphasis->setNoChange(); + } + } + + m_editTitle->setFocus(); +} + + +void K3bAudioTrackWidget::save() +{ + // save CD-Text, preemphasis, and copy protection for all tracks. no problem + for( K3bAudioTrack* track = m_tracks.first(); track != 0; track = m_tracks.next() ) { + + if( m_editTitle->isModified() ) + track->setTitle( m_editTitle->text() ); + + if( m_editPerformer->isModified() ) + track->setArtist( m_editPerformer->text() ); + + if( m_editArranger->isModified() ) + track->setArranger( m_editArranger->text() ); + + if( m_editSongwriter->isModified() ) + track->setSongwriter( m_editSongwriter->text() ); + + if( m_editComposer->isModified() ) + track->setComposer( m_editComposer->text() ); + + if( m_editIsrc->isModified() ) + track->setIsrc( m_editIsrc->text() ); + + if( m_editMessage->isModified() ) + track->setCdTextMessage( m_editMessage->text() ); + + if( m_checkCopyPermitted->state() != QButton::NoChange ) + track->setCopyProtection( !m_checkCopyPermitted->isChecked() ); + + if( m_checkPreemphasis->state() != QButton::NoChange ) + track->setPreEmp( m_checkPreemphasis->isChecked() ); + + track->setIndex0( track->length() - m_editPostGap->msfValue() ); + } +} + +#include "k3baudiotrackwidget.moc" diff --git a/src/projects/k3baudiotrackwidget.h b/src/projects/k3baudiotrackwidget.h new file mode 100644 index 0000000..8f02fbb --- /dev/null +++ b/src/projects/k3baudiotrackwidget.h @@ -0,0 +1,48 @@ +/* + * + * $Id: k3baudiotrackwidget.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_AUDIO_TRACK_WIDGET_H_ +#define _K3B_AUDIO_TRACK_WIDGET_H_ + +#include "base_k3baudiotrackwidget.h" + +#include <k3bmsf.h> + +#include <qptrlist.h> + + +class K3bAudioTrack; + + +/** + * This class is used internally by K3bAudioTrackDialog. + */ +class K3bAudioTrackWidget : public base_K3bAudioTrackWidget +{ + Q_OBJECT + + public: + K3bAudioTrackWidget( const QPtrList<K3bAudioTrack>& tracks, + QWidget* parent = 0, const char* name = 0 ); + ~K3bAudioTrackWidget(); + + public slots: + void save(); + void load(); + + QPtrList<K3bAudioTrack> m_tracks; +}; + +#endif diff --git a/src/projects/k3baudioview.cpp b/src/projects/k3baudioview.cpp new file mode 100644 index 0000000..3cfe0c0 --- /dev/null +++ b/src/projects/k3baudioview.cpp @@ -0,0 +1,136 @@ +/* + * + * $Id: k3baudioview.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include <config.h> + +#include "k3baudioview.h" +#include "k3baudiotrackview.h" +#include "k3baudioburndialog.h" +#include "k3baudiotrackplayer.h" +#include "k3baudioburndialog.h" +#include "k3baudiotrackaddingdialog.h" +#include <k3bapplication.h> + +#include <k3baudiodoc.h> +#include <k3baudiotrack.h> +#include <k3baudiofile.h> +#include <k3bpluginmanager.h> + +// this is not here becasue of base_*.ui troubles +#include "../rip/k3baudioprojectconvertingdialog.h" + +#include <k3bfillstatusdisplay.h> +#include <k3bmsf.h> +#include <k3btoolbox.h> +#include <kactionclasses.h> +#include <k3bprojectplugin.h> + +// QT-includes +#include <qlayout.h> +#include <qstring.h> + +// KDE-includes +#include <klocale.h> +#include <kapplication.h> +#include <kdebug.h> +#include <kmessagebox.h> + + + +K3bAudioView::K3bAudioView( K3bAudioDoc* pDoc, QWidget* parent, const char *name ) + : K3bView( pDoc, parent, name ) +{ + m_doc = pDoc; + + m_songlist = new K3bAudioTrackView( m_doc, this ); + setMainWidget( m_songlist ); + fillStatusDisplay()->showTime(); + + // add button for the audio conversion + KAction* conversionAction = new KAction( i18n("Convert Tracks"), "redo", 0, this, SLOT(slotAudioConversion()), + actionCollection(), "project_audio_convert" ); + conversionAction->setToolTip( i18n("Convert audio tracks to other audio formats." ) ); + + toolBox()->addButton( conversionAction ); + toolBox()->addSeparator(); + + toolBox()->addButton( m_songlist->player()->action( K3bAudioTrackPlayer::ACTION_PLAY ) ); + toolBox()->addButton( m_songlist->player()->action( K3bAudioTrackPlayer::ACTION_PAUSE ) ); + toolBox()->addButton( m_songlist->player()->action( K3bAudioTrackPlayer::ACTION_STOP ) ); + toolBox()->addSpacing(); + toolBox()->addButton( m_songlist->player()->action( K3bAudioTrackPlayer::ACTION_PREV ) ); + toolBox()->addButton( m_songlist->player()->action( K3bAudioTrackPlayer::ACTION_NEXT ) ); + toolBox()->addSpacing(); + toolBox()->addWidgetAction( static_cast<KWidgetAction*>(m_songlist->player()->action( K3bAudioTrackPlayer::ACTION_SEEK )) ); + toolBox()->addSeparator(); + +#ifdef HAVE_MUSICBRAINZ + kdDebug() << "(K3bAudioView) m_songlist->actionCollection()->actions().count() " << m_songlist->actionCollection()->actions().count() << endl; + toolBox()->addButton( m_songlist->actionCollection()->action( "project_audio_musicbrainz" ) ); + toolBox()->addSeparator(); +#endif + + addPluginButtons( K3bProjectPlugin::AUDIO_CD ); + + toolBox()->addStretch(); + + // this is just for testing (or not?) + // most likely every project type will have it's rc file in the future + // we only add the additional actions since K3bView already added the default actions + setXML( "<!DOCTYPE kpartgui SYSTEM \"kpartgui.dtd\">" + "<kpartgui name=\"k3bproject\" version=\"1\">" + "<MenuBar>" + " <Menu name=\"project\"><text>&Project</text>" + " <Action name=\"project_audio_convert\"/>" +#ifdef HAVE_MUSICBRAINZ + " <Action name=\"project_audio_musicbrainz\"/>" +#endif + " </Menu>" + "</MenuBar>" + "</kpartgui>", true ); +} + +K3bAudioView::~K3bAudioView() +{ +} + + +void K3bAudioView::init() +{ + if( k3bcore->pluginManager()->plugins( "AudioDecoder" ).isEmpty() ) + KMessageBox::error( this, i18n("No audio decoder plugins found. You will not be able to add any files " + "to the audio project!") ); +} + + +K3bProjectBurnDialog* K3bAudioView::newBurnDialog( QWidget* parent, const char* name ) +{ + return new K3bAudioBurnDialog( m_doc, parent, name, true ); +} + + +void K3bAudioView::slotAudioConversion() +{ + K3bAudioProjectConvertingDialog dlg( m_doc, this ); + dlg.exec(); +} + + +void K3bAudioView::addUrls( const KURL::List& urls ) +{ + K3bAudioTrackAddingDialog::addUrls( urls, m_doc, 0, 0, 0, this ); +} + +#include "k3baudioview.moc" diff --git a/src/projects/k3baudioview.h b/src/projects/k3baudioview.h new file mode 100644 index 0000000..99740a3 --- /dev/null +++ b/src/projects/k3baudioview.h @@ -0,0 +1,61 @@ +/* + * + * $Id: k3baudioview.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BAUDIOVIEW_H +#define K3BAUDIOVIEW_H + +#include <k3bview.h> +#include "k3baudiotrackview.h" + +#include <qstringlist.h> + + +class K3bAudioDoc; +class K3bAudioTrack; +class K3bAudioTrackView; + + +/** + *@author Sebastian Trueg + */ +class K3bAudioView : public K3bView +{ + Q_OBJECT + + public: + K3bAudioView( K3bAudioDoc* pDoc, QWidget* parent, const char *name = 0 ); + ~K3bAudioView(); + + K3bAudioTrackPlayer* player() const { return m_songlist->player(); } + + public slots: + void addUrls( const KURL::List& ); + + protected: + K3bProjectBurnDialog* newBurnDialog( QWidget* parent = 0, const char* name = 0 ); + + void init(); + + private slots: + void slotAudioConversion(); + + private: + K3bAudioDoc* m_doc; + + K3bAudioTrackView* m_songlist; +}; + +#endif diff --git a/src/projects/k3bbootimagedialog.cpp b/src/projects/k3bbootimagedialog.cpp new file mode 100644 index 0000000..c311082 --- /dev/null +++ b/src/projects/k3bbootimagedialog.cpp @@ -0,0 +1,45 @@ +/* + * + * $Id: k3bbootimagedialog.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bbootimagedialog.h" +#include "k3bbootimageview.h" + +#include <klocale.h> + + +K3bBootImageDialog::K3bBootImageDialog( K3bDataDoc* doc, + QWidget* parent, + const char* name, + bool modal ) + : KDialogBase( parent, name, modal, i18n("Boot Images"), Ok ) +{ + m_bootImageView = new K3bBootImageView( doc, this ); + setMainWidget( m_bootImageView ); +} + + +K3bBootImageDialog::~K3bBootImageDialog() +{ +} + + +void K3bBootImageDialog::slotOk() +{ + // m_bootImageView->save(); + done( Ok ); +} + +#include "k3bbootimagedialog.moc" diff --git a/src/projects/k3bbootimagedialog.h b/src/projects/k3bbootimagedialog.h new file mode 100644 index 0000000..161c4b5 --- /dev/null +++ b/src/projects/k3bbootimagedialog.h @@ -0,0 +1,44 @@ +/* + * + * $Id: k3bbootimagedialog.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BBOOTIMAGE_DIALOG_H +#define K3BBOOTIMAGE_DIALOG_H + +#include <kdialogbase.h> + +class K3bBootImageView; +class K3bDataDoc; + + +class K3bBootImageDialog : public KDialogBase +{ + Q_OBJECT + + public: + K3bBootImageDialog( K3bDataDoc*, + QWidget* parent = 0, + const char* name = 0, + bool modal = true ); + ~K3bBootImageDialog(); + + private slots: + void slotOk(); + + private: + K3bBootImageView* m_bootImageView; +}; + +#endif diff --git a/src/projects/k3bbootimageview.cpp b/src/projects/k3bbootimageview.cpp new file mode 100644 index 0000000..22907df --- /dev/null +++ b/src/projects/k3bbootimageview.cpp @@ -0,0 +1,273 @@ +/* + * + * $Id: k3bbootimageview.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bbootimageview.h" + +#include "k3bdatadoc.h" +#include "k3bbootitem.h" +#include <k3bintvalidator.h> + +#include <klocale.h> +#include <klistview.h> +#include <kfiledialog.h> +#include <kdebug.h> +#include <kmessagebox.h> + +#include <qpushbutton.h> +#include <qstring.h> +#include <qgroupbox.h> +#include <qlineedit.h> +#include <qcheckbox.h> +#include <qradiobutton.h> +#include <qbuttongroup.h> +#include <qregexp.h> + + + +class K3bBootImageView::PrivateBootImageViewItem : public KListViewItem +{ +public: + PrivateBootImageViewItem( K3bBootItem* image, QListView* parent ) + : KListViewItem( parent ), + m_image( image ) { + + } + + PrivateBootImageViewItem( K3bBootItem* image, QListView* parent, QListViewItem* after ) + : KListViewItem( parent, after ), + m_image( image ) { + + } + + QString text( int col ) const { + if( col == 0 ) { + if( m_image->imageType() == K3bBootItem::FLOPPY ) + return i18n("Floppy"); + else if( m_image->imageType() == K3bBootItem::HARDDISK ) + return i18n("Harddisk"); + else + return i18n("None"); + } + else if( col == 1 ) + return QString( "%1 KB" ).arg( m_image->size()/1024 ); + else if( col == 2 ) + return m_image->localPath(); + else + return QString::null; + } + + K3bBootItem* bootImage() const { return m_image; } + +private: + K3bBootItem* m_image; +}; + + +K3bBootImageView::K3bBootImageView( K3bDataDoc* doc, QWidget* parent, const char* name ) + : base_K3bBootImageView( parent, name ), + m_doc(doc) +{ + connect( m_buttonNew, SIGNAL(clicked()), + this, SLOT(slotNewBootImage()) ); + connect( m_buttonDelete, SIGNAL(clicked()), + this, SLOT(slotDeleteBootImage()) ); + connect( m_buttonToggleOptions, SIGNAL(clicked()), + this, SLOT(slotToggleOptions()) ); + connect( m_viewImages, SIGNAL(selectionChanged()), + this, SLOT(slotSelectionChanged()) ); + connect( m_radioNoEmulation, SIGNAL(toggled(bool)), + this, SLOT(slotNoEmulationToggled(bool)) ); + + K3bIntValidator* v = new K3bIntValidator( this ); + m_editLoadSegment->setValidator( v ); + m_editLoadSize->setValidator( v ); + + updateBootImages(); + + showAdvancedOptions( false ); + loadBootItemSettings(0); +} + +K3bBootImageView::~K3bBootImageView() +{ +} + + +void K3bBootImageView::slotToggleOptions() +{ + showAdvancedOptions( !m_groupOptions->isVisible() ); +} + + +void K3bBootImageView::showAdvancedOptions( bool show ) +{ + if( show ) { + m_groupOptions->show(); + m_buttonToggleOptions->setText( i18n("Hide Advanced Options") ); + } + else { + m_groupOptions->hide(); + m_buttonToggleOptions->setText( i18n("Show Advanced Options") ); + } +} + + +void K3bBootImageView::slotNewBootImage() +{ + QString file = KFileDialog::getOpenFileName( QString::null, QString::null, this, i18n("Please Choose Boot Image") ); + if( !file.isEmpty() ) { + KIO::filesize_t fsize = K3b::filesize( file ); + int boottype = K3bBootItem::FLOPPY; + if( fsize != 1200*1024 && + fsize != 1440*1024 && + fsize != 2880*1024 ) { + switch( KMessageBox::warningYesNoCancel( this, + i18n("<p>The file you selected is not a floppy image (floppy images are " + "of size 1200 KB, 1440 KB, or 2880 KB). You may still use boot images " + "of other sizes by emulating a harddisk or disabling emulation completely. " + "<p>If you are not familiar with terms like 'harddisk emulation' you most " + "likely want to use a floppy image here. Floppy images can be created by " + "directly extracting them from a real floppy disk:" + "<pre>dd if=/dev/floppy of=/tmp/floppy.img</pre>" + "or by using one of the many boot floppy generators that can be found on " + "<a href=\"http://www.google.com/search?q=linux+boot+floppy&ie=UTF-8&oe=UTF-8\">the internet</a>."), + i18n("No Floppy image selected"), + i18n("Use harddisk emulation"), + i18n("Use no emulation"), + QString::null, + KMessageBox::AllowLink ) ) { + case KMessageBox::Yes: + boottype = K3bBootItem::HARDDISK; + break; + case KMessageBox::No: + boottype = K3bBootItem::NONE; + break; + default: + return; + } + } + + m_doc->createBootItem( file )->setImageType( boottype ); + updateBootImages(); + } +} + + +void K3bBootImageView::slotDeleteBootImage() +{ + QListViewItem* item = m_viewImages->selectedItem(); + if( item ) { + K3bBootItem* i = ((PrivateBootImageViewItem*)item)->bootImage(); + delete item; + m_doc->removeItem( i ); + } +} + + +void K3bBootImageView::slotSelectionChanged() +{ + QListViewItem* item = m_viewImages->selectedItem(); + if( item ) + loadBootItemSettings( ((PrivateBootImageViewItem*)item)->bootImage() ); + else + loadBootItemSettings( 0 ); +} + + +void K3bBootImageView::updateBootImages() +{ + m_viewImages->clear(); + for( QPtrListIterator<K3bBootItem> it( m_doc->bootImages() ); it.current(); ++it ) { + (void)new PrivateBootImageViewItem( *it, m_viewImages, + m_viewImages->lastItem() ); + } +} + + +void K3bBootImageView::loadBootItemSettings( K3bBootItem* item ) +{ + // this is needed to prevent the slots to change stuff + m_loadingItem = true; + + if( item ) { + m_groupOptions->setEnabled(true); + m_groupImageType->setEnabled(true); + + m_checkNoBoot->setChecked( item->noBoot() ); + m_checkInfoTable->setChecked( item->bootInfoTable() ); + m_editLoadSegment->setText( "0x" + QString::number( item->loadSegment(), 16 ) ); + m_editLoadSize->setText( "0x" + QString::number( item->loadSize(), 16 ) ); + + if( item->imageType() == K3bBootItem::FLOPPY ) + m_radioFloppy->setChecked(true); + else if( item->imageType() == K3bBootItem::HARDDISK ) + m_radioHarddisk->setChecked(true); + else + m_radioNoEmulation->setChecked(true); + + // force floppy size + KIO::filesize_t fsize = K3b::filesize( item->localPath() ); + m_radioFloppy->setDisabled( fsize != 1200*1024 && + fsize != 1440*1024 && + fsize != 2880*1024 ); + } + else { + m_groupOptions->setEnabled(false); + m_groupImageType->setEnabled(false); + } + + m_loadingItem = false; +} + + +void K3bBootImageView::slotOptionsChanged() +{ + if( !m_loadingItem ) { + QListViewItem* item = m_viewImages->selectedItem(); + if( item ) { + K3bBootItem* i = ((PrivateBootImageViewItem*)item)->bootImage(); + + i->setNoBoot( m_checkNoBoot->isChecked() ); + i->setBootInfoTable( m_checkInfoTable->isChecked() ); + + // TODO: create some class K3bIntEdit : public QLineEdit + bool ok = true; + i->setLoadSegment( K3bIntValidator::toInt( m_editLoadSegment->text(), &ok ) ); + if( !ok ) + kdDebug() << "(K3bBootImageView) parsing number failed: " << m_editLoadSegment->text().lower() << endl; + i->setLoadSize( K3bIntValidator::toInt( m_editLoadSize->text(), &ok ) ); + if( !ok ) + kdDebug() << "(K3bBootImageView) parsing number failed: " << m_editLoadSize->text().lower() << endl; + + if( m_radioFloppy->isChecked() ) + i->setImageType( K3bBootItem::FLOPPY ); + else if( m_radioHarddisk->isChecked() ) + i->setImageType( K3bBootItem::HARDDISK ); + else + i->setImageType( K3bBootItem::NONE ); + } + } +} + + +void K3bBootImageView::slotNoEmulationToggled( bool on ) +{ + // it makes no sense to combine no emulation and no boot! + // the base_widget takes care of the disabling + if( on ) + m_checkNoBoot->setChecked(false); +} + +#include "k3bbootimageview.moc" diff --git a/src/projects/k3bbootimageview.h b/src/projects/k3bbootimageview.h new file mode 100644 index 0000000..cf41de1 --- /dev/null +++ b/src/projects/k3bbootimageview.h @@ -0,0 +1,57 @@ +/* + * + * $Id: k3bbootimageview.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3B_BOOTIMAGEVIEW_H +#define K3B_BOOTIMAGEVIEW_H + +#include "base_k3bbootimageview.h" + +class K3bDataDoc; +class K3bBootItem; + + +class K3bBootImageView : public base_K3bBootImageView +{ + Q_OBJECT + +public: + K3bBootImageView( K3bDataDoc* doc, QWidget* parent = 0, const char* name = 0 ); + ~K3bBootImageView(); + + private slots: + void slotNewBootImage(); + void slotDeleteBootImage(); + void slotToggleOptions(); + void slotSelectionChanged(); + + /* reimplemeted from base_...*/ + void slotOptionsChanged(); + + void slotNoEmulationToggled( bool ); + + private: + void updateBootImages(); + void showAdvancedOptions( bool ); + void loadBootItemSettings( K3bBootItem* ); + + class PrivateBootImageViewItem; + + K3bDataDoc* m_doc; + + bool m_loadingItem; +}; + +#endif diff --git a/src/projects/k3bdataadvancedimagesettingswidget.cpp b/src/projects/k3bdataadvancedimagesettingswidget.cpp new file mode 100644 index 0000000..ac24813 --- /dev/null +++ b/src/projects/k3bdataadvancedimagesettingswidget.cpp @@ -0,0 +1,352 @@ +/* + * + * $Id: k3bdataadvancedimagesettingswidget.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bdataadvancedimagesettingswidget.h" + +#include "k3bisooptions.h" + +#include <qcheckbox.h> +#include <qradiobutton.h> +#include <qbuttongroup.h> +#include <qheader.h> +#include <qwhatsthis.h> +#include <qpoint.h> +#include <qpainter.h> +#include <qpalette.h> +#include <qvalidator.h> +#include <qregexp.h> + +#include <klistview.h> +#include <kcombobox.h> +#include <klocale.h> +#include <kdebug.h> + + +static const char * mkisofsCharacterSets[] = { "cp10081", + "cp10079", + "cp10029", + "cp10007", + "cp10006", + "cp10000", + "koi8-u", + "koi8-r", + "cp1251", + "cp1250", + "cp874", + "cp869", + "cp866", + "cp865", + "cp864", + "cp863", + "cp862", + "cp861", + "cp860", + "cp857", + "cp855", + "cp852", + "cp850", + "cp775", + "cp737", + "cp437", + "iso8859-15", + "iso8859-14", + "iso8859-9", + "iso8859-8", + "iso8859-7", + "iso8859-6", + "iso8859-5", + "iso8859-4", + "iso8859-3", + "iso8859-2", + "iso8859-1", + 0 }; // terminating zero + + + +class K3bDataAdvancedImageSettingsWidget::PrivateIsoWhatsThis : public QWhatsThis +{ +public: + PrivateIsoWhatsThis( K3bDataAdvancedImageSettingsWidget* w ) + : QWhatsThis( w->m_viewIsoSettings->viewport() ) { + this->w = w; + } + + QString text( const QPoint& p ) { + QListViewItem* i = w->m_viewIsoSettings->selectedItem(); // dies funktioniert nur bei rechtsklick + QListViewItem* i2 = w->m_viewIsoSettings->itemAt( p ); // dies funktioniert nur bei action whatsthis + + if( i2 != 0 ) + kdDebug() << "at p " << i2->text(0) << endl; + + if( i == w->m_checkAllowUntranslatedFilenames ) + return i18n( "Force all options below" ); + else if( i == w->m_radioIsoLevel1 || + i == w->m_radioIsoLevel2 || + i == w->m_radioIsoLevel3 || + i == w->m_isoLevelController ) + return i18n( "<p>Set the ISO-9660 conformance level.\n" + "<ul>\n" + "<li>Level 1: Files may only consist of one section and filenames are restricted " + "to 8.3 characters.</li>\n" + "<li>Level 2: Files may only consist of one section.</li>\n" + "<li>Level 3: No restrictions.</li>\n" + "</ul>\n" + "<p>With all ISO-9660 levels, all filenames are restricted to upper case letters, " + "numbers and the underscore (_). The maximum filename length is 31 characters, the " + "directory nesting level is restricted to 8 and the maximum path length is limited " + "to 255 characters. (These restrictions may be violated with the additional ISO-9660 K3b offers)." ); + else + return i18n("Set special ISO9660 Filesystem preferences."); + } + +private: + K3bDataAdvancedImageSettingsWidget* w; +}; + + + +class K3bDataAdvancedImageSettingsWidget::PrivateCheckViewItem : public QCheckListItem +{ +public: + PrivateCheckViewItem( QListView* parent, const QString& text, Type tt = Controller ) + : QCheckListItem( parent, text, tt ) { + } + + PrivateCheckViewItem( QListViewItem* parent, const QString& text, Type tt = Controller ) + : QCheckListItem( parent, text, tt ) { + } + +protected: + void stateChange( bool on ) { + // enable or disable all children + QListViewItem* item = firstChild(); + while( item ) { + if( PrivateCheckViewItem* pi = dynamic_cast<PrivateCheckViewItem*>(item) ) + pi->setEnabled( !on ); + item = item->nextSibling(); + } + } +}; + + +K3bDataAdvancedImageSettingsWidget::K3bDataAdvancedImageSettingsWidget( QWidget* parent, const char* name ) + : base_K3bAdvancedDataImageSettings( parent, name ) +{ + m_viewIsoSettings->header()->hide(); + m_viewIsoSettings->setSorting( -1 ); + + // create WhatsThis for the isoSettings view + (void)new PrivateIsoWhatsThis( this ); + + // create all the view items + QCheckListItem* iso9660Root = new QCheckListItem( m_viewIsoSettings, + i18n("IS09660 Settings"), + QCheckListItem::Controller ); + QCheckListItem* rrRoot = new QCheckListItem( m_viewIsoSettings, + iso9660Root, + i18n("Rock Ridge Settings"), + QCheckListItem::Controller ); + QCheckListItem* jolietRoot = new QCheckListItem( m_viewIsoSettings, + rrRoot, + i18n("Joliet Settings"), + QCheckListItem::Controller ); + QCheckListItem* miscRoot = new QCheckListItem( m_viewIsoSettings, + jolietRoot, + i18n("Misc Settings"), + QCheckListItem::Controller ); + + // ISO9660 settings + m_checkAllowUntranslatedFilenames = new PrivateCheckViewItem( iso9660Root, + i18n( "Allow untranslated ISO9660 filenames" ), + QCheckListItem::CheckBox ); + m_checkAllowMaxLengthFilenames = new PrivateCheckViewItem( m_checkAllowUntranslatedFilenames, + i18n( "Allow max length ISO9660 filenames (37 characters)" ), + QCheckListItem::CheckBox ); + m_checkAllowFullAscii = new PrivateCheckViewItem( m_checkAllowUntranslatedFilenames, + i18n( "Allow full ASCII charset for ISO9660 filenames" ), + QCheckListItem::CheckBox ); + m_checkAllowOther = new PrivateCheckViewItem( m_checkAllowUntranslatedFilenames, + i18n( "Allow ~ and # in ISO9660 filenames" ), + QCheckListItem::CheckBox ); + m_checkAllowLowercaseCharacters = new PrivateCheckViewItem( m_checkAllowUntranslatedFilenames, + i18n( "Allow lowercase characters in ISO9660 filenames" ), + QCheckListItem::CheckBox ); + m_checkAllowMultiDot = new PrivateCheckViewItem( m_checkAllowUntranslatedFilenames, + i18n( "Allow multiple dots in ISO9660 filenames" ), + QCheckListItem::CheckBox ); + m_checkAllow31CharFilenames = new PrivateCheckViewItem( m_checkAllowUntranslatedFilenames, + i18n( "Allow 31 character ISO9660 filenames" ), + QCheckListItem::CheckBox ); + m_checkAllowBeginningPeriod = new PrivateCheckViewItem( m_checkAllowUntranslatedFilenames, + i18n( "Allow leading period in ISO9660 filenames" ), + QCheckListItem::CheckBox ); + m_checkOmitVersionNumbers = new PrivateCheckViewItem( m_checkAllowUntranslatedFilenames, + i18n( "Omit version numbers in ISO9660 filenames" ), + QCheckListItem::CheckBox ); + m_checkOmitTrailingPeriod = new PrivateCheckViewItem( m_checkAllowUntranslatedFilenames, + i18n( "Omit trailing period in ISO9660 filenames" ), + QCheckListItem::CheckBox ); + + m_checkAllowUntranslatedFilenames->setOpen(true); + m_isoLevelController = new QCheckListItem( iso9660Root, + m_checkAllowUntranslatedFilenames, + i18n("ISO Level") ); + + m_radioIsoLevel3 = new QCheckListItem( m_isoLevelController, + i18n("Level %1").arg(3), + QCheckListItem::RadioButton ); + m_radioIsoLevel2 = new QCheckListItem( m_isoLevelController, + i18n("Level %1").arg(2), + QCheckListItem::RadioButton ); + m_radioIsoLevel1 = new QCheckListItem( m_isoLevelController, + i18n("Level %1").arg(1), + QCheckListItem::RadioButton ); + + m_isoLevelController->setOpen(true); + + // Joliet Settings + m_checkJolietLong = new QCheckListItem( jolietRoot, + i18n("Allow 103 character Joliet filenames"), + QCheckListItem::CheckBox ); + + // Rock Ridge Settings + m_checkCreateTransTbl = new QCheckListItem( rrRoot, + i18n( "Create TRANS.TBL files" ), + QCheckListItem::CheckBox ); + m_checkHideTransTbl = new QCheckListItem( rrRoot, m_checkCreateTransTbl, + i18n( "Hide TRANS.TBL files in Joliet" ), + QCheckListItem::CheckBox ); + + // Misc Settings +// m_checkFollowSymbolicLinks = new QCheckListItem( m_viewIsoSettings, +// i18n( "Follow symbolic links" ), +// QCheckListItem::CheckBox ); + + m_checkDoNotCacheInodes = new QCheckListItem( miscRoot, + i18n("Do not cache inodes" ), + QCheckListItem::CheckBox ); + + iso9660Root->setOpen( true ); + jolietRoot->setOpen( true ); + rrRoot->setOpen( true ); + miscRoot->setOpen( true ); + + + m_comboInputCharset->setValidator( new QRegExpValidator( QRegExp("[\\w_-]*"), this ) ); + + // fill charset combo + for( int i = 0; mkisofsCharacterSets[i]; i++ ) { + m_comboInputCharset->insertItem( QString( mkisofsCharacterSets[i] ) ); + } + + connect( m_checkJoliet, SIGNAL(toggled(bool)), this, SLOT(slotJolietToggled(bool)) ); +} + + +K3bDataAdvancedImageSettingsWidget::~K3bDataAdvancedImageSettingsWidget() +{ +} + + +void K3bDataAdvancedImageSettingsWidget::load( const K3bIsoOptions& o ) +{ + m_checkRockRidge->setChecked( o.createRockRidge() ); + m_checkJoliet->setChecked( o.createJoliet() ); + m_checkUdf->setChecked( o.createUdf() ); + + switch( o.ISOLevel() ) { + case 1: + m_radioIsoLevel1->setOn(true); + break; + case 2: + m_radioIsoLevel2->setOn(true); + break; + case 3: + m_radioIsoLevel3->setOn(true); + break; + } + + m_checkForceInputCharset->setChecked( o.forceInputCharset() ); + m_comboInputCharset->setEditText( o.inputCharset() ); + m_checkPreservePermissions->setChecked( o.preserveFilePermissions() ); + + // RR settings + m_checkCreateTransTbl->setOn( o.createTRANS_TBL() ); + m_checkHideTransTbl->setOn( o.hideTRANS_TBL() ); + + // iso9660 settings + m_checkAllowUntranslatedFilenames->setOn( o.ISOuntranslatedFilenames() ); + m_checkAllow31CharFilenames->setOn( o.ISOallow31charFilenames() ); + m_checkAllowMaxLengthFilenames->setOn( o.ISOmaxFilenameLength() ); + m_checkAllowBeginningPeriod->setOn( o.ISOallowPeriodAtBegin() ); + m_checkAllowFullAscii->setOn( o.ISOrelaxedFilenames() ); + m_checkOmitVersionNumbers->setOn( o.ISOomitVersionNumbers() ); + m_checkOmitTrailingPeriod->setOn( o.ISOomitTrailingPeriod() ); + m_checkAllowOther->setOn( o.ISOnoIsoTranslate() ); + m_checkAllowMultiDot->setOn( o.ISOallowMultiDot() ); + m_checkAllowLowercaseCharacters->setOn( o.ISOallowLowercase() ); + + // joliet settings + m_checkJolietLong->setOn( o.jolietLong() ); + + // misc (FIXME: should not be here) + m_checkDoNotCacheInodes->setOn( o.doNotCacheInodes() ); + + slotJolietToggled( m_checkJoliet->isChecked() ); +} + + +void K3bDataAdvancedImageSettingsWidget::save( K3bIsoOptions& o ) +{ + o.setCreateRockRidge( m_checkRockRidge->isChecked() ); + o.setCreateJoliet( m_checkJoliet->isChecked() ); + o.setCreateUdf( m_checkUdf->isChecked() ); + + // save iso-level + if( m_radioIsoLevel3->isOn() ) + o.setISOLevel( 3 ); + else if( m_radioIsoLevel2->isOn() ) + o.setISOLevel( 2 ); + else + o.setISOLevel( 1 ); + + o.setForceInputCharset( m_checkForceInputCharset->isChecked() ); + o.setInputCharset( m_comboInputCharset->currentText() ); + o.setPreserveFilePermissions( m_checkPreservePermissions->isChecked() ); + + o.setCreateTRANS_TBL( m_checkCreateTransTbl->isOn() ); + o.setHideTRANS_TBL( m_checkHideTransTbl->isOn() ); + o.setISOuntranslatedFilenames( m_checkAllowUntranslatedFilenames->isOn() ); + o.setISOallow31charFilenames( m_checkAllow31CharFilenames->isOn() ); + o.setISOmaxFilenameLength( m_checkAllowMaxLengthFilenames->isOn() ); + o.setISOallowPeriodAtBegin( m_checkAllowBeginningPeriod->isOn() ); + o.setISOrelaxedFilenames( m_checkAllowFullAscii->isOn() ); + o.setISOomitVersionNumbers( m_checkOmitVersionNumbers->isOn() ); + o.setISOomitTrailingPeriod( m_checkOmitTrailingPeriod->isOn() ); + o.setISOnoIsoTranslate( m_checkAllowOther->isOn() ); + o.setISOallowMultiDot( m_checkAllowMultiDot->isOn() ); + o.setISOallowLowercase( m_checkAllowLowercaseCharacters->isOn() ); + // o.setFollowSymbolicLinks( m_checkFollowSymbolicLinks->isOn() ); + o.setJolietLong( m_checkJolietLong->isOn() ); + o.setDoNotCacheInodes( m_checkDoNotCacheInodes->isOn() ); +} + + +void K3bDataAdvancedImageSettingsWidget::slotJolietToggled( bool on ) +{ + m_checkJolietLong->setEnabled( on ); +} + +#include "k3bdataadvancedimagesettingswidget.moc" diff --git a/src/projects/k3bdataadvancedimagesettingswidget.h b/src/projects/k3bdataadvancedimagesettingswidget.h new file mode 100644 index 0000000..eb442e3 --- /dev/null +++ b/src/projects/k3bdataadvancedimagesettingswidget.h @@ -0,0 +1,69 @@ +/* + * + * $Id: k3bdataadvancedimagesettingswidget.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef K3B_DATA_ADVANCED_IMAGE_SETTINGS_WIDGET_H +#define K3B_DATA_ADVANCED_IMAGE_SETTINGS_WIDGET_H + + +#include "base_k3badvanceddataimagesettings.h" + +class K3bIsoOptions; +class QCheckListItem; + + +class K3bDataAdvancedImageSettingsWidget : public base_K3bAdvancedDataImageSettings +{ + Q_OBJECT + + public: + K3bDataAdvancedImageSettingsWidget( QWidget* parent = 0, const char* name = 0 ); + ~K3bDataAdvancedImageSettingsWidget(); + + void load( const K3bIsoOptions& ); + void save( K3bIsoOptions& ); + + private slots: + void slotJolietToggled( bool on ); + + private: + QCheckListItem* m_checkAllowUntranslatedFilenames; + QCheckListItem* m_checkAllowMaxLengthFilenames; + QCheckListItem* m_checkAllowFullAscii; + QCheckListItem* m_checkAllowOther; + QCheckListItem* m_checkAllowLowercaseCharacters; + QCheckListItem* m_checkAllowMultiDot; + QCheckListItem* m_checkOmitVersionNumbers; + QCheckListItem* m_checkOmitTrailingPeriod; + QCheckListItem* m_checkCreateTransTbl; + QCheckListItem* m_checkHideTransTbl; + QCheckListItem* m_checkFollowSymbolicLinks; + QCheckListItem* m_checkAllow31CharFilenames; + QCheckListItem* m_checkAllowBeginningPeriod; + QCheckListItem* m_checkJolietLong; + QCheckListItem* m_checkDoNotCacheInodes; + + QCheckListItem* m_isoLevelController; + QCheckListItem* m_radioIsoLevel1; + QCheckListItem* m_radioIsoLevel2; + QCheckListItem* m_radioIsoLevel3; + + class PrivateCheckViewItem; + class PrivateIsoWhatsThis; + + friend class PrivateIsoWhatsThis; +}; + + +#endif diff --git a/src/projects/k3bdataburndialog.cpp b/src/projects/k3bdataburndialog.cpp new file mode 100644 index 0000000..d920fd4 --- /dev/null +++ b/src/projects/k3bdataburndialog.cpp @@ -0,0 +1,289 @@ +/* + * + * $Id: k3bdataburndialog.cpp 690207 2007-07-20 10:40:19Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bdataburndialog.h" +#include "k3bdataimagesettingswidget.h" +#include "k3bdatavolumedescwidget.h" +#include "k3bdatamultisessioncombobox.h" +#include "k3bdataview.h" + +#include <k3bisooptions.h> +#include <k3bdatadoc.h> +#include <k3bdevice.h> +#include <k3bwriterselectionwidget.h> +#include <k3btempdirselectionwidget.h> +#include <k3bjob.h> +#include <k3bcore.h> +#include <k3bstdguiitems.h> +#include <k3bdatamodewidget.h> +#include <k3bglobals.h> +#include <k3bwritingmodewidget.h> + +#include <qcheckbox.h> +#include <qframe.h> +#include <qgroupbox.h> +#include <qlabel.h> +#include <qlineedit.h> +#include <qpushbutton.h> +#include <qtoolbutton.h> +#include <qlayout.h> +#include <qvariant.h> +#include <qtooltip.h> +#include <qwhatsthis.h> +#include <qpoint.h> +#include <qradiobutton.h> +#include <qbuttongroup.h> +#include <qfileinfo.h> +#include <qtabwidget.h> +#include <qspinbox.h> +#include <qfile.h> + +#include <kmessagebox.h> +#include <klineedit.h> +#include <klocale.h> +#include <kconfig.h> +#include <kstandarddirs.h> +#include <kfiledialog.h> +#include <kcombobox.h> +#include <kio/global.h> + + +#include "k3bfilecompilationsizehandler.h" + + +K3bDataBurnDialog::K3bDataBurnDialog(K3bDataDoc* _doc, QWidget *parent, const char *name, bool modal ) + : K3bProjectBurnDialog( _doc, parent, name, modal ) +{ + prepareGui(); + + setTitle( i18n("Data Project"), i18n("Size: %1").arg( KIO::convertSize(_doc->size()) ) ); + + // for now we just put the verify checkbox on the main page... + m_checkVerify = K3bStdGuiItems::verifyCheckBox( m_optionGroup ); + m_optionGroupLayout->addWidget( m_checkVerify ); + + QSpacerItem* spacer = new QSpacerItem( 20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding ); + m_optionGroupLayout->addItem( spacer ); + + // create image settings tab + m_imageSettingsWidget = new K3bDataImageSettingsWidget( this ); + addPage( m_imageSettingsWidget, i18n("Filesystem") ); + + setupSettingsTab(); + + connect( m_comboMultisession, SIGNAL(activated(int)), + this, SLOT(slotMultiSessionModeChanged()) ); + + m_writerSelectionWidget->setWantedMediumState( K3bDevice::STATE_EMPTY|K3bDevice::STATE_INCOMPLETE ); + + m_tempDirSelectionWidget->setSelectionMode( K3bTempDirSelectionWidget::FILE ); + QString path = _doc->tempDir(); + if( !path.isEmpty() ) { + m_tempDirSelectionWidget->setTempPath( path ); + } + if( !_doc->isoOptions().volumeID().isEmpty() ) { + m_tempDirSelectionWidget->setDefaultImageFileName( _doc->isoOptions().volumeID() + ".iso" ); + } + + connect( m_imageSettingsWidget->m_editVolumeName, SIGNAL(textChanged(const QString&)), + m_tempDirSelectionWidget, SLOT(setDefaultImageFileName(const QString&)) ); +} + +K3bDataBurnDialog::~K3bDataBurnDialog() +{ +} + + +void K3bDataBurnDialog::saveSettings() +{ + K3bProjectBurnDialog::saveSettings(); + + // save iso image settings + K3bIsoOptions o = ((K3bDataDoc*)doc())->isoOptions(); + m_imageSettingsWidget->save( o ); + ((K3bDataDoc*)doc())->setIsoOptions( o ); + + // save image file path + ((K3bDataDoc*)doc())->setTempDir( m_tempDirSelectionWidget->tempPath() ); + + // save multisession settings + ((K3bDataDoc*)doc())->setMultiSessionMode( m_comboMultisession->multiSessionMode() ); + + ((K3bDataDoc*)doc())->setDataMode( m_dataModeWidget->dataMode() ); + + ((K3bDataDoc*)doc())->setVerifyData( m_checkVerify->isChecked() ); +} + + +void K3bDataBurnDialog::readSettings() +{ + K3bProjectBurnDialog::readSettings(); + + // read multisession + m_comboMultisession->setMultiSessionMode( ((K3bDataDoc*)doc())->multiSessionMode() ); + + if( !doc()->tempDir().isEmpty() ) + m_tempDirSelectionWidget->setTempPath( doc()->tempDir() ); + else + m_tempDirSelectionWidget->setTempPath( K3b::defaultTempPath() + doc()->name() + ".iso" ); + + m_checkVerify->setChecked( ((K3bDataDoc*)doc())->verifyData() ); + + m_imageSettingsWidget->load( ((K3bDataDoc*)doc())->isoOptions() ); + + m_dataModeWidget->setDataMode( ((K3bDataDoc*)doc())->dataMode() ); + + toggleAll(); +} + + +void K3bDataBurnDialog::setupSettingsTab() +{ + QWidget* frame = new QWidget( this ); + QGridLayout* frameLayout = new QGridLayout( frame ); + frameLayout->setSpacing( spacingHint() ); + frameLayout->setMargin( marginHint() ); + + m_groupDataMode = new QGroupBox( 1, Qt::Vertical, i18n("Datatrack Mode"), frame ); + m_dataModeWidget = new K3bDataModeWidget( m_groupDataMode ); + + QGroupBox* groupMultiSession = new QGroupBox( 1, Qt::Vertical, i18n("Multisession Mode"), frame ); + m_comboMultisession = new K3bDataMultiSessionCombobox( groupMultiSession ); + + frameLayout->addWidget( m_groupDataMode, 0, 0 ); + frameLayout->addWidget( groupMultiSession, 1, 0 ); + frameLayout->setRowStretch( 2, 1 ); + + addPage( frame, i18n("Misc") ); +} + + +void K3bDataBurnDialog::slotStartClicked() +{ + if( m_checkOnlyCreateImage->isChecked() || + m_checkCacheImage->isChecked() ) { + QFileInfo fi( m_tempDirSelectionWidget->tempPath() ); + if( fi.isDir() ) + m_tempDirSelectionWidget->setTempPath( fi.filePath() + "/image.iso" ); + + if( QFile::exists( m_tempDirSelectionWidget->tempPath() ) ) { + if( KMessageBox::warningContinueCancel( this, + i18n("Do you want to overwrite %1?").arg(m_tempDirSelectionWidget->tempPath()), + i18n("File Exists"), i18n("Overwrite") ) + == KMessageBox::Continue ) { + // delete the file here to avoid problems with free space in K3bProjectBurnDialog::slotStartClicked + QFile::remove( m_tempDirSelectionWidget->tempPath() ); + } + else + return; + } + } + + if( m_writingModeWidget->writingMode() == K3b::DAO && + m_comboMultisession->multiSessionMode() != K3bDataDoc::NONE && + m_writerSelectionWidget->writingApp() == K3b::CDRECORD ) + if( KMessageBox::warningContinueCancel( this, + i18n("Most writers do not support writing " + "multisession CDs in DAO mode.") ) + == KMessageBox::Cancel ) + return; + + + K3bProjectBurnDialog::slotStartClicked(); +} + + +void K3bDataBurnDialog::loadK3bDefaults() +{ + K3bProjectBurnDialog::loadK3bDefaults(); + + m_dataModeWidget->setDataMode( K3b::DATA_MODE_AUTO ); + + m_imageSettingsWidget->load( K3bIsoOptions::defaults() ); + m_comboMultisession->setMultiSessionMode( K3bDataDoc::AUTO ); + m_checkVerify->setChecked( false ); + + toggleAll(); +} + + +void K3bDataBurnDialog::loadUserDefaults( KConfigBase* c ) +{ + K3bProjectBurnDialog::loadUserDefaults(c); + + m_dataModeWidget->loadConfig(c); + m_comboMultisession->loadConfig( c ); + + K3bIsoOptions o = K3bIsoOptions::load( c ); + m_imageSettingsWidget->load( o ); + + m_checkVerify->setChecked( c->readBoolEntry( "verify data", false ) ); + + toggleAll(); +} + + +void K3bDataBurnDialog::saveUserDefaults( KConfigBase* c ) +{ + K3bProjectBurnDialog::saveUserDefaults(c); + + m_dataModeWidget->saveConfig(c); + m_comboMultisession->saveConfig( c ); + + K3bIsoOptions o; + m_imageSettingsWidget->save( o ); + o.save( c ); + + c->writeEntry( "verify data", m_checkVerify->isChecked() ); +} + + +void K3bDataBurnDialog::toggleAll() +{ + K3bProjectBurnDialog::toggleAll(); + + if( m_checkSimulate->isChecked() || m_checkOnlyCreateImage->isChecked() ) { + m_checkVerify->setChecked(false); + m_checkVerify->setEnabled(false); + } + else + m_checkVerify->setEnabled(true); + + m_comboMultisession->setDisabled( m_checkOnlyCreateImage->isChecked() ); + m_dataModeWidget->setDisabled( m_checkOnlyCreateImage->isChecked() ); +} + + +void K3bDataBurnDialog::slotMultiSessionModeChanged() +{ + if( m_comboMultisession->multiSessionMode() == K3bDataDoc::CONTINUE || + m_comboMultisession->multiSessionMode() == K3bDataDoc::FINISH ) + m_spinCopies->setEnabled(false); + + // wait for the proper medium + // we have to do this in another slot than toggleAll to avoid an endless loop + // FIXME: K3bInteractionDialog::slotToggleAll is endless loop protected + if( m_comboMultisession->multiSessionMode() == K3bDataDoc::NONE ) + m_writerSelectionWidget->setWantedMediumState( K3bDevice::STATE_EMPTY ); + else if( m_comboMultisession->multiSessionMode() == K3bDataDoc::CONTINUE || + m_comboMultisession->multiSessionMode() == K3bDataDoc::FINISH ) + m_writerSelectionWidget->setWantedMediumState( K3bDevice::STATE_INCOMPLETE ); + else + m_writerSelectionWidget->setWantedMediumState( K3bDevice::STATE_EMPTY|K3bDevice::STATE_INCOMPLETE ); +} + + +#include "k3bdataburndialog.moc" diff --git a/src/projects/k3bdataburndialog.h b/src/projects/k3bdataburndialog.h new file mode 100644 index 0000000..1d1e994 --- /dev/null +++ b/src/projects/k3bdataburndialog.h @@ -0,0 +1,75 @@ +/* + * + * $Id: k3bdataburndialog.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BDATABURNDIALOG_H +#define K3BDATABURNDIALOG_H + +#include "k3bprojectburndialog.h" + +class QCheckBox; +class KComboBox; +class QGroupBox; +class QLabel; +class QToolButton; +class QRadioButton; +class QButtonGroup; +class K3bWriterSelectionWidget; +class K3bTempDirSelectionWidget; +class K3bDataDoc; +class KLineEdit; +class K3bDataImageSettingsWidget; +class K3bDataModeWidget; +class K3bDataMultiSessionCombobox; + + +/** + *@author Sebastian Trueg + */ + +class K3bDataBurnDialog : public K3bProjectBurnDialog +{ + Q_OBJECT + + public: + K3bDataBurnDialog(K3bDataDoc*, QWidget *parent=0, const char *name=0, bool modal = true ); + ~K3bDataBurnDialog(); + + protected: + void setupSettingsTab(); + void loadK3bDefaults(); + void loadUserDefaults( KConfigBase* ); + void saveUserDefaults( KConfigBase* ); + void toggleAll(); + + // --- settings tab --------------------------- + K3bDataImageSettingsWidget* m_imageSettingsWidget; + // ---------------------------------------------- + + QGroupBox* m_groupDataMode; + K3bDataModeWidget* m_dataModeWidget; + K3bDataMultiSessionCombobox* m_comboMultisession; + + QCheckBox* m_checkVerify; + + protected slots: + void slotStartClicked(); + void saveSettings(); + void readSettings(); + + void slotMultiSessionModeChanged(); +}; + +#endif diff --git a/src/projects/k3bdatadirtreeview.cpp b/src/projects/k3bdatadirtreeview.cpp new file mode 100644 index 0000000..4a7ec18 --- /dev/null +++ b/src/projects/k3bdatadirtreeview.cpp @@ -0,0 +1,506 @@ +/* + * + * $Id: k3bdatadirtreeview.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bdatadirtreeview.h" +#include "k3bdatafileview.h" +#include "k3bdataview.h" +#include "k3bdatadoc.h" +#include "k3bdataitem.h" +#include "k3bdiritem.h" +#include "k3bdatapropertiesdialog.h" +#include "k3bdataviewitem.h" +#include "k3bdataurladdingdialog.h" +#include <k3bview.h> +#include <k3bvalidators.h> + +#include <qdragobject.h> +#include <qheader.h> +#include <qtimer.h> + +#include <klocale.h> +#include <kaction.h> +#include <kurldrag.h> +#include <kinputdialog.h> +#include <kiconloader.h> +#include <kshortcut.h> + +#include <kdebug.h> + + +class K3bDataDirTreeView::Private +{ +public: + Private() + : animatedDirItem(0), + dropDirItem(0) { + } + + K3bDataDirViewItem* animatedDirItem; + K3bDataDirViewItem* dropDirItem; + int animationCounter; + QPixmap beforeAniPixmap; + + // used for the urladdingdialog hack + KURL::List addUrls; + K3bDirItem* addParentDir; + + QString lastUpdateVolumeId; + + QValidator* iso9660Validator; + QValidator* asciiValidator; +}; + + +K3bDataDirTreeView::K3bDataDirTreeView( K3bView* view, K3bDataDoc* doc, QWidget* parent ) + : K3bListView( parent ), m_view(view) +{ + d = new Private(); + + m_fileView = 0; + + setAcceptDrops( true ); + setDropVisualizer( false ); + setDropHighlighter( true ); + setRootIsDecorated( false ); + setFullWidth( true ); + setDragEnabled( true ); + setItemsMovable( false ); + setAlternateBackground( QColor() ); + // setSorting(-1); + + addColumn( i18n("Directory") ); + header()->hide(); + + m_doc = doc; + + m_root = new K3bDataRootViewItem( doc, this ); + m_itemMap.insert( doc->root(), m_root ); + + connect( m_doc, SIGNAL(changed()), this, SLOT(slotDocChanged()) ); + connect( this, SIGNAL(clicked(QListViewItem*)), this, SLOT(slotExecuted(QListViewItem*)) ); + connect( this, SIGNAL(selectionChanged(QListViewItem*)), this, SLOT(slotExecuted(QListViewItem*)) ); + connect( m_doc, SIGNAL(itemRemoved(K3bDataItem*)), this, SLOT(slotDataItemRemoved(K3bDataItem*)) ); + connect( m_doc, SIGNAL(itemAdded(K3bDataItem*)), this, SLOT(slotItemAdded(K3bDataItem*)) ); + connect( this, SIGNAL(contextMenu(KListView*,QListViewItem*, const QPoint&)), + this, SLOT(showPopupMenu(KListView*,QListViewItem*, const QPoint&)) ); + connect( this, SIGNAL(dropped(QDropEvent*, QListViewItem*, QListViewItem*)), + this, SLOT(slotDropped(QDropEvent*, QListViewItem*, QListViewItem*)) ); + + setupActions(); +} + + +K3bDataDirTreeView::~K3bDataDirTreeView() +{ + delete d; +} + + +void K3bDataDirTreeView::slotExecuted( QListViewItem* item ) +{ + if( K3bDataDirViewItem* viewItem = dynamic_cast<K3bDataDirViewItem*>(item) ) + emit dirSelected( viewItem->dirItem() ); +} + + +bool K3bDataDirTreeView::acceptDrag(QDropEvent* e) const{ + return ( e->source() == viewport() || KURLDrag::canDecode(e) || + ( m_fileView && e->source() == m_fileView->viewport() ) ); +} + + +void K3bDataDirTreeView::contentsDragMoveEvent( QDragMoveEvent* e ) +{ + K3bListView::contentsDragMoveEvent( e ); + + // highlight the folder the items would be added to + if( d->dropDirItem ) + d->dropDirItem->highlightIcon( false ); + + d->dropDirItem = dynamic_cast<K3bDataDirViewItem*>( itemAt(contentsToViewport(e->pos())) ); + if( !d->dropDirItem ) + d->dropDirItem = m_root; + + d->dropDirItem->highlightIcon( true ); +} + + +void K3bDataDirTreeView::contentsDragLeaveEvent( QDragLeaveEvent* e ) +{ + K3bListView::contentsDragLeaveEvent( e ); + + // remove any highlighting + if( d->dropDirItem ) { + d->dropDirItem->highlightIcon( false ); + d->dropDirItem = 0; + } +} + + +void K3bDataDirTreeView::slotDropped( QDropEvent* e, QListViewItem*, QListViewItem* ) +{ + // remove any highlighting + if( d->dropDirItem ) { + d->dropDirItem->highlightIcon( false ); + d->dropDirItem = 0; + } + + if( !e->isAccepted() ) + return; + + // determine K3bDirItem to add the items to + if( K3bDataDirViewItem* dirViewItem = dynamic_cast<K3bDataDirViewItem*>( itemAt(contentsToViewport(e->pos())) ) ) { + d->addParentDir = dirViewItem->dirItem(); + } + else { + d->addParentDir = m_doc->root(); + } + + if( d->addParentDir ) { + + // startDropAnimation( parent ); + + // check if items have been moved + if( m_fileView && + e->source() == m_fileView->viewport() ) { + // move all selected items + QPtrList<QListViewItem> selectedViewItems = m_fileView->selectedItems(); + QValueList<K3bDataItem*> selectedDataItems; + QPtrListIterator<QListViewItem> it( selectedViewItems ); + for( ; it.current(); ++it ) { + K3bDataViewItem* dataViewItem = dynamic_cast<K3bDataViewItem*>( it.current() ); + if( dataViewItem ) + selectedDataItems.append( dataViewItem->dataItem() ); + else + kdDebug() << "no dataviewitem" << endl; + } + + K3bDataUrlAddingDialog::copyMoveItems( selectedDataItems, d->addParentDir, this, e->action() == QDropEvent::Copy ); + } + else if( e->source() == viewport() ) { + // move the selected dir + if( K3bDataDirViewItem* dirItem = dynamic_cast<K3bDataDirViewItem*>( selectedItem() ) ) { + QValueList<K3bDataItem*> selectedDataItems; + selectedDataItems.append( dirItem->dirItem() ); + K3bDataUrlAddingDialog::copyMoveItems( selectedDataItems, d->addParentDir, this, e->action() == QDropEvent::Copy ); + } + } + else { + // seems that new items have been dropped + d->addUrls.clear(); + if( KURLDrag::decode( e, d->addUrls ) ) { + // + // This is a small (not to ugly) hack to circumvent problems with the + // event queues: the url adding dialog will be non-modal regardless of + // the settings in case we open it directly. + // + QTimer::singleShot( 0, this, SLOT(slotAddUrls()) ); + } + } + } + + // now grab that focus + setFocus(); +} + + +void K3bDataDirTreeView::slotAddUrls() +{ + K3bDataUrlAddingDialog::addUrls( d->addUrls, d->addParentDir, this ); +} + + +void K3bDataDirTreeView::slotItemAdded( K3bDataItem* item ) +{ + if( item->isDir() ) { + // + // We assume that we do not already have an item for the dir since the itemAdded signal + // should only be emitted once for every item + // + K3bDirItem* dirItem = static_cast<K3bDirItem*>( item ); + K3bDataDirViewItem* parentViewItem = m_itemMap[dirItem->parent()]; + K3bDataDirViewItem* newDirItem = new K3bDataDirViewItem( dirItem, parentViewItem ); + m_itemMap.insert( dirItem, newDirItem ); + } +} + + +void K3bDataDirTreeView::slotDataItemRemoved( K3bDataItem* item ) +{ + if( item->isDir() ) { + K3bDirItem* dirItem = static_cast<K3bDirItem*>( item ); + QMapIterator<K3bDirItem*, K3bDataDirViewItem*> it = m_itemMap.find( dirItem ); + if( it != m_itemMap.end() ) { + K3bDataDirViewItem* viewItem = it.data(); + m_itemMap.remove( it ); + + // we don't get removedInfo for the child items + // so we need to remove them here + QPtrListIterator<K3bDataItem> it( dirItem->children() ); + for( ; it.current(); ++it ) { + if( it.current()->isDir() ) + slotDataItemRemoved( it.current() ); + } + + delete viewItem; + } + } +} + + +void K3bDataDirTreeView::setCurrentDir( K3bDirItem* dirItem ) +{ + QMapIterator<K3bDirItem*, K3bDataDirViewItem*> it = m_itemMap.find( dirItem ); + if( it != m_itemMap.end() ) { + setCurrentItem( it.data() ); + it.data()->setOpen(true); + if( it.data() != root() ) + it.data()->parent()->setOpen(true); + } + else { + kdDebug() << "Tried to set unknown dirItem to current" << endl; + } +} + + +void K3bDataDirTreeView::setupActions() +{ + m_actionCollection = new KActionCollection( this ); + + m_actionProperties = new KAction( i18n("Properties"), "misc", 0, this, SLOT(slotProperties()), + actionCollection(), "properties" ); + m_actionNewDir = new KAction( i18n("New Directory..."), "folder_new", CTRL+Key_N, this, SLOT(slotNewDir()), + actionCollection(), "new_dir" ); + m_actionRemove = new KAction( i18n("Remove"), "editdelete", Key_Delete, this, SLOT(slotRemoveItem()), + actionCollection(), "remove" ); + KShortcut renameShortCut( Key_F2 ); + renameShortCut.append( KShortcut(CTRL+Key_R) ); // backwards compatibility + m_actionRename = new KAction( i18n("Rename"), "edit", renameShortCut, this, SLOT(slotRenameItem()), + actionCollection(), "rename" ); + + m_popupMenu = new KActionMenu( m_actionCollection, "contextMenu" ); + m_popupMenu->insert( m_actionRename ); + m_popupMenu->insert( m_actionRemove ); + m_popupMenu->insert( m_actionNewDir ); + m_popupMenu->insert( new KActionSeparator( this ) ); + m_popupMenu->insert( m_actionProperties ); + m_popupMenu->insert( new KActionSeparator( this ) ); + m_popupMenu->insert( m_view->actionCollection()->action("project_burn") ); +} + + +void K3bDataDirTreeView::showPopupMenu( KListView*, QListViewItem* item, const QPoint& point ) +{ + if( item ) { + if( K3bDataViewItem* di = dynamic_cast<K3bDataViewItem*>(item) ) { + m_actionRemove->setEnabled( di->dataItem()->isRemoveable() ); + m_actionRename->setEnabled( di->dataItem()->isRenameable() ); + } + else { + m_actionRemove->setEnabled( false ); + m_actionRename->setEnabled( false ); + } + m_actionProperties->setEnabled( true ); + } + else { + m_actionRemove->setEnabled( false ); + m_actionRename->setEnabled( false ); + m_actionProperties->setEnabled( false ); + } + + m_popupMenu->popup( point ); +} + + +void K3bDataDirTreeView::slotNewDir() +{ + if( K3bDataDirViewItem* vI = dynamic_cast<K3bDataDirViewItem*>(currentItem()) ) { + K3bDirItem* parent = vI->dirItem(); + + QString name; + bool ok; + + name = KInputDialog::getText( i18n("New Directory"), + i18n("Please insert the name for the new directory:"), + i18n("New Directory"), &ok, this ); + + while( ok && K3bDataDoc::nameAlreadyInDir( name, parent ) ) { + name = KInputDialog::getText( i18n("New Directory"), + i18n("A file with that name already exists. " + "Please insert the name for the new directory:"), + i18n("New Directory"), &ok, this ); + } + + if( !ok ) + return; + + + m_doc->addEmptyDir( name, parent ); + } +} + + +void K3bDataDirTreeView::slotRenameItem() +{ + showEditor( (K3bListViewItem*)currentItem(), 0 ); +} + + +void K3bDataDirTreeView::slotRemoveItem() +{ + if( currentItem() ) { + if( K3bDataDirViewItem* dirViewItem = dynamic_cast<K3bDataDirViewItem*>( currentItem() ) ) + m_doc->removeItem( dirViewItem->dirItem() ); + } +} + + +void K3bDataDirTreeView::slotProperties() +{ + K3bDataViewItem* viewItem = dynamic_cast<K3bDataViewItem*>( currentItem() ); + if( viewItem && currentItem() != root() ) { + K3bDataPropertiesDialog d( viewItem->dataItem(), this ); + if( d.exec() ) { + repaint(); + if( m_fileView ) + m_fileView->repaint(); + } + } + else + m_view->slotProperties(); +} + + +void K3bDataDirTreeView::startDropAnimation( K3bDirItem* dir ) +{ + stopDropAnimation(); + + K3bDataDirViewItem* vI = m_itemMap[dir]; + if( vI ) { + d->animationCounter = 0; + d->animatedDirItem = vI; + d->beforeAniPixmap = QPixmap( *vI->pixmap(0) ); + QTimer::singleShot( 0, this, SLOT(slotDropAnimate()) ); + } +} + + +void K3bDataDirTreeView::slotDropAnimate() +{ + if( d->animatedDirItem ) { + if( d->animationCounter > 5 ) + stopDropAnimation(); + else { + switch(d->animationCounter) { + case 0: + d->animatedDirItem->setPixmap( 0, SmallIcon( "folder_cyan" ) ); + break; + case 1: + d->animatedDirItem->setPixmap( 0, SmallIcon( "folder_green" ) ); + break; + case 2: + d->animatedDirItem->setPixmap( 0, SmallIcon( "folder_yellow" ) ); + break; + case 3: + d->animatedDirItem->setPixmap( 0, SmallIcon( "folder_orange" ) ); + break; + case 4: + d->animatedDirItem->setPixmap( 0, SmallIcon( "folder_red" ) ); + break; + case 5: + d->animatedDirItem->setPixmap( 0, SmallIcon( "folder_violet" ) ); + break; + } + + d->animationCounter++; + QTimer::singleShot( 300, this, SLOT(slotDropAnimate()) ); + } + } +} + + +void K3bDataDirTreeView::stopDropAnimation() +{ + if( d->animatedDirItem ) { + d->animatedDirItem->setPixmap( 0, d->beforeAniPixmap ); + d->animatedDirItem = 0; + } +} + + +// FIXME: remove this +void K3bDataDirTreeView::checkForNewItems() +{ + K3bDataItem* item = m_root->dirItem()->nextSibling(); + while( item != 0 ) + { + // check if we have an entry and if not, create one + // we can assume that a listViewItem for the parent exists + // since we go top to bottom + if( item->isDir() ) + { + K3bDirItem* dirItem = dynamic_cast<K3bDirItem*>( item ); + + QMapIterator<K3bDirItem*, K3bDataDirViewItem*> itDirItem = m_itemMap.find( dirItem ); + if( itDirItem == m_itemMap.end() ) { + K3bDataDirViewItem* parentViewItem = m_itemMap[dirItem->parent()]; + K3bDataDirViewItem* newDirItem = new K3bDataDirViewItem( dirItem, parentViewItem ); + m_itemMap.insert( dirItem, newDirItem ); + } + else { + // check if parent still correct (to get moved items) + K3bDataDirViewItem* dirViewItem = itDirItem.data(); + K3bDataDirViewItem* parentViewItem = (K3bDataDirViewItem*)dirViewItem->parent(); + K3bDataDirViewItem* dirParentViewItem = m_itemMap[dirItem->parent()]; + if( dirParentViewItem != parentViewItem ) { + // reparent it + parentViewItem->takeItem( dirViewItem ); + dirParentViewItem->insertItem( dirViewItem ); + } + } + } + + item = item->nextSibling(); + } + + + // check the directory depth + QListViewItemIterator it(root()); + while( it.current() != 0 ) { + if( K3bDataDirViewItem* dirViewItem = dynamic_cast<K3bDataDirViewItem*>(it.current()) ) + if( it.current() != m_root ) { + K3bDirItem* dirItem = dirViewItem->dirItem(); + dirViewItem->setPixmap( 0, dirItem->depth() > 7 ? SmallIcon( "folder_red" ) : SmallIcon( "folder" ) ); + } + + ++it; + } + + // always show the first level + m_root->setOpen( true ); +} + + +void K3bDataDirTreeView::slotDocChanged() +{ + // avoid flicker + if( d->lastUpdateVolumeId != m_doc->isoOptions().volumeID() ) { + d->lastUpdateVolumeId = m_doc->isoOptions().volumeID(); + root()->repaint(); + } +} + +#include "k3bdatadirtreeview.moc" diff --git a/src/projects/k3bdatadirtreeview.h b/src/projects/k3bdatadirtreeview.h new file mode 100644 index 0000000..c79a9c6 --- /dev/null +++ b/src/projects/k3bdatadirtreeview.h @@ -0,0 +1,115 @@ +/* + * + * $Id: k3bdatadirtreeview.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BDATADIRTREEVIEW_H +#define K3BDATADIRTREEVIEW_H + + +#include <k3blistview.h> +#include <kurl.h> + +#include <qmap.h> + +class K3bDataView; +class K3bDataDoc; +class K3bDataDirViewItem; +class K3bDirItem; +class K3bDataItem; +class K3bDataFileView; +class KActionCollection; +class KActionMenu; +class KAction; +class K3bView; +class QDragMoveEvent; +class QDragLeaveEvent; + + +/** + *@author Sebastian Trueg + */ + +class K3bDataDirTreeView : public K3bListView +{ + Q_OBJECT + + public: + K3bDataDirTreeView( K3bView*, K3bDataDoc*, QWidget* parent ); + virtual ~K3bDataDirTreeView(); + + K3bDataDirViewItem* root() { return m_root; } + + void setFileView( K3bDataFileView* view ) { m_fileView = view; } + + KActionCollection* actionCollection() const { return m_actionCollection; } + + public slots: + void checkForNewItems(); + void setCurrentDir( K3bDirItem* ); + + signals: + // void urlsDropped( const KURL::List&, QListViewItem* parent ); + void dirSelected( K3bDirItem* ); + + protected: + bool acceptDrag(QDropEvent* e) const; + void contentsDragMoveEvent( QDragMoveEvent* e ); + void contentsDragLeaveEvent( QDragLeaveEvent* e ); + + KActionCollection* m_actionCollection; + KActionMenu* m_popupMenu; + KAction* m_actionRemove; + KAction* m_actionRename; + KAction* m_actionNewDir; + KAction* m_actionProperties; + + protected slots: + virtual void slotDropped( QDropEvent* e, QListViewItem* after, QListViewItem* parent ); + + private: + void setupActions(); + void startDropAnimation( K3bDirItem* ); + void stopDropAnimation(); + + K3bView* m_view; + + K3bDataDoc* m_doc; + K3bDataDirViewItem* m_root; + K3bDataFileView* m_fileView; + + /** + * We save the dirItems in a map to have a fast way + * for checking for new or removed items + */ + QMap<K3bDirItem*, K3bDataDirViewItem*> m_itemMap; + + class Private; + Private* d; + + private slots: + void slotExecuted( QListViewItem* ); + void slotDataItemRemoved( K3bDataItem* ); + void showPopupMenu( KListView*, QListViewItem* _item, const QPoint& ); + void slotRenameItem(); + void slotRemoveItem(); + void slotNewDir(); + void slotProperties(); + void slotDropAnimate(); + void slotItemAdded( K3bDataItem* ); + void slotAddUrls(); + void slotDocChanged(); +}; + +#endif diff --git a/src/projects/k3bdatafileview.cpp b/src/projects/k3bdatafileview.cpp new file mode 100644 index 0000000..4c06bde --- /dev/null +++ b/src/projects/k3bdatafileview.cpp @@ -0,0 +1,483 @@ +/* + * + * $Id: k3bdatafileview.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bdatafileview.h" +#include "k3bdataview.h" +#include <k3bdatadoc.h> +#include <k3bdataitem.h> +#include <k3bdiritem.h> +#include <k3bfileitem.h> +#include <k3bspecialdataitem.h> +#include <k3bsessionimportitem.h> +#include "k3bdataurladdingdialog.h" +#include <k3bvalidators.h> +#include "k3bdatapropertiesdialog.h" +#include "k3bdatadirtreeview.h" +#include "k3bdataviewitem.h" +#include <k3bview.h> + + +#include <qdragobject.h> +#include <qpainter.h> +#include <qfontmetrics.h> +#include <qtimer.h> +#include <qheader.h> +#include <qfileinfo.h> + +#include <klocale.h> +#include <kaction.h> +#include <kurldrag.h> +#include <kinputdialog.h> +#include <kdebug.h> +#include <kshortcut.h> +#include <krun.h> +#include <kdeversion.h> + + +K3bDataFileView::K3bDataFileView( K3bView* view, K3bDataDirTreeView* dirTreeView, K3bDataDoc* doc, QWidget* parent ) + : K3bListView( parent ), + m_view(view), + m_dropDirItem(0) +{ + m_treeView = dirTreeView; + + setAcceptDrops( true ); + setDropVisualizer( false ); + setDropHighlighter( true ); + setDragEnabled( true ); + setItemsMovable( false ); + setAllColumnsShowFocus( true ); + setShowSortIndicator( true ); + + setNoItemText( i18n("Use drag'n'drop to add files and directories to the project.\n" + "To remove or rename files use the context menu.\n" + "After that press the burn button to write the CD.") ); + + + addColumn( i18n("Name") ); + addColumn( i18n("Type") ); + addColumn( i18n("Size") ); + addColumn( i18n("Local Path") ); + addColumn( i18n("Link") ); + + setSelectionModeExt( KListView::Extended ); + + m_doc = doc; + m_currentDir = doc->root(); + checkForNewItems(); + + connect( m_treeView, SIGNAL(dirSelected(K3bDirItem*)), this, SLOT(slotSetCurrentDir(K3bDirItem*)) ); + connect( m_doc, SIGNAL(itemRemoved(K3bDataItem*)), this, SLOT(slotDataItemRemoved(K3bDataItem*)) ); + connect( m_doc, SIGNAL(itemAdded(K3bDataItem*)), this, SLOT(slotItemAdded(K3bDataItem*)) ); + connect( this, SIGNAL(executed(QListViewItem*)), this, SLOT(slotExecuted(QListViewItem*)) ); + connect( this, SIGNAL(contextMenu(KListView*, QListViewItem*, const QPoint&)), + this, SLOT(showPopupMenu(KListView*, QListViewItem*, const QPoint&)) ); + connect( this, SIGNAL(dropped(QDropEvent*, QListViewItem*, QListViewItem*)), + this, SLOT(slotDropped(QDropEvent*, QListViewItem*, QListViewItem*)) ); + connect( this, SIGNAL(doubleClicked(QListViewItem*, const QPoint&, int)), + this, SLOT(slotDoubleClicked(QListViewItem*)) ); + + setupActions(); +} + + +K3bDataFileView::~K3bDataFileView() +{ +} + + +K3bDirItem* K3bDataFileView::currentDir() const +{ + if( !m_currentDir ) + m_currentDir = m_doc->root(); + return m_currentDir; +} + + +void K3bDataFileView::slotSetCurrentDir( K3bDirItem* dir ) +{ + if( dir ) { + m_currentDir = dir; + clearItems(); + checkForNewItems(); + } +} + + +void K3bDataFileView::clearItems() +{ + m_itemMap.clear(); + K3bListView::clear(); +} + + +void K3bDataFileView::slotItemAdded( K3bDataItem* item ) +{ + if( item->parent() == currentDir() ) { + K3bDataViewItem* vi = 0; + if( item->isDir() ) + vi = new K3bDataDirViewItem( static_cast<K3bDirItem*>(item), this ); + else if( item->isFile() ) + vi = new K3bDataFileViewItem( static_cast<K3bFileItem*>(item), this ); + else if( item->isSpecialFile() ) + vi = new K3bSpecialDataViewItem( static_cast<K3bSpecialDataItem*>(item), this ); + else if( item->isFromOldSession() ) + vi = new K3bSessionImportViewItem( static_cast<K3bSessionImportItem*>(item), this ); + else + kdDebug() << "(K3bDataFileView) ERROR: unknown data item type" << endl; + + if( vi ) + m_itemMap[item] = vi; + } +} + + +void K3bDataFileView::slotDataItemRemoved( K3bDataItem* item ) +{ + if( item->isDir() ) { + if( static_cast<K3bDirItem*>(item)->isSubItem( currentDir() ) ) { + slotSetCurrentDir( m_doc->root() ); + } + } + + if( m_itemMap.contains( item ) ) { + delete m_itemMap[item]; + m_itemMap.remove(item); + } +} + + +void K3bDataFileView::checkForNewItems() +{ + hideEditor(); + + // add items that are not there yet + for( QPtrListIterator<K3bDataItem> it( m_currentDir->children() ); it.current(); ++it ) { + if( !m_itemMap.contains( it.current() ) ) { + slotItemAdded( it.current() ); + } + } + + // now check if some of the items have been moved out of the currently showing dir. + for( QListViewItemIterator it( this ); it.current(); ++it ) { + K3bDataViewItem* dataViewItem = dynamic_cast<K3bDataViewItem*>( it.current() ); + if( dataViewItem && dataViewItem->dataItem()->parent() != currentDir() ) + delete dataViewItem; + } +} + + +QDragObject* K3bDataFileView::dragObject() +{ + QPtrList<QListViewItem> selectedViewItems = selectedItems(); + KURL::List urls; + for( QPtrListIterator<QListViewItem> it( selectedViewItems ); it.current(); ++it ) { + K3bDataViewItem* dataViewItem = dynamic_cast<K3bDataViewItem*>( it.current() ); + if( dataViewItem ) { + urls.append( KURL::fromPathOrURL(dataViewItem->dataItem()->localPath()) ); + } + else + kdDebug() << "no dataviewitem" << endl; + } + + if( urls.isEmpty() ) + return 0; + + return KURLDrag::newDrag( urls, viewport() ); +} + + +bool K3bDataFileView::acceptDrag(QDropEvent* e) const +{ + return ( e->source() == viewport() || + KURLDrag::canDecode(e) || + e->source() == m_treeView->viewport() ); +} + + +void K3bDataFileView::contentsDragMoveEvent( QDragMoveEvent* e ) +{ + K3bListView::contentsDragMoveEvent( e ); + + // highlight the folder the items would be added to + if( m_dropDirItem ) + m_dropDirItem->highlightIcon( false ); + + m_dropDirItem = dynamic_cast<K3bDataDirViewItem*>( itemAt(contentsToViewport(e->pos())) ); + if( m_dropDirItem ) + m_dropDirItem->highlightIcon( true ); +} + + +void K3bDataFileView::contentsDragLeaveEvent( QDragLeaveEvent* e ) +{ + K3bListView::contentsDragLeaveEvent( e ); + + // remove any highlighting + if( m_dropDirItem ) { + m_dropDirItem->highlightIcon( false ); + m_dropDirItem = 0; + } +} + + +void K3bDataFileView::slotDropped( QDropEvent* e, QListViewItem*, QListViewItem* ) +{ + // remove any highlighting + if( m_dropDirItem ) { + m_dropDirItem->highlightIcon( false ); + m_dropDirItem = 0; + } + + if( !e->isAccepted() ) + return; + + // determine K3bDirItem to add the items to + m_addParentDir = currentDir(); + + if( K3bDataDirViewItem* dirViewItem = dynamic_cast<K3bDataDirViewItem*>( itemAt(contentsToViewport(e->pos())) ) ) { + // only add to a dir if we drop directly on the name + if( header()->sectionAt( e->pos().x() ) == 0 ) + m_addParentDir = dirViewItem->dirItem(); + } + + if( m_addParentDir ) { + + // check if items have been moved + if( e->source() == viewport() ) { + // move all selected items + QPtrList<QListViewItem> selectedViewItems = selectedItems(); + QValueList<K3bDataItem*> selectedDataItems; + QPtrListIterator<QListViewItem> it( selectedViewItems ); + for( ; it.current(); ++it ) { + K3bDataViewItem* dataViewItem = dynamic_cast<K3bDataViewItem*>( it.current() ); + if( dataViewItem ) + selectedDataItems.append( dataViewItem->dataItem() ); + else + kdDebug() << "no dataviewitem" << endl; + } + + K3bDataUrlAddingDialog::copyMoveItems( selectedDataItems, m_addParentDir, this, e->action() == QDropEvent::Copy ); + } + else if( e->source() == m_treeView->viewport() ) { + // move the selected dir + if( K3bDataDirViewItem* dirItem = dynamic_cast<K3bDataDirViewItem*>( m_treeView->selectedItem() ) ) { + QValueList<K3bDataItem*> selectedDataItems; + selectedDataItems.append( dirItem->dirItem() ); + K3bDataUrlAddingDialog::copyMoveItems( selectedDataItems, m_addParentDir, this, e->action() == QDropEvent::Copy ); + } + } + else { + // seems that new items have been dropped + m_addUrls.clear(); + if( KURLDrag::decode( e, m_addUrls ) ) { + // + // This is a small (not to ugly) hack to circumvent problems with the + // event queues: the url adding dialog will be non-modal regardless of + // the settings in case we open it directly. + // + QTimer::singleShot( 0, this, SLOT(slotAddUrls()) ); + } + } + } + + // now grab that focus + setFocus(); +} + + +void K3bDataFileView::slotAddUrls() +{ + K3bDataUrlAddingDialog::addUrls( m_addUrls, m_addParentDir, this ); +} + + +void K3bDataFileView::slotExecuted( QListViewItem* item ) +{ + if( K3bDataDirViewItem* k = dynamic_cast<K3bDataDirViewItem*>( item ) ) { + hideEditor(); // disable the K3bListView Editor + slotSetCurrentDir( k->dirItem() ); + emit dirSelected( currentDir() ); + } +} + + +void K3bDataFileView::setupActions() +{ + m_actionCollection = new KActionCollection( this ); + + m_actionProperties = new KAction( i18n("Properties"), "misc", 0, this, SLOT(slotProperties()), + actionCollection(), "properties" ); + m_actionNewDir = new KAction( i18n("New Directory..."), "folder_new", CTRL+Key_N, this, SLOT(slotNewDir()), + actionCollection(), "new_dir" ); + m_actionRemove = new KAction( i18n("Remove"), "editdelete", Key_Delete, this, SLOT(slotRemoveItem()), + actionCollection(), "remove" ); + KShortcut renameShortCut( Key_F2 ); + renameShortCut.append( KShortcut(CTRL+Key_R) ); // backwards compatibility + m_actionRename = new KAction( i18n("Rename"), "edit", renameShortCut, this, SLOT(slotRenameItem()), + actionCollection(), "rename" ); + m_actionParentDir = new KAction( i18n("Parent Directory"), "up", 0, this, SLOT(slotParentDir()), + actionCollection(), "parent_dir" ); + m_actionOpen = new KAction( i18n("Open"), "fileopen", 0, this, SLOT(slotOpen()), + actionCollection(), "open" ); + + m_popupMenu = new KActionMenu( m_actionCollection, "contextMenu" ); + m_popupMenu->insert( m_actionParentDir ); + m_popupMenu->insert( new KActionSeparator( this ) ); + m_popupMenu->insert( m_actionRename ); + m_popupMenu->insert( m_actionRemove ); + m_popupMenu->insert( m_actionNewDir ); + m_popupMenu->insert( new KActionSeparator( this ) ); + m_popupMenu->insert( m_actionOpen ); + m_popupMenu->insert( new KActionSeparator( this ) ); + m_popupMenu->insert( m_actionProperties ); + m_popupMenu->insert( new KActionSeparator( this ) ); + m_popupMenu->insert( m_view->actionCollection()->action("project_burn") ); +} + + +void K3bDataFileView::showPopupMenu( KListView*, QListViewItem* item, const QPoint& point ) +{ + if( item ) { + K3bDataItem* di = static_cast<K3bDataViewItem*>(item)->dataItem(); + m_actionRemove->setEnabled( di->isRemoveable() ); + m_actionRename->setEnabled( di->isRenameable() ); + if( currentDir() == m_doc->root() ) + m_actionParentDir->setEnabled( false ); + else + m_actionParentDir->setEnabled( true ); + m_actionOpen->setEnabled( di->isFile() ); + } + else { + m_actionRemove->setEnabled( false ); + m_actionRename->setEnabled( false ); + m_actionOpen->setEnabled( false ); + } + + m_popupMenu->popup( point ); +} + + +void K3bDataFileView::slotNewDir() +{ + K3bDirItem* parent = currentDir(); + + QString name; + bool ok; + + name = KInputDialog::getText( i18n("New Directory"), + i18n("Please insert the name for the new directory:"), + i18n("New Directory"), &ok, this ); + + while( ok && K3bDataDoc::nameAlreadyInDir( name, parent ) ) { + name = KInputDialog::getText( i18n("New Directory"), + i18n("A file with that name already exists. " + "Please insert the name for the new directory:"), + i18n("New Directory"), &ok, this ); + } + + if( !ok ) + return; + + + m_doc->addEmptyDir( name, parent ); +} + + +void K3bDataFileView::slotRenameItem() +{ + if( currentItem() ) + showEditor( (K3bListViewItem*)currentItem(), 0 ); +} + + +void K3bDataFileView::slotRemoveItem() +{ + QPtrList<QListViewItem> items = selectedItems(); + QPtrListIterator<QListViewItem> it( items ); + for(; it.current(); ++it ) { + if( K3bDataViewItem* d = dynamic_cast<K3bDataViewItem*>( it.current() ) ) + m_doc->removeItem( d->dataItem() ); + } +} + + +void K3bDataFileView::slotParentDir() +{ + if( currentDir() != m_doc->root() ) { + slotSetCurrentDir( currentDir()->parent() ); + + emit dirSelected( currentDir() ); + } +} + + +void K3bDataFileView::slotProperties() +{ + K3bDataItem* dataItem = 0; + + // get selected item + if( K3bDataViewItem* viewItem = dynamic_cast<K3bDataViewItem*>( selectedItems().first() ) ) { + dataItem = viewItem->dataItem(); + } + else { + // default to current dir + dataItem = currentDir(); + } + + if( dataItem ) { + K3bDataPropertiesDialog d( dataItem, this ); + d.exec(); + } + else + m_view->slotProperties(); +} + + +void K3bDataFileView::slotOpen() +{ + if( K3bDataViewItem* viewItem = dynamic_cast<K3bDataViewItem*>( selectedItems().first() ) ) { + K3bDataItem* item = viewItem->dataItem(); + if( item->isFile() ) { + K3bDataFileViewItem* fvi = static_cast<K3bDataFileViewItem*>( viewItem ); + if( fvi->mimeType() && +#if KDE_IS_VERSION(3,3,0) + !KRun::isExecutableFile( KURL::fromPathOrURL(item->localPath()), + fvi->mimeType()->name() ) +#else + !QFileInfo( item->localPath() ).isExecutable() +#endif + ) + KRun::runURL( KURL::fromPathOrURL(item->localPath()), + fvi->mimeType()->name() ); + else + KRun::displayOpenWithDialog( KURL::fromPathOrURL(item->localPath()) ); + } + } +} + + +void K3bDataFileView::slotDoubleClicked( QListViewItem* ) +{ + if( K3bDataViewItem* viewItem = dynamic_cast<K3bDataViewItem*>( selectedItems().first() ) ) { + if( !viewItem->dataItem()->isDir() ) { + K3bDataPropertiesDialog d( viewItem->dataItem(), this ); + d.exec(); + } + } +} + +#include "k3bdatafileview.moc" diff --git a/src/projects/k3bdatafileview.h b/src/projects/k3bdatafileview.h new file mode 100644 index 0000000..580af96 --- /dev/null +++ b/src/projects/k3bdatafileview.h @@ -0,0 +1,115 @@ +/* + * + * $Id: k3bdatafileview.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BDATAFILEVIEW_H +#define K3BDATAFILEVIEW_H + +#include <k3blistview.h> + +#include <kurl.h> + +#include <qmap.h> + + +class K3bDataDoc; +class K3bDirItem; +class K3bDataView; +class K3bDataViewItem; +class K3bDataItem; +class QDropEvent; +class KActionCollection; +class KActionMenu; +class KAction; +class K3bDataDirTreeView; +class K3bDataDirViewItem; +class K3bView; +class QPainter; +class QDragMoveEvent; +class QDragLeaveEvent; + +/** + *@author Sebastian Trueg + */ + +class K3bDataFileView : public K3bListView +{ + Q_OBJECT + + public: + K3bDataFileView( K3bView*, K3bDataDirTreeView*, K3bDataDoc*, QWidget* parent ); + ~K3bDataFileView(); + + K3bDirItem* currentDir() const; + + KActionCollection* actionCollection() const { return m_actionCollection; } + + signals: + void dirSelected( K3bDirItem* ); + + public slots: + void slotSetCurrentDir( K3bDirItem* ); + void checkForNewItems(); + + private slots: + void slotDataItemRemoved( K3bDataItem* ); + void slotExecuted( QListViewItem* ); + void slotDropped( QDropEvent* e, QListViewItem* after, QListViewItem* parent ); + void showPopupMenu( KListView*, QListViewItem* _item, const QPoint& ); + void slotRenameItem(); + void slotRemoveItem(); + void slotNewDir(); + void slotParentDir(); + void slotProperties(); + void slotDoubleClicked( QListViewItem* item ); + void slotItemAdded( K3bDataItem* ); + void slotAddUrls(); + void slotOpen(); + + protected: + bool acceptDrag(QDropEvent* e) const; + void contentsDragMoveEvent( QDragMoveEvent* e ); + void contentsDragLeaveEvent( QDragLeaveEvent* e ); + QDragObject* dragObject(); + + private: + void clearItems(); + void setupActions(); + + KActionCollection* m_actionCollection; + KActionMenu* m_popupMenu; + KAction* m_actionParentDir; + KAction* m_actionRemove; + KAction* m_actionRename; + KAction* m_actionNewDir; + KAction* m_actionProperties; + KAction* m_actionOpen; + + K3bView* m_view; + + K3bDataDoc* m_doc; + mutable K3bDirItem* m_currentDir; + K3bDataDirTreeView* m_treeView; + + K3bDataDirViewItem* m_dropDirItem; + + QMap<K3bDataItem*, K3bDataViewItem*> m_itemMap; + + // used for the urladdingdialog hack + KURL::List m_addUrls; + K3bDirItem* m_addParentDir; +}; + +#endif diff --git a/src/projects/k3bdataimagesettingswidget.cpp b/src/projects/k3bdataimagesettingswidget.cpp new file mode 100644 index 0000000..331e1eb --- /dev/null +++ b/src/projects/k3bdataimagesettingswidget.cpp @@ -0,0 +1,400 @@ +/* + * + * $Id: k3bdataimagesettingswidget.cpp 691413 2007-07-23 16:01:13Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bdataimagesettingswidget.h" +#include "k3bdataadvancedimagesettingswidget.h" +#include "k3bdatavolumedescwidget.h" + +#include "k3bisooptions.h" + +#include <qcheckbox.h> +#include <qradiobutton.h> +#include <qbuttongroup.h> +#include <qlineedit.h> +#include <qcombobox.h> +#include <qpushbutton.h> +#include <qwhatsthis.h> +#include <qlayout.h> + +#include <kmessagebox.h> +#include <klocale.h> +#include <kdialogbase.h> +#include <kdebug.h> + + +// indices for the filesystems combobox +static const int FS_LINUX_ONLY = 0; +static const int FS_LINUX_AND_WIN = 1; +static const int FS_UDF = 2; +static const int FS_DOS_COMP = 3; +static const int FS_CUSTOM = 4; +static const int FS_MAX = 5; + +static const char* s_fsPresetNames[] = { + I18N_NOOP("Linux/Unix only"), + I18N_NOOP("Linux/Unix + Windows"), + I18N_NOOP("Very large files (UDF)"), + I18N_NOOP("DOS Compatibility"), + I18N_NOOP("Custom") +}; + +static bool s_fsPresetsInitialized = false; +static K3bIsoOptions s_fsPresets[FS_CUSTOM]; + +// indices for the whitespace treatment combobox +static const int WS_NO_CHANGE = 0; +static const int WS_STRIP = 1; +static const int WS_EXTENDED_STRIP = 2; +static const int WS_REPLACE = 3; + +// indices for the symlink handling combobox +static const int SYM_NO_CHANGE = 0; +static const int SYM_DISCARD_BROKEN = 1; +static const int SYM_DISCARD_ALL = 2; +static const int SYM_FOLLOW = 3; + + +// +// returns true if the part of the options that is presented in the advanced custom +// settings dialog is equal. used to determine if some preset is used. +// +static bool compareAdvancedOptions( const K3bIsoOptions& o1, const K3bIsoOptions& o2 ) +{ + return ( o1.forceInputCharset() == o2.forceInputCharset() && + ( !o1.forceInputCharset() || o1.inputCharset() == o2.inputCharset() ) && + o1.createRockRidge() == o2.createRockRidge() && + o1.createJoliet() == o2.createJoliet() && + o1.createUdf() == o2.createUdf() && + o1.ISOallowLowercase() == o2.ISOallowLowercase() && + o1.ISOallowPeriodAtBegin() == o2.ISOallowPeriodAtBegin() && + o1.ISOallow31charFilenames() == o2.ISOallow31charFilenames() && + o1.ISOomitVersionNumbers() == o2.ISOomitVersionNumbers() && + o1.ISOomitTrailingPeriod() == o2.ISOomitTrailingPeriod() && + o1.ISOmaxFilenameLength() == o2.ISOmaxFilenameLength() && + o1.ISOrelaxedFilenames() == o2.ISOrelaxedFilenames() && + o1.ISOnoIsoTranslate() == o2.ISOnoIsoTranslate() && + o1.ISOallowMultiDot() == o2.ISOallowMultiDot() && + o1.ISOuntranslatedFilenames() == o2.ISOuntranslatedFilenames() && + o1.createTRANS_TBL() == o2.createTRANS_TBL() && + o1.hideTRANS_TBL() == o2.hideTRANS_TBL() && + o1.jolietLong() == o2.jolietLong() && + o1.ISOLevel() == o2.ISOLevel() && + o1.preserveFilePermissions() == o2.preserveFilePermissions() && + o1.doNotCacheInodes() == o2.doNotCacheInodes() ); +} + + +static void initializePresets() +{ + // Linux-only + s_fsPresets[FS_LINUX_ONLY].setCreateJoliet( false ); + s_fsPresets[FS_LINUX_ONLY].setISOallow31charFilenames( true ); + + // Linux + Windows + s_fsPresets[FS_LINUX_AND_WIN].setCreateJoliet( true ); + s_fsPresets[FS_LINUX_AND_WIN].setJolietLong( true ); + s_fsPresets[FS_LINUX_AND_WIN].setISOallow31charFilenames( true ); + + // UDF + s_fsPresets[FS_UDF].setCreateJoliet( false ); + s_fsPresets[FS_UDF].setCreateUdf( true ); + s_fsPresets[FS_UDF].setISOallow31charFilenames( true ); + + // DOS comp + s_fsPresets[FS_DOS_COMP].setCreateJoliet( false ); + s_fsPresets[FS_DOS_COMP].setCreateRockRidge( false ); + s_fsPresets[FS_DOS_COMP].setISOallow31charFilenames( false ); + s_fsPresets[FS_DOS_COMP].setISOLevel( 1 ); + + s_fsPresetsInitialized = true; +} + + + +class K3bDataImageSettingsWidget::CustomFilesystemsDialog : public KDialogBase +{ +public: + CustomFilesystemsDialog( QWidget* parent ) + : KDialogBase( parent, + "custom_filesystems_dialog", + true, + i18n("Custom Data Project Filesystems"), + Ok|Cancel, + Ok, + true ) { + w = new K3bDataAdvancedImageSettingsWidget( this ); + setMainWidget( w ); + } + + K3bDataAdvancedImageSettingsWidget* w; +}; + + +class K3bDataImageSettingsWidget::VolumeDescDialog : public KDialogBase +{ +public: + VolumeDescDialog( QWidget* parent ) + : KDialogBase( parent, + "voldesc_dialog", + true, + i18n("Volume Descriptor"), + Ok|Cancel, + Ok, + true ) { + w = new K3bDataVolumeDescWidget( this ); + setMainWidget( w ); + + // give ourselves a reasonable size + QSize s = sizeHint(); + s.setWidth( QMAX(s.width(), 300) ); + resize( s ); + } + + K3bDataVolumeDescWidget* w; +}; + + + +K3bDataImageSettingsWidget::K3bDataImageSettingsWidget( QWidget* parent, const char* name ) + : base_K3bDataImageSettings( parent, name ), + m_fileSystemOptionsShown(true) +{ + layout()->setMargin( KDialog::marginHint() ); + + m_customFsDlg = new CustomFilesystemsDialog( this ); + m_volDescDlg = new VolumeDescDialog( this ); + + connect( m_buttonCustomFilesystems, SIGNAL(clicked()), + this, SLOT(slotCustomFilesystems()) ); + connect( m_buttonMoreVolDescFields, SIGNAL(clicked()), + this, SLOT(slotMoreVolDescFields()) ); + connect( m_comboSpaceHandling, SIGNAL(activated(int)), + this, SLOT(slotSpaceHandlingChanged(int)) ); + + for( int i = 0; i < FS_MAX; ++i ) + m_comboFilesystems->insertItem( i18n( s_fsPresetNames[i] ) ); + + if( !s_fsPresetsInitialized ) + initializePresets(); + + QWhatsThis::add( m_comboFilesystems, + i18n("<p><b>File System Presets</b>" + "<p>K3b provides the following file system Presets which allow for a quick selection " + "of the most frequently used settings.") + + "<p><b>" + i18n(s_fsPresetNames[0]) + "</b><br>" + + i18n("The file system is optimized for usage on Linux/Unix systems. This mainly means that " + "it uses the Rock Ridge extensions to provide long filenames, symbolic links, and POSIX " + "compatible file permissions.") + + "<p><b>" + i18n(s_fsPresetNames[1]) + "</b><br>" + + i18n("In addition to the settings for Linux/Unix the file system contains a Joliet tree which " + "allows for long file names on Windows which does not support the Rock Ridget extensions. " + "Be aware that the file name length is restricted to 103 characters.") + + "<p><b>" + i18n(s_fsPresetNames[2]) + "</b><br>" + + i18n("The file system has additional UDF entries attached to it. This raises the maximal file " + "size to 4 GB. Be aware that the UDF support in K3b is limited.") + + "<p><b>" + i18n(s_fsPresetNames[3]) + "</b><br>" + + i18n("The file system is optimized for compatibility with old systems. That means file names " + "are restricted to 8.3 characters and no symbolic links or file permissions are supported.") ); +} + + +K3bDataImageSettingsWidget::~K3bDataImageSettingsWidget() +{ +} + + +void K3bDataImageSettingsWidget::showFileSystemOptions( bool b ) +{ + m_groupFileSystem->setShown(b); + m_groupSymlinks->setShown(b); + m_groupWhitespace->setShown(b); + + m_fileSystemOptionsShown = b; +} + + +void K3bDataImageSettingsWidget::slotSpaceHandlingChanged( int i ) +{ + m_editReplace->setEnabled( i == WS_REPLACE ); +} + + +void K3bDataImageSettingsWidget::slotCustomFilesystems() +{ + // load settings in custom window + if( m_comboFilesystems->currentItem() != FS_CUSTOM ) { + m_customFsDlg->w->load( s_fsPresets[m_comboFilesystems->currentItem()] ); + } + + // store the current settings in case the user cancels the changes + K3bIsoOptions o; + m_customFsDlg->w->save( o ); + + if( m_customFsDlg->exec() == QDialog::Accepted ) { + slotFilesystemsChanged(); + } + else { + // reload the old settings discarding any changes + m_customFsDlg->w->load( o ); + } +} + + +void K3bDataImageSettingsWidget::slotFilesystemsChanged() +{ + if( !m_fileSystemOptionsShown ) + return; + + // new custom entry + QStringList s; + if( m_customFsDlg->w->m_checkRockRidge->isChecked() ) + s += i18n("Rock Ridge"); + if( m_customFsDlg->w->m_checkJoliet->isChecked() ) + s += i18n("Joliet"); + if( m_customFsDlg->w->m_checkUdf->isChecked() ) + s += i18n("UDF"); + if( s.isEmpty() ) + m_comboFilesystems->changeItem( i18n("Custom (ISO9660 only)"), FS_CUSTOM ); + else + m_comboFilesystems->changeItem( i18n("Custom (%1)").arg( s.join(", ") ), FS_CUSTOM ); + + // see if any of the presets is loaded + m_comboFilesystems->setCurrentItem( FS_CUSTOM ); + K3bIsoOptions o; + m_customFsDlg->w->save( o ); + for( int i = 0; i < FS_CUSTOM; ++i ) { + if( compareAdvancedOptions( o, s_fsPresets[i] ) ) { + kdDebug() << "(K3bDataImageSettingsWidget) found preset settings: " << s_fsPresetNames[i] << endl; + m_comboFilesystems->setCurrentItem( i ); + break; + } + } + + if( m_comboFilesystems->currentItem() == FS_CUSTOM ) { + if( !m_customFsDlg->w->m_checkRockRidge->isChecked() ) { + KMessageBox::information( this, + i18n("<p>Be aware that it is not recommended to disable the Rock Ridge " + "Extensions. There is no disadvantage in enabling Rock Ridge (except " + "for a very small space overhead) but a lot of advantages." + "<p>Without Rock Ridge Extensions symbolic links are not supported " + "and will always be followed as if the \"Follow Symbolic Links\" option " + "was enabled."), + i18n("Rock Ridge Extensions Disabled"), + "warning_about_rock_ridge" ); + } + + if( !m_customFsDlg->w->m_checkJoliet->isChecked() ) + KMessageBox::information( this, + i18n("<p>Be aware that without the Joliet extensions Windows " + "systems will not be able to display long filenames. You " + "will only see the ISO9660 filenames." + "<p>If you do not intend to use the CD/DVD on a Windows " + "system it is safe to disable Joliet."), + i18n("Joliet Extensions Disabled"), + "warning_about_joliet" ); + } +} + + +void K3bDataImageSettingsWidget::slotMoreVolDescFields() +{ + // update dlg to current state + m_volDescDlg->w->m_editVolumeName->setText( m_editVolumeName->text() ); + + // remember old settings + K3bIsoOptions o; + m_volDescDlg->w->save( o ); + + // exec dlg + if( m_volDescDlg->exec() == QDialog::Accepted ) { + // accept new entries + m_volDescDlg->w->save( o ); + m_editVolumeName->setText( o.volumeID() ); + } + else { + // restore old settings + m_volDescDlg->w->load( o ); + } +} + + +void K3bDataImageSettingsWidget::load( const K3bIsoOptions& o ) +{ + m_customFsDlg->w->load( o ); + m_volDescDlg->w->load( o ); + + slotFilesystemsChanged(); + + if( o.discardBrokenSymlinks() ) + m_comboSymlinkHandling->setCurrentItem( SYM_DISCARD_BROKEN ); + else if( o.discardSymlinks() ) + m_comboSymlinkHandling->setCurrentItem( SYM_DISCARD_ALL ); + else if( o.followSymbolicLinks() ) + m_comboSymlinkHandling->setCurrentItem( SYM_FOLLOW ); + else + m_comboSymlinkHandling->setCurrentItem( SYM_NO_CHANGE ); + + switch( o.whiteSpaceTreatment() ) { + case K3bIsoOptions::strip: + m_comboSpaceHandling->setCurrentItem( WS_STRIP ); + break; + case K3bIsoOptions::extended: + m_comboSpaceHandling->setCurrentItem( WS_EXTENDED_STRIP ); + break; + case K3bIsoOptions::replace: + m_comboSpaceHandling->setCurrentItem( WS_REPLACE ); + break; + default: + m_comboSpaceHandling->setCurrentItem( WS_NO_CHANGE ); + } + slotSpaceHandlingChanged( m_comboSpaceHandling->currentItem() ); + + m_editReplace->setText( o.whiteSpaceTreatmentReplaceString() ); + + m_editVolumeName->setText( o.volumeID() ); +} + + +void K3bDataImageSettingsWidget::save( K3bIsoOptions& o ) +{ + if( m_comboFilesystems->currentItem() != FS_CUSTOM ) + m_customFsDlg->w->load( s_fsPresets[m_comboFilesystems->currentItem()] ); + m_customFsDlg->w->save( o ); + + m_volDescDlg->w->save( o ); + + o.setDiscardSymlinks( m_comboSymlinkHandling->currentItem() == SYM_DISCARD_ALL ); + o.setDiscardBrokenSymlinks( m_comboSymlinkHandling->currentItem() == SYM_DISCARD_BROKEN ); + o.setFollowSymbolicLinks( m_comboSymlinkHandling->currentItem() == SYM_FOLLOW ); + + switch( m_comboSpaceHandling->currentItem() ) { + case WS_STRIP: + o.setWhiteSpaceTreatment( K3bIsoOptions::strip ); + break; + case WS_EXTENDED_STRIP: + o.setWhiteSpaceTreatment( K3bIsoOptions::extended ); + break; + case WS_REPLACE: + o.setWhiteSpaceTreatment( K3bIsoOptions::replace ); + break; + default: + o.setWhiteSpaceTreatment( K3bIsoOptions::noChange ); + } + o.setWhiteSpaceTreatmentReplaceString( m_editReplace->text() ); + + o.setVolumeID( m_editVolumeName->text() ); +} + +#include "k3bdataimagesettingswidget.moc" diff --git a/src/projects/k3bdataimagesettingswidget.h b/src/projects/k3bdataimagesettingswidget.h new file mode 100644 index 0000000..e16226f --- /dev/null +++ b/src/projects/k3bdataimagesettingswidget.h @@ -0,0 +1,54 @@ +/* + * + * $Id: k3bdataimagesettingswidget.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef K3B_DATAIMAGE_SETTINGS_WIDGET_H +#define K3B_DATAIMAGE_SETTINGS_WIDGET_H + + +#include "base_k3bdataimagesettings.h" + +class K3bIsoOptions; + + +class K3bDataImageSettingsWidget : public base_K3bDataImageSettings +{ + Q_OBJECT + + public: + K3bDataImageSettingsWidget( QWidget* parent = 0, const char* name = 0 ); + ~K3bDataImageSettingsWidget(); + + void load( const K3bIsoOptions& ); + void save( K3bIsoOptions& ); + + void showFileSystemOptions( bool ); + + private slots: + void slotSpaceHandlingChanged( int i ); + void slotCustomFilesystems(); + void slotMoreVolDescFields(); + void slotFilesystemsChanged(); + + private: + class CustomFilesystemsDialog; + class VolumeDescDialog; + CustomFilesystemsDialog* m_customFsDlg; + VolumeDescDialog* m_volDescDlg; + + bool m_fileSystemOptionsShown; +}; + + +#endif diff --git a/src/projects/k3bdatamultisessioncombobox.cpp b/src/projects/k3bdatamultisessioncombobox.cpp new file mode 100644 index 0000000..57dd818 --- /dev/null +++ b/src/projects/k3bdatamultisessioncombobox.cpp @@ -0,0 +1,177 @@ +/* + * + * $Id: k3bdatamultisessioncombobox.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bdatamultisessioncombobox.h" + +#include <klocale.h> +#include <kconfig.h> + +#include <qwhatsthis.h> +#include <qtooltip.h> + + +static const int s_autoIndex = 0; +static const int s_noneIndex = 1; +static const int s_startIndex = 2; +static const int s_continueIndex = 3; +static const int s_finishIndex = 4; + + +K3bDataMultiSessionCombobox::K3bDataMultiSessionCombobox( QWidget* parent, const char* name ) + : QComboBox( parent, name ), + m_forceNoMultiSession(false) +{ + init( false ); + + QToolTip::add( this, i18n("Select the Multisession Mode for the project.") ); + QWhatsThis::add( this, i18n("<p><b>Multisession Mode</b>" + "<p><b>Auto</b><br>" + "Let K3b decide which mode to use. The decision will be based " + "on the size of the project (does it fill the whole media) and " + "the state of the inserted media (appendable or not)." + "<p><b>No Multisession</b><br>" + "Create a single-session CD or DVD and close the disk." + "<p><b>Start Multisession</b><br>" + "Start a multisession CD or DVD, not closing the disk to " + "allow further sessions to be apppended." + "<p><b>Continue Multisession</b><br>" + "Continue an appendable data CD (as for example created in " + "<em>Start Multisession</em> mode) and add another session " + "without closing the disk to " + "allow further sessions to be apppended." + "<p><b>Finish Multisession</b><br>" + "Continue an appendable data CD (as for example created in " + "<em>Start Multisession</em> mode), add another session, " + "and close the disk." + "<p><em>In the case of DVD+RW and DVD-RW restricted overwrite media " + "K3b will not actually create multiple sessions but grow the " + "file system to include the new data.</em>") ); +} + + +K3bDataMultiSessionCombobox::~K3bDataMultiSessionCombobox() +{ +} + + +void K3bDataMultiSessionCombobox::init( bool force ) +{ + m_forceNoMultiSession = force; + + clear(); + + insertItem( i18n("Auto"), s_autoIndex ); + insertItem( i18n("No Multisession"), s_noneIndex ); + if( !m_forceNoMultiSession ) { + insertItem( i18n("Start Multisession"), s_startIndex ); + insertItem( i18n("Continue Multisession "), s_continueIndex ); + insertItem( i18n("Finish Multisession "), s_finishIndex ); + } +} + + +K3bDataDoc::MultiSessionMode K3bDataMultiSessionCombobox::multiSessionMode() const +{ + switch( currentItem() ) { + case s_noneIndex: + return K3bDataDoc::NONE; + case s_startIndex: + return K3bDataDoc::START; + case s_continueIndex: + return K3bDataDoc::CONTINUE; + case s_finishIndex: + return K3bDataDoc::FINISH; + default: + return K3bDataDoc::AUTO; + } +} + + +void K3bDataMultiSessionCombobox::saveConfig( KConfigBase* c ) +{ + QString s; + switch( currentItem() ) { + case s_autoIndex: + s = "auto"; + break; + case s_noneIndex: + s = "none"; + break; + case s_startIndex: + s = "start"; + break; + case s_continueIndex: + s = "continue"; + break; + case s_finishIndex: + s = "finish"; + break; + } + + c->writeEntry( "multisession mode", s ); +} + + +void K3bDataMultiSessionCombobox::loadConfig( KConfigBase* c ) +{ + QString s = c->readEntry( "multisession mode" ); + if( s == "none" ) + setMultiSessionMode( K3bDataDoc::NONE ); + else if( s == "start" ) + setMultiSessionMode( K3bDataDoc::START ); + else if( s == "continue" ) + setMultiSessionMode( K3bDataDoc::CONTINUE ); + else if( s == "finish" ) + setMultiSessionMode( K3bDataDoc::FINISH ); + else + setMultiSessionMode( K3bDataDoc::AUTO ); +} + + +void K3bDataMultiSessionCombobox::setMultiSessionMode( K3bDataDoc::MultiSessionMode m ) +{ + switch( m ) { + case K3bDataDoc::AUTO: + setCurrentItem( s_autoIndex ); + break; + case K3bDataDoc::NONE: + setCurrentItem( s_noneIndex ); + break; + case K3bDataDoc::START: + if( !m_forceNoMultiSession ) + setCurrentItem( s_startIndex ); + break; + case K3bDataDoc::CONTINUE: + if( !m_forceNoMultiSession ) + setCurrentItem( s_continueIndex ); + break; + case K3bDataDoc::FINISH: + if( !m_forceNoMultiSession ) + setCurrentItem( s_finishIndex ); + break; + } +} + + +void K3bDataMultiSessionCombobox::setForceNoMultisession( bool f ) +{ + if( f != m_forceNoMultiSession ) { + K3bDataDoc::MultiSessionMode m = multiSessionMode(); + init( f ); + setMultiSessionMode( m ); + } +} + +#include "k3bdatamultisessioncombobox.moc" diff --git a/src/projects/k3bdatamultisessioncombobox.h b/src/projects/k3bdatamultisessioncombobox.h new file mode 100644 index 0000000..cb44989 --- /dev/null +++ b/src/projects/k3bdatamultisessioncombobox.h @@ -0,0 +1,52 @@ +/* + * + * $Id: k3bdatamultisessioncombobox.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_DATA_MULTISESSION_COMBOBOX_H_ +#define _K3B_DATA_MULTISESSION_COMBOBOX_H_ + +#include <qcombobox.h> +#include <k3bdatadoc.h> + +class KConfigBase; + + +class K3bDataMultiSessionCombobox : public QComboBox +{ + Q_OBJECT + + public: + K3bDataMultiSessionCombobox( QWidget* parent = 0, const char* name = 0 ); + ~K3bDataMultiSessionCombobox(); + + /** + * returnes K3bDataDoc::multiSessionModes + */ + K3bDataDoc::MultiSessionMode multiSessionMode() const; + + void setForceNoMultisession( bool ); + + void saveConfig( KConfigBase* ); + void loadConfig( KConfigBase* ); + + public slots: + void setMultiSessionMode( K3bDataDoc::MultiSessionMode ); + + private: + void init( bool forceNo ); + + bool m_forceNoMultiSession; +}; + +#endif diff --git a/src/projects/k3bdatapropertiesdialog.cpp b/src/projects/k3bdatapropertiesdialog.cpp new file mode 100644 index 0000000..39fec61 --- /dev/null +++ b/src/projects/k3bdatapropertiesdialog.cpp @@ -0,0 +1,248 @@ +/* + * + * $Id: k3bdatapropertiesdialog.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bdatapropertiesdialog.h" + +#include "k3bdiritem.h" +#include "k3bfileitem.h" +#include <kcutlabel.h> +#include <k3bvalidators.h> + +#include <qpushbutton.h> +#include <qlayout.h> +#include <qlabel.h> +#include <qframe.h> +#include <qcheckbox.h> +#include <qtooltip.h> +#include <qwhatsthis.h> +#include <qtabwidget.h> +#include <qvalidator.h> + +#include <klineedit.h> +#include <kiconloader.h> +#include <klocale.h> +#include <kmimetype.h> +#include <kurl.h> +#include <kio/global.h> +#include <kfileitem.h> + + + +K3bDataPropertiesDialog::K3bDataPropertiesDialog( K3bDataItem* dataItem, QWidget* parent, const char* name ) + : KDialogBase( Plain, i18n("File Properties"), Ok|Cancel, Ok, parent, name, true, false ) +{ + m_dataItem = dataItem; + + QLabel* labelMimeType = new QLabel( plainPage() ); + QLabel* extraInfoLabel = new QLabel( plainPage() ); + m_editName = new KLineEdit( plainPage() ); + m_labelType = new QLabel( plainPage() ); + m_labelLocation = new KCutLabel( plainPage() ); + m_labelSize = new QLabel( plainPage() ); + m_labelBlocks = new QLabel( plainPage() ); + m_labelLocalName = new KCutLabel( plainPage() ); + m_labelLocalLocation = new KCutLabel( plainPage() ); + + + QGridLayout* grid = new QGridLayout( plainPage() ); + grid->setSpacing( spacingHint() ); + grid->setMargin( marginHint() ); + + grid->addWidget( labelMimeType, 0, 0 ); + grid->addWidget( m_editName, 0, 2 ); + QFrame* line = new QFrame( plainPage() ); + line->setFrameStyle( QFrame::HLine | QFrame::Sunken ); + grid->addMultiCellWidget( line, 1, 1, 0, 2 ); + grid->addWidget( new QLabel( i18n("Type:"), plainPage() ), 2, 0 ); + grid->addWidget( new QLabel( i18n("Location:"), plainPage() ), 4, 0 ); + grid->addWidget( new QLabel( i18n("Size:"), plainPage() ), 5, 0 ); + grid->addWidget( new QLabel( i18n("Used blocks:"), plainPage() ), 6, 0 ); + grid->addWidget( m_labelType, 2, 2 ); + grid->addWidget( extraInfoLabel, 3, 2 ); + grid->addWidget( m_labelLocation, 4, 2 ); + grid->addWidget( m_labelSize, 5, 2 ); + grid->addWidget( m_labelBlocks, 6, 2 ); + line = new QFrame( plainPage() ); + line->setFrameStyle( QFrame::HLine | QFrame::Sunken ); + grid->addMultiCellWidget( line, 7, 7, 0, 2 ); + QLabel* label1 = new QLabel( i18n("Local name:"), plainPage() ); + grid->addWidget( label1, 8, 0 ); + QLabel* label2 = new QLabel( i18n("Local location:"), plainPage() ); + grid->addWidget( label2, 9, 0 ); + grid->addWidget( m_labelLocalName, 8, 2 ); + grid->addWidget( m_labelLocalLocation, 9, 2 ); + + grid->addColSpacing( 1, 50 ); + grid->setColStretch( 2, 1 ); + + + + if( K3bFileItem* fileItem = dynamic_cast<K3bFileItem*>(dataItem) ) { + KFileItem kFileItem( KFileItem::Unknown, KFileItem::Unknown, KURL::fromPathOrURL(fileItem->localPath()) ); + labelMimeType->setPixmap( kFileItem.pixmap(KIcon::SizeLarge) ); + if( fileItem->isSymLink() ) + m_labelType->setText( i18n("Link to %1").arg(kFileItem.mimeComment()) ); + else + m_labelType->setText( kFileItem.mimeComment() ); + m_labelLocalName->setText( kFileItem.name() ); + QString localLocation = kFileItem.url().path(-1); + localLocation.truncate( localLocation.findRev('/') ); + m_labelLocalLocation->setText( localLocation ); + m_labelSize->setText( KIO::convertSize(dataItem->size()) ); + } + else if( K3bDirItem* dirItem = dynamic_cast<K3bDirItem*>(dataItem) ) { + labelMimeType->setPixmap( KMimeType::pixmapForURL( KURL( "/" )) ); + m_labelType->setText( i18n("Directory") ); + label1->hide(); + label2->hide(); + m_labelLocalName->hide(); + m_labelLocalLocation->hide(); + line->hide(); + m_labelSize->setText( KIO::convertSize(dataItem->size()) + "\n(" + + i18n("in 1 file", "in %n files", dirItem->numFiles()) + " " + + i18n("and 1 directory", "and %n directories", dirItem->numDirs()) + ")" ); + } + else { + labelMimeType->setPixmap( DesktopIcon("unknown", KIcon::SizeLarge) ); + m_labelType->setText( i18n("Special file") ); + m_labelLocalName->hide(); + m_labelLocalLocation->hide(); + label1->hide(); + label2->hide(); + line->hide(); + m_labelSize->setText( KIO::convertSize(dataItem->size()) ); + } + + m_editName->setText( dataItem->k3bName() ); + m_labelBlocks->setText( QString::number(dataItem->blocks().lba()) ); + + QString location = "/" + dataItem->k3bPath(); + if( location[location.length()-1] == '/' ) + location.truncate( location.length()-1 ); + location.truncate( location.findRev('/') ); + if( location.isEmpty() ) + location = "/"; + m_labelLocation->setText( location ); + extraInfoLabel->setText( QString( "(%1)" ).arg(dataItem->extraInfo()) ); + if( dataItem->extraInfo().isEmpty() ) + extraInfoLabel->hide(); + + // OPTIONS + // ///////////////////////////////////////////////// + QTabWidget* optionTab = new QTabWidget( plainPage() ); + line = new QFrame( plainPage() ); + line->setFrameStyle( QFrame::HLine | QFrame::Sunken ); + + grid->addMultiCellWidget( line, 10, 10, 0, 2 ); + grid->addMultiCellWidget( optionTab, 12, 12, 0, 2 ); + grid->setRowStretch( 11, 1 ); + + QWidget* hideBox = new QWidget( optionTab ); + QGridLayout* hideBoxGrid = new QGridLayout( hideBox ); + hideBoxGrid->setSpacing( spacingHint() ); + hideBoxGrid->setMargin( marginHint() ); + m_checkHideOnRockRidge = new QCheckBox( i18n("Hide on Rockridge"), hideBox ); + m_checkHideOnJoliet = new QCheckBox( i18n("Hide on Joliet"), hideBox ); + hideBoxGrid->addWidget( m_checkHideOnRockRidge, 0, 0 ); + hideBoxGrid->addWidget( m_checkHideOnJoliet, 1, 0 ); + hideBoxGrid->setRowStretch( 2, 1 ); +// grid->addMultiCellWidget( m_checkHideOnRockRidge, 10, 10, 0, 2 ); +// grid->addMultiCellWidget( m_checkHideOnJoliet, 11, 11, 0, 2 ); + + QWidget* sortingBox = new QWidget( optionTab ); + QGridLayout* sortingBoxGrid = new QGridLayout( sortingBox ); + sortingBoxGrid->setSpacing( spacingHint() ); + sortingBoxGrid->setMargin( marginHint() ); + m_editSortWeight = new KLineEdit( sortingBox ); + m_editSortWeight->setValidator( new QIntValidator( -2147483647, 2147483647, m_editSortWeight ) ); + m_editSortWeight->setAlignment( Qt::AlignRight ); + sortingBoxGrid->addWidget( new QLabel( i18n("Sort weight:"), sortingBox ), 0, 0 ); + sortingBoxGrid->addWidget( m_editSortWeight, 0, 1 ); + sortingBoxGrid->setColStretch( 1, 1 ); + sortingBoxGrid->setRowStretch( 1, 1 ); + + optionTab->addTab( hideBox, i18n("Settings") ); + optionTab->addTab( sortingBox, i18n("Advanced") ); + + + m_checkHideOnJoliet->setChecked( dataItem->hideOnJoliet() ); + m_checkHideOnRockRidge->setChecked( dataItem->hideOnRockRidge() ); + m_editSortWeight->setText( QString::number(dataItem->sortWeight()) ); + + // if the parent is hidden the value cannot be changed (see K3bDataItem::setHide...) + if( dataItem->parent() ) { + m_checkHideOnRockRidge->setDisabled( dataItem->parent()->hideOnRockRidge() ); + m_checkHideOnJoliet->setDisabled( dataItem->parent()->hideOnJoliet() ); + } + + if( !dataItem->isHideable() ) { + m_checkHideOnJoliet->setDisabled(true); + m_checkHideOnRockRidge->setDisabled(true); + // line->hide(); + } + + QToolTip::add( m_checkHideOnRockRidge, i18n("Hide this file in the RockRidge filesystem") ); + QToolTip::add( m_checkHideOnJoliet, i18n("Hide this file in the Joliet filesystem") ); + QToolTip::add( m_editSortWeight, i18n("Modify the physical sorting") ); + QWhatsThis::add( m_checkHideOnRockRidge, i18n("<p>If this option is checked, the file or directory " + "(and its entire contents) will be hidden on the " + "ISO9660 and RockRidge filesystem.</p>" + "<p>This is useful, for example, for having different README " + "files for RockRidge and Joliet, which can be managed " + "by hiding README.joliet on RockRidge and README.rr " + "on the Joliet filesystem.</p>") ); + QWhatsThis::add( m_checkHideOnJoliet, i18n("<p>If this option is checked, the file or directory " + "(and its entire contents) will be hidden on the " + "Joliet filesystem.</p>" + "<p>This is useful, for example, for having different README " + "files for RockRidge and Joliet, which can be managed " + "by hiding README.joliet on RockRidge and README.rr " + "on the Joliet filesystem.</p>") ); + QWhatsThis::add( m_editSortWeight, i18n("<p>This value modifies the physical sort order of the files " + "in the ISO9660 filesystem. A higher weighting means that the " + "file will be located closer to the beginning of the image " + "(and the disk)." + "<p>This option is useful in order to optimize the data layout " + "on a CD/DVD." + "<p><b>Caution:</b> This does not sort the order of the file " + "names that appear in the ISO9660 directory." + "It sorts the order in which the file data is " + "written to the image.") ); + + m_editName->setValidator( K3bValidators::iso9660Validator( false, this ) ); + m_editName->setReadOnly( !dataItem->isRenameable() ); + m_editName->setFocus(); +} + + +K3bDataPropertiesDialog::~K3bDataPropertiesDialog() +{ +} + + +void K3bDataPropertiesDialog::slotOk() +{ + // save filename + m_dataItem->setK3bName( m_editName->text() ); + m_dataItem->setHideOnRockRidge( m_checkHideOnRockRidge->isChecked() ); + m_dataItem->setHideOnJoliet( m_checkHideOnJoliet->isChecked() ); + m_dataItem->setSortWeight( m_editSortWeight->text().toInt() ); + + KDialogBase::slotOk(); +} + + +#include "k3bdatapropertiesdialog.moc" diff --git a/src/projects/k3bdatapropertiesdialog.h b/src/projects/k3bdatapropertiesdialog.h new file mode 100644 index 0000000..eb585ce --- /dev/null +++ b/src/projects/k3bdatapropertiesdialog.h @@ -0,0 +1,61 @@ +/* + * + * $Id: k3bdatapropertiesdialog.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BDATAPROPERTIESDIALOG_H +#define K3BDATAPROPERTIESDIALOG_H + +#include <kdialogbase.h> + +class K3bDataItem; + +class KLineEdit; +class QPushButton; +class QLabel; +class QCheckBox; + + +/** + *@author Sebastian Trueg + */ +class K3bDataPropertiesDialog : public KDialogBase +{ +Q_OBJECT + + public: + K3bDataPropertiesDialog( K3bDataItem*, QWidget* parent = 0, const char* name = 0 ); + ~K3bDataPropertiesDialog(); + + protected slots: + void slotOk(); + + private: + KLineEdit* m_editName; + QLabel* m_labelType; + QLabel* m_labelLocation; + QLabel* m_labelSize; + QLabel* m_labelBlocks; + + QLabel* m_labelLocalName; + QLabel* m_labelLocalLocation; + + QCheckBox* m_checkHideOnRockRidge; + QCheckBox* m_checkHideOnJoliet; + KLineEdit* m_editSortWeight; + + K3bDataItem* m_dataItem; +}; + +#endif diff --git a/src/projects/k3bdatasessionimportdialog.cpp b/src/projects/k3bdatasessionimportdialog.cpp new file mode 100644 index 0000000..f6f1b85 --- /dev/null +++ b/src/projects/k3bdatasessionimportdialog.cpp @@ -0,0 +1,137 @@ +/* + * + * $Id: sourceheader 380067 2005-01-19 13:03:46Z trueg $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bdatasessionimportdialog.h" +#include "k3bmediaselectioncombobox.h" + +#include <k3bdatadoc.h> +#include <k3bapplication.h> +#include <k3biso9660.h> +#include <k3bmediacache.h> +#include <k3b.h> + +#include <qpushbutton.h> +#include <qcursor.h> +#include <qapplication.h> + +#include <klocale.h> +#include <kmessagebox.h> + + +K3bDataSessionImportDialog::K3bDataSessionImportDialog( QWidget* parent ) + : KDialogBase( parent, + "session_import_dialog", + true, + i18n("Session Import"), + KDialogBase::Ok|KDialogBase::Cancel, + KDialogBase::Ok, + false ) +{ + m_comboMedia = new K3bMediaSelectionComboBox( this ); + setMainWidget( m_comboMedia ); + + connect( m_comboMedia, SIGNAL(selectionChanged(K3bDevice::Device*)), + this, SLOT(slotSelectionChanged(K3bDevice::Device*)) ); +} + + +K3bDataSessionImportDialog::~K3bDataSessionImportDialog() +{ +} + + +void K3bDataSessionImportDialog::importSession( K3bDataDoc* doc ) +{ + m_doc = doc; + + if( doc ) { + m_comboMedia->setWantedMediumType( m_doc->type() == K3bDoc::DVD + ? K3bDevice::MEDIA_WRITABLE_DVD + : K3bDevice::MEDIA_WRITABLE_CD ); + } + else + m_comboMedia->setWantedMediumType( K3bDevice::MEDIA_WRITABLE ); + + m_comboMedia->setWantedMediumState( K3bDevice::STATE_INCOMPLETE ); + + slotSelectionChanged( m_comboMedia->selectedDevice() ); +} + + +void K3bDataSessionImportDialog::slotOk() +{ + // find the selected device, show a busy mouse cursor and call K3bDataDoc::importSession + if( K3bDevice::Device* dev = m_comboMedia->selectedDevice() ) { + QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); + + // + // Mkisofs does not properly import joliet filenames from an old session + // + // See bug 79215 for details + // + K3bIso9660 iso( dev ); + if( iso.open() ) { + if( iso.firstRRDirEntry() == 0 && iso.jolietLevel() > 0 ) + KMessageBox::sorry( this, + i18n("<p>K3b found session containing Joliet information for long filenames " + "but no Rock Ridge extensions." + "<p>The filenames in the imported session will be converted to a restricted " + "character set in the new session. This character set is based on the ISO9660 " + "settings in the K3b project. K3b is not able to display these converted filenames yet."), + i18n("Session Import Warning") ); + iso.close(); + } + + if( !m_doc ) { + if( k3bappcore->mediaCache()->diskInfo( dev ).isDvdMedia() ) + m_doc = static_cast<K3bDataDoc*>( k3bappcore->k3bMainWindow()->slotNewDvdDoc() ); + else + m_doc = static_cast<K3bDataDoc*>( k3bappcore->k3bMainWindow()->slotNewDataDoc() ); + } + + m_doc->setBurner( dev ); + m_doc->importSession( dev ); + + QApplication::restoreOverrideCursor(); + + done( 0 ); + } + else + done( 1 ); +} + + +void K3bDataSessionImportDialog::slotCancel() +{ + KDialogBase::slotCancel(); +} + + +void K3bDataSessionImportDialog::slotSelectionChanged( K3bDevice::Device* dev ) +{ + actionButton( KDialogBase::Ok )->setEnabled( dev != 0 ); +} + + +K3bDataDoc* K3bDataSessionImportDialog::importSession( K3bDataDoc* doc, QWidget* parent ) +{ + K3bDataSessionImportDialog dlg( parent ); + dlg.importSession( doc ); + dlg.exec(); + return dlg.m_doc; +} + + +#include "k3bdatasessionimportdialog.moc" diff --git a/src/projects/k3bdatasessionimportdialog.h b/src/projects/k3bdatasessionimportdialog.h new file mode 100644 index 0000000..77c074f --- /dev/null +++ b/src/projects/k3bdatasessionimportdialog.h @@ -0,0 +1,64 @@ +/* + * + * $Id: sourceheader 380067 2005-01-19 13:03:46Z trueg $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_SESSION_IMPORT_DIALOG_H_ +#define _K3B_SESSION_IMPORT_DIALOG_H_ + +#include <kdialogbase.h> + +#include <qptrlist.h> +#include <qmap.h> + +#include <k3bdevice.h> + + +class QLabel; +class KListBox; +class K3bDataDoc; +class K3bMediaSelectionComboBox; + + +class K3bDataSessionImportDialog : public KDialogBase +{ + Q_OBJECT + + public: + /** + * Import a session into the project. + * If the project is a DVD data project only DVD media are + * presented for selection. + * + * \param doc if 0 a new project will be created. + * + * \return the project + */ + static K3bDataDoc* importSession( K3bDataDoc* doc, QWidget* parent ); + + private slots: + void slotOk(); + void slotCancel(); + + void importSession( K3bDataDoc* doc ); + void slotSelectionChanged( K3bDevice::Device* ); + + private: + K3bDataSessionImportDialog( QWidget* parent = 0 ); + ~K3bDataSessionImportDialog(); + + K3bDataDoc* m_doc; + K3bMediaSelectionComboBox* m_comboMedia; +}; + +#endif diff --git a/src/projects/k3bdataurladdingdialog.cpp b/src/projects/k3bdataurladdingdialog.cpp new file mode 100644 index 0000000..2edb43b --- /dev/null +++ b/src/projects/k3bdataurladdingdialog.cpp @@ -0,0 +1,826 @@ +/* + * + * $Id: sourceheader 380067 2005-01-19 13:03:46Z trueg $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include <k3bglobals.h> + +#include "k3bdataurladdingdialog.h" +#include "k3bencodingconverter.h" + +#include <qtimer.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qdir.h> +#include <qfileinfo.h> + +#include <k3bdatadoc.h> +#include <k3bdiritem.h> +#include <k3bcore.h> +#include <k3bfileitem.h> +#include <k3bmultichoicedialog.h> +#include <k3bvalidators.h> +#include <k3bglobals.h> +#include <k3bisooptions.h> +#include <k3b.h> +#include <k3bapplication.h> +#include <k3biso9660.h> +#include <k3bdirsizejob.h> +#include <k3binteractiondialog.h> +#include <k3bthread.h> +#include <k3bsignalwaiter.h> +#include <k3bexternalbinmanager.h> + +#include <klocale.h> +#include <kurl.h> +#include <kinputdialog.h> +#include <kmessagebox.h> +#include <kiconloader.h> +#include <kglobal.h> +#include <kstdguiitem.h> +#include <kconfig.h> +#include <ksqueezedtextlabel.h> +#include <kprogress.h> + +#include <unistd.h> + + +K3bDataUrlAddingDialog::K3bDataUrlAddingDialog( K3bDataDoc* doc, QWidget* parent, const char* name ) + : KDialogBase( Plain, + i18n("Adding files to project '%1'").arg(doc->URL().fileName()), + Cancel, + Cancel, + parent, + name, + true, + true ), + m_bExistingItemsReplaceAll(false), + m_bExistingItemsIgnoreAll(false), + m_bFolderLinksFollowAll(false), + m_bFolderLinksAddAll(false), + m_iAddHiddenFiles(0), + m_iAddSystemFiles(0), + m_bCanceled(false), + m_totalFiles(0), + m_filesHandled(0), + m_lastProgress(0) +{ + m_encodingConverter = new K3bEncodingConverter(); + + QWidget* page = plainPage(); + QGridLayout* grid = new QGridLayout( page ); + grid->setSpacing( spacingHint() ); + grid->setMargin( 0 ); + + m_counterLabel = new QLabel( page ); + m_infoLabel = new KSqueezedTextLabel( i18n("Adding files to project '%1'") + .arg(doc->URL().fileName()) + "...", page ); + m_progressWidget = new KProgress( 0, page ); + + grid->addWidget( m_counterLabel, 0, 1 ); + grid->addWidget( m_infoLabel, 0, 0 ); + grid->addMultiCellWidget( m_progressWidget, 1, 1, 0, 1 ); + + m_dirSizeJob = new K3bDirSizeJob( this ); + connect( m_dirSizeJob, SIGNAL(finished(bool)), + this, SLOT(slotDirSizeDone(bool)) ); + + // try to start with a reasonable size + resize( (int)( fontMetrics().width( caption() ) * 1.5 ), sizeHint().height() ); +} + + +K3bDataUrlAddingDialog::~K3bDataUrlAddingDialog() +{ + delete m_encodingConverter; +} + + +int K3bDataUrlAddingDialog::addUrls( const KURL::List& urls, + K3bDirItem* dir, + QWidget* parent ) +{ + if( urls.isEmpty() ) + return 0; + + // + // A common mistake by beginners is to try to burn an iso image + // with a data project. Let's warn them + // + if( urls.count() == 1 ) { + K3bIso9660 isoF( urls.first().path() ); + if( isoF.open() ) { + if( KMessageBox::warningYesNo( parent, + i18n("<p>The file you are about to add to the project is an ISO9660 image. As such " + "it can be burned to a medium directly since it already contains a file " + "system.<br>" + "Are you sure you want to add this file to the project?"), + i18n("Adding image file to project"), + i18n("Add the file to the project"), + i18n("Burn the image directly") ) == KMessageBox::No ) { + // very rough dvd image size test + if( K3b::filesize( urls.first() ) > 1000*1024*1024 ) + k3bappcore->k3bMainWindow()->slotWriteDvdIsoImage( urls.first() ); + else + k3bappcore->k3bMainWindow()->slotWriteCdImage( urls.first() ); + return 0; + } + } + } + + K3bDataUrlAddingDialog dlg( dir->doc(), parent ); + dlg.m_urls = urls; + for( KURL::List::ConstIterator it = urls.begin(); it != urls.end(); ++it ) + dlg.m_urlQueue.append( qMakePair( K3b::convertToLocalUrl(*it), dir ) ); + + dlg.slotAddUrls(); + int ret = QDialog::Accepted; + if( !dlg.m_urlQueue.isEmpty() ) { + dlg.m_dirSizeJob->setUrls( urls ); + dlg.m_dirSizeJob->setFollowSymlinks( dir->doc()->isoOptions().followSymbolicLinks() ); + dlg.m_dirSizeJob->start(); + ret = dlg.exec(); + } + + // make sure the dir size job is finished + dlg.m_dirSizeJob->cancel(); + K3bSignalWaiter::waitForJob( dlg.m_dirSizeJob ); + + QString message = dlg.resultMessage(); + if( !message.isEmpty() ) + KMessageBox::detailedSorry( parent, i18n("Problems while adding files to the project."), message ); + + return ret; +} + + +QString K3bDataUrlAddingDialog::resultMessage() const +{ + QString message; + if( !m_unreadableFiles.isEmpty() ) + message += QString("<p><b>%1:</b><br>%2") + .arg( i18n("Insufficient permissions to read the following files") ) + .arg( m_unreadableFiles.join( "<br>" ) ); + if( !m_notFoundFiles.isEmpty() ) + message += QString("<p><b>%1:</b><br>%2") + .arg( i18n("Unable to find the following files") ) + .arg( m_notFoundFiles.join( "<br>" ) ); + if( !m_nonLocalFiles.isEmpty() ) + message += QString("<p><b>%1:</b><br>%2") + .arg( i18n("No non-local files supported") ) + .arg( m_unreadableFiles.join( "<br>" ) ); + if( !m_tooBigFiles.isEmpty() ) + message += QString("<p><b>%1:</b><br>%2") + .arg( i18n("It is not possible to add files bigger than %1").arg(KIO::convertSize(0xFFFFFFFF)) ) + .arg( m_tooBigFiles.join( "<br>" ) ); + if( !m_mkisofsLimitationRenamedFiles.isEmpty() ) + message += QString("<p><b>%1:</b><br>%2") + .arg( i18n("Some filenames had to be modified due to limitations in mkisofs") ) + .arg( m_mkisofsLimitationRenamedFiles.join( "<br>" ) ); + if( !m_invalidFilenameEncodingFiles.isEmpty() ) + message += QString("<p><b>%1:</b><br>%2") + .arg( i18n("The following filenames have an invalid encoding. You may fix this " + "with the convmv tool") ) + .arg( m_invalidFilenameEncodingFiles.join( "<br>" ) ); + + return message; +} + + +int K3bDataUrlAddingDialog::moveItems( const QValueList<K3bDataItem*>& items, + K3bDirItem* dir, + QWidget* parent ) +{ + return copyMoveItems( items, dir, parent, false ); +} + + +int K3bDataUrlAddingDialog::copyItems( const QValueList<K3bDataItem*>& items, + K3bDirItem* dir, + QWidget* parent ) +{ + return copyMoveItems( items, dir, parent, true ); +} + + +int K3bDataUrlAddingDialog::copyMoveItems( const QValueList<K3bDataItem*>& items, + K3bDirItem* dir, + QWidget* parent, + bool copy ) +{ + if( items.isEmpty() ) + return 0; + + K3bDataUrlAddingDialog dlg( dir->doc(), parent ); + dlg.m_infoLabel->setText( i18n("Moving files to project \"%1\"...").arg(dir->doc()->URL().fileName()) ); + dlg.m_copyItems = copy; + + for( QValueList<K3bDataItem*>::const_iterator it = items.begin(); it != items.end(); ++it ) { + dlg.m_items.append( qMakePair( *it, dir ) ); + ++dlg.m_totalFiles; + if( (*it)->isDir() ) { + dlg.m_totalFiles += static_cast<K3bDirItem*>( *it )->numFiles(); + dlg.m_totalFiles += static_cast<K3bDirItem*>( *it )->numDirs(); + } + } + + dlg.slotCopyMoveItems(); + int ret = QDialog::Accepted; + if( !dlg.m_items.isEmpty() ) { + dlg.m_progressWidget->setTotalSteps( dlg.m_totalFiles ); + ret = dlg.exec(); + } + + return ret; +} + + +void K3bDataUrlAddingDialog::slotCancel() +{ + m_bCanceled = true; + m_dirSizeJob->cancel(); + KDialogBase::slotCancel(); +} + + +void K3bDataUrlAddingDialog::slotAddUrls() +{ + if( m_bCanceled ) + return; + + // add next url + KURL url = m_urlQueue.first().first; + K3bDirItem* dir = m_urlQueue.first().second; + m_urlQueue.remove( m_urlQueue.begin() ); + // + // HINT: + // we only use QFileInfo::absFilePath() and QFileInfo::isHidden() + // both do not cause QFileInfo to stat, thus no speed improvement + // can come from removing QFileInfo usage here. + // + QFileInfo info(url.path()); + QString absFilePath( info.absFilePath() ); + QString resolved( absFilePath ); + + bool valid = true; + k3b_struct_stat statBuf, resolvedStatBuf; + bool isSymLink = false; + bool isDir = false; + bool isFile = false; + + ++m_filesHandled; + +#if 0 + m_infoLabel->setText( url.path() ); + if( m_totalFiles == 0 ) + m_counterLabel->setText( QString("(%1)").arg(m_filesHandled) ); + else + m_counterLabel->setText( QString("(%1/%2)").arg(m_filesHandled).arg(m_totalFiles) ); +#endif + + // + // 1. Check if we want and can add the url + // + + if( !url.isLocalFile() ) { + valid = false; + m_nonLocalFiles.append( url.path() ); + } + + else if( k3b_lstat( QFile::encodeName(absFilePath), &statBuf ) != 0 ) { + valid = false; + m_notFoundFiles.append( url.path() ); + } + + else if( !m_encodingConverter->encodedLocally( QFile::encodeName( url.path() ) ) ) { + valid = false; + m_invalidFilenameEncodingFiles.append( url.path() ); + } + + else { + isSymLink = S_ISLNK(statBuf.st_mode); + isFile = S_ISREG(statBuf.st_mode); + isDir = S_ISDIR(statBuf.st_mode); + + // symlinks are always readable and can always be added to a project + // but we need to know if the symlink points to a directory + if( isSymLink ) { + resolved = K3b::resolveLink( absFilePath ); + k3b_stat( QFile::encodeName(resolved), &resolvedStatBuf ); + isDir = S_ISDIR(resolvedStatBuf.st_mode); + } + + else { + if( ::access( QFile::encodeName( absFilePath ), R_OK ) != 0 ) { + valid = false; + m_unreadableFiles.append( url.path() ); + } + else if( isFile && (unsigned long long)statBuf.st_size >= 0xFFFFFFFFULL ) { + if ( !k3bcore->externalBinManager()->binObject( "mkisofs" )->hasFeature( "no-4gb-limit" ) ) { + valid = false; + m_tooBigFiles.append( url.path() ); + } + } + } + + // FIXME: if we do not add hidden dirs the progress gets messed up! + + // + // check for hidden and system files + // + if( valid ) { + if( info.isHidden() && !addHiddenFiles() ) + valid = false; + if( S_ISCHR(statBuf.st_mode) || + S_ISBLK(statBuf.st_mode) || + S_ISFIFO(statBuf.st_mode) || + S_ISSOCK(statBuf.st_mode) ) + if( !addSystemFiles() ) + valid = false; + if( isSymLink ) + if( S_ISCHR(resolvedStatBuf.st_mode) || + S_ISBLK(resolvedStatBuf.st_mode) || + S_ISFIFO(resolvedStatBuf.st_mode) || + S_ISSOCK(resolvedStatBuf.st_mode) ) + if( !addSystemFiles() ) + valid = false; + } + } + + + // + // 2. Handle the url + // + + QString newName = url.fileName(); + + // filenames cannot end in backslashes (mkisofs problem. See comments in k3bisoimager.cpp (escapeGraftPoint())) + bool bsAtEnd = false; + while( newName[newName.length()-1] == '\\' ) { + newName.truncate( newName.length()-1 ); + bsAtEnd = true; + } + if( bsAtEnd ) + m_mkisofsLimitationRenamedFiles.append( url.path() + " -> " + newName ); + + // backup dummy name + if( newName.isEmpty() ) + newName = "1"; + + K3bDirItem* newDirItem = 0; + + // + // The source is valid. Now check if the project already contains a file with that name + // and if so handle it properly + // + if( valid ) { + if( K3bDataItem* oldItem = dir->find( newName ) ) { + // + // reuse an existing dir + // + if( oldItem->isDir() && isDir ) + newDirItem = dynamic_cast<K3bDirItem*>(oldItem); + + // + // we cannot replace files in the old session with dirs and vice versa (I think) + // files are handled in K3bFileItem constructor and dirs handled above + // + else if( oldItem->isFromOldSession() && + isDir != oldItem->isDir() ) { + if( !getNewName( newName, dir, newName ) ) + valid = false; + } + + else if( m_bExistingItemsIgnoreAll ) + valid = false; + + else if( oldItem->localPath() == resolved ) { + // + // Just ignore if the same file is added again + // + valid = false; + } + + else if( m_bExistingItemsReplaceAll ) { + // if we replace an item from an old session the K3bFileItem constructor takes care + // of replacing the item + if( !oldItem->isFromOldSession() ) + delete oldItem; + } + + // + // Let the user choose + // + else { + switch( K3bMultiChoiceDialog::choose( i18n("File already exists"), + i18n("<p>File <em>%1</em> already exists in " + "project folder <em>%2</em>.") + .arg(newName) + .arg('/' + dir->k3bPath()), + QMessageBox::Warning, + this, + 0, + 6, + KGuiItem( i18n("Replace"), + QString::null, + i18n("Replace the existing file") ), + KGuiItem( i18n("Replace All"), + QString::null, + i18n("Always replace existing files") ), + KGuiItem( i18n("Ignore"), + QString::null, + i18n("Keep the existing file") ), + KGuiItem( i18n("Ignore All"), + QString::null, + i18n("Always keep the existing file") ), + KGuiItem( i18n("Rename"), + QString::null, + i18n("Rename the new file") ), + KStdGuiItem::cancel() ) ) { + case 2: // replace all + m_bExistingItemsReplaceAll = true; + // fallthrough + case 1: // replace + // if we replace an item from an old session the K3bFileItem constructor takes care + // of replacing the item + if( !oldItem->isFromOldSession() ) + delete oldItem; + break; + case 4: // ignore all + m_bExistingItemsIgnoreAll = true; + // fallthrough + case 3: // ignore + valid = false; + break; + case 5: // rename + if( !getNewName( newName, dir, newName ) ) + valid = false; + break; + case 6: // cancel + slotCancel(); + return; + } + } + } + } + + + // + // One more thing to warn the user about: We cannot follow links to folders since that + // would change the doc. So we simply ask the user what to do with a link to a folder + // + if( valid ) { + // let's see if this link starts a loop + // that means if it points to some folder above this one + // if so we cannot follow it anyway + if( isDir && isSymLink && !absFilePath.startsWith( resolved ) ) { + bool followLink = dir->doc()->isoOptions().followSymbolicLinks() || m_bFolderLinksFollowAll; + if( !followLink && !m_bFolderLinksAddAll ) { + switch( K3bMultiChoiceDialog::choose( i18n("Adding link to folder"), + i18n("<p>'%1' is a symbolic link to folder '%2'." + "<p>If you intend to make K3b follow symbolic links you should consider letting K3b do this now " + "since K3b will not be able to do so afterwards because symbolic links to folders inside a " + "K3b project cannot be resolved." + "<p><b>If you do not intend to enable the option <em>follow symbolic links</em> you may safely " + "ignore this warning and choose to add the link to the project.</b>") + .arg(absFilePath) + .arg(resolved ), + QMessageBox::Warning, + this, + 0, + 5, + i18n("Follow link now"), + i18n("Always follow links"), + i18n("Add link to project"), + i18n("Always add links"), + KStdGuiItem::cancel() ) ) { + case 2: + m_bFolderLinksFollowAll = true; + case 1: + followLink = true; + break; + case 4: + m_bFolderLinksAddAll = true; + case 3: + followLink = false; + break; + case 5: + slotCancel(); + return; + } + } + + if( followLink ) { + absFilePath = resolved; + isSymLink = false; + + // count the files in the followed dir + if( m_dirSizeJob->active() ) + m_dirSizeQueue.append( KURL::fromPathOrURL(absFilePath) ); + else { + m_progressWidget->setTotalSteps( 0 ); + m_dirSizeJob->setUrls( KURL::fromPathOrURL(absFilePath) ); + m_dirSizeJob->start(); + } + } + } + } + + + // + // Project valid also (we overwrite or renamed) + // now create the new item + // + if( valid ) { + // + // Set the volume id from the first added url + // only if the doc was not changed yet + // + if( m_urls.count() == 1 && + !dir->doc()->isModified() && + !dir->doc()->isSaved() ) { + dir->doc()->setVolumeID( K3b::removeFilenameExtension( newName ) ); + } + + if( isDir && !isSymLink ) { + if( !newDirItem ) { // maybe we reuse an already existing dir + newDirItem = new K3bDirItem( newName , dir->doc(), dir ); + newDirItem->setLocalPath( url.path() ); // HACK: see k3bdiritem.h + } + + QDir newDir( absFilePath ); + int dirFilter = QDir::All|QDir::Hidden|QDir::System; + + QStringList dlist = newDir.entryList( dirFilter ); + const QString& dot = KGlobal::staticQString( "." ); + const QString& dotdot = KGlobal::staticQString( ".." ); + dlist.remove( dot ); + dlist.remove( dotdot ); + + for( QStringList::Iterator it = dlist.begin(); it != dlist.end(); ++it ) { + m_urlQueue.append( qMakePair( KURL::fromPathOrURL(absFilePath + '/' + *it), newDirItem ) ); + } + } + else { + (void)new K3bFileItem( &statBuf, &resolvedStatBuf, url.path(), dir->doc(), dir, newName ); + } + } + + if( m_urlQueue.isEmpty() ) { + m_dirSizeJob->cancel(); + m_progressWidget->setProgress( 100 ); + accept(); + } + else { + updateProgress(); + QTimer::singleShot( 0, this, SLOT(slotAddUrls()) ); + } +} + + +void K3bDataUrlAddingDialog::slotCopyMoveItems() +{ + if( m_bCanceled ) + return; + + // + // Pop first item from the item list + // + K3bDataItem* item = m_items.first().first; + K3bDirItem* dir = m_items.first().second; + m_items.remove( m_items.begin() ); + + ++m_filesHandled; + m_infoLabel->setText( item->k3bPath() ); + if( m_totalFiles == 0 ) + m_counterLabel->setText( QString("(%1)").arg(m_filesHandled) ); + else + m_counterLabel->setText( QString("(%1/%2)").arg(m_filesHandled).arg(m_totalFiles) ); + + + if( dir == item->parent() ) { + kdDebug() << "(K3bDataUrlAddingDialog) trying to move an item into its own parent dir." << endl; + } + else if( dir == item ) { + kdDebug() << "(K3bDataUrlAddingDialog) trying to move an item into itselft." << endl; + } + else { + // + // Let's see if an item with that name alredy exists + // + if( K3bDataItem* oldItem = dir->find( item->k3bName() ) ) { + // + // reuse an existing dir: move all child items into the old dir + // + if( oldItem->isDir() && item->isDir() ) { + const QPtrList<K3bDataItem>& cl = dynamic_cast<K3bDirItem*>( item )->children(); + for( QPtrListIterator<K3bDataItem> it( cl ); *it; ++it ) + m_items.append( qMakePair( *it, dynamic_cast<K3bDirItem*>( oldItem ) ) ); + + // FIXME: we need to remove the old dir item + } + + // + // we cannot replace files in the old session with dirs and vice versa (I think) + // files are handled in K3bFileItem constructor and dirs handled above + // + else if( oldItem->isFromOldSession() && + item->isDir() != oldItem->isDir() ) { + QString newName; + if( getNewName( newName, dir, newName ) ) { + if( m_copyItems ) + item = item->copy(); + item->setK3bName( newName ); + dir->addDataItem( item ); + } + } + + else if( m_bExistingItemsReplaceAll ) { + // + // if we replace an item from an old session K3bDirItem::addDataItem takes care + // of replacing the item + // + if( !oldItem->isFromOldSession() ) + delete oldItem; + if( m_copyItems ) + item = item->copy(); + dir->addDataItem( item ); + } + + else if( !m_bExistingItemsIgnoreAll ) { + switch( K3bMultiChoiceDialog::choose( i18n("File already exists"), + i18n("<p>File <em>%1</em> already exists in " + "project folder <em>%2</em>.") + .arg( item->k3bName() ) + .arg("/" + dir->k3bPath()), + QMessageBox::Warning, + this, + 0, + 6, + KGuiItem( i18n("Replace"), + QString::null, + i18n("Replace the existing file") ), + KGuiItem( i18n("Replace All"), + QString::null, + i18n("Always replace existing files") ), + KGuiItem( i18n("Ignore"), + QString::null, + i18n("Keep the existing file") ), + KGuiItem( i18n("Ignore All"), + QString::null, + i18n("Always keep the existing file") ), + KGuiItem( i18n("Rename"), + QString::null, + i18n("Rename the new file") ), + KStdGuiItem::cancel() ) ) { + case 2: // replace all + m_bExistingItemsReplaceAll = true; + // fallthrough + case 1: // replace + // + // if we replace an item from an old session K3bDirItem::addDataItem takes care + // of replacing the item + // + if( !oldItem->isFromOldSession() ) + delete oldItem; + if( m_copyItems ) + item = item->copy(); + dir->addDataItem( item ); + break; + case 4: // ignore all + m_bExistingItemsIgnoreAll = true; + // fallthrough + case 3: // ignore + // do nothing + break; + case 5: {// rename + QString newName; + if( getNewName( newName, dir, newName ) ) { + if( m_copyItems ) + item = item->copy(); + item->setK3bName( newName ); + dir->addDataItem( item ); + } + break; + } + case 6: // cancel + slotCancel(); + return; + } + } + } + + // + // No old item with the same name + // + else { + if( m_copyItems ) + item = item->copy(); + dir->addDataItem( item ); + } + } + + if( m_items.isEmpty() ) { + m_dirSizeJob->cancel(); + accept(); + } + else { + updateProgress(); + QTimer::singleShot( 0, this, SLOT(slotCopyMoveItems()) ); + } +} + + +bool K3bDataUrlAddingDialog::getNewName( const QString& oldName, K3bDirItem* dir, QString& newName ) +{ + bool ok = true; + newName = oldName; + QValidator* validator = K3bValidators::iso9660Validator( false, this ); + do { + newName = KInputDialog::getText( i18n("Enter New Filename"), + i18n("A file with that name already exists. Please enter a new name:"), + newName, &ok, this, "renamedialog", validator ); + + } while( ok && dir->find( newName ) ); + + delete validator; + + return ok; +} + + +bool K3bDataUrlAddingDialog::addHiddenFiles() +{ + if( m_iAddHiddenFiles == 0 ) { + // FIXME: the isVisible() stuff makes the static addUrls method not return (same below) + if( KMessageBox::questionYesNo( /*isVisible() ? */this/* : parentWidget()*/, + i18n("Do you also want to add hidden files?"), + i18n("Hidden Files"), i18n("Add"), i18n("Do Not Add") ) == KMessageBox::Yes ) + m_iAddHiddenFiles = 1; + else + m_iAddHiddenFiles = -1; + } + + return ( m_iAddHiddenFiles == 1 ); +} + + +bool K3bDataUrlAddingDialog::addSystemFiles() +{ + if( m_iAddSystemFiles == 0 ) { + if( KMessageBox::questionYesNo( /*isVisible() ? */this/* : parentWidget()*/, + i18n("Do you also want to add system files " + "(FIFOs, sockets, device files, and broken symlinks)?"), + i18n("System Files"), i18n("Add"), i18n("Do Not Add") ) == KMessageBox::Yes ) + m_iAddSystemFiles = 1; + else + m_iAddSystemFiles = -1; + } + + return ( m_iAddSystemFiles == 1 ); +} + + +void K3bDataUrlAddingDialog::slotDirSizeDone( bool success ) +{ + if( success ) { + m_totalFiles += m_dirSizeJob->totalFiles() + m_dirSizeJob->totalDirs(); + if( m_dirSizeQueue.isEmpty() ) { + m_progressWidget->setTotalSteps( 100 ); + updateProgress(); + } + else { + m_dirSizeJob->setUrls( m_dirSizeQueue.back() ); + m_dirSizeQueue.pop_back(); + m_dirSizeJob->start(); + } + } +} + + +void K3bDataUrlAddingDialog::updateProgress() +{ + if( m_totalFiles > 0 ) { + unsigned int p = 100*m_filesHandled/m_totalFiles; + if( p > m_lastProgress ) { + m_lastProgress = p; + m_progressWidget->setProgress( p ); + } + } + else { + // make sure the progress bar shows something + m_progressWidget->setProgress( m_filesHandled ); + } +} + +#include "k3bdataurladdingdialog.moc" diff --git a/src/projects/k3bdataurladdingdialog.h b/src/projects/k3bdataurladdingdialog.h new file mode 100644 index 0000000..cb7c0ac --- /dev/null +++ b/src/projects/k3bdataurladdingdialog.h @@ -0,0 +1,110 @@ +/* + * + * $Id: sourceheader 380067 2005-01-19 13:03:46Z trueg $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_DATA_URL_ADDING_DIALOG_H_ +#define _K3B_DATA_URL_ADDING_DIALOG_H_ + +#include <kdialogbase.h> +#include <kurl.h> +#include <qstringlist.h> +#include <qpair.h> +#include <qdir.h> + +class KProgress; +class QLabel; +class K3bDataItem; +class K3bDirItem; +class K3bEncodingConverter; +class K3bDirSizeJob; +class K3bDataDoc; + + +class K3bDataUrlAddingDialog : public KDialogBase +{ + Q_OBJECT + + public: + ~K3bDataUrlAddingDialog(); + + /** + * \return \see QDialog::exec() + */ + static int addUrls( const KURL::List& urls, K3bDirItem* dir = 0, + QWidget* parent = 0 ); + + static int moveItems( const QValueList<K3bDataItem*>& items, K3bDirItem* dir, + QWidget* parent = 0 ); + + static int copyItems( const QValueList<K3bDataItem*>& items, K3bDirItem* dir, + QWidget* parent = 0 ); + + static int copyMoveItems( const QValueList<K3bDataItem*>& items, K3bDirItem* dir, + QWidget* parent, bool copy ); + + private slots: + void slotAddUrls(); + void slotCopyMoveItems(); + void slotCancel(); + void slotDirSizeDone( bool ); + void updateProgress(); + + private: + K3bDataUrlAddingDialog( K3bDataDoc* doc, QWidget* parent = 0, const char* name = 0 ); + + bool getNewName( const QString& oldName, K3bDirItem* dir, QString& newName ); + + bool addHiddenFiles(); + bool addSystemFiles(); + + QString resultMessage() const; + + KProgress* m_progressWidget; + QLabel* m_infoLabel; + QLabel* m_counterLabel; + K3bEncodingConverter* m_encodingConverter; + + KURL::List m_urls; + QValueList< QPair<KURL, K3bDirItem*> > m_urlQueue; + + QValueList< QPair<K3bDataItem*, K3bDirItem*> > m_items; + + QValueList<KURL> m_dirSizeQueue; + + bool m_bExistingItemsReplaceAll; + bool m_bExistingItemsIgnoreAll; + bool m_bFolderLinksFollowAll; + bool m_bFolderLinksAddAll; + int m_iAddHiddenFiles; + int m_iAddSystemFiles; + + QStringList m_unreadableFiles; + QStringList m_notFoundFiles; + QStringList m_nonLocalFiles; + QStringList m_tooBigFiles; + QStringList m_mkisofsLimitationRenamedFiles; + QStringList m_invalidFilenameEncodingFiles; + + bool m_bCanceled; + + bool m_copyItems; + + KIO::filesize_t m_totalFiles; + KIO::filesize_t m_filesHandled; + K3bDirSizeJob* m_dirSizeJob; + + unsigned int m_lastProgress; +}; + +#endif diff --git a/src/projects/k3bdataview.cpp b/src/projects/k3bdataview.cpp new file mode 100644 index 0000000..9539b5c --- /dev/null +++ b/src/projects/k3bdataview.cpp @@ -0,0 +1,196 @@ +/* + * + * $Id: k3bdataview.cpp 731898 2007-11-02 08:22:18Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bdataview.h" +#include "k3bdatadoc.h" +#include "k3bdataburndialog.h" +#include "k3bbootimageview.h" +#include "k3bdatadirtreeview.h" +#include "k3bdatafileview.h" +#include "k3bdataurladdingdialog.h" +#include "k3bdatasessionimportdialog.h" +#include "k3bdiritem.h" +#include <k3bdevice.h> +#include <k3bdeviceselectiondialog.h> +#include <k3bfillstatusdisplay.h> +#include <k3bcore.h> +#include <k3bprojectplugin.h> +#include <k3btoolbox.h> +#include <k3bvalidators.h> + +#include <klocale.h> +#include <kurl.h> +#include <kapplication.h> +#include <kpopupmenu.h> +#include <kaction.h> +#include <kmessagebox.h> +#include <kio/global.h> +#include <kio/job.h> +#include <kdialogbase.h> + +#include <qpixmap.h> +#include <qsplitter.h> +#include <qlayout.h> +#include <qdragobject.h> +#include <qheader.h> +#include <qptrlist.h> +#include <qlineedit.h> + +#include <assert.h> +#include <kdebug.h> + + +K3bDataView::K3bDataView(K3bDataDoc* doc, QWidget *parent, const char *name ) + : K3bView(doc, parent,name) +{ + m_doc = doc; + + // --- setup GUI --------------------------------------------------- + QSplitter* mainSplitter = new QSplitter( this ); + m_dataDirTree = new K3bDataDirTreeView( this, doc, mainSplitter ); + m_dataFileView = new K3bDataFileView( this, m_dataDirTree, doc, mainSplitter ); + m_dataDirTree->setFileView( m_dataFileView ); + setMainWidget( mainSplitter ); + + + connect( m_dataFileView, SIGNAL(dirSelected(K3bDirItem*)), + m_dataDirTree, SLOT(setCurrentDir(K3bDirItem*)) ); + connect( m_doc, SIGNAL(changed()), this, SLOT(slotDocChanged()) ); + + m_dataDirTree->checkForNewItems(); + m_dataFileView->checkForNewItems(); + + + // the data actions + KAction* actionImportSession = new KAction(i18n("&Import Session..."), "gear", 0, this, SLOT(importSession()), + actionCollection(), "project_data_import_session" ); + KAction* actionClearSession = new KAction(i18n("&Clear Imported Session"), "gear", 0, this, + SLOT(clearImportedSession()), actionCollection(), + "project_data_clear_imported_session" ); + KAction* actionEditBootImages = new KAction(i18n("&Edit Boot Images..."), "cdtrack", 0, this, + SLOT(editBootImages()), actionCollection(), + "project_data_edit_boot_images" ); + + actionImportSession->setToolTip( i18n("Import a previously burned session into the current project") ); + actionClearSession->setToolTip( i18n("Remove the imported items from a previous session") ); + actionEditBootImages->setToolTip( i18n("Modify the bootable settings of the current project") ); + + toolBox()->addButton( actionImportSession ); + toolBox()->addButton( actionClearSession ); + toolBox()->addButton( actionEditBootImages ); + toolBox()->addSeparator(); + toolBox()->addButton( m_dataFileView->actionCollection()->action("parent_dir") ); + toolBox()->addSeparator(); + + addPluginButtons( K3bProjectPlugin::DATA_CD ); + + toolBox()->addStretch(); + + m_volumeIDEdit = new QLineEdit( doc->isoOptions().volumeID(), toolBox() ); + m_volumeIDEdit->setValidator( new K3bLatin1Validator( m_volumeIDEdit ) ); + toolBox()->addLabel( i18n("Volume Name:") ); + toolBox()->addSpacing(); + toolBox()->addWidget( m_volumeIDEdit ); + connect( m_volumeIDEdit, SIGNAL(textChanged(const QString&)), + m_doc, + SLOT(setVolumeID(const QString&)) ); + + // this is just for testing (or not?) + // most likely every project type will have it's rc file in the future + // we only add the additional actions since K3bView already added the default actions + setXML( "<!DOCTYPE kpartgui SYSTEM \"kpartgui.dtd\">" + "<kpartgui name=\"k3bproject\" version=\"1\">" + "<MenuBar>" + " <Menu name=\"project\"><text>&Project</text>" + " <Action name=\"project_data_import_session\"/>" + " <Action name=\"project_data_clear_imported_session\"/>" + " <Action name=\"project_data_edit_boot_images\"/>" + " </Menu>" + "</MenuBar>" + "</kpartgui>", true ); +} + + +K3bDataView::~K3bDataView(){ +} + + +K3bDirItem* K3bDataView::currentDir() const +{ + return m_dataFileView->currentDir(); +} + + +void K3bDataView::importSession() +{ + K3bDataSessionImportDialog::importSession( m_doc, this ); +} + + +void K3bDataView::clearImportedSession() +{ + m_doc->clearImportedSession(); +} + + +void K3bDataView::editBootImages() +{ + KDialogBase* d = new KDialogBase( this, "", true, i18n("Edit Boot Images"), + KDialogBase::Ok, KDialogBase::Ok, true ); + d->setMainWidget( new K3bBootImageView( m_doc, d ) ); + d->exec(); + delete d; +} + + +K3bProjectBurnDialog* K3bDataView::newBurnDialog( QWidget* parent, const char* name ) +{ + return new K3bDataBurnDialog( m_doc, parent, name, true ); +} + + +void K3bDataView::slotBurn() +{ + // Little hack which at least handles most situations (better in 1.1): + // If a session has been importet we cannot use the file count since that + // includes imported items + if( m_doc->sessionImported() && m_doc->burningSize() == 0 || + m_doc->root()->numFiles() == 0 ) { + KMessageBox::information( this, i18n("Please add files to your project first."), + i18n("No Data to Burn"), QString::null, false ); + } + else { + K3bProjectBurnDialog* dlg = newBurnDialog( this ); + dlg->execBurnDialog(true); + delete dlg; + } +} + + +void K3bDataView::slotDocChanged() +{ + // do not update the editor in case it changed the volume id itself + if( m_doc->isoOptions().volumeID() != m_volumeIDEdit->text() ) + m_volumeIDEdit->setText( m_doc->isoOptions().volumeID() ); +} + + +void K3bDataView::addUrls( const KURL::List& urls ) +{ + K3bDataUrlAddingDialog::addUrls( urls, m_dataFileView->currentDir() ); +} + +#include "k3bdataview.moc" diff --git a/src/projects/k3bdataview.h b/src/projects/k3bdataview.h new file mode 100644 index 0000000..bb9154e --- /dev/null +++ b/src/projects/k3bdataview.h @@ -0,0 +1,78 @@ +/* + * + * $Id: k3bdataview.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BDATAVIEW_H +#define K3BDATAVIEW_H + +#include <k3bview.h> + +class K3bDataDoc; +class K3bDataItem; +class K3bFileItem; +class K3bDirItem; +class K3bDataDirTreeView; +class K3bDataFileView; +class QLineEdit; + + +namespace KIO { + class Job; +} +namespace K3bDevice { + class Device; +} + + + +/** + *@author Sebastian Trueg + */ +class K3bDataView : public K3bView +{ + Q_OBJECT + + public: + K3bDataView(K3bDataDoc* doc, QWidget *parent=0, const char *name=0); + virtual ~K3bDataView(); + + K3bDirItem* currentDir() const; + + public slots: + void slotBurn(); + void importSession(); + void clearImportedSession(); + void editBootImages(); + + void slotDocChanged(); + + void addUrls( const KURL::List& ); + + protected: + K3bDataDirTreeView* m_dataDirTree; + K3bDataFileView* m_dataFileView; + QLineEdit* m_volumeIDEdit; + + virtual K3bProjectBurnDialog* newBurnDialog( QWidget* parent = 0, const char* name = 0 ); + + private: + K3bDataDoc* m_doc; + + // used for mounting when importing old session + K3bDevice::Device* m_device; +}; + + +#endif diff --git a/src/projects/k3bdataviewitem.cpp b/src/projects/k3bdataviewitem.cpp new file mode 100644 index 0000000..78c044d --- /dev/null +++ b/src/projects/k3bdataviewitem.cpp @@ -0,0 +1,340 @@ +/* + * + * $Id: k3bdataviewitem.cpp 689533 2007-07-18 14:19:39Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bdataviewitem.h" + +#include "k3bfileitem.h" +#include "k3bdiritem.h" +#include "k3bspecialdataitem.h" +#include "k3bsessionimportitem.h" +#include "k3bdatadoc.h" +#include <k3bvalidators.h> + +#include <kio/global.h> +#include <kiconloader.h> +#include <klocale.h> +#include <kmimetype.h> +#include <kurl.h> +#include <kpixmapeffect.h> +#include <kpixmap.h> + +#include <qpainter.h> +#include <qpalette.h> +#include <qfileinfo.h> + + +K3bDataViewItem::K3bDataViewItem( K3bDataItem* item, QListView* parent ) + : K3bListViewItem( parent ), + m_dataItem(item) +{ + init(); +} + +K3bDataViewItem::K3bDataViewItem( K3bDataItem* item, QListViewItem* parent ) + : K3bListViewItem( parent ), + m_dataItem(item) +{ + init(); +} + +K3bDataViewItem::~K3bDataViewItem() +{} + + +void K3bDataViewItem::init() +{ + setEditor( 0, LINE ); + static QValidator* s_validator = K3bValidators::iso9660Validator(); + setValidator( 0, s_validator ); +} + +void K3bDataViewItem::paintCell( QPainter* p, const QColorGroup& cg, int column, int width, int align ) +{ + QColorGroup _cg = cg; + + if( !dataItem()->isRemoveable() && dataItem()->doc()->root() != dataItem() ) { + _cg.setColor( QColorGroup::Text, listView()->palette().disabled().foreground() ); + } + + if( column == 0 ) { + QFontMetrics fm = p->fontMetrics(); + + if( dataItem()->hideOnRockRidge() ) { + int tw = QMAX( fm.width( "rr" ) + 2*listView()->itemMargin(), height() ); + p->fillRect( width-tw, 0, tw, height(), isSelected() ? _cg.highlight() : _cg.brush(QColorGroup::Base) ); + p->setPen( isSelected() ? _cg.highlightedText() : red ); + p->drawEllipse( width-tw, 0, tw, height() ); + p->drawText( width-tw, 0, tw, height(), Qt::AlignCenter, "rr" ); + width -= tw; + } + + if( dataItem()->hideOnJoliet() ) { + int tw = QMAX( fm.width( "j" ) + 2*listView()->itemMargin(), height() ); + p->fillRect( width-tw, 0, tw, height(), isSelected() ? _cg.highlight() : _cg.brush(QColorGroup::Base) ); + p->setPen( isSelected() ? _cg.highlightedText() : blue ); + p->drawEllipse( width-tw, 0, tw, height() ); + p->drawText( width-tw, 0, tw, height(), Qt::AlignCenter, "j" ); + width -= tw; + } + } + else if( column == 4 ) { + if( dataItem()->isSymLink() ) { + if( !dataItem()->doc()->isoOptions().followSymbolicLinks() && + dataItem()->doc()->isoOptions().createRockRidge() && + !dataItem()->isValid() ) { + // paint the link in red + _cg.setColor( QColorGroup::Text, Qt::red ); + } + } + } + + K3bListViewItem::paintCell( p, _cg, column, width, align ); +} + + +void K3bDataViewItem::setText( int col, const QString& text ) +{ + if( col == 0 && dataItem()->isRenameable() ) { + dataItem()->setK3bName( text ); + } + K3bListViewItem::setText( col, text ); +} + + +QString K3bDataViewItem::key( int col, bool a ) const +{ + if( col == 2 ) { + // to have correct sorting we need to justify the size in bytes + // 100 TB should be enough for the next year... ;-) + + if( a ) + return ( dataItem()->isDir() ? QString("0") : QString("1") ) + + QString::number( dataItem()->size() ).rightJustify( 16, '0' ); + else + return ( dataItem()->isDir() ? QString("1") : QString("0") ) + + QString::number( dataItem()->size() ).rightJustify( 16, '0' ); + } + + if( a ) + return ( dataItem()->isDir() ? QString("0") : QString("1") ) + text(col); + else + return ( dataItem()->isDir() ? QString("1") : QString("0") ) + text(col); +} + + +K3bDataDirViewItem::K3bDataDirViewItem( K3bDirItem* dir, QListView* parent ) + : K3bDataViewItem( dir, parent ) +{ + m_dirItem = dir; + setPixmap( 0, dir->depth() > 7 ? SmallIcon( "folder_red" ) : SmallIcon( "folder" ) ); +} + + +K3bDataDirViewItem::K3bDataDirViewItem( K3bDirItem* dir, QListViewItem* parent ) + : K3bDataViewItem( dir, parent ) +{ + m_dirItem = dir; + setPixmap( 0, dir->depth() > 7 ? SmallIcon( "folder_red" ) : SmallIcon( "folder" ) ); +} + + +K3bDataDirViewItem::~K3bDataDirViewItem() +{ +} + + +void K3bDataDirViewItem::dragEntered() +{ + setOpen( true ); +} + + +QString K3bDataDirViewItem::text( int index ) const +{ + switch( index ) { + case 0: + return m_dirItem->k3bName(); + case 1: + return i18n("Directory"); + case 2: + return KIO::convertSize( m_dirItem->size() ); + default: + return ""; + } +} + + +void K3bDataDirViewItem::highlightIcon( bool b ) +{ + if( m_pixmap.isNull() ) + m_pixmap = *pixmap(0); + + if( b ) + setPixmap( 0, KPixmapEffect::selectedPixmap( m_pixmap, listView()->colorGroup().highlight() ) ); + else + setPixmap( 0, m_pixmap ); +} + + + +K3bDataFileViewItem::K3bDataFileViewItem( K3bFileItem* file, QListView* parent ) + : K3bDataViewItem( file, parent ) +{ + init( file ); +} + + +K3bDataFileViewItem::K3bDataFileViewItem( K3bFileItem* file, QListViewItem* parent ) + : K3bDataViewItem( file, parent ) +{ + init( file ); +} + + +void K3bDataFileViewItem::init( K3bFileItem* file ) +{ + m_fileItem = file; + + // determine the mimetype + m_pMimeType = KMimeType::findByURL( KURL::fromPathOrURL(file->localPath()) ); + if( !m_pMimeType ) + setPixmap( 0, DesktopIcon( "unknown", 16, KIcon::DefaultState ) ); + else + setPixmap( 0, m_pMimeType->pixmap( KURL::fromPathOrURL(file->localPath()), KIcon::Desktop, 16, KIcon::DefaultState ) ); +} + + +QString K3bDataFileViewItem::text( int index ) const +{ + switch( index ) { + case 0: + return m_fileItem->k3bName(); + case 1: + { + QString comment = m_pMimeType->comment( KURL::fromPathOrURL(m_fileItem->localPath()), true ); + if( comment.isEmpty() ) + comment = m_pMimeType->name(); + + if( m_fileItem->isSymLink() ) + return i18n("Link to %1").arg(comment); + else + return comment; + } + case 2: + return KIO::convertSize( m_fileItem->size() ); + case 3: + return m_fileItem->localPath(); + case 4: { + if( !m_fileItem->isSymLink() ) { + return QString::null; + } + + QString s; + if ( m_fileItem->doc()->isoOptions().followSymbolicLinks() ) { + s = K3b::resolveLink( m_fileItem->localPath() ); + } + else { + s = QFileInfo( m_fileItem->localPath() ).readLink(); + } + + if( !m_fileItem->isValid() ) { + s += " (" + i18n("outside of project") + ")"; + } + + return s; + } + default: + return ""; + } +} + + + +K3bDataRootViewItem::K3bDataRootViewItem( K3bDataDoc* doc, QListView* parent ) + : K3bDataDirViewItem( doc->root(), parent ) +{ + m_doc = doc; + setPixmap( 0, SmallIcon( "cdrom_unmount" ) ); + setValidator( 0, new K3bLatin1Validator() ); +} + + +K3bDataRootViewItem::~K3bDataRootViewItem() +{ + delete validator(0); +} + + +QString K3bDataRootViewItem::text( int index ) const +{ + switch( index ) { + case 0: + return ( m_doc->isoOptions().volumeID().isEmpty() ? i18n("root") : m_doc->isoOptions().volumeID() ); + default: + return ""; + } +} + + +void K3bDataRootViewItem::setText( int col, const QString& text ) +{ + if( col == 0 ) + m_doc->setVolumeID( text ); + + K3bDataViewItem::setText( col, text ); +} + + +K3bSpecialDataViewItem::K3bSpecialDataViewItem( K3bSpecialDataItem* item, QListView* parent ) + : K3bDataViewItem( item, parent ) +{ + setPixmap( 0, SmallIcon("unknown") ); +} + +QString K3bSpecialDataViewItem::text( int col ) const +{ + switch( col ) { + case 0: + return dataItem()->k3bName(); + case 1: + return ((K3bSpecialDataItem*)dataItem())->mimeType(); + case 2: + return KIO::convertSize( dataItem()->size() ); + default: + return ""; + } +} + + + +K3bSessionImportViewItem::K3bSessionImportViewItem( K3bSessionImportItem* item, QListView* parent ) + : K3bDataViewItem( item, parent ) +{ + setPixmap( 0, SmallIcon("unknown") ); +} + +QString K3bSessionImportViewItem::text( int col ) const +{ + switch( col ) { + case 0: + return dataItem()->k3bName(); + case 1: + return i18n("From previous session"); + case 2: + return KIO::convertSize( dataItem()->size() ); + default: + return ""; + } +} diff --git a/src/projects/k3bdataviewitem.h b/src/projects/k3bdataviewitem.h new file mode 100644 index 0000000..60d68d2 --- /dev/null +++ b/src/projects/k3bdataviewitem.h @@ -0,0 +1,135 @@ +/* + * + * $Id: k3bdataviewitem.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef K3BDATAVIEWITEM_H +#define K3BDATAVIEWITEM_H + +#include <k3blistview.h> +#include <kmimetype.h> + +class K3bDataItem; +class K3bFileItem; +class K3bDirItem; +class K3bDataDoc; +class K3bSpecialDataItem; +class K3bSessionImportItem; + +class QPainter; +class QColorGroup; + + + +class K3bDataViewItem : public K3bListViewItem +{ + public: + K3bDataViewItem( K3bDataItem*, QListView* parent ); + K3bDataViewItem( K3bDataItem*, QListViewItem* parent ); + virtual ~K3bDataViewItem(); + + virtual K3bDataItem* dataItem() const { return m_dataItem; } + + void setText( int col, const QString& text ); + + /** + * reimplemented to have directories always sorted before files + */ + QString key( int, bool ) const; + + virtual void paintCell( QPainter* p, const QColorGroup& cg, int column, int width, int align ); + + private: + void init(); + + K3bDataItem* m_dataItem; +}; + + +class K3bDataDirViewItem : public K3bDataViewItem +{ + public: + K3bDataDirViewItem( K3bDirItem* dir, QListView* parent ); + K3bDataDirViewItem( K3bDirItem* dir, QListViewItem* parent ); + ~K3bDataDirViewItem(); + + virtual QString text( int ) const; + + K3bDirItem* dirItem() const { return m_dirItem; } + + void highlightIcon( bool ); + + protected: + virtual void dragEntered(); + + private: + K3bDirItem* m_dirItem; + QPixmap m_pixmap; +}; + + +class K3bDataFileViewItem : public K3bDataViewItem +{ + public: + K3bDataFileViewItem( K3bFileItem*, QListView* parent ); + K3bDataFileViewItem( K3bFileItem*, QListViewItem* parent ); + ~K3bDataFileViewItem() {} + + QString text( int ) const; + + K3bFileItem* fileItem() const { return m_fileItem; } + + const KMimeType::Ptr mimeType() const { return m_pMimeType; } + + private: + void init( K3bFileItem* ); + + K3bFileItem* m_fileItem; + KMimeType::Ptr m_pMimeType; +}; + + +class K3bDataRootViewItem : public K3bDataDirViewItem +{ + public: + K3bDataRootViewItem( K3bDataDoc*, QListView* parent ); + ~K3bDataRootViewItem(); + + QString text( int ) const; + + /** reimplemented from QListViewItem */ + void setText(int col, const QString& text ); + + private: + K3bDataDoc* m_doc; +}; + + +class K3bSpecialDataViewItem : public K3bDataViewItem +{ + public: + K3bSpecialDataViewItem( K3bSpecialDataItem*, QListView* ); + + QString text( int ) const; +}; + + +class K3bSessionImportViewItem : public K3bDataViewItem +{ + public: + K3bSessionImportViewItem( K3bSessionImportItem*, QListView* ); + + QString text( int ) const; +}; + +#endif diff --git a/src/projects/k3bdatavolumedescwidget.cpp b/src/projects/k3bdatavolumedescwidget.cpp new file mode 100644 index 0000000..1edbc7b --- /dev/null +++ b/src/projects/k3bdatavolumedescwidget.cpp @@ -0,0 +1,93 @@ +/* + * + * $Id: k3bdatavolumedescwidget.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bdatavolumedescwidget.h" + +#include "k3bisooptions.h" +#include <k3bvalidators.h> + +#include <qlineedit.h> +#include <qspinbox.h> +#include <qlabel.h> +#include <qtoolbutton.h> + + +K3bDataVolumeDescWidget::K3bDataVolumeDescWidget( QWidget* parent, const char* name ) + : base_K3bDataVolumeDescWidget( parent, name ) +{ + // the maximal number of characters that can be inserted are set in the ui file! + + QValidator* isoValidator = new K3bLatin1Validator( this ); + + m_editVolumeName->setValidator( isoValidator ); + m_editVolumeSetName->setValidator( isoValidator ); + m_editPublisher->setValidator( isoValidator ); + m_editPreparer->setValidator( isoValidator ); + m_editSystem->setValidator( isoValidator ); + m_editApplication->setValidator( isoValidator ); + + connect( m_spinVolumeSetSize, SIGNAL(valueChanged(int)), + this, SLOT(slotVolumeSetSizeChanged(int)) ); + + // for now we hide the volume set size stuff since it's not working anymore in mkisofs 2.01a34 + textLabel1->hide(); + textLabel2->hide(); + m_spinVolumeSetSize->hide(); + m_spinVolumeSetNumber->hide(); + + // FIXME: show the buttons and allow the selection of a file from the project + m_buttonFindAbstract->hide(); + m_buttonFindCopyright->hide(); + m_buttonFindBiblio->hide(); +} + + +K3bDataVolumeDescWidget::~K3bDataVolumeDescWidget() +{ +} + + +void K3bDataVolumeDescWidget::load( const K3bIsoOptions& o ) +{ + m_editVolumeName->setText( o.volumeID() ); + m_editVolumeSetName->setText( o.volumeSetId() ); + m_spinVolumeSetSize->setValue( o.volumeSetSize() ); + m_spinVolumeSetNumber->setValue( o.volumeSetNumber() ); + m_editPublisher->setText( o.publisher() ); + m_editPreparer->setText( o.preparer() ); + m_editSystem->setText( o.systemId() ); + m_editApplication->setText( o.applicationID() ); +} + + +void K3bDataVolumeDescWidget::save( K3bIsoOptions& o ) +{ + o.setVolumeID( m_editVolumeName->text() ); + o.setVolumeSetId( m_editVolumeSetName->text() ); + o.setVolumeSetSize( 1/*m_spinVolumeSetSize->value() */); + o.setVolumeSetNumber( 1/*m_spinVolumeSetNumber->value() */); + o.setPublisher( m_editPublisher->text() ); + o.setPreparer( m_editPreparer->text() ); + o.setSystemId( m_editSystem->text() ); + o.setApplicationID( m_editApplication->text() ); +} + + +void K3bDataVolumeDescWidget::slotVolumeSetSizeChanged( int i ) +{ + m_spinVolumeSetNumber->setMaxValue( i ); +} + +#include "k3bdatavolumedescwidget.moc" diff --git a/src/projects/k3bdatavolumedescwidget.h b/src/projects/k3bdatavolumedescwidget.h new file mode 100644 index 0000000..8b4a388 --- /dev/null +++ b/src/projects/k3bdatavolumedescwidget.h @@ -0,0 +1,40 @@ +/* + * + * $Id: k3bdatavolumedescwidget.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef K3B_DATA_VOLUMEDESC_WIDGET_H +#define K3B_DATA_VOLUMEDESC_WIDGET_H + + +#include "base_k3bdatavolumedescwidget.h" + +class K3bIsoOptions; + + +class K3bDataVolumeDescWidget : public base_K3bDataVolumeDescWidget +{ + Q_OBJECT + + public: + K3bDataVolumeDescWidget( QWidget* parent = 0, const char* name = 0 ); + ~K3bDataVolumeDescWidget(); + + void load( const K3bIsoOptions& ); + void save( K3bIsoOptions& ); + + private slots: + void slotVolumeSetSizeChanged( int ); +}; + +#endif diff --git a/src/projects/k3bdvdburndialog.cpp b/src/projects/k3bdvdburndialog.cpp new file mode 100644 index 0000000..873afbf --- /dev/null +++ b/src/projects/k3bdvdburndialog.cpp @@ -0,0 +1,300 @@ +/* + * + * $Id: k3bdvdburndialog.cpp 690207 2007-07-20 10:40:19Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bdvdburndialog.h" +#include "k3bdvddoc.h" +#include "k3bdatamultisessioncombobox.h" + +#include <k3bdevice.h> +#include <k3bwriterselectionwidget.h> +#include <k3btempdirselectionwidget.h> +#include <k3bcore.h> +#include <k3bwritingmodewidget.h> +#include <k3bglobals.h> +#include <k3bdataimagesettingswidget.h> +#include <k3bisooptions.h> +#include <k3bstdguiitems.h> +#include <k3bglobalsettings.h> + +#include <kconfig.h> +#include <klocale.h> +#include <kio/global.h> +#include <kmessagebox.h> + +#include <qlayout.h> +#include <qcheckbox.h> +#include <qgroupbox.h> +#include <qlabel.h> +#include <qtooltip.h> +#include <qwhatsthis.h> +#include <qradiobutton.h> +#include <qbuttongroup.h> +#include <qspinbox.h> + + +K3bDvdBurnDialog::K3bDvdBurnDialog( K3bDvdDoc* doc, QWidget *parent, const char *name, bool modal ) + : K3bProjectBurnDialog( doc, parent, name, modal, true ), + m_doc( doc ) +{ + prepareGui(); + + setTitle( i18n("DVD Project"), i18n("Size: %1").arg( KIO::convertSize(doc->size()) ) ); + + // for now we just put the verify checkbox on the main page... + m_checkVerify = K3bStdGuiItems::verifyCheckBox( m_optionGroup ); + m_optionGroupLayout->addWidget( m_checkVerify ); + + QSpacerItem* spacer = new QSpacerItem( 20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding ); + m_optionGroupLayout->addItem( spacer ); + + // create image settings tab + m_imageSettingsWidget = new K3bDataImageSettingsWidget( this ); + addPage( m_imageSettingsWidget, i18n("Filesystem") ); + + setupSettingsTab(); + + m_tempDirSelectionWidget->setSelectionMode( K3bTempDirSelectionWidget::FILE ); + + m_writerSelectionWidget->setWantedMediumState( K3bDevice::STATE_EMPTY|K3bDevice::STATE_INCOMPLETE ); + + QString path = doc->tempDir(); + if( !path.isEmpty() ) { + m_tempDirSelectionWidget->setTempPath( path ); + } + if( !doc->isoOptions().volumeID().isEmpty() ) { + m_tempDirSelectionWidget->setDefaultImageFileName( doc->isoOptions().volumeID() + ".iso" ); + } + + connect( m_imageSettingsWidget->m_editVolumeName, SIGNAL(textChanged(const QString&)), + m_tempDirSelectionWidget, SLOT(setDefaultImageFileName(const QString&)) ); +} + + +K3bDvdBurnDialog::~K3bDvdBurnDialog() +{ +} + + +void K3bDvdBurnDialog::setupSettingsTab() +{ + QWidget* frame = new QWidget( this ); + QGridLayout* frameLayout = new QGridLayout( frame ); + frameLayout->setSpacing( spacingHint() ); + frameLayout->setMargin( marginHint() ); + + // Multisession + // //////////////////////////////////////////////////////////////////////// + QGroupBox* groupMultiSession = new QGroupBox( 1, Qt::Vertical, i18n("Multisession Mode"), frame ); + m_comboMultisession = new K3bDataMultiSessionCombobox( groupMultiSession ); + + frameLayout->addWidget( groupMultiSession, 0, 0 ); + frameLayout->setRowStretch( 1, 1 ); + + addPage( frame, i18n("Misc") ); + + connect( m_comboMultisession, SIGNAL(activated(int)), + this, SLOT(slotMultiSessionModeChanged()) ); +} + + +void K3bDvdBurnDialog::saveSettings() +{ + K3bProjectBurnDialog::saveSettings(); + + // save iso image settings + K3bIsoOptions o = m_doc->isoOptions(); + m_imageSettingsWidget->save( o ); + m_doc->setIsoOptions( o ); + + // save image file path + m_doc->setTempDir( m_tempDirSelectionWidget->tempPath() ); + + // save multisession settings + m_doc->setMultiSessionMode( m_comboMultisession->multiSessionMode() ); + + m_doc->setVerifyData( m_checkVerify->isChecked() ); +} + + +void K3bDvdBurnDialog::readSettings() +{ + K3bProjectBurnDialog::readSettings(); + + // read multisession + m_comboMultisession->setMultiSessionMode( m_doc->multiSessionMode() ); + + if( !doc()->tempDir().isEmpty() ) + m_tempDirSelectionWidget->setTempPath( doc()->tempDir() ); + else + m_tempDirSelectionWidget->setTempPath( K3b::defaultTempPath() + doc()->name() + ".iso" ); + + m_checkVerify->setChecked( m_doc->verifyData() ); + + m_imageSettingsWidget->load( m_doc->isoOptions() ); + + // for now we do not support dual layer multisession (growisofs does not handle layer jump yet) + // in case overburn is enabled we allow some made up max size + // before we force a DL medium + if( doc()->size() > 4700372992LL && + ( !k3bcore->globalSettings()->overburn() || + doc()->size() > 4900000000LL ) ) + m_writerSelectionWidget->setWantedMediumType( K3bDevice::MEDIA_WRITABLE_DVD_DL ); + else + m_writerSelectionWidget->setWantedMediumType( K3bDevice::MEDIA_WRITABLE_DVD ); + + toggleAll(); +} + + +void K3bDvdBurnDialog::toggleAll() +{ + K3bProjectBurnDialog::toggleAll(); + + // Multisession in DAO is not possible + if( m_writingModeWidget->writingMode() == K3b::DAO ) { + if( m_comboMultisession->multiSessionMode() == K3bDataDoc::START || + m_comboMultisession->multiSessionMode() == K3bDataDoc::CONTINUE || + m_comboMultisession->multiSessionMode() == K3bDataDoc::FINISH ) + KMessageBox::information( this, i18n("It is not possible to write multisession DVDs in DAO mode." + "Multisession has been disabled."), + i18n("DVD multisession"), + "dvd_multisession_no_dao" ); + + m_comboMultisession->setEnabled(false); + } + else { +// // for some reason I don't know yet when writing multisession volume set size needs to be 1 +// if( m_comboMultisession->multiSessionMode() != K3bDataDoc::NONE ) { +// m_volumeDescWidget->m_spinVolumeSetSize->setValue( 1 ); +// m_volumeDescWidget->m_spinVolumeSetSize->setEnabled( false ); +// } +// else { +// m_volumeDescWidget->m_spinVolumeSetSize->setEnabled( true ); +// } + + m_comboMultisession->setEnabled(true); + +// if( !m_checkOnTheFly->isChecked() ) { +// // no continue and finish multisession in non-the-fly mode since +// // we can only continue ms with growisofsimager +// if( m_comboMultisession->multiSessionMode() == K3bDataDoc::START || +// m_comboMultisession->multiSessionMode() == K3bDataDoc::FINISH || +// m_comboMultisession->multiSessionMode() == K3bDataDoc::CONTINUE ) { +// KMessageBox::information( this, i18n("K3b does only support writing multisession DVDs on-the-fly. " +// "Multisession has been disabled."), +// i18n("DVD Multisession"), +// "dvd_multisession_only_on_the_fly" ); +// } +// m_comboMultisession->setForceNoMultisession( true ); +// } +// else { +// m_comboMultisession->setForceNoMultisession( false ); +// } + } + + if( m_checkSimulate->isChecked() || m_checkOnlyCreateImage->isChecked() ) { + m_checkVerify->setChecked(false); + m_checkVerify->setEnabled(false); + } + else + m_checkVerify->setEnabled(true); +} + + +void K3bDvdBurnDialog::slotMultiSessionModeChanged() +{ + if( m_comboMultisession->multiSessionMode() == K3bDataDoc::CONTINUE || + m_comboMultisession->multiSessionMode() == K3bDataDoc::FINISH ) + m_spinCopies->setEnabled(false); + + // wait for the proper medium + // we have to do this in another slot than toggleAllOptions to avoid an endless loop + if( m_comboMultisession->multiSessionMode() == K3bDataDoc::NONE ) + m_writerSelectionWidget->setWantedMediumState( K3bDevice::STATE_EMPTY ); + else if( m_comboMultisession->multiSessionMode() == K3bDataDoc::CONTINUE || + m_comboMultisession->multiSessionMode() == K3bDataDoc::FINISH ) + m_writerSelectionWidget->setWantedMediumState( K3bDevice::STATE_INCOMPLETE ); + else + m_writerSelectionWidget->setWantedMediumState( K3bDevice::STATE_EMPTY|K3bDevice::STATE_INCOMPLETE ); +} + + +void K3bDvdBurnDialog::loadK3bDefaults() +{ + K3bProjectBurnDialog::loadK3bDefaults(); + + m_imageSettingsWidget->load( K3bIsoOptions::defaults() ); + m_checkVerify->setChecked( false ); + + m_comboMultisession->setMultiSessionMode( K3bDataDoc::AUTO ); + + toggleAll(); +} + + +void K3bDvdBurnDialog::loadUserDefaults( KConfigBase* c ) +{ + K3bProjectBurnDialog::loadUserDefaults(c); + + K3bIsoOptions o = K3bIsoOptions::load( c ); + m_imageSettingsWidget->load( o ); + + m_comboMultisession->loadConfig( c ); + + m_checkVerify->setChecked( c->readBoolEntry( "verify data", false ) ); + + toggleAll(); +} + + +void K3bDvdBurnDialog::saveUserDefaults( KConfigBase* c ) +{ + K3bProjectBurnDialog::saveUserDefaults(c); + + K3bIsoOptions o; + m_imageSettingsWidget->save( o ); + o.save( c ); + + m_comboMultisession->saveConfig( c ); + + c->writeEntry( "verify data", m_checkVerify->isChecked() ); +} + + +void K3bDvdBurnDialog::slotStartClicked() +{ + if( m_checkOnlyCreateImage->isChecked() || + m_checkCacheImage->isChecked() ) { + QFileInfo fi( m_tempDirSelectionWidget->tempPath() ); + if( fi.isDir() ) + m_tempDirSelectionWidget->setTempPath( fi.filePath() + "/image.iso" ); + + if( QFile::exists( m_tempDirSelectionWidget->tempPath() ) ) { + if( KMessageBox::warningContinueCancel( this, + i18n("Do you want to overwrite %1?").arg(m_tempDirSelectionWidget->tempPath()), + i18n("File Exists"), i18n("Overwrite") ) + == KMessageBox::Continue ) { + // delete the file here to avoid problems with free space in K3bProjectBurnDialog::slotStartClicked + QFile::remove( m_tempDirSelectionWidget->tempPath() ); + } + else + return; + } + } + + K3bProjectBurnDialog::slotStartClicked(); +} + +#include "k3bdvdburndialog.moc" diff --git a/src/projects/k3bdvdburndialog.h b/src/projects/k3bdvdburndialog.h new file mode 100644 index 0000000..deb9620 --- /dev/null +++ b/src/projects/k3bdvdburndialog.h @@ -0,0 +1,69 @@ +/* + * + * $Id: k3bdvdburndialog.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_DVD_BURNDIALOG_H_ +#define _K3B_DVD_BURNDIALOG_H_ + +#include "k3bprojectburndialog.h" + + +class K3bDvdDoc; +class K3bDataImageSettingsWidget; +class QGroupBox; +class QRadioButton; +class QButtonGroup; +class QCheckBox; +class K3bDataMultiSessionCombobox; + + +class K3bDvdBurnDialog : public K3bProjectBurnDialog +{ + Q_OBJECT + + public: + K3bDvdBurnDialog( K3bDvdDoc*, QWidget *parent = 0, const char *name = 0, bool modal = true ); + ~K3bDvdBurnDialog(); + + protected slots: + void slotMultiSessionModeChanged(); + + void saveSettings(); + void readSettings(); + + protected: + void slotStartClicked(); + void loadK3bDefaults(); + void loadUserDefaults( KConfigBase* ); + void saveUserDefaults( KConfigBase* ); + void toggleAll(); + + private: + void setupSettingsTab(); + + // --- settings tab --------------------------- + K3bDataImageSettingsWidget* m_imageSettingsWidget; + // ---------------------------------------------- + + // --- multisession tab ------------------------- + K3bDataMultiSessionCombobox* m_comboMultisession; + // --------------------------------------------- + + QCheckBox* m_checkVerify; + + K3bDvdDoc* m_doc; +}; + +#endif diff --git a/src/projects/k3bdvdview.cpp b/src/projects/k3bdvdview.cpp new file mode 100644 index 0000000..512ec4b --- /dev/null +++ b/src/projects/k3bdvdview.cpp @@ -0,0 +1,48 @@ +/* + * + * $Id: k3bdvdview.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bdvdview.h" +#include "k3bdvddoc.h" +#include "k3bdvdburndialog.h" +#include <k3bfillstatusdisplay.h> +#include <k3bdatafileview.h> + +#include <klocale.h> + + +K3bDvdView::K3bDvdView( K3bDvdDoc* doc, QWidget *parent, const char *name ) + : K3bDataView( doc, parent, name ) +{ + m_doc = doc; + + fillStatusDisplay()->showDvdSizes(true); + + m_dataFileView->setNoItemText( i18n("Use drag'n'drop to add files and directories to the project.\n" + "To remove or rename files use the context menu.\n" + "After that press the burn button to write the DVD.") ); +} + + +K3bDvdView::~K3bDvdView() +{ +} + + +K3bProjectBurnDialog* K3bDvdView::newBurnDialog( QWidget* parent, const char* name ) +{ + return new K3bDvdBurnDialog( m_doc, parent, name, true ); +} + +#include "k3bdvdview.moc" diff --git a/src/projects/k3bdvdview.h b/src/projects/k3bdvdview.h new file mode 100644 index 0000000..d9f30f3 --- /dev/null +++ b/src/projects/k3bdvdview.h @@ -0,0 +1,40 @@ +/* + * + * $Id: k3bdvdview.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_DVDVIEW_H_ +#define _K3B_DVDVIEW_H_ + +#include <k3bdataview.h> + +class K3bDvdDoc; + + +class K3bDvdView : public K3bDataView +{ + Q_OBJECT + + public: + K3bDvdView( K3bDvdDoc* doc, QWidget *parent = 0, const char *name = 0 ); + ~K3bDvdView(); + + protected: + virtual K3bProjectBurnDialog* newBurnDialog( QWidget* parent = 0, const char* name = 0 ); + + private: + K3bDvdDoc* m_doc; +}; + +#endif diff --git a/src/projects/k3bencodingconverter.cpp b/src/projects/k3bencodingconverter.cpp new file mode 100644 index 0000000..460abbe --- /dev/null +++ b/src/projects/k3bencodingconverter.cpp @@ -0,0 +1,130 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include <config.h> + +#include "k3bencodingconverter.h" + +#include <qwidget.h> +#include <qlayout.h> + +#include <kdebug.h> + +#ifdef HAVE_ICONV_H +#include <langinfo.h> +#include <iconv.h> +#endif + + +class K3bEncodingConverter::Private +{ + public: + iconv_t ic; + QString localEncoding; + QString lastEncoding; +}; + + +K3bEncodingConverter::K3bEncodingConverter() +{ + d = new Private; +#ifdef HAVE_ICONV_H + char* codec = nl_langinfo( CODESET ); + d->localEncoding = QString::fromLocal8Bit( codec ); + kdDebug() << "(K3bDataUrlAddingDialog) using locale codec: " << codec << endl; + d->ic = ::iconv_open( "UCS-2BE", codec ); +#endif +} + + +K3bEncodingConverter::~K3bEncodingConverter() +{ +#ifdef HAVE_ICONV_H + ::iconv_close( d->ic ); +#endif + delete d; +} + + +bool K3bEncodingConverter::encodedLocally( const QCString& s ) +{ +#ifdef HAVE_ICONV_H + QCString utf8Encoded( s.length()*2 ); +#if defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) + const char* in = s.data(); +#else + char* in = s.data(); +#endif + char* out = utf8Encoded.data(); + size_t inSize = s.length(); + size_t outSize = utf8Encoded.size(); + return( (size_t)-1 != ::iconv( d->ic, &in, &inSize, &out, &outSize ) ); +#else + return true; +#endif +} + + +bool K3bEncodingConverter::fixEncoding( const QCString& s, QCString& result, QWidget* parent, bool cache ) +{ +#ifdef IMPLEMENT_THIS_METHOD // HAVE_ICONV_H + if( !d->lastEncoding.isEmpty() ) { + // + // try converting with the last encoding + // + if( convert( s, result, d->lastEncoding, d->localEncoding ) + && encodedLocally( result ) ) { + return true; + } + } + + + + if( cache ) { + + } + else + d->lastEncoding = QString::null; +#else + return false; +#endif +} + + +bool K3bEncodingConverter::convert( const QCString& s, QCString& result, const QString& from, const QString& to ) +{ + bool r = false; + +#ifdef HAVE_ICONV_H + iconv_t ic = ::iconv_open( to.local8Bit(), from.local8Bit() ); + + result.resize( s.length() * 2 ); +#if defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) + const char* in = s.data(); +#else + char* in = s.data(); +#endif + char* out = result.data(); + size_t inSize = s.length(); + size_t outSize = result.size(); + + if( (size_t)-1 != ::iconv( ic, &in, &inSize, &out, &outSize ) ) + r = true; + + ::iconv_close( ic ); +#endif + + return r; +} diff --git a/src/projects/k3bencodingconverter.h b/src/projects/k3bencodingconverter.h new file mode 100644 index 0000000..e40003c --- /dev/null +++ b/src/projects/k3bencodingconverter.h @@ -0,0 +1,59 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_ENCODING_CONVERTER_H_ +#define _K3B_ENCODING_CONVERTER_H_ + +#include <qcstring.h> +#include <qstring.h> + +class QWidget; + +class K3bEncodingConverter +{ + public: + K3bEncodingConverter(); + ~K3bEncodingConverter(); + + /** + * Check if a string is encoded using the local codeset + * + * \return True if the string is encoded in the local encoding. + */ + bool encodedLocally( const QCString& ); + + /** + * Tries to fix the encoding of a string to fit the local + * encoding. + * It presents a dialog to the user that let's them choose + * the proper encoding based on example conversions. + * + * \param s The string to be fixed. + * \param parent The parent widget to be used when showing the encoding selection dialog. + * \param cacheEncoding If true the codeset used for successful conversion is cached and + * reused for the next call to fixEncoding. + * + * \return True if the conversion was successful. + */ + bool fixEncoding( const QCString& s, QCString& result, QWidget* parent = 0, bool cacheEncoding = true ); + + private: + bool convert( const QCString& s, QCString& result, const QString& from, const QString& to ); + + class Private; + Private* d; +}; + +#endif diff --git a/src/projects/k3bfillstatusdisplay.cpp b/src/projects/k3bfillstatusdisplay.cpp new file mode 100644 index 0000000..2d39bc7 --- /dev/null +++ b/src/projects/k3bfillstatusdisplay.cpp @@ -0,0 +1,759 @@ +/* + * + * $Id: k3bfillstatusdisplay.cpp 768504 2008-01-30 08:53:22Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bfillstatusdisplay.h" +#include "k3bdoc.h" + +#include <k3bapplication.h> +#include <k3bmediaselectiondialog.h> +#include <k3bdevice.h> +#include <k3bdevicemanager.h> +#include <k3bdevice.h> +#include <k3bmsf.h> +#include <k3bradioaction.h> +#include <k3bmediacache.h> + +#include <qevent.h> +#include <qpainter.h> +#include <qcolor.h> +#include <qrect.h> +#include <qfont.h> +#include <qfontmetrics.h> +#include <qvalidator.h> +#include <qtoolbutton.h> +#include <qtooltip.h> +#include <qlayout.h> +#include <qwhatsthis.h> +#include <qtimer.h> + +#include <kaction.h> +#include <kpopupmenu.h> +#include <klocale.h> +#include <kinputdialog.h> +#include <kconfig.h> +#include <kdebug.h> +#include <kiconloader.h> +#include <kio/global.h> +#include <kmessagebox.h> +#include <kglobal.h> +#include <kpixmapeffect.h> + + +static const int DEFAULT_CD_SIZE_74 = 74*60*75; +static const int DEFAULT_CD_SIZE_80 = 80*60*75; +static const int DEFAULT_CD_SIZE_100 = 100*60*75; +static const int DEFAULT_DVD_SIZE_4_4 = 2295104; +static const int DEFAULT_DVD_SIZE_8_0 = 4173824; + +class K3bFillStatusDisplayWidget::Private +{ +public: + K3b::Msf cdSize; + bool showTime; + K3bDoc* doc; +}; + + +K3bFillStatusDisplayWidget::K3bFillStatusDisplayWidget( K3bDoc* doc, QWidget* parent ) + : QWidget( parent, 0, WRepaintNoErase ) +{ + d = new Private(); + d->doc = doc; + setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Preferred ) ); +} + + +K3bFillStatusDisplayWidget::~K3bFillStatusDisplayWidget() +{ + delete d; +} + + +const K3b::Msf& K3bFillStatusDisplayWidget::cdSize() const +{ + return d->cdSize; +} + + +void K3bFillStatusDisplayWidget::setShowTime( bool b ) +{ + d->showTime = b; + update(); +} + + +void K3bFillStatusDisplayWidget::setCdSize( const K3b::Msf& size ) +{ + d->cdSize = size; + update(); +} + + +QSize K3bFillStatusDisplayWidget::sizeHint() const +{ + return minimumSizeHint(); +} + + +QSize K3bFillStatusDisplayWidget::minimumSizeHint() const +{ + int margin = 2; + QFontMetrics fm( font() ); + return QSize( -1, fm.height() + 2 * margin ); +} + + +void K3bFillStatusDisplayWidget::mousePressEvent( QMouseEvent* e ) +{ + if( e->button() == Qt::RightButton ) + emit contextMenu( e->globalPos() ); +} + + +void K3bFillStatusDisplayWidget::paintEvent( QPaintEvent* ) +{ + // double buffer + QPixmap buffer( size() ); + buffer.fill( colorGroup().base() ); + QPainter p; + p.begin( &buffer, this ); + p.setPen( Qt::black ); // we use a fixed bar color (which is not very nice btw, so we also fix the text color) + + long long docSize; + long long cdSize; + long long maxValue; + long tolerance; + + if( d->showTime ) { + docSize = d->doc->length().totalFrames() / 75 / 60; + cdSize = d->cdSize.totalFrames() / 75 / 60; + maxValue = (cdSize > docSize ? cdSize : docSize) + 10; + tolerance = 1; + } + else { + docSize = d->doc->size()/1024/1024; + cdSize = d->cdSize.mode1Bytes()/1024/1024; + maxValue = (cdSize > docSize ? cdSize : docSize) + 100; + tolerance = 10; + } + + // so split width() in maxValue pieces + double one = (double)rect().width() / (double)maxValue; + QRect crect( rect() ); + crect.setWidth( (int)(one*(double)docSize) ); + + p.setClipping(true); + p.setClipRect(crect); + + p.fillRect( crect, Qt::green ); + + QRect oversizeRect(crect); + // draw yellow if cdSize - tolerance < docSize + if( docSize > cdSize - tolerance ) { + oversizeRect.setLeft( oversizeRect.left() + (int)(one * (cdSize - tolerance)) ); + p.fillRect( oversizeRect, Qt::yellow ); + KPixmap pix; + pix.resize( rect().height()*2, rect().height() ); + KPixmapEffect::gradient( pix, green, yellow, KPixmapEffect::HorizontalGradient, 0 ); + p.drawPixmap( oversizeRect.left() - pix.width()/2, 0, pix ); + } + + // draw red if docSize > cdSize + tolerance + if( docSize > cdSize + tolerance ) { + oversizeRect.setLeft( oversizeRect.left() + (int)(one * tolerance*2) ); + p.fillRect( oversizeRect, Qt::red ); + KPixmap pix; + pix.resize( rect().height()*2, rect().height() ); + KPixmapEffect::gradient( pix, yellow, red, KPixmapEffect::HorizontalGradient, 0 ); + p.drawPixmap( oversizeRect.left() - pix.width()/2, 0, pix ); + } + + p.setClipping(false); + + // ==================================================================================== + // Now the colored bar is painted + // Continue with the texts + // ==================================================================================== + + // first we determine the text to display + // ==================================================================================== + QString docSizeText; + if( d->showTime ) + docSizeText = d->doc->length().toString(false) + " " + i18n("min"); + else + docSizeText = KIO::convertSize( d->doc->size() ); + + QString overSizeText; + if( d->cdSize.mode1Bytes() >= d->doc->size() ) + overSizeText = i18n("Available: %1 of %2") + .arg( d->showTime + ? i18n("%1 min").arg((K3b::Msf( cdSize*60*75 ) - d->doc->length()).toString(false)) + : KIO::convertSize( QMAX( (cdSize * 1024LL * 1024LL) - (long long)d->doc->size(), 0LL ) ) ) + .arg( d->showTime + ? i18n("%1 min").arg(K3b::Msf( cdSize*60*75 ).toString(false)) + : KIO::convertSizeFromKB( cdSize * 1024 ) ); + else + overSizeText = i18n("Capacity exceeded by %1") + .arg( d->showTime + ? i18n("%1 min").arg( (d->doc->length() - K3b::Msf( cdSize*60*75 ) ).toString(false)) + : KIO::convertSize( (long long)d->doc->size() - (cdSize * 1024LL * 1024LL) ) ); + // ==================================================================================== + + // draw the medium size marker + // ==================================================================================== + int mediumSizeMarkerPos = rect().left() + (int)(one*cdSize); + p.drawLine( mediumSizeMarkerPos, rect().bottom(), + mediumSizeMarkerPos, rect().top() + ((rect().bottom()-rect().top())/2) ); + // ==================================================================================== + + + + // we want to draw the docSizeText centered in the filled area + // if there is not enough space we just align it left + // ==================================================================================== + int docSizeTextPos = 0; + int docSizeTextLength = fontMetrics().width(docSizeText); + if( docSizeTextLength + 5 > crect.width() ) { + docSizeTextPos = crect.left() + 5; // a little margin + } + else { + docSizeTextPos = ( crect.width() - docSizeTextLength ) / 2; + + // make sure the text does not cross the medium size marker + if( docSizeTextPos <= mediumSizeMarkerPos && mediumSizeMarkerPos <= docSizeTextPos + docSizeTextLength ) + docSizeTextPos = QMAX( crect.left() + 5, mediumSizeMarkerPos - docSizeTextLength - 5 ); + } + // ==================================================================================== + + // draw the over size text + // ==================================================================================== + QFont fnt(font()); + fnt.setPointSize( QMAX( 8, fnt.pointSize()-4 ) ); + fnt.setBold(false); + + QRect overSizeTextRect( rect() ); + int overSizeTextLength = QFontMetrics(fnt).width(overSizeText); + if( overSizeTextLength + 5 > overSizeTextRect.width() - (int)(one*cdSize) ) { + // we don't have enough space on the right, so we paint to the left of the line + overSizeTextRect.setLeft( (int)(one*cdSize) - overSizeTextLength - 5 ); + } + else { + overSizeTextRect.setLeft( mediumSizeMarkerPos + 5 ); + } + + // make sure the two text do not overlap (this does not cover all cases though) + if( overSizeTextRect.left() < docSizeTextPos + docSizeTextLength ) + docSizeTextPos = QMAX( crect.left() + 5, QMIN( overSizeTextRect.left() - docSizeTextLength - 5, mediumSizeMarkerPos - docSizeTextLength - 5 ) ); + + QRect docTextRect( rect() ); + docTextRect.setLeft( docSizeTextPos ); + p.drawText( docTextRect, Qt::AlignLeft | Qt::AlignVCenter, docSizeText ); + + p.setFont(fnt); + p.drawText( overSizeTextRect, Qt::AlignLeft | Qt::AlignVCenter, overSizeText ); + // ==================================================================================== + + p.end(); + + bitBlt( this, 0, 0, &buffer ); +} + + + +// ---------------------------------------------------------------------------------------------------- + + +class K3bFillStatusDisplay::ToolTip : public QToolTip +{ +public: + ToolTip( K3bDoc* doc, QWidget* parent ) + : QToolTip( parent, 0 ), + m_doc(doc) { + } + + void maybeTip( const QPoint& ) { + tip( parentWidget()->rect(), + KIO::convertSize( m_doc->size() ) + + " (" + KGlobal::locale()->formatNumber( m_doc->size(), 0 ) + "), " + + m_doc->length().toString(false) + " " + i18n("min") + + " (" + i18n("Right click for media sizes") + ")"); + } + +private: + K3bDoc* m_doc; +}; + +class K3bFillStatusDisplay::Private +{ +public: + KActionCollection* actionCollection; + KRadioAction* actionShowMinutes; + KRadioAction* actionShowMegs; + KRadioAction* actionAuto; + KRadioAction* action74Min; + KRadioAction* action80Min; + KRadioAction* action100Min; + KRadioAction* actionDvd4_7GB; + KRadioAction* actionDvdDoubleLayer; + K3bRadioAction* actionCustomSize; + K3bRadioAction* actionDetermineSize; + KAction* actionSaveUserDefaults; + KAction* actionLoadUserDefaults; + + KPopupMenu* popup; + KPopupMenu* dvdPopup; + + QToolButton* buttonMenu; + + K3bFillStatusDisplayWidget* displayWidget; + + bool showDvdSizes; + bool showTime; + + K3bDoc* doc; + + QTimer updateTimer; +}; + + +K3bFillStatusDisplay::K3bFillStatusDisplay( K3bDoc* doc, QWidget *parent, const char *name ) + : QFrame(parent,name) +{ + d = new Private; + d->doc = doc; + + m_toolTip = new ToolTip( doc, this ); + + setFrameStyle( Panel | Sunken ); + + d->displayWidget = new K3bFillStatusDisplayWidget( doc, this ); +// d->buttonMenu = new QToolButton( this ); +// d->buttonMenu->setIconSet( SmallIconSet("cdrom_unmount") ); +// d->buttonMenu->setAutoRaise(true); +// QToolTip::add( d->buttonMenu, i18n("Fill display properties") ); +// connect( d->buttonMenu, SIGNAL(clicked()), this, SLOT(slotMenuButtonClicked()) ); + + QGridLayout* layout = new QGridLayout( this ); + layout->setSpacing(5); + layout->setMargin(frameWidth()); + layout->addWidget( d->displayWidget, 0, 0 ); + // layout->addWidget( d->buttonMenu, 0, 1 ); + layout->setColStretch( 0, 1 ); + + setupPopupMenu(); + + showDvdSizes( false ); + + connect( d->doc, SIGNAL(changed()), this, SLOT(slotDocChanged()) ); + connect( &d->updateTimer, SIGNAL(timeout()), this, SLOT(slotUpdateDisplay()) ); + connect( k3bappcore->mediaCache(), SIGNAL(mediumChanged(K3bDevice::Device*)), + this, SLOT(slotMediumChanged(K3bDevice::Device*)) ); +} + +K3bFillStatusDisplay::~K3bFillStatusDisplay() +{ + delete d; + delete m_toolTip; +} + + +void K3bFillStatusDisplay::setupPopupMenu() +{ + d->actionCollection = new KActionCollection( this ); + + // we use a nother popup for the dvd sizes + d->popup = new KPopupMenu( this, "popup" ); + d->dvdPopup = new KPopupMenu( this, "dvdpopup" ); + + d->actionShowMinutes = new KRadioAction( i18n("Minutes"), 0, this, SLOT(showTime()), + d->actionCollection, "fillstatus_show_minutes" ); + d->actionShowMegs = new KRadioAction( i18n("Megabytes"), 0, this, SLOT(showSize()), + d->actionCollection, "fillstatus_show_megabytes" ); + + d->actionShowMegs->setExclusiveGroup( "show_size_in" ); + d->actionShowMinutes->setExclusiveGroup( "show_size_in" ); + + d->actionAuto = new KRadioAction( i18n("Auto"), 0, this, SLOT(slotAutoSize()), + d->actionCollection, "fillstatus_auto" ); + d->action74Min = new KRadioAction( i18n("%1 MB").arg(650), 0, this, SLOT(slot74Minutes()), + d->actionCollection, "fillstatus_74minutes" ); + d->action80Min = new KRadioAction( i18n("%1 MB").arg(700), 0, this, SLOT(slot80Minutes()), + d->actionCollection, "fillstatus_80minutes" ); + d->action100Min = new KRadioAction( i18n("%1 MB").arg(880), 0, this, SLOT(slot100Minutes()), + d->actionCollection, "fillstatus_100minutes" ); + d->actionDvd4_7GB = new KRadioAction( KIO::convertSizeFromKB((int)(4.4*1024.0*1024.0)), 0, this, SLOT(slotDvd4_7GB()), + d->actionCollection, "fillstatus_dvd_4_7gb" ); + d->actionDvdDoubleLayer = new KRadioAction( KIO::convertSizeFromKB((int)(8.0*1024.0*1024.0)), + 0, this, SLOT(slotDvdDoubleLayer()), + d->actionCollection, "fillstatus_dvd_double_layer" ); + d->actionCustomSize = new K3bRadioAction( i18n("Custom..."), 0, this, SLOT(slotCustomSize()), + d->actionCollection, "fillstatus_custom_size" ); + d->actionCustomSize->setAlwaysEmitActivated(true); + d->actionDetermineSize = new K3bRadioAction( i18n("From Medium..."), "cdrom_unmount", 0, + this, SLOT(slotDetermineSize()), + d->actionCollection, "fillstatus_size_from_disk" ); + d->actionDetermineSize->setAlwaysEmitActivated(true); + + d->actionAuto->setExclusiveGroup( "cd_size" ); + d->action74Min->setExclusiveGroup( "cd_size" ); + d->action80Min->setExclusiveGroup( "cd_size" ); + d->action100Min->setExclusiveGroup( "cd_size" ); + d->actionDvd4_7GB->setExclusiveGroup( "cd_size" ); + d->actionDvdDoubleLayer->setExclusiveGroup( "cd_size" ); + d->actionCustomSize->setExclusiveGroup( "cd_size" ); + d->actionDetermineSize->setExclusiveGroup( "cd_size" ); + + d->actionLoadUserDefaults = new KAction( i18n("User Defaults"), "", 0, + this, SLOT(slotLoadUserDefaults()), + d->actionCollection, "load_user_defaults" ); + d->actionSaveUserDefaults = new KAction( i18n("Save User Defaults"), "", 0, + this, SLOT(slotSaveUserDefaults()), + d->actionCollection, "save_user_defaults" ); + + KAction* dvdSizeInfoAction = new KAction( i18n("Why 4.4 instead of 4.7?"), "", 0, + this, SLOT(slotWhy44()), + d->actionCollection, "why_44_gb" ); + + d->popup->insertTitle( i18n("Show Size In") ); + d->actionShowMinutes->plug( d->popup ); + d->actionShowMegs->plug( d->popup ); + d->popup->insertTitle( i18n("CD Size") ); + d->actionAuto->plug( d->popup ); + d->action74Min->plug( d->popup ); + d->action80Min->plug( d->popup ); + d->action100Min->plug( d->popup ); + d->actionCustomSize->plug( d->popup ); + d->actionDetermineSize->plug( d->popup ); + d->popup->insertSeparator(); + d->actionLoadUserDefaults->plug( d->popup ); + d->actionSaveUserDefaults->plug( d->popup ); + + d->dvdPopup->insertTitle( i18n("DVD Size") ); + dvdSizeInfoAction->plug( d->dvdPopup ); + d->actionAuto->plug( d->dvdPopup ); + d->actionDvd4_7GB->plug( d->dvdPopup ); + d->actionDvdDoubleLayer->plug( d->dvdPopup ); + d->actionCustomSize->plug( d->dvdPopup ); + d->actionDetermineSize->plug( d->dvdPopup ); + d->dvdPopup->insertSeparator(); + d->actionLoadUserDefaults->plug( d->dvdPopup ); + d->actionSaveUserDefaults->plug( d->dvdPopup ); + + connect( d->displayWidget, SIGNAL(contextMenu(const QPoint&)), this, SLOT(slotPopupMenu(const QPoint&)) ); +} + + +void K3bFillStatusDisplay::showSize() +{ + d->actionShowMegs->setChecked( true ); + + d->action74Min->setText( i18n("%1 MB").arg(650) ); + d->action80Min->setText( i18n("%1 MB").arg(700) ); + d->action100Min->setText( i18n("%1 MB").arg(880) ); + + d->showTime = false; + d->displayWidget->setShowTime(false); +} + +void K3bFillStatusDisplay::showTime() +{ + d->actionShowMinutes->setChecked( true ); + + d->action74Min->setText( i18n("unused", "%n minutes", 74) ); + d->action80Min->setText( i18n("unused", "%n minutes", 80) ); + d->action100Min->setText( i18n("unused", "%n minutes", 100) ); + + d->showTime = true; + d->displayWidget->setShowTime(true); +} + + +void K3bFillStatusDisplay::showDvdSizes( bool b ) +{ + d->showDvdSizes = b; + slotLoadUserDefaults(); +} + + +void K3bFillStatusDisplay::slotAutoSize() +{ + slotMediumChanged( 0 ); +} + + +void K3bFillStatusDisplay::slot74Minutes() +{ + d->displayWidget->setCdSize( DEFAULT_CD_SIZE_74 ); +} + + +void K3bFillStatusDisplay::slot80Minutes() +{ + d->displayWidget->setCdSize( DEFAULT_CD_SIZE_80 ); +} + + +void K3bFillStatusDisplay::slot100Minutes() +{ + d->displayWidget->setCdSize( DEFAULT_CD_SIZE_100 ); +} + + +void K3bFillStatusDisplay::slotDvd4_7GB() +{ + d->displayWidget->setCdSize( DEFAULT_DVD_SIZE_4_4 ); +} + + +void K3bFillStatusDisplay::slotDvdDoubleLayer() +{ + d->displayWidget->setCdSize( DEFAULT_DVD_SIZE_8_0 ); +} + + +void K3bFillStatusDisplay::slotWhy44() +{ + QWhatsThis::display( i18n("<p><b>Why does K3b offer 4.4 GB and 8.0 GB instead of 4.7 and 8.5 like " + "it says on the media?</b>" + "<p>A single layer DVD media has a capacity of approximately " + "4.4 GB which equals 4.4*1024<sup>3</sup> bytes. Media producers just " + "calculate with 1000 instead of 1024 for advertising reasons.<br>" + "This results in 4.4*1024<sup>3</sup>/1000<sup>3</sup> = 4.7 GB.") ); +} + + +void K3bFillStatusDisplay::slotCustomSize() +{ + // allow the units to be translated + QString gbS = i18n("gb"); + QString mbS = i18n("mb"); + QString minS = i18n("min"); + + QRegExp rx( "(\\d+\\" + KGlobal::locale()->decimalSymbol() + "?\\d*)(" + gbS + "|" + mbS + "|" + minS + ")?" ); + bool ok; + QString size = KInputDialog::getText( i18n("Custom Size"), + i18n("<p>Please specify the size of the media. Use suffixes <b>gb</b>,<b>mb</b>, " + "and <b>min</b> for <em>gigabytes</em>, <em>megabytes</em>, and <em>minutes</em>" + " respectively."), + d->showDvdSizes ? QString("4%14%2").arg(KGlobal::locale()->decimalSymbol()).arg(gbS) : + (d->showTime ? QString("74")+minS : QString("650")+mbS), + &ok, this, (const char*)0, + new QRegExpValidator( rx, this ) ); + if( ok ) { + // determine size + if( rx.exactMatch( size ) ) { + QString valStr = rx.cap(1); + if( valStr.endsWith( KGlobal::locale()->decimalSymbol() ) ) + valStr += "0"; + double val = KGlobal::locale()->readNumber( valStr, &ok ); + if( ok ) { + QString s = rx.cap(2); + if( s == gbS || (s.isEmpty() && d->showDvdSizes) ) + val *= 1024*512; + else if( s == mbS || (s.isEmpty() && !d->showTime) ) + val *= 512; + else + val *= 60*75; + d->displayWidget->setCdSize( (int)val ); + update(); + } + } + } +} + + +void K3bFillStatusDisplay::slotMenuButtonClicked() +{ + QSize size = d->showDvdSizes ? d->dvdPopup->sizeHint() : d->popup->sizeHint(); + slotPopupMenu( d->buttonMenu->mapToGlobal(QPoint(d->buttonMenu->width(), 0)) + + QPoint(-1*size.width(), -1*size.height()) ); +} + + +void K3bFillStatusDisplay::slotPopupMenu( const QPoint& p ) +{ + if( d->showDvdSizes ) + d->dvdPopup->popup(p); + else + d->popup->popup(p); +} + + +void K3bFillStatusDisplay::slotDetermineSize() +{ + bool canceled = false; + K3bDevice::Device* dev = K3bMediaSelectionDialog::selectMedium( d->showDvdSizes ? K3bDevice::MEDIA_WRITABLE_DVD : K3bDevice::MEDIA_WRITABLE_CD, + K3bDevice::STATE_EMPTY|K3bDevice::STATE_INCOMPLETE, + parentWidget(), + QString::null, QString::null, &canceled ); + + if( dev ) { + K3b::Msf size = k3bappcore->mediaCache()->diskInfo( dev ).capacity(); + if( size > 0 ) { + d->displayWidget->setCdSize( size ); + d->actionCustomSize->setChecked(true); + update(); + } + else + KMessageBox::error( parentWidget(), i18n("Medium is not empty.") ); + } + else if( !canceled ) + KMessageBox::error( parentWidget(), i18n("No usable medium found.") ); +} + + +void K3bFillStatusDisplay::slotLoadUserDefaults() +{ + // load project specific values + KConfig* c = k3bcore->config(); + c->setGroup( "default " + d->doc->typeString() + " settings" ); + + // defaults to megabytes + d->showTime = c->readBoolEntry( "show minutes", false ); + d->displayWidget->setShowTime(d->showTime); + d->actionShowMegs->setChecked( !d->showTime ); + d->actionShowMinutes->setChecked( d->showTime ); + + + long size = c->readNumEntry( "default media size", 0 ); + + switch( size ) { + case 0: + // automatic mode + d->actionAuto->setChecked( true ); + break; + case 74: + d->action74Min->setChecked( true ); + break; + case 80: + d->action80Min->setChecked( true ); + break; + case 100: + d->action100Min->setChecked( true ); + break; + case 510: + d->actionDvd4_7GB->setChecked( true ); + break; + default: + d->actionCustomSize->setChecked( true ); + break; + } + + if( size == 0 ) { + slotMediumChanged( 0 ); + } + else { + d->displayWidget->setCdSize( size*60*75 ); + } +} + + +void K3bFillStatusDisplay::slotMediumChanged( K3bDevice::Device* ) +{ + if( d->actionAuto->isChecked() ) { + // + // now search for a usable medium + // if we find exactly one usable or multiple with the same size + // we use that size + // + + // TODO: once we have only one data project we need to change this to handle both + + K3bDevice::Device* dev = 0; + QPtrList<K3bDevice::Device> devs; + if( d->showDvdSizes ) + devs = k3bcore->deviceManager()->dvdWriter(); + else + devs = k3bcore->deviceManager()->cdWriter(); + + for( QPtrListIterator<K3bDevice::Device> it( devs ); *it; ++it ) { + const K3bMedium& medium = k3bappcore->mediaCache()->medium( *it ); + + if( ( medium.diskInfo().empty() || + medium.diskInfo().appendable() || + medium.diskInfo().rewritable() ) && + ( medium.diskInfo().isDvdMedia() == d->showDvdSizes ) && + d->doc->length() <= medium.diskInfo().capacity() ) { + + // first usable medium + if( !dev ) { + dev = medium.device(); + } + + // roughly compare the sizes of the two usable media. If they match, carry on. + else if( k3bappcore->mediaCache()->diskInfo( dev ).capacity().lba()/75/60 + != medium.diskInfo().capacity().lba()/75/60 ) { + // different usable media -> fallback + dev = 0; + break; + } + // else continue; + } + } + + if( dev ) { + d->displayWidget->setCdSize( k3bappcore->mediaCache()->diskInfo( dev ).capacity().lba() ); + } + else { + // default fallback + if( d->showDvdSizes ) { + if( d->doc->length().lba() > DEFAULT_DVD_SIZE_4_4 ) + d->displayWidget->setCdSize( DEFAULT_DVD_SIZE_8_0 ); + else + d->displayWidget->setCdSize( DEFAULT_DVD_SIZE_4_4 ); + } + else + d->displayWidget->setCdSize( DEFAULT_CD_SIZE_80 ); + } + } +} + + +void K3bFillStatusDisplay::slotSaveUserDefaults() +{ + // save project specific values + KConfig* c = k3bcore->config(); + c->setGroup( "default " + d->doc->typeString() + " settings" ); + + c->writeEntry( "show minutes", d->showTime ); + c->writeEntry( "default media size", d->actionAuto->isChecked() ? 0 : d->displayWidget->cdSize().totalFrames() ); +} + + +void K3bFillStatusDisplay::slotUpdateDisplay() +{ + if( d->actionAuto->isChecked() ) { + // + // also update the medium list in case the docs size exceeds the capacity + // + slotMediumChanged( 0 ); + } + else { + d->displayWidget->update(); + } +} + + +void K3bFillStatusDisplay::slotDocChanged() +{ + // cache updates + if( !d->updateTimer.isActive() ) { + slotUpdateDisplay(); + d->updateTimer.start( 500, false ); + } +} + +#include "k3bfillstatusdisplay.moc" diff --git a/src/projects/k3bfillstatusdisplay.h b/src/projects/k3bfillstatusdisplay.h new file mode 100644 index 0000000..f477faa --- /dev/null +++ b/src/projects/k3bfillstatusdisplay.h @@ -0,0 +1,117 @@ + +/* + * + * $Id: k3bfillstatusdisplay.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BFILLSTATUSDISPLAY_H +#define K3BFILLSTATUSDISPLAY_H + +#include <qframe.h> +#include <qtooltip.h> + + +class QPaintEvent; +class QMouseEvent; +class K3bDoc; +class KToggleAction; +class KAction; +class KActionCollection; +class KPopupMenu; +class QToolButton; + +namespace K3bDevice { + class Device; +} +namespace K3b { + class Msf; +} + + +/** + *@author Sebastian Trueg + */ +class K3bFillStatusDisplayWidget : public QWidget +{ + Q_OBJECT + + public: + K3bFillStatusDisplayWidget( K3bDoc* doc, QWidget* parent ); + ~K3bFillStatusDisplayWidget(); + + QSize sizeHint() const; + QSize minimumSizeHint() const; + + const K3b::Msf& cdSize() const; + + public slots: + void setShowTime( bool b ); + void setCdSize( const K3b::Msf& ); + + signals: + void contextMenu( const QPoint& ); + + protected: + void mousePressEvent( QMouseEvent* ); + void paintEvent(QPaintEvent*); + + private: + class Private; + Private* d; +}; + + +class K3bFillStatusDisplay : public QFrame { + + Q_OBJECT + + public: + K3bFillStatusDisplay(K3bDoc* doc, QWidget *parent=0, const char *name=0); + ~K3bFillStatusDisplay(); + + public slots: + void showSize(); + void showTime(); + void showDvdSizes( bool ); + + protected: + void setupPopupMenu(); + + private slots: + void slotAutoSize(); + void slot74Minutes(); + void slot80Minutes(); + void slot100Minutes(); + void slotDvd4_7GB(); + void slotDvdDoubleLayer(); + void slotWhy44(); + void slotCustomSize(); + void slotMenuButtonClicked(); + void slotPopupMenu(const QPoint&); + void slotDetermineSize(); + void slotDocChanged(); + void slotMediumChanged( K3bDevice::Device* dev ); + void slotUpdateDisplay(); + + void slotLoadUserDefaults(); + void slotSaveUserDefaults(); + + private: + class ToolTip; + ToolTip* m_toolTip; + class Private; + Private* d; +}; + +#endif diff --git a/src/projects/k3bmixedburndialog.cpp b/src/projects/k3bmixedburndialog.cpp new file mode 100644 index 0000000..5d5ad28 --- /dev/null +++ b/src/projects/k3bmixedburndialog.cpp @@ -0,0 +1,353 @@ +/* + * + * $Id: k3bmixedburndialog.cpp 627521 2007-01-26 22:39:53Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bmixedburndialog.h" +#include "k3bmixeddoc.h" +#include "k3bmixedview.h" + +#include <k3bdataimagesettingswidget.h> +#include <k3bdatadoc.h> +#include <k3baudiodoc.h> +#include <k3bdevice.h> +#include <k3bwriterselectionwidget.h> +#include <k3btempdirselectionwidget.h> +#include <k3bisooptions.h> +#include <k3bglobals.h> +#include <k3baudiocdtextwidget.h> +#include <k3bdatamodewidget.h> +#include <k3bmsf.h> +#include <k3bstdguiitems.h> +#include <k3bwritingmodewidget.h> +#include <k3bexternalbinmanager.h> +#include <k3bversion.h> +#include <k3bcore.h> +#include <k3baudiotrackplayer.h> +#include <k3bintmapcombobox.h> + +#include <qtabwidget.h> +#include <qcheckbox.h> +#include <qframe.h> +#include <qgroupbox.h> +#include <qlabel.h> +#include <qlineedit.h> +#include <qpushbutton.h> +#include <qtoolbutton.h> +#include <qlayout.h> +#include <qvariant.h> +#include <qtooltip.h> +#include <qwhatsthis.h> +#include <qvbox.h> +#include <qbuttongroup.h> +#include <qradiobutton.h> + +#include <klocale.h> +#include <kconfig.h> +#include <kapplication.h> +#include <kdebug.h> +#include <kmessagebox.h> + + +K3bMixedBurnDialog::K3bMixedBurnDialog( K3bMixedDoc* doc, QWidget *parent, const char *name, bool modal ) + : K3bProjectBurnDialog( doc, parent, name, modal ), m_doc(doc) +{ + prepareGui(); + + setTitle( i18n("Mixed Project"), i18n("1 track (%1 minutes)", + "%n tracks (%1 minutes)", + m_doc->numOfTracks()).arg(m_doc->length().toString()) ); + + m_checkOnlyCreateImage->hide(); + + // create cd-text page + m_cdtextWidget = new K3bAudioCdTextWidget( this ); + addPage( m_cdtextWidget, i18n("CD-Text") ); + + // create image settings tab + m_imageSettingsWidget = new K3bDataImageSettingsWidget( this ); + addPage( m_imageSettingsWidget, i18n("Filesystem") ); + + setupSettingsPage(); + + QSpacerItem* spacer = new QSpacerItem( 20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding ); + m_optionGroupLayout->addItem( spacer ); + + connect( m_checkNormalize, SIGNAL(toggled(bool)), this, SLOT(slotNormalizeToggled(bool)) ); + connect( m_checkCacheImage, SIGNAL(toggled(bool)), this, SLOT(slotCacheImageToggled(bool)) ); + connect( m_writerSelectionWidget, SIGNAL(writingAppChanged(int)), this, SLOT(slotToggleAll()) ); + connect( m_writingModeWidget, SIGNAL(writingModeChanged(int)), this, SLOT(slotToggleAll()) ); +} + + +void K3bMixedBurnDialog::setupSettingsPage() +{ + QWidget* w = new QWidget( this ); + + QGroupBox* groupDataMode = new QGroupBox( 1, Qt::Vertical, i18n("Datatrack Mode"), w ); + m_dataModeWidget = new K3bDataModeWidget( groupDataMode ); + + QGroupBox* groupNormalize = new QGroupBox( 1, Qt::Vertical, i18n("Misc"), w ); + m_checkNormalize = K3bStdGuiItems::normalizeCheckBox( groupNormalize ); + + QGroupBox* groupMixedType = new QGroupBox( 1, Qt::Vertical, i18n("Mixed Mode Type"), w ); + m_comboMixedModeType = new K3bIntMapComboBox( groupMixedType ); + + m_comboMixedModeType->insertItem( K3bMixedDoc::DATA_SECOND_SESSION, + i18n("Data in second session (CD-Extra)"), + i18n("<em>Blue book CD</em>" + "<br>K3b will create a multisession CD with " + "2 sessions. The first session will contain all " + "audio tracks and the second session will contain " + "a mode 2 form 1 data track." + "<br>This mode is based on the <em>Blue book</em> " + "standard (also known as <em>Extended Audio CD</em>, " + "<em>CD-Extra</em>, or <em>CD Plus</em>) " + "and has the advantage that a hifi audio " + "CD player will only recognize the first session " + "and ignore the second session with the data track." + "<br>If the CD is intended to be used in a hifi audio CD player " + "this is the recommended mode." + "<br>Some older CD-ROMs may have problems reading " + "a blue book CD since it is a multisession CD.") ); + m_comboMixedModeType->insertItem( K3bMixedDoc::DATA_FIRST_TRACK, + i18n("Data in first track"), + i18n("K3b will write the data track before all " + "audio tracks.") ); + m_comboMixedModeType->insertItem( K3bMixedDoc::DATA_LAST_TRACK, + i18n("Data in last track"), + i18n("K3b will write the data track after all " + "audio tracks.") ); + m_comboMixedModeType->addGlobalWhatsThisText( QString(), + i18n("<b>Caution:</b> The last two modes should only be used for CDs that are unlikely to " + "be played on a hifi audio CD player." + "<br>It could lead to problems with some older " + "hifi audio CD players that try to play the data track.") ); + + QGridLayout* grid = new QGridLayout( w ); + grid->setMargin( marginHint() ); + grid->setSpacing( spacingHint() ); + grid->addWidget( groupMixedType, 0, 0 ); + grid->addWidget( groupDataMode, 1, 0 ); + grid->addWidget( groupNormalize, 2, 0 ); + grid->setRowStretch( 3, 1 ); + + addPage( w, i18n("Misc") ); +} + + +void K3bMixedBurnDialog::slotStartClicked() +{ + // FIXME: this should not be done via the doc. So remove all gui stuff from the doc + static_cast<K3bMixedView*>(m_doc->view())->player()->stop(); + K3bProjectBurnDialog::slotStartClicked(); +} + + +void K3bMixedBurnDialog::saveSettings() +{ + K3bProjectBurnDialog::saveSettings(); + + m_doc->setMixedType( (K3bMixedDoc::MixedType)m_comboMixedModeType->selectedValue() ); + + m_cdtextWidget->save( m_doc->audioDoc() ); + + m_doc->audioDoc()->setNormalize( m_checkNormalize->isChecked() ); + + // save iso image settings + K3bIsoOptions o = m_doc->dataDoc()->isoOptions(); + m_imageSettingsWidget->save( o ); + m_doc->dataDoc()->setIsoOptions( o ); + + m_doc->dataDoc()->setDataMode( m_dataModeWidget->dataMode() ); + + // save image file path + m_doc->setTempDir( m_tempDirSelectionWidget->tempPath() ); +} + + +void K3bMixedBurnDialog::readSettings() +{ + K3bProjectBurnDialog::readSettings(); + + m_checkNormalize->setChecked( m_doc->audioDoc()->normalize() ); + + if( !m_doc->tempDir().isEmpty() ) + m_tempDirSelectionWidget->setTempPath( m_doc->tempDir() ); + + m_comboMixedModeType->setSelectedValue( m_doc->mixedType() ); + + m_cdtextWidget->load( m_doc->audioDoc() ); + + m_imageSettingsWidget->load( m_doc->dataDoc()->isoOptions() ); + + m_dataModeWidget->setDataMode( m_doc->dataDoc()->dataMode() ); + + toggleAll(); +} + + +void K3bMixedBurnDialog::loadK3bDefaults() +{ + K3bProjectBurnDialog::loadK3bDefaults(); + + m_cdtextWidget->setChecked( false ); + m_checkNormalize->setChecked( false ); + + m_comboMixedModeType->setSelectedValue( K3bMixedDoc::DATA_SECOND_SESSION ); + + m_dataModeWidget->setDataMode( K3b::DATA_MODE_AUTO ); + + m_imageSettingsWidget->load( K3bIsoOptions::defaults() ); + + toggleAll(); +} + + +void K3bMixedBurnDialog::loadUserDefaults( KConfigBase* c ) +{ + K3bProjectBurnDialog::loadUserDefaults( c ); + + m_cdtextWidget->setChecked( c->readBoolEntry( "cd_text", false ) ); + m_checkNormalize->setChecked( c->readBoolEntry( "normalize", false ) ); + + // load mixed type + if( c->readEntry( "mixed_type" ) == "last_track" ) + m_comboMixedModeType->setSelectedValue( K3bMixedDoc::DATA_LAST_TRACK ); + else if( c->readEntry( "mixed_type" ) == "first_track" ) + m_comboMixedModeType->setSelectedValue( K3bMixedDoc::DATA_FIRST_TRACK ); + else + m_comboMixedModeType->setSelectedValue( K3bMixedDoc::DATA_SECOND_SESSION ); + + m_dataModeWidget->loadConfig(c); + + K3bIsoOptions o = K3bIsoOptions::load( c ); + m_imageSettingsWidget->load( o ); + + toggleAll(); +} + + +void K3bMixedBurnDialog::saveUserDefaults( KConfigBase* c ) +{ + K3bProjectBurnDialog::saveUserDefaults(c); + + c->writeEntry( "cd_text", m_cdtextWidget->isChecked() ); + c->writeEntry( "normalize", m_checkNormalize->isChecked() ); + + // save mixed type + switch( m_comboMixedModeType->selectedValue() ) { + case K3bMixedDoc::DATA_LAST_TRACK: + c->writeEntry( "mixed_type", "last_track" ); + break; + case K3bMixedDoc::DATA_FIRST_TRACK: + c->writeEntry( "mixed_type", "first_track" ); + break; + default: + c->writeEntry( "mixed_type", "second_session" ); + } + + m_dataModeWidget->saveConfig(c); + + K3bIsoOptions o; + m_imageSettingsWidget->save( o ); + o.save( c ); + + if( m_tempDirSelectionWidget->isEnabled() ) { + m_tempDirSelectionWidget->saveConfig(); + } +} + + +void K3bMixedBurnDialog::toggleAll() +{ + K3bProjectBurnDialog::toggleAll(); + + bool cdrecordOnTheFly = false; + bool cdrecordCdText = false; + if ( k3bcore->externalBinManager()->binObject("cdrecord") ) { + cdrecordOnTheFly = k3bcore->externalBinManager()->binObject("cdrecord")->hasFeature( "audio-stdin" ); + cdrecordCdText = k3bcore->externalBinManager()->binObject("cdrecord")->hasFeature( "cdtext" ); + } + + // cdrdao always knows onthefly and cdtext + bool onTheFly = true; + bool cdText = true; + if( m_writingModeWidget->writingMode() == K3b::TAO || + m_writingModeWidget->writingMode() == K3b::RAW || + m_writerSelectionWidget->writingApp() == K3b::CDRECORD ) { + onTheFly = cdrecordOnTheFly; + cdText = cdrecordCdText; + } + + m_checkCacheImage->setEnabled( !m_checkOnlyCreateImage->isChecked() && + onTheFly ); + if( !onTheFly ) + m_checkCacheImage->setChecked( true ); + + m_cdtextWidget->setEnabled( !m_checkOnlyCreateImage->isChecked() && + cdText && + m_writingModeWidget->writingMode() != K3b::TAO ); + if( !cdText || m_writingModeWidget->writingMode() == K3b::TAO ) + m_cdtextWidget->setChecked( false ); +} + + +void K3bMixedBurnDialog::slotNormalizeToggled( bool on ) +{ + if( on ) { + // we are not able to normalize in on-the-fly mode + if( !k3bcore->externalBinManager()->foundBin( "normalize" ) ) { + KMessageBox::sorry( this, i18n("<p><b>External program <em>normalize-audio</em> is not installed.</b>" + "<p>K3b uses <em>normalize-audio</em> (http://www1.cs.columbia.edu/~cvaill/normalize/) " + "to normalize audio tracks. In order to " + "use this functionality, please install it first (sudo apt-get install normalize-audio.") ); + m_checkNormalize->setChecked( false ); + } + else if( !m_checkCacheImage->isChecked() && !m_checkOnlyCreateImage->isChecked() ) { + if( KMessageBox::warningYesNo( this, i18n("<p>K3b is not able to normalize audio tracks when burning on-the-fly. " + "The external program used for this task only supports normalizing a set " + "of audio files."), + QString::null, + i18n("Disable normalization"), + i18n("Disable on-the-fly burning"), + "audioProjectNormalizeOrOnTheFly" ) == KMessageBox::Yes ) + m_checkNormalize->setChecked( false ); + else + m_checkCacheImage->setChecked( true ); + } + } +} + + +void K3bMixedBurnDialog::slotCacheImageToggled( bool on ) +{ + if( on ) { + if( m_checkNormalize->isChecked() ) { + if( KMessageBox::warningYesNo( this, i18n("<p>K3b is not able to normalize audio tracks when burning on-the-fly. " + "The external program used for this task only supports normalizing a set " + "of audio files."), + QString::null, + i18n("Disable normalization"), + i18n("Disable on-the-fly burning"), + "audioProjectNormalizeOrOnTheFly" ) == KMessageBox::Yes ) + m_checkNormalize->setChecked( false ); + else + m_checkCacheImage->setChecked( true ); + } + } +} + + +#include "k3bmixedburndialog.moc" + diff --git a/src/projects/k3bmixedburndialog.h b/src/projects/k3bmixedburndialog.h new file mode 100644 index 0000000..363d26e --- /dev/null +++ b/src/projects/k3bmixedburndialog.h @@ -0,0 +1,78 @@ +/* + * + * $Id: k3bmixedburndialog.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BMIXEDBURNDIALOG_H +#define K3BMIXEDBURNDIALOG_H + +#include "k3bprojectburndialog.h" + +class QCheckBox; +class K3bWriterSelectionWidget; +class K3bTempDirSelectionWidget; +class K3bMixedDoc; +class K3bDataImageSettingsWidget; +class QButtonGroup; +class QRadioButton; +class K3bAudioCdTextWidget; +class K3bDataModeWidget; +class K3bIntMapComboBox; + + +/** + *@author Sebastian Trueg + */ +class K3bMixedBurnDialog : public K3bProjectBurnDialog +{ + Q_OBJECT + + public: + K3bMixedBurnDialog( K3bMixedDoc*, QWidget *parent=0, const char *name=0, bool modal = true ); + + protected: + void loadK3bDefaults(); + void loadUserDefaults( KConfigBase* ); + void saveUserDefaults( KConfigBase* ); + void toggleAll(); + + K3bDataImageSettingsWidget* m_imageSettingsWidget; + K3bAudioCdTextWidget* m_cdtextWidget; + + protected slots: + /** + * Reimplemented for internal reasons (shut down the audio player) + */ + void slotStartClicked(); + void saveSettings(); + void readSettings(); + + void slotCacheImageToggled( bool on ); + void slotNormalizeToggled( bool on ); + + private: + void setupSettingsPage(); + K3bMixedDoc* m_doc; + + K3bIntMapComboBox* m_comboMixedModeType; + QRadioButton* m_radioMixedTypeFirstTrack; + QRadioButton* m_radioMixedTypeLastTrack; + QRadioButton* m_radioMixedTypeSessions; + + QCheckBox* m_checkNormalize; + + K3bDataModeWidget* m_dataModeWidget; +}; + +#endif diff --git a/src/projects/k3bmixeddirtreeview.cpp b/src/projects/k3bmixeddirtreeview.cpp new file mode 100644 index 0000000..50d818a --- /dev/null +++ b/src/projects/k3bmixeddirtreeview.cpp @@ -0,0 +1,103 @@ +/* + * + * $Id: k3bmixeddirtreeview.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bmixeddirtreeview.h" + +#include "k3bmixeddoc.h" +#include "k3baudiotrackaddingdialog.h" +#include <k3blistview.h> +#include <k3baudiodoc.h> +#include <k3bdataviewitem.h> + +#include <qevent.h> + +#include <kdebug.h> +#include <kiconloader.h> +#include <kurldrag.h> +#include <klocale.h> + + +class K3bMixedDirTreeView::PrivateAudioRootViewItem : public K3bListViewItem +{ +public: + PrivateAudioRootViewItem( K3bMixedDoc* doc, QListView* parent, QListViewItem* after ) + : K3bListViewItem( parent, after ), + m_doc(doc) + { + setPixmap( 0, SmallIcon("sound") ); + } + + QString text( int col ) const { + if( col == 0 ) + return i18n("Audio Tracks") + QString(" (%1)").arg(m_doc->audioDoc()->numOfTracks()); + else + return QString::null; + } + + private: + K3bMixedDoc* m_doc; +}; + + +K3bMixedDirTreeView::K3bMixedDirTreeView( K3bView* view, K3bMixedDoc* doc, QWidget* parent, const char* ) + : K3bDataDirTreeView( view, doc->dataDoc(), parent ), m_doc(doc) +{ + m_audioRootItem = new PrivateAudioRootViewItem( doc, this, root() ); + + connect( this, SIGNAL(selectionChanged(QListViewItem*)), + this, SLOT(slotSelectionChanged(QListViewItem*)) ); + connect( m_doc->audioDoc(), SIGNAL(changed()), this, SLOT(slotNewAudioTracks()) ); +} + + +K3bMixedDirTreeView::~K3bMixedDirTreeView() +{ +} + + +void K3bMixedDirTreeView::slotDropped( QDropEvent* e, QListViewItem* parent, QListViewItem* after ) +{ + if( !e->isAccepted() ) + return; + + QListViewItem* droppedItem = itemAt(e->pos()); + if( droppedItem == m_audioRootItem ) { + KURL::List urls; + if( KURLDrag::decode( e, urls ) ) { + K3bAudioTrackAddingDialog::addUrls( urls, m_doc->audioDoc(), 0, 0, 0, this ); + } + } + else + K3bDataDirTreeView::slotDropped( e, parent, after ); +} + + +void K3bMixedDirTreeView::slotSelectionChanged( QListViewItem* i ) +{ + if( i == m_audioRootItem ) + emit audioTreeSelected(); + else + emit dataTreeSelected(); +} + + +void K3bMixedDirTreeView::slotNewAudioTracks() +{ + // update the tracknumber + m_audioRootItem->repaint(); +} + +#include "k3bmixeddirtreeview.moc" diff --git a/src/projects/k3bmixeddirtreeview.h b/src/projects/k3bmixeddirtreeview.h new file mode 100644 index 0000000..8a8bfe9 --- /dev/null +++ b/src/projects/k3bmixeddirtreeview.h @@ -0,0 +1,56 @@ +/* + * + * $Id: k3bmixeddirtreeview.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + + +#ifndef _K3B_MIXED_DIRTREEVIEW_H_ +#define _K3B_MIXED_DIRTREEVIEW_H_ + +#include <k3bdatadirtreeview.h> + +class K3bView; +class K3bMixedDoc; +class QDropEvent; +class QListViewItem; + + +class K3bMixedDirTreeView : public K3bDataDirTreeView +{ + Q_OBJECT + + public: + K3bMixedDirTreeView( K3bView* view, K3bMixedDoc* doc, QWidget* parent = 0, const char* name = 0 ); + ~K3bMixedDirTreeView(); + + signals: + void audioTreeSelected(); + void dataTreeSelected(); + + protected slots: + void slotDropped( QDropEvent* e, QListViewItem* after, QListViewItem* parent ); + + private slots: + void slotSelectionChanged( QListViewItem* i ); + void slotNewAudioTracks(); + + private: + K3bMixedDoc* m_doc; + + class PrivateAudioRootViewItem; + PrivateAudioRootViewItem* m_audioRootItem; +}; + + +#endif diff --git a/src/projects/k3bmixedview.cpp b/src/projects/k3bmixedview.cpp new file mode 100644 index 0000000..68900c7 --- /dev/null +++ b/src/projects/k3bmixedview.cpp @@ -0,0 +1,155 @@ +/* + * + * $Id: k3bmixedview.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bmixedview.h" + +#include "k3bmixeddoc.h" +#include "k3bmixedburndialog.h" +#include "k3bmixeddirtreeview.h" +#include "k3baudiotrackaddingdialog.h" +#include "k3bdataurladdingdialog.h" + +#include <k3baudiotrackplayer.h> +#include <k3baudiodoc.h> +#include <k3bdataviewitem.h> +#include <k3bdatafileview.h> +#include <k3bdatadoc.h> +#include <k3baudiotrackview.h> +#include <k3bfillstatusdisplay.h> +#include <k3btoolbox.h> +#include <k3bprojectplugin.h> + +#include <qwidgetstack.h> +#include <qsplitter.h> +#include <qlayout.h> +#include <qvaluelist.h> + +#include <kdialog.h> +#include <klocale.h> +#include <kiconloader.h> +#include <kdebug.h> +#include <kmessagebox.h> +#include <kactionclasses.h> + + +K3bMixedView::K3bMixedView( K3bMixedDoc* doc, QWidget* parent, const char* name ) + : K3bView( doc, parent, name ), m_doc(doc) +{ + QSplitter* splitter = new QSplitter( this ); + m_mixedDirTreeView = new K3bMixedDirTreeView( this, doc, splitter ); + m_widgetStack = new QWidgetStack( splitter ); + m_dataFileView = new K3bDataFileView( this, m_mixedDirTreeView, doc->dataDoc(), m_widgetStack ); + m_mixedDirTreeView->setFileView( m_dataFileView ); + m_audioListView = new K3bAudioTrackView( doc->audioDoc(), m_widgetStack ); + + setMainWidget( splitter ); + + connect( m_mixedDirTreeView, SIGNAL(audioTreeSelected()), + this, SLOT(slotAudioTreeSelected()) ); + connect( m_mixedDirTreeView, SIGNAL(dataTreeSelected()), + this, SLOT(slotDataTreeSelected()) ); + + m_widgetStack->raiseWidget( m_dataFileView ); + + toolBox()->addButton( m_audioListView->player()->action( K3bAudioTrackPlayer::ACTION_PLAY ) ); + toolBox()->addButton( m_audioListView->player()->action( K3bAudioTrackPlayer::ACTION_PAUSE ) ); + toolBox()->addButton( m_audioListView->player()->action( K3bAudioTrackPlayer::ACTION_STOP ) ); + toolBox()->addSpacing(); + toolBox()->addButton( m_audioListView->player()->action( K3bAudioTrackPlayer::ACTION_PREV ) ); + toolBox()->addButton( m_audioListView->player()->action( K3bAudioTrackPlayer::ACTION_NEXT ) ); + toolBox()->addSpacing(); + toolBox()->addWidgetAction( static_cast<KWidgetAction*>(m_audioListView->player()->action( K3bAudioTrackPlayer::ACTION_SEEK )) ); + toolBox()->addSeparator(); + +#ifdef HAVE_MUSICBRAINZ + toolBox()->addButton( m_audioListView->actionCollection()->action( "project_audio_musicbrainz" ) ); + toolBox()->addSeparator(); +#endif + + addPluginButtons( K3bProjectPlugin::MIXED_CD ); + + toolBox()->addStretch(); + + m_mixedDirTreeView->checkForNewItems(); + m_dataFileView->checkForNewItems(); +} + + +K3bMixedView::~K3bMixedView() +{ +} + + +K3bAudioTrackPlayer* K3bMixedView::player() const +{ + return m_audioListView->player(); +} + + +void K3bMixedView::slotAudioTreeSelected() +{ + m_widgetStack->raiseWidget( m_audioListView ); +} + + +void K3bMixedView::slotDataTreeSelected() +{ + m_widgetStack->raiseWidget( m_dataFileView ); +} + + +K3bDirItem* K3bMixedView::currentDir() const +{ + if( m_widgetStack->visibleWidget() == m_dataFileView ) + return m_dataFileView->currentDir(); + else + return 0; +} + + +void K3bMixedView::slotBurn() +{ + if( m_doc->audioDoc()->numOfTracks() == 0 || m_doc->dataDoc()->size() == 0 ) { + KMessageBox::information( this, i18n("Please add files and audio titles to your project first."), + i18n("No Data to Burn"), QString::null, false ); + } + else { + K3bProjectBurnDialog* dlg = newBurnDialog( this ); + if( dlg ) { + dlg->execBurnDialog(true); + delete dlg; + } + else { + kdDebug() << "(K3bDoc) Error: no burndialog available." << endl; + } + } +} + + +K3bProjectBurnDialog* K3bMixedView::newBurnDialog( QWidget* parent, const char* name ) +{ + return new K3bMixedBurnDialog( m_doc, parent, name, true ); +} + + +void K3bMixedView::addUrls( const KURL::List& urls ) +{ + if( m_widgetStack->visibleWidget() == m_dataFileView ) + K3bDataUrlAddingDialog::addUrls( urls, currentDir() ); + else + K3bAudioTrackAddingDialog::addUrls( urls, m_doc->audioDoc(), 0, 0, 0, this ); +} + +#include "k3bmixedview.moc" diff --git a/src/projects/k3bmixedview.h b/src/projects/k3bmixedview.h new file mode 100644 index 0000000..8e52df7 --- /dev/null +++ b/src/projects/k3bmixedview.h @@ -0,0 +1,66 @@ +/* + * + * $Id: k3bmixedview.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef K3B_MIXED_VIEW_H +#define K3B_MIXED_VIEW_H + +#include <k3bview.h> + +#include <kurl.h> + +class K3bMixedDoc; +class QWidgetStack; +class K3bDataFileView; +class K3bMixedDirTreeView; +class K3bAudioTrackView; +class QListViewItem; +class K3bDirItem; +class K3bAudioTrackPlayer; + + +class K3bMixedView : public K3bView +{ + Q_OBJECT + + public: + K3bMixedView( K3bMixedDoc* doc, QWidget* parent = 0, const char* name = 0 ); + ~K3bMixedView(); + + K3bDirItem* currentDir() const; + + K3bAudioTrackPlayer* player() const; + + public slots: + void slotBurn(); + void addUrls( const KURL::List& ); + + protected: + K3bProjectBurnDialog* newBurnDialog( QWidget* parent = 0, const char* name = 0 ); + + private slots: + void slotAudioTreeSelected(); + void slotDataTreeSelected(); + + private: + K3bMixedDoc* m_doc; + + QWidgetStack* m_widgetStack; + + K3bMixedDirTreeView* m_mixedDirTreeView; + K3bDataFileView* m_dataFileView; + K3bAudioTrackView* m_audioListView; +}; + +#endif diff --git a/src/projects/k3bmovixburndialog.cpp b/src/projects/k3bmovixburndialog.cpp new file mode 100644 index 0000000..94238a7 --- /dev/null +++ b/src/projects/k3bmovixburndialog.cpp @@ -0,0 +1,265 @@ +/* + * + * $Id: k3bmovixburndialog.cpp 690207 2007-07-20 10:40:19Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bmovixburndialog.h" +#include "k3bmovixdoc.h" +#include "k3bmovixprogram.h" +#include "k3bmovixoptionswidget.h" + +#include <k3bdataimagesettingswidget.h> +#include <k3bexternalbinmanager.h> +#include <k3bwriterselectionwidget.h> +#include <k3btempdirselectionwidget.h> +#include <k3bstdguiitems.h> +#include <k3bglobals.h> +#include <k3bdatamodewidget.h> +#include <k3bisooptions.h> +#include <k3bwritingmodewidget.h> +#include <k3bcore.h> + +#include <klocale.h> +#include <kdebug.h> +#include <kmessagebox.h> +#include <kio/global.h> +#include <kapplication.h> +#include <kconfig.h> + +#include <qcheckbox.h> +#include <qlayout.h> +#include <qgroupbox.h> +#include <qfileinfo.h> + + +K3bMovixBurnDialog::K3bMovixBurnDialog( K3bMovixDoc* doc, QWidget* parent, const char* name, bool modal ) + : K3bProjectBurnDialog( doc, parent, name, modal ), + m_doc(doc) +{ + prepareGui(); + + m_tempDirSelectionWidget->setSelectionMode( K3bTempDirSelectionWidget::FILE ); + + setTitle( i18n("eMovix CD Project"), + i18n("1 file (%1)", "%n files (%1)", m_doc->movixFileItems().count()).arg(KIO::convertSize(m_doc->size())) ); + + m_movixOptionsWidget = new K3bMovixOptionsWidget( this ); + addPage( m_movixOptionsWidget, i18n("eMovix") ); + + // create image settings tab + m_imageSettingsWidget = new K3bDataImageSettingsWidget( this ); + addPage( m_imageSettingsWidget, i18n("Filesystem") ); + + setupSettingsPage(); + + // for now we just put the verify checkbox on the main page... + m_checkVerify = K3bStdGuiItems::verifyCheckBox( m_optionGroup ); + m_optionGroupLayout->addWidget( m_checkVerify ); + + QSpacerItem* spacer = new QSpacerItem( 20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding ); + m_optionGroupLayout->addItem( spacer ); + + m_tempDirSelectionWidget->setSelectionMode( K3bTempDirSelectionWidget::FILE ); + QString path = m_doc->tempDir(); + if( !path.isEmpty() ) { + m_tempDirSelectionWidget->setTempPath( path ); + } + if( !m_doc->isoOptions().volumeID().isEmpty() ) { + m_tempDirSelectionWidget->setDefaultImageFileName( m_doc->isoOptions().volumeID() + ".iso" ); + } + + connect( m_imageSettingsWidget->m_editVolumeName, SIGNAL(textChanged(const QString&)), + m_tempDirSelectionWidget, SLOT(setDefaultImageFileName(const QString&)) ); +} + + +K3bMovixBurnDialog::~K3bMovixBurnDialog() +{ +} + + +void K3bMovixBurnDialog::setupSettingsPage() +{ + QWidget* frame = new QWidget( this ); + QGridLayout* frameLayout = new QGridLayout( frame ); + frameLayout->setSpacing( spacingHint() ); + frameLayout->setMargin( marginHint() ); + + QGroupBox* groupDataMode = new QGroupBox( 1, Qt::Vertical, i18n("Datatrack Mode"), frame ); + m_dataModeWidget = new K3bDataModeWidget( groupDataMode ); + + QGroupBox* groupMultisession = new QGroupBox( 1, Qt::Vertical, i18n("Multisession"), frame ); + m_checkStartMultiSesssion = K3bStdGuiItems::startMultisessionCheckBox( groupMultisession ); + + frameLayout->addWidget( groupDataMode, 0, 0 ); + frameLayout->addWidget( groupMultisession, 1, 0 ); + frameLayout->setRowStretch( 2, 1 ); + + addPage( frame, i18n("Misc") ); +} + + +void K3bMovixBurnDialog::loadK3bDefaults() +{ + K3bProjectBurnDialog::loadK3bDefaults(); + + m_checkStartMultiSesssion->setChecked( false ); + m_dataModeWidget->setDataMode( K3b::DATA_MODE_AUTO ); + + m_imageSettingsWidget->load( K3bIsoOptions::defaults() ); + + m_movixOptionsWidget->loadDefaults(); + + m_checkVerify->setChecked( false ); + + toggleAll(); +} + + +void K3bMovixBurnDialog::loadUserDefaults( KConfigBase* c ) +{ + K3bProjectBurnDialog::loadUserDefaults(c); + + m_checkStartMultiSesssion->setChecked( c->readBoolEntry( "start_multisession", false ) ); + + m_dataModeWidget->loadConfig(c); + + K3bIsoOptions o = K3bIsoOptions::load( c ); + m_imageSettingsWidget->load( o ); + + m_movixOptionsWidget->loadConfig(c); + + m_checkVerify->setChecked( c->readBoolEntry( "verify data", false ) ); + + toggleAll(); +} + + +void K3bMovixBurnDialog::saveUserDefaults( KConfigBase* c ) +{ + K3bProjectBurnDialog::saveUserDefaults(c); + + c->writeEntry( "start_multisession", m_checkStartMultiSesssion->isChecked() ); + + m_dataModeWidget->saveConfig(c); + + K3bIsoOptions o; + m_imageSettingsWidget->save( o ); + o.save( c ); + + c->writeEntry( "verify data", m_checkVerify->isChecked() ); + + m_movixOptionsWidget->saveConfig(c); +} + + +void K3bMovixBurnDialog::saveSettings() +{ + K3bProjectBurnDialog::saveSettings(); + + m_movixOptionsWidget->saveSettings( m_doc ); + + m_doc->setMultiSessionMode( m_checkStartMultiSesssion->isChecked() ? K3bDataDoc::START : K3bDataDoc::NONE ); + + // save iso image settings + K3bIsoOptions o = m_doc->isoOptions(); + m_imageSettingsWidget->save( o ); + m_doc->setIsoOptions( o ); + + m_doc->setDataMode( m_dataModeWidget->dataMode() ); + + // save image file path + m_doc->setTempDir( m_tempDirSelectionWidget->tempPath() ); + + m_doc->setVerifyData( m_checkVerify->isChecked() ); +} + + +void K3bMovixBurnDialog::readSettings() +{ + K3bProjectBurnDialog::readSettings(); + + m_checkStartMultiSesssion->setChecked( m_doc->multiSessionMode() == K3bDataDoc::START ); + + m_checkVerify->setChecked( m_doc->verifyData() ); + + m_imageSettingsWidget->load( m_doc->isoOptions() ); + + m_dataModeWidget->setDataMode( m_doc->dataMode() ); + + if( !doc()->tempDir().isEmpty() ) + m_tempDirSelectionWidget->setTempPath( doc()->tempDir() ); + else + m_tempDirSelectionWidget->setTempPath( K3b::defaultTempPath() + doc()->name() + ".iso" ); + + // first of all we need a movix installation object + const K3bMovixBin* bin = dynamic_cast<const K3bMovixBin*>( k3bcore->externalBinManager()->binObject("eMovix") ); + if( bin ) { + m_movixOptionsWidget->init( bin ); + m_movixOptionsWidget->readSettings( m_doc ); + } + else { + KMessageBox::error( this, i18n("Could not find a valid eMovix installation.") ); + slotCancelClicked(); + } +} + + +void K3bMovixBurnDialog::slotStartClicked() +{ + if( m_checkOnlyCreateImage->isChecked() || + m_checkCacheImage->isChecked() ) { + QFileInfo fi( m_tempDirSelectionWidget->tempPath() ); + if( fi.isDir() ) + m_tempDirSelectionWidget->setTempPath( fi.filePath() + "/image.iso" ); + + if( QFile::exists( m_tempDirSelectionWidget->tempPath() ) ) { + if( KMessageBox::warningContinueCancel( this, + i18n("Do you want to overwrite %1?").arg(m_tempDirSelectionWidget->tempPath()), + i18n("File Exists"), i18n("Overwrite") ) + != KMessageBox::Continue ) + return; + } + } + + if( m_writingModeWidget->writingMode() == K3b::DAO && + m_checkStartMultiSesssion->isChecked() && + m_writerSelectionWidget->writingApp() == K3b::CDRECORD ) + if( KMessageBox::warningContinueCancel( this, + i18n("Most writers do not support writing " + "multisession CDs in DAO mode.") ) + == KMessageBox::Cancel ) + return; + + + K3bProjectBurnDialog::slotStartClicked(); +} + + +void K3bMovixBurnDialog::toggleAll() +{ + K3bProjectBurnDialog::toggleAll(); + + if( m_checkSimulate->isChecked() || m_checkOnlyCreateImage->isChecked() ) { + m_checkVerify->setChecked(false); + m_checkVerify->setEnabled(false); + } + else + m_checkVerify->setEnabled(true); + + m_dataModeWidget->setDisabled( m_checkOnlyCreateImage->isChecked() ); + m_checkStartMultiSesssion->setDisabled( m_checkOnlyCreateImage->isChecked() ); +} + +#include "k3bmovixburndialog.moc" diff --git a/src/projects/k3bmovixburndialog.h b/src/projects/k3bmovixburndialog.h new file mode 100644 index 0000000..ff237c0 --- /dev/null +++ b/src/projects/k3bmovixburndialog.h @@ -0,0 +1,64 @@ +/* + * + * $Id: k3bmovixburndialog.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + + +#ifndef _K3B_MOVIX_BURN_DIALOG_H_ +#define _K3B_MOVIX_BURN_DIALOG_H_ + +#include "k3bprojectburndialog.h" + +class K3bMovixDoc; +class K3bMovixOptionsWidget; +class K3bDataImageSettingsWidget; +class QCheckBox; +class K3bDataModeWidget; + + +class K3bMovixBurnDialog : public K3bProjectBurnDialog +{ + Q_OBJECT + + public: + K3bMovixBurnDialog( K3bMovixDoc* doc, QWidget* parent = 0, const char* name = 0, bool modal = true ); + ~K3bMovixBurnDialog(); + + protected slots: + void slotStartClicked(); + + protected: + void saveSettings(); + void readSettings(); + void loadK3bDefaults(); + void loadUserDefaults( KConfigBase* ); + void saveUserDefaults( KConfigBase* ); + void toggleAll(); + + private: + void setupSettingsPage(); + + K3bMovixDoc* m_doc; + K3bMovixOptionsWidget* m_movixOptionsWidget; + K3bDataImageSettingsWidget* m_imageSettingsWidget; + + QCheckBox* m_checkStartMultiSesssion; + K3bDataModeWidget* m_dataModeWidget; + + QCheckBox* m_checkVerify; +}; + + +#endif + diff --git a/src/projects/k3bmovixdvdburndialog.cpp b/src/projects/k3bmovixdvdburndialog.cpp new file mode 100644 index 0000000..3707e3a --- /dev/null +++ b/src/projects/k3bmovixdvdburndialog.cpp @@ -0,0 +1,219 @@ +/* + * + * $Id: k3bmovixdvdburndialog.cpp 690207 2007-07-20 10:40:19Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bmovixdvdburndialog.h" +#include "k3bmovixdvddoc.h" + +#include <k3bmovixprogram.h> +#include <k3bmovixoptionswidget.h> + +#include <k3bdataimagesettingswidget.h> +#include <k3bexternalbinmanager.h> +#include <k3bwriterselectionwidget.h> +#include <k3btempdirselectionwidget.h> +#include <k3bstdguiitems.h> +#include <k3bglobals.h> +#include <k3bdatamodewidget.h> +#include <k3bisooptions.h> +#include <k3bwritingmodewidget.h> +#include <k3bcore.h> +#include <k3bglobalsettings.h> + +#include <klocale.h> +#include <kmessagebox.h> +#include <kio/global.h> +#include <kapplication.h> +#include <kconfig.h> +#include <kdebug.h> + +#include <qcheckbox.h> +#include <qlayout.h> +#include <qgroupbox.h> +#include <qfileinfo.h> + + +K3bMovixDvdBurnDialog::K3bMovixDvdBurnDialog( K3bMovixDvdDoc* doc, QWidget* parent, const char* name, bool modal ) + : K3bProjectBurnDialog( doc, parent, name, modal, true ), + m_doc(doc) +{ + prepareGui(); + + m_tempDirSelectionWidget->setSelectionMode( K3bTempDirSelectionWidget::FILE ); + + setTitle( i18n("eMovix DVD Project"), + i18n("1 file (%1)", "%n files (%1)", m_doc->movixFileItems().count()).arg(KIO::convertSize(m_doc->size())) ); + + m_movixOptionsWidget = new K3bMovixOptionsWidget( this ); + addPage( m_movixOptionsWidget, i18n("eMovix") ); + + // create image settings tab + m_imageSettingsWidget = new K3bDataImageSettingsWidget( this ); + addPage( m_imageSettingsWidget, i18n("Filesystem") ); + + // for now we just put the verify checkbox on the main page... + m_checkVerify = K3bStdGuiItems::verifyCheckBox( m_optionGroup ); + m_optionGroupLayout->addWidget( m_checkVerify ); + + QSpacerItem* spacer = new QSpacerItem( 20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding ); + m_optionGroupLayout->addItem( spacer ); + + m_tempDirSelectionWidget->setSelectionMode( K3bTempDirSelectionWidget::FILE ); + QString path = m_doc->tempDir(); + if( !path.isEmpty() ) { + m_tempDirSelectionWidget->setTempPath( path ); + } + if( !m_doc->isoOptions().volumeID().isEmpty() ) { + m_tempDirSelectionWidget->setDefaultImageFileName( m_doc->isoOptions().volumeID() + ".iso" ); + } + + connect( m_imageSettingsWidget->m_editVolumeName, SIGNAL(textChanged(const QString&)), + m_tempDirSelectionWidget, SLOT(setDefaultImageFileName(const QString&)) ); +} + + +K3bMovixDvdBurnDialog::~K3bMovixDvdBurnDialog() +{ +} + + +void K3bMovixDvdBurnDialog::loadK3bDefaults() +{ + K3bProjectBurnDialog::loadK3bDefaults(); + + m_imageSettingsWidget->load( K3bIsoOptions::defaults() ); + + m_movixOptionsWidget->loadDefaults(); + + m_checkVerify->setChecked( false ); + + toggleAll(); +} + + +void K3bMovixDvdBurnDialog::loadUserDefaults( KConfigBase* c ) +{ + K3bProjectBurnDialog::loadUserDefaults(c); + + K3bIsoOptions o = K3bIsoOptions::load( c ); + m_imageSettingsWidget->load( o ); + + m_movixOptionsWidget->loadConfig(c); + + m_checkVerify->setChecked( c->readBoolEntry( "verify data", false ) ); + + toggleAll(); +} + + +void K3bMovixDvdBurnDialog::saveUserDefaults( KConfigBase* c ) +{ + K3bProjectBurnDialog::saveUserDefaults(c); + + K3bIsoOptions o; + m_imageSettingsWidget->save( o ); + o.save( c ); + + c->writeEntry( "verify data", m_checkVerify->isChecked() ); + + m_movixOptionsWidget->saveConfig(c); +} + + +void K3bMovixDvdBurnDialog::saveSettings() +{ + K3bProjectBurnDialog::saveSettings(); + + m_movixOptionsWidget->saveSettings( m_doc ); + + // save iso image settings + K3bIsoOptions o = m_doc->isoOptions(); + m_imageSettingsWidget->save( o ); + m_doc->setIsoOptions( o ); + + m_doc->setVerifyData( m_checkVerify->isChecked() ); + + // save image file path + m_doc->setTempDir( m_tempDirSelectionWidget->tempPath() ); +} + + +void K3bMovixDvdBurnDialog::readSettings() +{ + K3bProjectBurnDialog::readSettings(); + + m_imageSettingsWidget->load( m_doc->isoOptions() ); + + m_checkVerify->setChecked( m_doc->verifyData() ); + + if( !doc()->tempDir().isEmpty() ) + m_tempDirSelectionWidget->setTempPath( doc()->tempDir() ); + else + m_tempDirSelectionWidget->setTempPath( K3b::defaultTempPath() + doc()->name() + ".iso" ); + + // first of all we need a movix installation object + const K3bMovixBin* bin = dynamic_cast<const K3bMovixBin*>( k3bcore->externalBinManager()->binObject("eMovix") ); + if( bin ) { + m_movixOptionsWidget->init( bin ); + m_movixOptionsWidget->readSettings( m_doc ); + } + else { + KMessageBox::error( this, i18n("Could not find a valid eMovix installation.") ); + slotCancelClicked(); + } + + if( doc()->size() > 4700372992LL && + ( !k3bcore->globalSettings()->overburn() || + doc()->size() > 4900000000LL ) ) + m_writerSelectionWidget->setWantedMediumType( K3bDevice::MEDIA_WRITABLE_DVD_DL ); + else + m_writerSelectionWidget->setWantedMediumType( K3bDevice::MEDIA_WRITABLE_DVD ); +} + + +void K3bMovixDvdBurnDialog::slotStartClicked() +{ + if( m_checkOnlyCreateImage->isChecked() || + m_checkCacheImage->isChecked() ) { + QFileInfo fi( m_tempDirSelectionWidget->tempPath() ); + if( fi.isDir() ) + m_tempDirSelectionWidget->setTempPath( fi.filePath() + "/image.iso" ); + + if( QFile::exists( m_tempDirSelectionWidget->tempPath() ) ) { + if( KMessageBox::warningContinueCancel( this, + i18n("Do you want to overwrite %1?").arg(m_tempDirSelectionWidget->tempPath()), + i18n("File Exists"), i18n("Overwrite") ) + != KMessageBox::Continue ) + return; + } + } + + K3bProjectBurnDialog::slotStartClicked(); +} + + +void K3bMovixDvdBurnDialog::toggleAll() +{ + K3bProjectBurnDialog::toggleAll(); + + if( m_checkSimulate->isChecked() || m_checkOnlyCreateImage->isChecked() ) { + m_checkVerify->setChecked(false); + m_checkVerify->setEnabled(false); + } + else + m_checkVerify->setEnabled(true); +} + +#include "k3bmovixdvdburndialog.moc" diff --git a/src/projects/k3bmovixdvdburndialog.h b/src/projects/k3bmovixdvdburndialog.h new file mode 100644 index 0000000..df7b456 --- /dev/null +++ b/src/projects/k3bmovixdvdburndialog.h @@ -0,0 +1,57 @@ +/* + * + * $Id: k3bmovixdvdburndialog.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + + +#ifndef _K3B_MOVIX_DVD_BURN_DIALOG_H_ +#define _K3B_MOVIX_DVD_BURN_DIALOG_H_ + +#include "k3bprojectburndialog.h" + +class K3bMovixDvdDoc; +class K3bMovixOptionsWidget; +class K3bDataImageSettingsWidget; +class QCheckBox; + + +class K3bMovixDvdBurnDialog : public K3bProjectBurnDialog +{ + Q_OBJECT + + public: + K3bMovixDvdBurnDialog( K3bMovixDvdDoc* doc, QWidget* parent = 0, const char* name = 0, bool modal = true ); + ~K3bMovixDvdBurnDialog(); + + protected slots: + void slotStartClicked(); + + protected: + void saveSettings(); + void readSettings(); + void loadK3bDefaults(); + void loadUserDefaults( KConfigBase* ); + void saveUserDefaults( KConfigBase* ); + void toggleAll(); + + private: + K3bMovixDvdDoc* m_doc; + K3bMovixOptionsWidget* m_movixOptionsWidget; + K3bDataImageSettingsWidget* m_imageSettingsWidget; + + QCheckBox* m_checkVerify; +}; + +#endif + diff --git a/src/projects/k3bmovixdvdview.cpp b/src/projects/k3bmovixdvdview.cpp new file mode 100644 index 0000000..8173199 --- /dev/null +++ b/src/projects/k3bmovixdvdview.cpp @@ -0,0 +1,48 @@ +/* + * + * $Id: k3bmovixdvdview.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bmovixdvdview.h" +#include "k3bmovixdvddoc.h" +#include "k3bmovixdvdburndialog.h" +#include <k3bmovixlistview.h> +#include <k3bfillstatusdisplay.h> + +#include <klocale.h> + + +K3bMovixDvdView::K3bMovixDvdView( K3bMovixDvdDoc* doc, QWidget *parent, const char *name ) + : K3bMovixView( doc, parent, name ) +{ + m_doc = doc; + + fillStatusDisplay()->showDvdSizes(true); + + m_listView->setNoItemText( i18n("Use drag'n'drop to add files to the project.") +"\n" + + i18n("To remove or rename files use the context menu.") + "\n" + + i18n("After that press the burn button to write the DVD.") ); +} + + +K3bMovixDvdView::~K3bMovixDvdView() +{ +} + + +K3bProjectBurnDialog* K3bMovixDvdView::newBurnDialog( QWidget* parent, const char* name ) +{ + return new K3bMovixDvdBurnDialog( m_doc, parent, name, true ); +} + +#include "k3bmovixdvdview.moc" diff --git a/src/projects/k3bmovixdvdview.h b/src/projects/k3bmovixdvdview.h new file mode 100644 index 0000000..643b259 --- /dev/null +++ b/src/projects/k3bmovixdvdview.h @@ -0,0 +1,40 @@ +/* + * + * $Id: k3bmovixdvdview.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_MOVIX_DVD_VIEW_H_ +#define _K3B_MOVIX_DVD_VIEW_H_ + +#include <k3bmovixview.h> + +class K3bMovixDvdDoc; + + +class K3bMovixDvdView : public K3bMovixView +{ + Q_OBJECT + + public: + K3bMovixDvdView( K3bMovixDvdDoc* doc, QWidget *parent = 0, const char *name = 0 ); + ~K3bMovixDvdView(); + + protected: + K3bProjectBurnDialog* newBurnDialog( QWidget* parent = 0, const char* name = 0 ); + + private: + K3bMovixDvdDoc* m_doc; +}; + +#endif diff --git a/src/projects/k3bmovixlistview.cpp b/src/projects/k3bmovixlistview.cpp new file mode 100644 index 0000000..9b943d3 --- /dev/null +++ b/src/projects/k3bmovixlistview.cpp @@ -0,0 +1,327 @@ +/* + * + * $Id: k3bmovixlistview.cpp 628165 2007-01-29 11:01:22Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bmovixlistview.h" +#include "k3bmovixdoc.h" +#include "k3bmovixfileitem.h" +#include <k3bdiritem.h> + +#include <klocale.h> +#include <kdebug.h> +#include <kio/global.h> +#include <kurldrag.h> + +#include <qdragobject.h> +#include <qptrlist.h> +#include <qevent.h> +#include <qheader.h> + + +K3bMovixListViewItem::K3bMovixListViewItem( K3bMovixDoc* doc, + K3bMovixFileItem* item, + QListView* parent, + QListViewItem* after ) + : K3bListViewItem( parent, after ), + m_doc(doc), + m_fileItem(item) +{ +} + + +K3bMovixListViewItem::K3bMovixListViewItem( K3bMovixDoc* doc, + K3bMovixFileItem* item, + QListViewItem* parent ) + : K3bListViewItem( parent ), + m_doc(doc), + m_fileItem(item) +{ +} + + +K3bMovixListViewItem::~K3bMovixListViewItem() +{ +} + + +K3bMovixFileViewItem::K3bMovixFileViewItem( K3bMovixDoc* doc, + K3bMovixFileItem* item, + QListView* parent, + QListViewItem* after ) + : K3bMovixListViewItem( doc, item, parent, after ), + KFileItem( 0, 0, KURL::fromPathOrURL(item->localPath()) ) +{ + setPixmap( 1, KFileItem::pixmap( 16, KIcon::DefaultState ) ); + setEditor( 1, LINE ); +} + + +QString K3bMovixFileViewItem::text( int col ) const +{ + // + // We add two spaces after all strings (except the once renamable) + // to increase readability + // + + switch( col ) { + case 0: + // allowing 999 files to be added. + return QString::number( doc()->indexOf( fileItem() ) ).rightJustify( 3, ' ' ); + case 1: + return fileItem()->k3bName(); + case 2: + { + if( fileItem()->isSymLink() ) + return i18n("Link to %1").arg(const_cast<K3bMovixFileViewItem*>(this)->mimeComment()) + " "; + else + return const_cast<K3bMovixFileViewItem*>(this)->mimeComment() + " "; + } + case 3: + return KIO::convertSize( fileItem()->size() ) + " "; + case 4: + return fileItem()->localPath() + " "; + case 5: + return ( fileItem()->isValid() ? fileItem()->linkDest() : fileItem()->linkDest() + i18n(" (broken)") ); + default: + return ""; + } +} + + +void K3bMovixFileViewItem::setText( int col, const QString& text ) +{ + if( col == 1 ) + fileItem()->setK3bName( text ); + + K3bMovixListViewItem::setText( col, text ); +} + + +QString K3bMovixFileViewItem::key( int, bool ) const +{ + return QString::number( doc()->indexOf( fileItem() ) ).rightJustify( 10, '0' ); +} + + + + +K3bMovixSubTitleViewItem::K3bMovixSubTitleViewItem( K3bMovixDoc* doc, + K3bMovixFileItem* item, + K3bMovixListViewItem* parent ) + : K3bMovixListViewItem( doc, item, parent ), + KFileItem( 0, 0, KURL::fromPathOrURL(item->subTitleItem()->localPath()) ) +{ +} + + +K3bMovixSubTitleViewItem::~K3bMovixSubTitleViewItem() +{ +} + + +QString K3bMovixSubTitleViewItem::text( int c ) const +{ + switch( c ) { + case 1: + return fileItem()->subTitleItem()->k3bName(); + case 2: + { + if( fileItem()->subTitleItem()->isSymLink() ) + return i18n("Link to %1").arg(const_cast<K3bMovixSubTitleViewItem*>(this)->mimeComment()); + else + return const_cast<K3bMovixSubTitleViewItem*>(this)->mimeComment(); + } + case 3: + return KIO::convertSize( fileItem()->subTitleItem()->size() ); + case 4: + return fileItem()->subTitleItem()->localPath(); + case 5: + return ( fileItem()->subTitleItem()->isValid() ? + fileItem()->subTitleItem()->linkDest() : + fileItem()->subTitleItem()->linkDest() + i18n(" (broken)") ); + default: + return ""; + } +} + + + + + + + + + + + +K3bMovixListView::K3bMovixListView( K3bMovixDoc* doc, QWidget* parent, const char* name ) + : K3bListView( parent, name ), + m_doc(doc) +{ + addColumn( i18n("No.") ); + addColumn( i18n("Name") ); + addColumn( i18n("Type") ); + addColumn( i18n("Size") ); + addColumn( i18n("Local Path") ); + addColumn( i18n("Link") ); + + setAcceptDrops( true ); + setDropVisualizer( true ); + setAllColumnsShowFocus( true ); + setDragEnabled( true ); + setItemsMovable( false ); + setSelectionModeExt( KListView::Extended ); + setSorting(0); + + setNoItemText( i18n("Use drag'n'drop to add files to the project.") +"\n" + + i18n("To remove or rename files use the context menu.") + "\n" + + i18n("After that press the burn button to write the CD.") ); + + connect( m_doc, SIGNAL(changed()), this, SLOT(slotChanged()) ); + connect( m_doc, SIGNAL(newMovixFileItems()), this, SLOT(slotNewFileItems()) ); + connect( m_doc, SIGNAL(movixItemRemoved(K3bMovixFileItem*)), this, SLOT(slotFileItemRemoved(K3bMovixFileItem*)) ); + connect( m_doc, SIGNAL(subTitleItemRemoved(K3bMovixFileItem*)), this, SLOT(slotSubTitleItemRemoved(K3bMovixFileItem*)) ); + connect( this, SIGNAL(dropped(KListView*, QDropEvent*, QListViewItem*)), + this, SLOT(slotDropped(KListView*, QDropEvent*, QListViewItem*)) ); + + // let's see what the doc already has + slotNewFileItems(); + slotChanged(); +} + + +K3bMovixListView::~K3bMovixListView() +{ +} + + +bool K3bMovixListView::acceptDrag(QDropEvent* e) const +{ + // the first is for built-in item moving, the second for dropping urls + return ( K3bListView::acceptDrag(e) || KURLDrag::canDecode(e) ); +} + + +void K3bMovixListView::slotNewFileItems() +{ + K3bMovixFileItem* lastItem = 0; + for( QPtrListIterator<K3bMovixFileItem> it( m_doc->movixFileItems() ); it.current(); ++it ) { + K3bMovixFileItem* item = it.current(); + if( !m_itemMap.contains( item ) ) + m_itemMap.insert( item, new K3bMovixFileViewItem( m_doc, item, this, lastItem ? m_itemMap[lastItem] : 0L ) ); + + if( item->subTitleItem() ) { + K3bMovixFileViewItem* vi = m_itemMap[item]; + if( vi->childCount() <= 0 ) { + (void)new K3bMovixSubTitleViewItem( m_doc, item, vi ); + vi->setOpen(true); + } + } + + lastItem = item; + } + + // arghhh + sort(); +} + + +void K3bMovixListView::slotFileItemRemoved( K3bMovixFileItem* item ) +{ + if( m_itemMap.contains( item ) ) { + K3bMovixFileViewItem* vi = m_itemMap[item]; + m_itemMap.erase(item); + delete vi; + } +} + + +void K3bMovixListView::slotSubTitleItemRemoved( K3bMovixFileItem* item ) +{ + if( m_itemMap.contains( item ) ) { + K3bMovixFileViewItem* vi = m_itemMap[item]; + if( vi->childCount() >= 1 ) + delete vi->firstChild(); + } +} + + +void K3bMovixListView::slotDropped( KListView*, QDropEvent* e, QListViewItem* after ) +{ + if( !e->isAccepted() ) + return; + + int pos; + if( after == 0L ) + pos = 0; + else + pos = m_doc->indexOf( ((K3bMovixListViewItem*)after)->fileItem() ); + + if( e->source() == viewport() ) { + QPtrList<QListViewItem> sel = selectedItems(); + QPtrListIterator<QListViewItem> it(sel); + K3bMovixFileItem* itemAfter = ( after ? ((K3bMovixListViewItem*)after)->fileItem() : 0 ); + while( it.current() ) { + K3bMovixListViewItem* vi = (K3bMovixListViewItem*)it.current(); + if( vi->isMovixFileItem() ) { + K3bMovixFileItem* item = vi->fileItem(); + m_doc->moveMovixItem( item, itemAfter ); + itemAfter = item; + } + else + kdDebug() << "(K3bMovixListView) I don't move subtitle items!" << endl; + + ++it; + } + + sort(); // This is so lame! + } + else { + KURL::List urls; + KURLDrag::decode( e, urls ); + + for( KURL::List::ConstIterator it = urls.begin(); it != urls.end(); ++it ) { + m_doc->addMovixFile( *it, pos++ ); + } + } + + // now grab that focus + setFocus(); +} + + +QDragObject* K3bMovixListView::dragObject() +{ + QPtrList<QListViewItem> list = selectedItems(); + + if( list.isEmpty() ) + return 0; + + QPtrListIterator<QListViewItem> it(list); + KURL::List urls; + + for( ; it.current(); ++it ) + urls.append( KURL( ((K3bMovixListViewItem*)it.current())->fileItem()->localPath() ) ); + + return KURLDrag::newDrag( urls, viewport() ); +} + + +void K3bMovixListView::slotChanged() +{ + header()->setShown( m_doc->root()->numFiles() > 0 ); +} + +#include "k3bmovixlistview.moc" diff --git a/src/projects/k3bmovixlistview.h b/src/projects/k3bmovixlistview.h new file mode 100644 index 0000000..7426ddb --- /dev/null +++ b/src/projects/k3bmovixlistview.h @@ -0,0 +1,100 @@ +/* + * + * $Id: k3bmovixlistview.h 628165 2007-01-29 11:01:22Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + + +#ifndef _K3B_MOVIX_LISTVIEW_H_ +#define _K3B_MOVIX_LISTVIEW_H_ + +#include <k3blistview.h> +#include <kfileitem.h> + +#include <qmap.h> + + +class K3bMovixDoc; +class K3bMovixFileItem; +class K3bFileItem; + + +class K3bMovixListViewItem : public K3bListViewItem +{ + public: + K3bMovixListViewItem( K3bMovixDoc* doc, K3bMovixFileItem*, QListView* parent, QListViewItem* after ); + K3bMovixListViewItem( K3bMovixDoc* doc, K3bMovixFileItem*, QListViewItem* parent ); + ~K3bMovixListViewItem(); + + K3bMovixFileItem* fileItem() const { return m_fileItem; } + K3bMovixDoc* doc() const { return m_doc; } + + virtual bool isMovixFileItem() const { return true; } + + private: + K3bMovixDoc* m_doc; + K3bMovixFileItem* m_fileItem; +}; + + +class K3bMovixFileViewItem : public K3bMovixListViewItem, public KFileItem +{ + public: + K3bMovixFileViewItem( K3bMovixDoc* doc, K3bMovixFileItem*, QListView* parent, QListViewItem* ); + + QString text( int ) const; + void setText(int col, const QString& text ); + + /** always sort according to the playlist order */ + QString key( int, bool ) const; +}; + +class K3bMovixSubTitleViewItem : public K3bMovixListViewItem, public KFileItem +{ + public: + K3bMovixSubTitleViewItem( K3bMovixDoc*, K3bMovixFileItem* item, K3bMovixListViewItem* parent ); + ~K3bMovixSubTitleViewItem(); + + QString text( int ) const; + + bool isMovixFileItem() const { return false; } +}; + + +class K3bMovixListView : public K3bListView +{ + Q_OBJECT + + public: + K3bMovixListView( K3bMovixDoc* doc, QWidget* parent = 0, const char* name = 0 ); + ~K3bMovixListView(); + + QDragObject* dragObject(); + + protected: + bool acceptDrag(QDropEvent* e) const; + + private slots: + void slotNewFileItems(); + void slotFileItemRemoved( K3bMovixFileItem* ); + void slotSubTitleItemRemoved( K3bMovixFileItem* ); + void slotDropped( KListView*, QDropEvent* e, QListViewItem* after ); + void slotChanged(); + + private: + K3bMovixDoc* m_doc; + + QMap<K3bFileItem*, K3bMovixFileViewItem*> m_itemMap; +}; + +#endif diff --git a/src/projects/k3bmovixoptionswidget.cpp b/src/projects/k3bmovixoptionswidget.cpp new file mode 100644 index 0000000..131af6b --- /dev/null +++ b/src/projects/k3bmovixoptionswidget.cpp @@ -0,0 +1,243 @@ +/* + * + * $Id: k3bmovixoptionswidget.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bmovixoptionswidget.h" +#include "k3bmovixdoc.h" +#include "k3bmovixprogram.h" + +#include <kcombobox.h> +#include <klocale.h> +#include <kconfig.h> +#include <kglobal.h> +#include <kdebug.h> + +#include <qcheckbox.h> +#include <qspinbox.h> +#include <qstringlist.h> +#include <qmap.h> +#include <qlabel.h> + + +class K3bMovixOptionsWidget::LanguageSelectionHelper +{ +public: + LanguageSelectionHelper( QComboBox* box ) + : m_box(box) { + } + + void insertLanguages( const QStringList& langs ) { + m_box->clear(); + m_langMap.clear(); + + for( QStringList::const_iterator it = langs.begin(); it != langs.end(); ++it ) { + if( *it == i18n("default") ) + m_box->insertItem( *it ); + else { + QString lang = KGlobal::locale()->twoAlphaToLanguageName( *it ); + if( lang.isEmpty() ) + lang = *it; + + m_langMap[m_box->count()] = *it; + m_indexMap[*it] = m_box->count(); + m_box->insertItem( lang ); + } + } + } + + QString selectedLanguage() const { + if( m_box->currentItem() == 0 ) + return i18n("default"); + else + return m_langMap[m_box->currentItem()]; + } + + void setLanguage( const QString& l ) { + QMap<QString,int>::const_iterator it = m_indexMap.find(l); + if( it == m_indexMap.end() ) + m_box->setCurrentItem( 0 ); + else + m_box->setCurrentItem( it.data() ); + } + +private: + QComboBox* m_box; + QMap<int,QString> m_langMap; + QMap<QString,int> m_indexMap; +}; + + +K3bMovixOptionsWidget::K3bMovixOptionsWidget( QWidget* parent, const char* name ) + : base_K3bMovixOptionsWidget( parent, name ) +{ + m_keyboardLangHelper = new LanguageSelectionHelper( m_comboKeyboardLayout ); + m_helpLangHelper = new LanguageSelectionHelper( m_comboBootMessageLanguage ); +} + + +K3bMovixOptionsWidget::~K3bMovixOptionsWidget() +{ + delete m_keyboardLangHelper; + delete m_helpLangHelper; +} + + +void K3bMovixOptionsWidget::init( const K3bMovixBin* bin ) +{ + m_labelAudioBackground->setShown( bin->hasFeature( "newfiles" ) ); + m_comboAudioBackground->setShown( bin->hasFeature( "newfiles" ) ); + m_labelKeyboardLayout->setShown( bin->hasFeature( "newfiles" ) ); + m_comboKeyboardLayout->setShown( bin->hasFeature( "newfiles" ) ); + + m_comboSubtitleFontset->insertStringList( bin->supportedSubtitleFonts() ); + m_helpLangHelper->insertLanguages( bin->supportedLanguages() ); + m_comboDefaultBootLabel->insertStringList( bin->supportedBootLabels() ); + m_keyboardLangHelper->insertLanguages( bin->supportedKbdLayouts() ); + m_comboAudioBackground->insertStringList( bin->supportedBackgrounds() ); +} + + +void K3bMovixOptionsWidget::readSettings( K3bMovixDoc* doc ) +{ + m_comboSubtitleFontset->setCurrentItem( doc->subtitleFontset(), false ); + m_spinLoop->setValue( doc->loopPlaylist() ); + m_editAdditionalMplayerOptions->setText( doc->additionalMPlayerOptions() ); + m_editUnwantedMplayerOptions->setText( doc->unwantedMPlayerOptions() ); + m_helpLangHelper->setLanguage( doc->bootMessageLanguage() ); + m_comboDefaultBootLabel->setCurrentItem( doc->defaultBootLabel(), false ); + m_comboAudioBackground->setCurrentItem( doc->audioBackground(), false ); + m_keyboardLangHelper->setLanguage( doc->keyboardLayout() ); + m_checkShutdown->setChecked( doc->shutdown() ); + m_checkReboot->setChecked( doc->reboot() ); + m_checkEject->setChecked( doc->ejectDisk() ); + m_checkRandomPlay->setChecked( doc->randomPlay() ); + m_checkNoDma->setChecked( doc->noDma() ); +} + + +void K3bMovixOptionsWidget::saveSettings( K3bMovixDoc* doc ) +{ + doc->setShutdown( m_checkShutdown->isChecked() ); + doc->setReboot( m_checkReboot->isChecked() ); + doc->setEjectDisk( m_checkEject->isChecked() ); + doc->setSubtitleFontset( m_comboSubtitleFontset->currentText() ); + doc->setBootMessageLanguage( m_helpLangHelper->selectedLanguage() ); + doc->setDefaultBootLabel( m_comboDefaultBootLabel->currentText() ); + doc->setKeyboardLayout( m_keyboardLangHelper->selectedLanguage() ); + doc->setAudioBackground( m_comboAudioBackground->currentText() ); + doc->setAdditionalMPlayerOptions( m_editAdditionalMplayerOptions->text() ); + doc->setUnwantedMPlayerOptions( m_editUnwantedMplayerOptions->text() ); + doc->setLoopPlaylist( m_spinLoop->value() ); + doc->setRandomPlay( m_checkRandomPlay->isChecked() ); + doc->setNoDma( m_checkNoDma->isChecked() ); +} + + +void K3bMovixOptionsWidget::loadDefaults() +{ + m_comboSubtitleFontset->setCurrentItem( 0 ); // default + m_comboAudioBackground->setCurrentItem( 0 ); // default + m_comboKeyboardLayout->setCurrentItem( 0 ); // default + m_spinLoop->setValue( 1 ); + m_editAdditionalMplayerOptions->setText( QString::null ); + m_editUnwantedMplayerOptions->setText( QString::null ); + m_comboBootMessageLanguage->setCurrentItem( 0 ); // default + m_comboDefaultBootLabel->setCurrentItem( 0 ); // default + m_checkShutdown->setChecked( false ); + m_checkReboot->setChecked( false ); + m_checkEject->setChecked( false ); + m_checkRandomPlay->setChecked( false ); + m_checkNoDma->setChecked( false ); +} + + +void K3bMovixOptionsWidget::loadConfig( KConfigBase* c ) +{ + QString s = c->readEntry("subtitle_fontset"); + if( !s.isEmpty() && s != "none" && m_comboSubtitleFontset->contains(s) ) + m_comboSubtitleFontset->setCurrentItem( s, false ); + else + m_comboSubtitleFontset->setCurrentItem( 0 ); // none + + m_spinLoop->setValue( c->readNumEntry("loop", 1 ) ); + m_editAdditionalMplayerOptions->setText( c->readEntry( "additional_mplayer_options" ) ); + m_editUnwantedMplayerOptions->setText( c->readEntry( "unwanted_mplayer_options" ) ); + + s = c->readEntry("boot_message_language"); + m_helpLangHelper->setLanguage( s == "default" ? QString::null : s ); + + s = c->readEntry( "default_boot_label" ); + if( !s.isEmpty() && s != "default" && m_comboDefaultBootLabel->contains(s) ) + m_comboDefaultBootLabel->setCurrentItem( s, false ); + else + m_comboDefaultBootLabel->setCurrentItem( 0 ); // default + + s = c->readEntry("audio_background"); + if( !s.isEmpty() && s != "default" && m_comboAudioBackground->contains(s) ) + m_comboAudioBackground->setCurrentItem( s, false ); + else + m_comboAudioBackground->setCurrentItem( 0 ); // default + + s = c->readEntry("keyboard_layout"); + m_keyboardLangHelper->setLanguage( s == "default" ? QString::null : s ); + + m_checkShutdown->setChecked( c->readBoolEntry( "shutdown", false) ); + m_checkReboot->setChecked( c->readBoolEntry( "reboot", false ) ); + m_checkEject->setChecked( c->readBoolEntry( "eject", false ) ); + m_checkRandomPlay->setChecked( c->readBoolEntry( "random_play", false ) ); + m_checkNoDma->setChecked( c->readBoolEntry( "no_dma", false ) ); +} + + +void K3bMovixOptionsWidget::saveConfig( KConfigBase* c ) +{ + if( m_comboSubtitleFontset->currentItem() == 0 ) + c->writeEntry( "subtitle_fontset", "none" ); + else + c->writeEntry( "subtitle_fontset", m_comboSubtitleFontset->currentText() ); + + c->writeEntry( "loop", m_spinLoop->value() ); + c->writeEntry( "additional_mplayer_options", m_editAdditionalMplayerOptions->text() ); + c->writeEntry( "unwanted_mplayer_options", m_editUnwantedMplayerOptions->text() ); + + if( m_comboBootMessageLanguage->currentItem() == 0 ) + c->writeEntry( "boot_message_language", "default" ); + else + c->writeEntry( "boot_message_language", m_helpLangHelper->selectedLanguage() ); + + if( m_comboDefaultBootLabel->currentItem() == 0 ) + c->writeEntry( "default_boot_label", "default" ); + else + c->writeEntry( "default_boot_label", m_comboDefaultBootLabel->currentText() ); + + if( m_comboAudioBackground->currentItem() == 0 ) + c->writeEntry( "audio_background", "default" ); + else + c->writeEntry( "audio_background", m_comboAudioBackground->currentText() ); + + if( m_comboKeyboardLayout->currentItem() == 0 ) + c->writeEntry( "keyboard_layout", "default" ); + else + c->writeEntry( "keyboard_layout", m_keyboardLangHelper->selectedLanguage() ); + + c->writeEntry( "shutdown", m_checkShutdown->isChecked() ); + c->writeEntry( "reboot", m_checkReboot->isChecked() ); + c->writeEntry( "eject", m_checkEject->isChecked() ); + c->writeEntry( "random_play", m_checkRandomPlay->isChecked() ); + c->writeEntry( "no_dma", m_checkNoDma->isChecked() ); +} + +#include "k3bmovixoptionswidget.moc" + diff --git a/src/projects/k3bmovixoptionswidget.h b/src/projects/k3bmovixoptionswidget.h new file mode 100644 index 0000000..3b9e367 --- /dev/null +++ b/src/projects/k3bmovixoptionswidget.h @@ -0,0 +1,50 @@ +/* + * + * $Id: k3bmovixoptionswidget.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_MOVIX_OPTIONSWIDGET_H_ +#define _K3B_MOVIX_OPTIONSWIDGET_H_ + +#include "base_k3bmovixoptionswidget.h" + +class K3bMovixDoc; +class K3bMovixBin; +class KConfigBase; + + +class K3bMovixOptionsWidget : public base_K3bMovixOptionsWidget +{ + Q_OBJECT + + public: + K3bMovixOptionsWidget( QWidget* parent = 0, const char* name = 0 ); + ~K3bMovixOptionsWidget(); + + public slots: + void init( const K3bMovixBin* ); + void readSettings( K3bMovixDoc* ); + void saveSettings( K3bMovixDoc* ); + void loadConfig( KConfigBase* c ); + void saveConfig( KConfigBase* c ); + void loadDefaults(); + + private: + class LanguageSelectionHelper; + LanguageSelectionHelper* m_keyboardLangHelper; + LanguageSelectionHelper* m_helpLangHelper; +}; + + +#endif diff --git a/src/projects/k3bmovixview.cpp b/src/projects/k3bmovixview.cpp new file mode 100644 index 0000000..825b10b --- /dev/null +++ b/src/projects/k3bmovixview.cpp @@ -0,0 +1,192 @@ +/* + * + * $Id: k3bmovixview.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bmovixview.h" +#include "k3bmovixdoc.h" +#include "k3bmovixlistview.h" +#include "k3bmovixburndialog.h" +#include "k3bmovixfileitem.h" + +#include <k3bfillstatusdisplay.h> +#include <k3bdatapropertiesdialog.h> +#include <k3bprojectplugin.h> +#include <k3btoolbox.h> + +#include <klocale.h> +#include <kdebug.h> +#include <kaction.h> +#include <kpopupmenu.h> +#include <kfiledialog.h> +#include <kmessagebox.h> +#include <kurl.h> + +#include <qlayout.h> +#include <qlabel.h> +#include <qlineedit.h> + + +K3bMovixView::K3bMovixView( K3bMovixDoc* doc, QWidget* parent, const char* name ) + : K3bView( doc, parent, name ), + m_doc(doc) +{ + m_listView = new K3bMovixListView( m_doc, this ); + setMainWidget( m_listView ); + + connect( m_listView, SIGNAL(contextMenuRequested( QListViewItem*, const QPoint& , int )), + this, SLOT(slotContextMenuRequested(QListViewItem*, const QPoint& , int )) ); + + + // setup actions + m_actionProperties = new KAction( i18n("Properties"), "misc", + 0, this, SLOT(showPropertiesDialog()), + actionCollection(), "movix_show_props" ); + m_actionRemove = new KAction( i18n( "Remove" ), "editdelete", + Key_Delete, this, SLOT(slotRemoveItems()), + actionCollection(), "movix_remove_item" ); + m_actionRemoveSubTitle = new KAction( i18n( "Remove Subtitle File" ), "editdelete", + 0, this, SLOT(slotRemoveSubTitleItems()), + actionCollection(), "movix_remove_subtitle_item" ); + m_actionAddSubTitle = new KAction( i18n("Add Subtitle File..."), "", + 0, this, SLOT(slotAddSubTitleFile()), + actionCollection(), "movix_add_subtitle" ); + + m_popupMenu = new KPopupMenu( this ); + m_actionRemove->plug( m_popupMenu ); + m_actionRemoveSubTitle->plug( m_popupMenu ); + m_actionAddSubTitle->plug( m_popupMenu ); + m_popupMenu->insertSeparator(); + m_actionProperties->plug( m_popupMenu ); + m_popupMenu->insertSeparator(); + // k3bMain()->actionCollection()->action("file_burn")->plug( m_popupMenu ); + + + addPluginButtons( K3bProjectPlugin::MOVIX_CD ); + + toolBox()->addStretch(); + + m_volumeIDEdit = new QLineEdit( doc->isoOptions().volumeID(), toolBox() ); + toolBox()->addLabel( i18n("Volume Name:") ); + toolBox()->addSpacing(); + toolBox()->addWidget( m_volumeIDEdit ); + connect( m_volumeIDEdit, SIGNAL(textChanged(const QString&)), + m_doc, + SLOT(setVolumeID(const QString&)) ); + + connect( m_doc, SIGNAL(changed()), this, SLOT(slotDocChanged()) ); +} + + +K3bMovixView::~K3bMovixView() +{ +} + + +void K3bMovixView::slotContextMenuRequested(QListViewItem* item, const QPoint& p, int ) +{ + if( item ) { + m_actionRemove->setEnabled(true); + m_actionRemoveSubTitle->setEnabled( true ); + } + else { + m_actionRemove->setEnabled(false); + m_actionRemoveSubTitle->setEnabled( false ); + } + + m_popupMenu->popup( p ); +} + + +void K3bMovixView::showPropertiesDialog() +{ + K3bFileItem* dataItem = 0; + + // get selected item + if( K3bMovixListViewItem* viewItem = dynamic_cast<K3bMovixListViewItem*>( m_listView->selectedItems().first() ) ) { + dataItem = viewItem->fileItem(); + } + + if( dataItem ) { + K3bDataPropertiesDialog d( dataItem, this ); + d.exec(); + } + else + slotProperties(); +} + + +void K3bMovixView::slotRemoveItems() +{ + QPtrList<QListViewItem> list = m_listView->selectedItems(); + QPtrListIterator<QListViewItem> it(list); + + if( list.isEmpty() ) + kdDebug() << "nothing to remove" << endl; + + for( ; it.current(); ++it ) { + K3bMovixListViewItem* vi = static_cast<K3bMovixListViewItem*>(*it); + if( vi->isMovixFileItem() ) + m_doc->removeItem( vi->fileItem() ); + else + m_doc->removeSubTitleItem( ((K3bMovixSubTitleViewItem*)*it)->fileItem() ); + } +} + + +void K3bMovixView::slotRemoveSubTitleItems() +{ + QPtrList<QListViewItem> list = m_listView->selectedItems(); + QPtrListIterator<QListViewItem> it(list); + + if( list.isEmpty() ) + kdDebug() << "nothing to remove" << endl; + + for( ; it.current(); ++it ) { + K3bMovixListViewItem* vi = static_cast<K3bMovixListViewItem*>(*it); + m_doc->removeSubTitleItem( vi->fileItem() ); + } +} + + +void K3bMovixView::slotAddSubTitleFile() +{ + QListViewItem* item = m_listView->selectedItems().first(); + if( K3bMovixListViewItem* vi = dynamic_cast<K3bMovixListViewItem*>(item) ) { + + KURL url = KFileDialog::getOpenURL(); + if( url.isValid() ) { + if( url.isLocalFile() ) + m_doc->addSubTitleItem( vi->fileItem(), url ); + else + KMessageBox::error( 0, i18n("K3b currently only supports local files.") ); + } + } +} + + +K3bProjectBurnDialog* K3bMovixView::newBurnDialog( QWidget* parent, const char* name ) +{ + return new K3bMovixBurnDialog( m_doc, parent, name, true ); +} + + +void K3bMovixView::slotDocChanged() +{ + // do not update the editor in case it changed the volume id itself + if( m_doc->isoOptions().volumeID() != m_volumeIDEdit->text() ) + m_volumeIDEdit->setText( m_doc->isoOptions().volumeID() ); +} + +#include "k3bmovixview.moc" diff --git a/src/projects/k3bmovixview.h b/src/projects/k3bmovixview.h new file mode 100644 index 0000000..e174b64 --- /dev/null +++ b/src/projects/k3bmovixview.h @@ -0,0 +1,65 @@ +/* + * + * $Id: k3bmovixview.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + + +#ifndef _K3B_MOVIX_VIEW_H_ +#define _K3B_MOVIX_VIEW_H_ + +#include <k3bview.h> + +class K3bMovixDoc; +class K3bMovixListView; +class KAction; +class KPopupMenu; +class QListViewItem; +class QPoint; +class QLineEdit; + + +class K3bMovixView : public K3bView +{ + Q_OBJECT + + public: + K3bMovixView( K3bMovixDoc* doc, QWidget* parent = 0, const char* name = 0 ); + virtual ~K3bMovixView(); + + private slots: + void slotContextMenuRequested(QListViewItem*, const QPoint& , int ); + void slotRemoveItems(); + void slotRemoveSubTitleItems(); + void showPropertiesDialog(); + void slotAddSubTitleFile(); + void slotDocChanged(); + + protected: + virtual K3bProjectBurnDialog* newBurnDialog( QWidget* parent = 0, const char* name = 0 ); + + K3bMovixListView* m_listView; + + private: + K3bMovixDoc* m_doc; + + KAction* m_actionProperties; + KAction* m_actionRemove; + KAction* m_actionRemoveSubTitle; + KAction* m_actionAddSubTitle; + KPopupMenu* m_popupMenu; + + QLineEdit* m_volumeIDEdit; +}; + +#endif diff --git a/src/projects/k3bmusicbrainzjob.cpp b/src/projects/k3bmusicbrainzjob.cpp new file mode 100644 index 0000000..b52c766 --- /dev/null +++ b/src/projects/k3bmusicbrainzjob.cpp @@ -0,0 +1,287 @@ +/* + * + * $Id: k3bmusicbrainzjob.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include <config.h> + +#ifdef HAVE_MUSICBRAINZ + +#include "k3bmusicbrainzjob.h" +#include "k3btrm.h" +#include "k3bmusicbrainz.h" + +#include <k3bthread.h> +#include <k3bthreadjob.h> +#include <k3baudiotrack.h> +#include <k3baudiodatasource.h> +#include <k3bsimplejobhandler.h> + +#include <kmessagebox.h> +#include <kinputdialog.h> +#include <klocale.h> + + +// determine one trm +class K3bMusicBrainzJob::TRMThread : public K3bThread +{ +public: + TRMThread(); + + void init() { + m_canceled = false; + } + void run(); + void cancel(); + const QCString& signature() const { + return m_trm.signature(); + } + + K3bAudioTrack* track; + +private: + bool m_canceled; + K3bTRM m_trm; +}; + + +class K3bMusicBrainzJob::MusicBrainzThread : public K3bThread +{ +public: + MusicBrainzThread() { + } + + void run(); + + void setSignature( const QCString& sig ) { + m_sig = sig; + } + + unsigned int results() { + return m_results; + } + + const QString& title( unsigned int i = 0 ) const { + return m_mb.title( i ); + } + + const QString& artist( unsigned int i = 0 ) const { + return m_mb.artist( i ); + } + +private: + K3bMusicBrainz m_mb; + int m_results; + QCString m_sig; +}; + + +K3bMusicBrainzJob::TRMThread::TRMThread() + : m_canceled(false) +{ +} + + +void K3bMusicBrainzJob::TRMThread::run() +{ + emitStarted(); + + track->seek(0); + m_trm.start( track->length() ); + + char buffer[2352*10]; + int len = 0; + long long dataRead = 0; + while( !m_canceled && + (len = track->read( buffer, 2352*10 )) > 0 ) { + + dataRead += len; + + // swap data + char buf; + for( int i = 0; i < len-1; i+=2 ) { + buf = buffer[i]; + buffer[i] = buffer[i+1]; + buffer[i+1] = buf; + } + + if( m_trm.generate( buffer, len ) ) { + len = 0; + break; + } + + // FIXME: useless since libmusicbrainz does never need all the data + emitPercent( 100*dataRead/track->length().audioBytes() ); + } + + if( m_canceled ) { + emitCanceled(); + emitFinished( false ); + } + else if( len == 0 ) { + emitFinished( m_trm.finalize() ); + } + else + emitFinished( false ); +} + + +void K3bMusicBrainzJob::TRMThread::cancel() +{ + m_canceled = true; +} + + +void K3bMusicBrainzJob::MusicBrainzThread::run() +{ + emitStarted(); + m_results = m_mb.query( m_sig ); + emitFinished( m_results > 0 ); +} + + + + +// cannot use this as parent for the K3bSimpleJobHandler since this has not been constructed yet +K3bMusicBrainzJob::K3bMusicBrainzJob( QWidget* parent, const char* name ) + : K3bJob( new K3bSimpleJobHandler( 0 ), parent, name ), + m_canceled( false ) +{ + m_trmThread = new TRMThread(); + m_mbThread = new MusicBrainzThread(); + m_trmJob = new K3bThreadJob( m_trmThread, this, this ); + m_mbJob = new K3bThreadJob( m_mbThread, this, this ); + + connect( m_trmJob, SIGNAL(percent(int)), this, SIGNAL(subPercent(int)) ); + connect( m_trmJob, SIGNAL(percent(int)), this, SLOT(slotTrmPercent(int)) ); + connect( m_trmJob, SIGNAL(finished(bool)), this, SLOT(slotTrmJobFinished(bool)) ); + connect( m_mbJob, SIGNAL(finished(bool)), this, SLOT(slotMbJobFinished(bool)) ); +} + + +K3bMusicBrainzJob::~K3bMusicBrainzJob() +{ + delete m_trmThread; + delete m_trmJob; + delete m_mbThread; + delete m_mbJob; + delete jobHandler(); +} + + +void K3bMusicBrainzJob::start() +{ + jobStarted(); + + m_canceled = false; + + m_trmThread->track = m_tracks.first(); + + emit infoMessage( i18n("Generating fingerprint for track %1.") + .arg(m_tracks.current()->trackNumber()), INFO ); + + m_trmJob->start(); +} + + +void K3bMusicBrainzJob::cancel() +{ + m_canceled = true; + m_trmJob->cancel(); + m_mbJob->cancel(); +} + + +void K3bMusicBrainzJob::slotTrmPercent( int p ) +{ + // the easy way (inaccurate) + emit percent( (100*m_tracks.at() + p) / m_tracks.count() ); +} + + +void K3bMusicBrainzJob::slotTrmJobFinished( bool success ) +{ + if( success ) { + // now query musicbrainz + m_mbThread->setSignature( m_trmThread->signature() ); + emit infoMessage( i18n("Querying MusicBrainz for track %1.") + .arg(m_tracks.current()->trackNumber()), INFO ); + m_mbJob->start(); + } + else { + if( hasBeenCanceled() ) + emit canceled(); + jobFinished(false); + } +} + + +void K3bMusicBrainzJob::slotMbJobFinished( bool success ) +{ + if( hasBeenCanceled() ) { + emit canceled(); + jobFinished(false); + } + else { + emit trackFinished( m_tracks.current(), success ); + + if( success ) { + // found entries + QStringList resultStrings, resultStringsUnique; + for( unsigned int i = 0; i < m_mbThread->results(); ++i ) + resultStrings.append( m_mbThread->artist(i) + " - " + m_mbThread->title(i) ); + + // since we are only using the title and the artist a lot of entries are alike to us + // so to not let the user have to choose between two equal entries we trim the list down + for( QStringList::const_iterator it = resultStrings.begin(); + it != resultStrings.end(); ++it ) + if( resultStringsUnique.find( *it ) == resultStringsUnique.end() ) + resultStringsUnique.append( *it ); + + QString s; + bool ok = true; + if( resultStringsUnique.count() > 1 ) + s = KInputDialog::getItem( i18n("MusicBrainz Query"), + i18n("Found multiple matches for track %1 (%2). Please select one.") + .arg(m_tracks.current()->trackNumber()) + .arg(m_tracks.current()->firstSource()->sourceComment()), + resultStringsUnique, + 0, + false, + &ok, + dynamic_cast<QWidget*>(parent()) ); + else + s = resultStringsUnique.first(); + + if( ok ) { + int i = resultStrings.findIndex( s ); + m_tracks.current()->setTitle( m_mbThread->title(i) ); + m_tracks.current()->setArtist( m_mbThread->artist(i) ); + } + } + + // query next track + if( m_tracks.next() ) { + emit infoMessage( i18n("Generating fingerprint for track %1.") + .arg(m_tracks.current()->trackNumber()), INFO ); + m_trmThread->track = m_tracks.current(); + m_trmJob->start(); + } + else + jobFinished( true ); + } +} + +#include "k3bmusicbrainzjob.moc" + +#endif diff --git a/src/projects/k3bmusicbrainzjob.h b/src/projects/k3bmusicbrainzjob.h new file mode 100644 index 0000000..5007a47 --- /dev/null +++ b/src/projects/k3bmusicbrainzjob.h @@ -0,0 +1,89 @@ +/* + * + * $Id: k3bmusicbrainzjob.h 630384 2007-02-05 09:33:17Z mlaurent $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_MUSICBRAINZ_JOB_H_ +#define _K3B_MUSICBRAINZ_JOB_H_ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#ifdef HAVE_MUSICBRAINZ + +#include <k3bjob.h> + + +class K3bAudioTrack; +class K3bThreadJob; +class QWidget; + + +/** + * This job tries to determine K3bAudioTrack's title and artist using + * Musicbrainz. + */ +class K3bMusicBrainzJob : public K3bJob +{ + Q_OBJECT + + public: + /** + * \param parent since we do not use this job with a normal progressdialog we need a widget + * as parent + */ + K3bMusicBrainzJob( QWidget* parent = 0, const char* name = 0 ); + ~K3bMusicBrainzJob(); + + bool hasBeenCanceled() const { return m_canceled; } + + signals: + /** + * Emitted for each track. This is signal can be used + * to display further information. + * + * \param track The track for which metadata was searched. + * \param success True if metadata was found + */ + void trackFinished( K3bAudioTrack* track, bool success ); + + public slots: + void start(); + void cancel(); + + void setTracks( const QPtrList<K3bAudioTrack>& tracks ) { m_tracks = tracks; } + + private slots: + void slotTrmPercent( int p ); + void slotTrmJobFinished( bool success ); + void slotMbJobFinished( bool success ); + + private: + class TRMThread; + class MusicBrainzThread; + TRMThread* m_trmThread; + MusicBrainzThread* m_mbThread; + + K3bThreadJob* m_trmJob; + K3bThreadJob* m_mbJob; + + QPtrList<K3bAudioTrack> m_tracks; + + bool m_canceled; +}; + + +#endif + +#endif diff --git a/src/projects/k3bprojectburndialog.cpp b/src/projects/k3bprojectburndialog.cpp new file mode 100644 index 0000000..09444b0 --- /dev/null +++ b/src/projects/k3bprojectburndialog.cpp @@ -0,0 +1,413 @@ +/* + * + * $Id: k3bprojectburndialog.cpp 630454 2007-02-05 13:06:45Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bprojectburndialog.h" +#include "k3bdoc.h" +#include "k3bburnprogressdialog.h" +#include "k3bjob.h" +#include "k3btempdirselectionwidget.h" +#include "k3bwriterselectionwidget.h" +#include "k3bstdguiitems.h" +#include "k3bwritingmodewidget.h" +#include <k3bdevice.h> +#include <k3bdevicemanager.h> +#include <k3bglobals.h> +#include <k3bcore.h> + +#include <qstring.h> +#include <qpushbutton.h> +#include <qtooltip.h> +#include <qwhatsthis.h> +#include <qlayout.h> +#include <qvbox.h> +#include <qcheckbox.h> +#include <qtabwidget.h> +#include <qgroupbox.h> +#include <qspinbox.h> +#include <qlabel.h> + +#include <klocale.h> +#include <kconfig.h> +#include <kmessagebox.h> +#include <kguiitem.h> +#include <kstdguiitem.h> +#include <kdebug.h> +#include <kglobal.h> +#include <kstandarddirs.h> +#include <kapplication.h> +#include <kiconloader.h> + + +K3bProjectBurnDialog::K3bProjectBurnDialog( K3bDoc* doc, QWidget *parent, const char *name, bool modal, bool dvd ) + : K3bInteractionDialog( parent, name, i18n("Project"), QString::null, + START_BUTTON|SAVE_BUTTON|CANCEL_BUTTON, START_BUTTON, + "default " + doc->typeString() + " settings", modal ), + m_writerSelectionWidget(0), + m_tempDirSelectionWidget(0), + m_dvd(dvd) +{ + m_doc = doc; + + /** + * There is at least one scenario in which this is useful: change the volume id (or rename a file) + * without explicit confirmation (by pressing enter for example). Then click the "burn" button. + * The "focus out" event which results in a rename in the listviewitem will be processed after the + * initialization of the burn dialog. Thus, the burn dialog will read the old volume id. + */ + setDelayedInitialization( true ); + + setButtonGui( SAVE_BUTTON, + KStdGuiItem::close() ); + setButtonText( SAVE_BUTTON, + i18n("Close"), + i18n("Save Settings and close"), + i18n("Saves the settings to the project and closes the dialog.") ); + setButtonGui( CANCEL_BUTTON, KStdGuiItem::cancel() ); + setButtonText( CANCEL_BUTTON, + i18n("Cancel"), + i18n("Discard all changes and close"), + i18n("Discards all changes made in the dialog and closes it.") ); + + m_job = 0; +} + + +K3bProjectBurnDialog::~K3bProjectBurnDialog(){ +} + + +void K3bProjectBurnDialog::init() +{ + readSettings(); +// if( !m_writerSelectionWidget->writerDevice() ) +// m_checkOnlyCreateImage->setChecked(true); +} + + +void K3bProjectBurnDialog::slotWriterChanged() +{ + slotToggleAll(); +} + + +void K3bProjectBurnDialog::slotWritingAppChanged( int ) +{ + slotToggleAll(); +} + + +void K3bProjectBurnDialog::toggleAll() +{ + K3bDevice::Device* dev = m_writerSelectionWidget->writerDevice(); + if( dev ) { + if( m_dvd ) { + if( (dev->type() & (K3bDevice::DVDPR|K3bDevice::DVDPRW)) && + !(dev->type() & (K3bDevice::DVDR|K3bDevice::DVDRW)) ) { + // no simulation support for DVD+R(W) only drives + m_checkSimulate->setChecked(false); + m_checkSimulate->setEnabled(false); + } + else { + m_checkSimulate->setEnabled(true); + } + } + + setButtonEnabled( START_BUTTON, true ); + } + else + setButtonEnabled( START_BUTTON, false ); + + m_writingModeWidget->determineSupportedModesFromMedium( dev ); + + m_writingModeWidget->setDisabled( m_checkOnlyCreateImage->isChecked() ); + m_checkSimulate->setDisabled( m_checkOnlyCreateImage->isChecked() ); + m_checkCacheImage->setDisabled( m_checkOnlyCreateImage->isChecked() ); + m_checkRemoveBufferFiles->setDisabled( m_checkOnlyCreateImage->isChecked() || !m_checkCacheImage->isChecked() ); + if( m_checkOnlyCreateImage->isChecked() ) { + m_checkRemoveBufferFiles->setChecked(false); + setButtonEnabled( START_BUTTON, true ); + } + m_tempDirSelectionWidget->setDisabled( !m_checkCacheImage->isChecked() && !m_checkOnlyCreateImage->isChecked() ); + m_writerSelectionWidget->setDisabled( m_checkOnlyCreateImage->isChecked() ); + m_spinCopies->setDisabled( m_checkSimulate->isChecked() || m_checkOnlyCreateImage->isChecked() ); + + if( !m_dvd ) { + // we only support DAO with cdrdao + if( m_writerSelectionWidget->writingApp() == K3b::CDRDAO ) + m_writingModeWidget->setSupportedModes( K3b::DAO ); + } + + if( m_checkOnlyCreateImage->isChecked() ) + setButtonText( START_BUTTON, + i18n("Start"), + i18n("Start the image creation") ); + else + setButtonText( START_BUTTON, i18n("Burn"), + i18n("Start the burning process") ); +} + + +int K3bProjectBurnDialog::execBurnDialog( bool burn ) +{ + if( burn && m_job == 0 ) { + setButtonShown( START_BUTTON, true ); + setDefaultButton( START_BUTTON ); + } + else { + setButtonShown( START_BUTTON, false ); + setDefaultButton( SAVE_BUTTON ); + } + + return K3bInteractionDialog::exec(false); +} + + +void K3bProjectBurnDialog::slotSaveClicked() +{ + saveSettings(); + done( Saved ); +} + + +void K3bProjectBurnDialog::slotCancelClicked() +{ + done( Canceled ); +} + + +void K3bProjectBurnDialog::slotStartClicked() +{ + saveSettings(); + + if( m_tempDirSelectionWidget ) { + if( !doc()->onTheFly() || doc()->onlyCreateImages() ) { + // + // check if the temp dir exists + // + QString tempDir = m_tempDirSelectionWidget->tempDirectory(); + if( !QFile::exists( tempDir ) ) { + if( KMessageBox::warningYesNo( this, i18n("Image folder '%1' does not exist. Do you want K3b to create it?").arg( tempDir ) ) + == KMessageBox::Yes ) { + if( !KStandardDirs::makeDir( tempDir ) ) { + KMessageBox::error( this, i18n("Failed to create folder '%1'.").arg( tempDir ) ); + return; + } + } + else + return; + } + + // + // check if enough space in tempdir if not on-the-fly + // + if( doc()->size()/1024 > m_tempDirSelectionWidget->freeTempSpace() ) { + if( KMessageBox::warningContinueCancel( this, i18n("There seems to be not enough free space in temporary directory. " + "Write anyway?") ) == KMessageBox::Cancel ) + return; + } + } + } + + K3bJobProgressDialog* dlg = 0; + if( m_checkOnlyCreateImage && m_checkOnlyCreateImage->isChecked() ) + dlg = new K3bJobProgressDialog( parentWidget() ); + else + dlg = new K3bBurnProgressDialog( parentWidget() ); + + m_job = m_doc->newBurnJob( dlg ); + + if( m_writerSelectionWidget ) + m_job->setWritingApp( m_writerSelectionWidget->writingApp() ); + prepareJob( m_job ); + + if( !exitLoopOnHide() ) + hide(); + + dlg->startJob(m_job); + + kdDebug() << "(K3bProjectBurnDialog) job done. cleaning up." << endl; + + delete m_job; + m_job = 0; + delete dlg; + + done( Burn ); +} + + +void K3bProjectBurnDialog::prepareGui() +{ + QVBoxLayout* mainLay = new QVBoxLayout( mainWidget() ); + mainLay->setAutoAdd( true ); + mainLay->setMargin( 0 ); + mainLay->setSpacing( KDialog::spacingHint() ); + + m_writerSelectionWidget = new K3bWriterSelectionWidget( mainWidget() ); + m_writerSelectionWidget->setWantedMediumType( m_dvd ? K3bDevice::MEDIA_WRITABLE_DVD : K3bDevice::MEDIA_WRITABLE_CD ); + m_writerSelectionWidget->setWantedMediumState( K3bDevice::STATE_EMPTY ); + + m_tabWidget = new QTabWidget( mainWidget() ); + + QWidget* w = new QWidget( m_tabWidget ); + m_tabWidget->addTab( w, i18n("Writing") ); + + QGroupBox* groupWritingMode = new QGroupBox( 1, Qt::Vertical, i18n("Writing Mode"), w ); + groupWritingMode->setInsideMargin( marginHint() ); + m_writingModeWidget = new K3bWritingModeWidget( groupWritingMode ); + + m_optionGroup = new QGroupBox( 0, Qt::Vertical, i18n("Settings"), w ); + m_optionGroup->layout()->setMargin(0); + m_optionGroup->layout()->setSpacing(0); + m_optionGroupLayout = new QVBoxLayout( m_optionGroup->layout() ); + m_optionGroupLayout->setMargin( KDialog::marginHint() ); + m_optionGroupLayout->setSpacing( KDialog::spacingHint() ); + + // add the options + m_checkCacheImage = K3bStdGuiItems::createCacheImageCheckbox( m_optionGroup ); + m_checkSimulate = K3bStdGuiItems::simulateCheckbox( m_optionGroup ); + m_checkRemoveBufferFiles = K3bStdGuiItems::removeImagesCheckbox( m_optionGroup ); + m_checkOnlyCreateImage = K3bStdGuiItems::onlyCreateImagesCheckbox( m_optionGroup ); + + m_optionGroupLayout->addWidget(m_checkSimulate); + m_optionGroupLayout->addWidget(m_checkCacheImage); + m_optionGroupLayout->addWidget(m_checkOnlyCreateImage); + m_optionGroupLayout->addWidget(m_checkRemoveBufferFiles); + + QGroupBox* groupCopies = new QGroupBox( 2, Qt::Horizontal, i18n("Copies"), w ); + groupCopies->setInsideSpacing( spacingHint() ); + groupCopies->setInsideMargin( marginHint() ); + QLabel* pixLabel = new QLabel( groupCopies ); + pixLabel->setPixmap( SmallIcon( "cdcopy", KIcon::SizeMedium ) ); + pixLabel->setScaledContents( false ); + m_spinCopies = new QSpinBox( 1, 999, 1, groupCopies ); + + // arrange it + QGridLayout* grid = new QGridLayout( w ); + grid->setMargin( KDialog::marginHint() ); + grid->setSpacing( KDialog::spacingHint() ); + + grid->addWidget( groupWritingMode, 0, 0 ); + grid->addMultiCellWidget( m_optionGroup, 0, 2, 1, 1 ); + grid->addWidget( groupCopies, 2, 0 ); + // grid->addMultiCellWidget( m_tempDirSelectionWidget, 1, 3, 1, 1 ); + grid->setRowStretch( 1, 1 ); + grid->setColStretch( 1, 1 ); + + QWidget* tempW = new QWidget( m_tabWidget ); + grid = new QGridLayout( tempW ); + grid->setMargin( KDialog::marginHint() ); + grid->setSpacing( KDialog::spacingHint() ); + m_tabWidget->addTab( tempW, i18n("Image") ); + m_tempDirSelectionWidget = new K3bTempDirSelectionWidget( tempW ); + grid->addWidget( m_tempDirSelectionWidget, 0, 0 ); + m_tempDirSelectionWidget->setNeededSize( doc()->size() ); + + // tab order + setTabOrder( m_writerSelectionWidget, m_writingModeWidget ); + setTabOrder( m_writingModeWidget, groupCopies ); + setTabOrder( groupCopies, m_optionGroup ); + + // some default connections that should always be useful + connect( m_writerSelectionWidget, SIGNAL(writerChanged()), this, SLOT(slotWriterChanged()) ); + connect( m_writerSelectionWidget, SIGNAL(writerChanged(K3bDevice::Device*)), + m_writingModeWidget, SLOT(determineSupportedModesFromMedium(K3bDevice::Device*)) ); + connect( m_writerSelectionWidget, SIGNAL(writingAppChanged(int)), this, SLOT(slotWritingAppChanged(int)) ); + connect( m_checkCacheImage, SIGNAL(toggled(bool)), this, SLOT(slotToggleAll()) ); + connect( m_checkSimulate, SIGNAL(toggled(bool)), this, SLOT(slotToggleAll()) ); + connect( m_checkOnlyCreateImage, SIGNAL(toggled(bool)), this, SLOT(slotToggleAll()) ); + connect( m_writingModeWidget, SIGNAL(writingModeChanged(int)), this, SLOT(slotToggleAll()) ); +} + + +void K3bProjectBurnDialog::addPage( QWidget* page, const QString& title ) +{ + m_tabWidget->addTab( page, title ); +} + + +void K3bProjectBurnDialog::saveSettings() +{ + m_doc->setDummy( m_checkSimulate->isChecked() ); + m_doc->setOnTheFly( !m_checkCacheImage->isChecked() ); + m_doc->setOnlyCreateImages( m_checkOnlyCreateImage->isChecked() ); + m_doc->setRemoveImages( m_checkRemoveBufferFiles->isChecked() ); + m_doc->setSpeed( m_writerSelectionWidget->writerSpeed() ); + m_doc->setBurner( m_writerSelectionWidget->writerDevice() ); + m_doc->setWritingMode( m_writingModeWidget->writingMode() ); + m_doc->setWritingApp( m_writerSelectionWidget->writingApp() ); + m_doc->setCopies( m_spinCopies->value() ); +} + + +void K3bProjectBurnDialog::readSettings() +{ + m_checkSimulate->setChecked( doc()->dummy() ); + m_checkCacheImage->setChecked( !doc()->onTheFly() ); + m_checkOnlyCreateImage->setChecked( m_doc->onlyCreateImages() ); + m_checkRemoveBufferFiles->setChecked( m_doc->removeImages() ); + m_writingModeWidget->setWritingMode( doc()->writingMode() ); + m_writerSelectionWidget->setWriterDevice( doc()->burner() ); + m_writerSelectionWidget->setSpeed( doc()->speed() ); + m_writerSelectionWidget->setWritingApp( doc()->writingApp() ); + m_spinCopies->setValue( m_doc->copies() ); +} + + +void K3bProjectBurnDialog::saveUserDefaults( KConfigBase* c ) +{ + m_writingModeWidget->saveConfig( c ); + c->writeEntry( "simulate", m_checkSimulate->isChecked() ); + c->writeEntry( "on_the_fly", !m_checkCacheImage->isChecked() ); + c->writeEntry( "remove_image", m_checkRemoveBufferFiles->isChecked() ); + c->writeEntry( "only_create_image", m_checkOnlyCreateImage->isChecked() ); + c->writeEntry( "copies", m_spinCopies->value() ); + + m_tempDirSelectionWidget->saveConfig( c ); + m_writerSelectionWidget->saveConfig( c ); +} + + +void K3bProjectBurnDialog::loadUserDefaults( KConfigBase* c ) +{ + m_writingModeWidget->loadConfig( c ); + m_checkSimulate->setChecked( c->readBoolEntry( "simulate", false ) ); + m_checkCacheImage->setChecked( !c->readBoolEntry( "on_the_fly", true ) ); + m_checkRemoveBufferFiles->setChecked( c->readBoolEntry( "remove_image", true ) ); + m_checkOnlyCreateImage->setChecked( c->readBoolEntry( "only_create_image", false ) ); + m_spinCopies->setValue( c->readNumEntry( "copies", 1 ) ); + + m_tempDirSelectionWidget->readConfig( c ); + m_writerSelectionWidget->loadConfig( c ); +} + + +void K3bProjectBurnDialog::loadK3bDefaults() +{ + m_writerSelectionWidget->loadDefaults(); + m_writingModeWidget->setWritingMode( K3b::WRITING_MODE_AUTO ); + m_checkSimulate->setChecked( false ); + m_checkCacheImage->setChecked( false ); + m_checkRemoveBufferFiles->setChecked( true ); + m_checkOnlyCreateImage->setChecked( false ); + m_spinCopies->setValue( 1 ); + + if( m_tempDirSelectionWidget->selectionMode() == K3bTempDirSelectionWidget::DIR ) + m_tempDirSelectionWidget->setTempPath( K3b::defaultTempPath() ); + else + m_tempDirSelectionWidget->setTempPath( K3b::defaultTempPath() + doc()->name() + ".iso" ); +} + +#include "k3bprojectburndialog.moc" diff --git a/src/projects/k3bprojectburndialog.h b/src/projects/k3bprojectburndialog.h new file mode 100644 index 0000000..f011ae8 --- /dev/null +++ b/src/projects/k3bprojectburndialog.h @@ -0,0 +1,191 @@ +/* + * + * $Id: k3bprojectburndialog.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BPROJECTBURNDIALOG_H +#define K3BPROJECTBURNDIALOG_H + +#include <k3binteractiondialog.h> + + +class K3bDoc; +class K3bBurnJob; +class K3bWriterSelectionWidget; +class K3bTempDirSelectionWidget; +class QGroupBox; +class QCheckBox; +class QTabWidget; +class QSpinBox; +class QVBoxLayout; +class K3bWritingModeWidget; +class KConfigBase; + + +/** + *@author Sebastian Trueg + */ +class K3bProjectBurnDialog : public K3bInteractionDialog +{ + Q_OBJECT + + public: + K3bProjectBurnDialog( K3bDoc* doc, QWidget *parent=0, const char *name=0, + bool modal = true, bool dvd = false ); + ~K3bProjectBurnDialog(); + + enum resultCode { Canceled = 0, Saved = 1, Burn = 2 }; + + /** + * shows the dialog with exec(). + * Use this instead of K3bInteractionDialog::exec + * \param burn If true the dialog shows the Burn-button + */ + int execBurnDialog( bool burn ); + + K3bDoc* doc() const { return m_doc; } + + protected slots: + /** burn */ + virtual void slotStartClicked(); + /** save */ + virtual void slotSaveClicked(); + virtual void slotCancelClicked(); + + /** + * gets called if the user changed the writer + * default implementation just calls + * toggleAllOptions() + */ + virtual void slotWriterChanged(); + + /** + * gets called if the user changed the writing app + * default implementation just calls + * toggleAllOptions() + */ + virtual void slotWritingAppChanged( int ); + + signals: + void writerChanged(); + + protected: + /** + * The default implementation loads the following defaults: + * <ul> + * <li>Writing mode</li> + * <li>Simulate</li> + * <li>on the fly</li> + * <li>remove images</li> + * <li>only create images</li> + * </ul> + */ + virtual void loadK3bDefaults(); + + /** + * The default implementation loads the following settings from the KConfig. + * May be used in subclasses. + * <ul> + * <li>Writing mode</li> + * <li>Simulate</li> + * <li>on the fly</li> + * <li>remove images</li> + * <li>only create images</li> + * <li>writer</li> + * <li>writing speed</li> + * </ul> + */ + virtual void loadUserDefaults( KConfigBase* ); + + /** + * The default implementation saves the following settings to the KConfig. + * May be used in subclasses. + * <ul> + * <li>Writing mode</li> + * <li>Simulate</li> + * <li>on the fly</li> + * <li>remove images</li> + * <li>only create images</li> + * <li>writer</li> + * <li>writing speed</li> + * </ul> + */ + virtual void saveUserDefaults( KConfigBase* ); + + /** + * The default implementation saves the following settings to the doc and may be called + * in subclasses: + * <ul> + * <li>Writing mode</li> + * <li>Simulate</li> + * <li>on the fly</li> + * <li>remove images</li> + * <li>only create images</li> + * <li>writer</li> + * <li>writing speed</li> + * </ul> + */ + virtual void saveSettings(); + + /** + * The default implementation reads the following settings from the doc and may be called + * in subclasses: + * <ul> + * <li>Writing mode</li> + * <li>Simulate</li> + * <li>on the fly</li> + * <li>remove images</li> + * <li>only create images</li> + * <li>writer</li> + * <li>writing speed</li> + * </ul> + */ + virtual void readSettings(); + + virtual void toggleAll(); + + /** + * use this to set additionell stuff in the job + */ + virtual void prepareJob( K3bBurnJob* ) {}; + + void prepareGui(); + + void addPage( QWidget*, const QString& title ); + + /** + * Call this if you must reimplement it. + * \reimplemented from K3bInteractionDialog + */ + virtual void init(); + + K3bWriterSelectionWidget* m_writerSelectionWidget; + K3bTempDirSelectionWidget* m_tempDirSelectionWidget; + K3bWritingModeWidget* m_writingModeWidget; + QGroupBox* m_optionGroup; + QVBoxLayout* m_optionGroupLayout; + QCheckBox* m_checkCacheImage; + QCheckBox* m_checkSimulate; + QCheckBox* m_checkRemoveBufferFiles; + QCheckBox* m_checkOnlyCreateImage; + QSpinBox* m_spinCopies; + + private: + K3bDoc* m_doc; + K3bBurnJob* m_job; + QTabWidget* m_tabWidget; + bool m_dvd; +}; + +#endif diff --git a/src/projects/k3bprojectplugindialog.cpp b/src/projects/k3bprojectplugindialog.cpp new file mode 100644 index 0000000..a28f563 --- /dev/null +++ b/src/projects/k3bprojectplugindialog.cpp @@ -0,0 +1,68 @@ +/* + * + * $Id: k3bprojectplugindialog.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bprojectplugindialog.h" + +#include <k3bprojectplugin.h> + +#include <qwidget.h> + + +K3bProjectPluginDialog::K3bProjectPluginDialog( K3bProjectPlugin* plugin, K3bDoc* doc, QWidget* parent, const char* name ) + : K3bInteractionDialog( parent, name, + QString::null, + QString::null, + START_BUTTON|CANCEL_BUTTON, + START_BUTTON, + plugin->className() ), + m_plugin(plugin) +{ + m_pluginGui = plugin->createGUI( doc, this, 0 ); + Q_ASSERT( m_pluginGui ); + Q_ASSERT( m_pluginGui->qWidget() ); + setMainWidget( m_pluginGui->qWidget() ); + setTitle( m_pluginGui->title(), m_pluginGui->subTitle() ); +} + + +K3bProjectPluginDialog::~K3bProjectPluginDialog() +{ +} + + +void K3bProjectPluginDialog::slotStartClicked() +{ + m_pluginGui->activate(); +} + + +void K3bProjectPluginDialog::saveUserDefaults( KConfigBase* config ) +{ + m_pluginGui->saveSettings( config ); +} + + +void K3bProjectPluginDialog::loadUserDefaults( KConfigBase* config ) +{ + m_pluginGui->readSettings( config ); +} + + +void K3bProjectPluginDialog::loadK3bDefaults() +{ + m_pluginGui->loadDefaults(); +} + +#include "k3bprojectplugindialog.moc" diff --git a/src/projects/k3bprojectplugindialog.h b/src/projects/k3bprojectplugindialog.h new file mode 100644 index 0000000..f2250d7 --- /dev/null +++ b/src/projects/k3bprojectplugindialog.h @@ -0,0 +1,46 @@ +/* + * + * $Id: k3bprojectplugindialog.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_PROJECTPLUGIN_DIALOG_H_ +#define _K3B_PROJECTPLUGIN_DIALOG_H_ + +#include <k3binteractiondialog.h> + +class K3bProjectPlugin; +class K3bProjectPluginGUIBase; +class K3bDoc; +class KConfigBase; + + +class K3bProjectPluginDialog : public K3bInteractionDialog +{ + Q_OBJECT + + public: + K3bProjectPluginDialog( K3bProjectPlugin*, K3bDoc*, QWidget*, const char* name = 0 ); + ~K3bProjectPluginDialog(); + + protected slots: + void slotStartClicked(); + void saveUserDefaults( KConfigBase* config ); + void loadUserDefaults( KConfigBase* config ); + void loadK3bDefaults(); + + private: + K3bProjectPlugin* m_plugin; + K3bProjectPluginGUIBase* m_pluginGui; +}; + +#endif diff --git a/src/projects/k3bvcdburndialog.cpp b/src/projects/k3bvcdburndialog.cpp new file mode 100644 index 0000000..3c45c14 --- /dev/null +++ b/src/projects/k3bvcdburndialog.cpp @@ -0,0 +1,1088 @@ +/* +* +* $Id: k3bvcdburndialog.cpp 619556 2007-01-03 17:38:12Z trueg $ +* Copyright (C) 2003-2004 Christian Kvasny <chris@k3b.org> +* +* This file is part of the K3b project. +* Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> +* +* 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 2 of the License, or +* (at your option) any later version. +* See the file "COPYING" for the exact licensing terms. +*/ + +#include <qcheckbox.h> +#include <qgroupbox.h> +#include <qspinbox.h> +#include <qbuttongroup.h> +#include <qradiobutton.h> +#include <qlabel.h> +#include <qlineedit.h> +#include <qlayout.h> +#include <qtooltip.h> +#include <qwhatsthis.h> +#include <qgrid.h> +#include <qtoolbutton.h> +#include <qfileinfo.h> + +#include <klocale.h> +#include <kconfig.h> +#include <kmessagebox.h> +#include <kstandarddirs.h> +#include <kio/global.h> +#include <kapplication.h> + +#include "k3bvcdburndialog.h" +#include "k3bvcddoc.h" +#include "k3bvcdoptions.h" +#include <k3bdevice.h> +#include <k3bcore.h> +#include <k3bwriterselectionwidget.h> +#include <k3btempdirselectionwidget.h> +#include <k3bstdguiitems.h> +#include <k3bglobals.h> +#include <k3bwritingmodewidget.h> +#include <k3bexternalbinmanager.h> +#include <k3bvalidators.h> + +K3bVcdBurnDialog::K3bVcdBurnDialog( K3bVcdDoc* _doc, QWidget *parent, const char *name, bool modal ) + : K3bProjectBurnDialog( _doc, parent, name, modal ) +{ + m_vcdDoc = _doc; + + prepareGui(); + + QString vcdType; + switch ( m_vcdDoc->vcdType() ) { + case K3bVcdDoc::VCD11: + vcdType = i18n( "Video CD (Version 1.1)" ); + case K3bVcdDoc::VCD20: + vcdType = i18n( "Video CD (Version 2.0)" ); + case K3bVcdDoc::SVCD10: + vcdType = i18n( "Super Video CD" ); + case K3bVcdDoc::HQVCD: + vcdType = i18n( "High-Quality Video CD" ); + default: + vcdType = i18n( "Video CD" ); + } + + setTitle( vcdType, i18n( "1 MPEG (%1)", "%n MPEGs (%1)", + m_vcdDoc->tracks() ->count() ).arg( KIO::convertSize( m_vcdDoc->size() ) ) ); + + const K3bExternalBin* cdrecordBin = k3bcore->externalBinManager() ->binObject( "cdrecord" ); + if ( cdrecordBin && cdrecordBin->hasFeature( "cuefile" ) ) + m_writerSelectionWidget->setSupportedWritingApps( K3b::CDRDAO | K3b::CDRECORD ); + else + m_writerSelectionWidget->setSupportedWritingApps( K3b::CDRDAO ); + + m_checkCacheImage->hide(); + + QSpacerItem* spacer = new QSpacerItem( 20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding ); + m_optionGroupLayout->addItem( spacer ); + + setupVideoCdTab(); + setupLabelTab(); + setupAdvancedTab(); + + connect( m_spinVolumeCount, SIGNAL( valueChanged( int ) ), this, SLOT( slotSpinVolumeCount() ) ); + connect( m_groupVcdFormat, SIGNAL( clicked( int ) ), this, SLOT( slotVcdTypeClicked( int ) ) ); + connect( m_checkCdiSupport, SIGNAL( toggled( bool ) ), this, SLOT( slotCdiSupportChecked( bool ) ) ); + connect( m_checkAutoDetect, SIGNAL( toggled( bool ) ), this, SLOT( slotAutoDetect( bool ) ) ); + connect( m_checkGaps, SIGNAL( toggled( bool ) ), this, SLOT( slotGapsChecked( bool ) ) ); + + // ToolTips + // ------------------------------------------------------------------------- + QToolTip::add + ( m_radioVcd11, i18n( "Select Video CD type %1" ).arg( "(VCD 1.1)" ) ); + QToolTip::add + ( m_radioVcd20, i18n( "Select Video CD type %1" ).arg( "(VCD 2.0)" ) ); + QToolTip::add + ( m_radioSvcd10, i18n( "Select Video CD type %1" ).arg( "(SVCD 1.0)" ) ); + QToolTip::add + ( m_radioHqVcd10, i18n( "Select Video CD type %1" ).arg( "(HQ-VCD 1.0)" ) ); + QToolTip::add + ( m_checkAutoDetect, i18n( "Automatic video type recognition." ) ); + QToolTip::add + ( m_checkNonCompliant, i18n( "Non-compliant compatibility mode for broken devices" ) ); + QToolTip::add + ( m_checkVCD30interpretation, i18n( "Chinese VCD3.0 track interpretation" ) ); + QToolTip::add + ( m_check2336, i18n( "Use 2336 byte sectors for output" ) ); + + QToolTip::add + ( m_editVolumeId, i18n( "Specify ISO volume label for Video CD" ) ); + QToolTip::add + ( m_editAlbumId, i18n( "Specify album id for VideoCD set" ) ); + QToolTip::add + ( m_spinVolumeNumber, i18n( "Specify album set sequence number ( <= volume-count )" ) ); + QToolTip::add + ( m_spinVolumeCount, i18n( "Specify number of volumes in album set" ) ); + + QToolTip::add + ( m_checkCdiSupport, i18n( "Enable CD-i Application Support for VideoCD Type 1.1 & 2.0" ) ); + QToolTip::add + ( m_editCdiCfg, i18n( "Configuration parameters (only for VCD 2.0)" ) ); + + QToolTip::add + ( m_checkPbc, i18n( "Playback control, PBC, is available for Video CD 2.0 and Super Video CD 1.0 disc formats." ) ); + QToolTip::add + ( m_checkSegmentFolder, i18n( "Add always an empty `/SEGMENT' directory" ) ); + QToolTip::add + ( m_checkRelaxedAps, i18n( "This controls whether APS constraints are strict or relaxed. " ) ); + QToolTip::add + ( m_checkUpdateScanOffsets, i18n( "This controls whether to update the scan data information contained in the MPEG-2 video streams." ) ); + QToolTip::add + ( m_labelRestriction, i18n( "This element allows to set viewing restrictions which may be interpreted by the playing device." ) ); + + QToolTip::add + ( m_checkGaps, i18n( "This option allows customization of Gaps and Margins." ) ); + QToolTip::add + ( m_labelPreGapLeadout, i18n( "Used to set the number of empty sectors added before the lead-out area begins." ) ); + QToolTip::add + ( m_labelPreGapTrack, i18n( "Used to set the track pre-gap for all tracks in sectors globally." ) ); + QToolTip::add + ( m_labelFrontMarginTrack, i18n( "Sets the front margin for sequence items." ) ); + QToolTip::add + ( m_labelRearMarginTrack, i18n( "Sets the rear margin for sequence items." ) ); + + // What's This info + // ------------------------------------------------------------------------- + QWhatsThis::add + ( m_radioVcd11, i18n( "<p>This is the most basic <b>Video CD</b> specification dating back to 1993, which has the following characteristics:" + "<ul><li>One mode2 mixed form ISO-9660 track containing file pointers to the information areas.</li>" + "<li>Up to 98 multiplex-ed MPEG-1 audio/video streams or CD-DA audio tracks.</li>" + "<li>Up to 500 MPEG sequence entry points used as chapter divisions.</li></ul>" + "<p>The Video CD specification requires the multiplex-ed MPEG-1 stream to have a CBR of less than 174300 bytes (1394400 bits) per second in order to accommodate single speed CD-ROM drives.<br>" + "The specification allows for the following two resolutions:" + "<ul><li>352 x 240 @ 29.97 Hz (NTSC SIF).</li>" + "<li>352 x 240 @ 23.976 Hz (FILM SIF).</li></ul>" + "<p>The CBR MPEG-1, layer II audio stream is fixed at 224 kbps with 1 stereo or 2 mono channels." + "<p><b>It is recommended to keep the video bit-rate under 1151929.1 bps.</b>" ) ); + + QWhatsThis::add + ( m_radioVcd20, i18n( "<p>About two years after the Video CD 1.1 specification came out, an improved <b>Video CD 2.0</b> standard was published in 1995." + "<p>This one added the following items to the features already available in the Video CD 1.1 specification:" + "<ul><li>Support for MPEG segment play items (<b>\"SPI\"</b>), consisting of still pictures, motion pictures and/or audio (only) streams was added.</li>" + "<li>Note Segment Items::.</li>" + "<li>Support for interactive playback control (<b>\"PBC\"</b>) was added.</li>" + "<li>Support for playing related access by providing a scan point index file was added. (<b>\"/EXT/SCANDATA.DAT\"</b>)</li>" + "<li>Support for closed captions.</li>" + "<li>Support for mixing NTSC and PAL content.</li></ul>" + "<p>By adding PAL support to the Video CD 1.1 specification, the following resolutions became available:" + "<ul><li>352 x 240 @ 29.97 Hz (NTSC SIF).</li>" + "<li>352 x 240 @ 23.976 Hz (FILM SIF).</li>" + "<li>352 x 288 @ 25 Hz (PAL SIF).</li></ul>" + "<p>For segment play items the following audio encodings became available:" + "<ul><li>Joint stereo, stereo or dual channel audio streams at 128, 192, 224 or 384 kbit/sec bit-rate.</li>" + "<li>Mono audio streams at 64, 96 or 192 kbit/sec bit-rate.</li></ul>" + "<p>Also the possibility to have audio only streams and still pictures was provided." + "<p><b>The bit-rate of multiplex-ed streams should be kept under 174300 bytes/sec (except for single still picture items) in order to accommodate single speed drives.</b>" ) ); + + QWhatsThis::add + ( m_radioSvcd10, i18n( "<p>With the upcoming of the DVD-V media, a new VCD standard had to be published in order to be able to keep up with technology, so the Super Video CD specification was called into life 1999." + "<p>In the midst of 2000 a full subset of this <b>Super Video CD</b> specification was published as <b>IEC-62107</b>." + "<p>As the most notable change over Video CD 2.0 is a switch from MPEG-1 CBR to MPEG-2 VBR encoding for the video stream was performed." + "<p>The following new features--building upon the Video CD 2.0 specification--are:" + "<ul><li>Use of MPEG-2 encoding instead of MPEG-1 for the video stream.</li>" + "<li>Allowed VBR encoding of MPEG-1 audio stream.</li>" + "<li>Higher resolutions (see below) for video stream resolution.</li>" + "<li>Up to 4 overlay graphics and text (<b>\"OGT\"</b>) sub-channels for user switchable subtitle displaying in addition to the already existing closed caption facility.</li>" + "<li>Command lists for controlling the SVCD virtual machine.</li></ul>" + "<p>For the <b>Super Video CD</b>, only the following two resolutions are supported for motion video and (low resolution) still pictures:" + "<ul><li>480 x 480 @ 29.97 Hz (NTSC 2/3 D-2).</li>" + "<li>480 x 576 @ 25 Hz (PAL 2/3 D-2).</li></ul>" ) ); + + QWhatsThis::add + ( m_radioHqVcd10, i18n( "<p>This is actually just a minor variation defined in IEC-62107 on the Super Video CD 1.0 format for compatibility with current products in the market." + "<p>It differs from the Super Video CD 1.0 format in the following items:" + "<ul><li>The system profile tag field in <b>/SVCD/INFO.SVD</b> is set to <b>1</b> instead of <b>0</b>.</li>" + "<li>The system identification field value in <b>/SVCD/INFO.SVD</b> is set to <b>HQ-VCD</b> instead of <b>SUPERVCD</b>.</li>" + "<li><b>/EXT/SCANDATA.DAT</b> is mandatory instead of being optional.</li>" + "<li><b>/SVCD/SEARCH.DAT</b> is optional instead of being mandatory.</li></ul>" ) ); + + QWhatsThis::add + ( m_checkAutoDetect, i18n( "<p>If Autodetect is:</p>" + "<ul><li>ON then K3b will set the correct VideoCD type.</li>" + "<li>OFF then the correct VideoCD type needs to be set by the user.</li></ul>" + "<p>If you are not sure about the correct VideoCD type, it is best to turn Autodetect ON.</p>" + "<p>If you want to force the VideoCD type, you must turn Autodetect OFF. This is useful for some standalone DVD players without SVCD support.</p>" ) ); + + QWhatsThis::add + ( m_checkNonCompliant, i18n( "<ul><li>Rename <b>\"/MPEG2\"</b> folder on SVCDs to (non-compliant) \"/MPEGAV\".</li>" + "<li>Enables the use of the (deprecated) signature <b>\"ENTRYSVD\"</b> instead of <b>\"ENTRYVCD\"</b> for the file <b>\"/SVCD/ENTRY.SVD\"</b>.</li></ul>" ) ); + QWhatsThis::add + ( m_checkVCD30interpretation, i18n( "<ul><li>Enables the use of the (deprecated) Chinese <b>\"/SVCD/TRACKS.SVD\"</b> format which differs from the format defined in the <b>IEC-62107</b> specification.</li></ul>" + "<p><b>The differences are most exposed on SVCDs containing more than one video track.</b>" ) ); + + QWhatsThis::add + ( m_check2336, i18n( "<p>though most devices will have problems with such an out-of-specification media." + "<p><b>You may want use this option for images longer than 80 minutes</b>" ) ); + + QWhatsThis::add + ( m_checkCdiSupport, i18n( "<p>To allow the play of Video-CDs on a CD-i player, the Video-CD standard requires that a CD-i application program must be present." + "<p>This program is designed to:" + "<ul><li>provide full play back control as defined in the PSD of the standard</l>" + "<li>be extremely simple to use and easy-to-learn for the end-user</li></ul>" + "<p>The program runs on CD-i players equipped with the CDRTOS 1.1(.1) operating system and a Digital Video extension cartridge." ) ); + + QWhatsThis::add + ( m_editCdiCfg, i18n( "<p>Configuration parameters only available for VideoCD 2.0" + "<p>The engine works perfectly well when used as-is." + "<p>You have the option to configure the VCD application." + "<p>You can adapt the color and/or the shape of the cursor and lots more." ) ); + + + QWhatsThis::add + ( m_checkPbc, i18n( "<p>Playback control, PBC, is available for Video CD 2.0 and Super Video CD 1.0 disc formats." + "<p>PBC allows control of the playback of play items and the possibility of interaction with the user through the remote control or some other input device available." ) ); + + QWhatsThis::add + ( m_checkSegmentFolder, i18n( "<p>Here you can specify that the folder <b>SEGMENT</b> should always be present." + "<p>Some DVD players need the folder to give a faultless rendition." ) ); + + QWhatsThis::add + ( m_checkRelaxedAps, i18n( "<p>An Access Point Sector, APS, is an MPEG video sector on the VCD/SVCD which is suitable to be jumped to directly." + "<p>APS are required for entry points and scantables. APS have to fulfil the requirement to precede every I-frame by a GOP header which shall be preceded by a sequence header in its turn." + "<p>The start codes of these 3 items are required to be contained all in the same MPEG pack/sector, thus forming a so-called access point sector." + "<p>This requirement can be relaxed by enabling the relaxed aps option, i.e. every sector containing an I-frame will be regarded as an APS." + "<p><b>Warning:</b> The sequence header is needed for a playing device to figure out display parameters, such as display resolution and frame rate, relaxing the aps requirement may lead to non-working entry points." ) ); + + QWhatsThis::add + ( m_checkUpdateScanOffsets, i18n( "<p>According to the specification, it is mandatory for Super Video CDs to encode scan information data into user data blocks in the picture layer of all intra coded picture." + "<p>It can be used by playing devices for implementing fast forward & fast reverse scanning." + "<p>The already existing scan information data can be updated by enabling the update scan offsets option." ) ); + + QWhatsThis::add + ( m_labelRestriction, i18n( "<p>Viewing Restriction may be interpreted by the playing device." + "<p>The allowed range goes from 0 to 3." + "<ul><li>0 = unrestricted, free to view for all</li>" + "<li>3 = restricted, content not suitable for ages under 18</li></ul>" + "<p>Actually, the exact meaning is not defined and is player dependant." + "<p><b>Most players ignore that value.<b>" ) ); + + QWhatsThis::add + ( m_checkGaps, i18n( "<p>This option allows customization of Gaps and Margins." ) ); + QWhatsThis::add + ( m_labelPreGapLeadout, i18n( "<p>This option allows to set the number of empty sectors added before the lead-out area begins, i.e. the number of post-gap sectors." + "<p>The ECMA-130 specification requires the last data track before the lead-out to carry a post-gap of at least 150 sectors, which is used as default for this parameter." + "<p>Some operating systems may encounter I/O errors due to read-ahead issues when reading the last MPEG track if this parameter is set too low." + "<p>Allowed value content: [0..300]. Default: 150." ) ); + + QWhatsThis::add + ( m_labelPreGapTrack, i18n( "<p>Used to set the track pre-gap for all tracks in sectors globally." + "<p>The specification requires the pre-gaps to be at least 150 sectors long." + "<p>Allowed value content: [0..300]. Default: 150." ) ); + + QWhatsThis::add + ( m_labelFrontMarginTrack, i18n( "Margins are used to compensate for inaccurate sector-addressing issues on CD-ROM media. Interestingly, they have been abandoned for Super Video CDs." + "<p>For Video CD 1.0/1.1/2.0 this margin should be at least 15 sectors long." + "<p>Allowed value content: [0..150]. Default: 30 for Video CD 1.0/1.1/2.0, otherwise (i.e. Super Video CD 1.0 and HQ-VCD 1.0) 0." ) ); + + QWhatsThis::add + ( m_labelRearMarginTrack, i18n( "<p>Margins are used to compensate for inaccurate sector-addressing issues on CD-ROM media. Interestingly, they have been abandoned for Super Video CDs." + "<p>For Video CD 1.0/1.1/2.0 this margin should be at least 15 sectors long." + "<p>Allowed value content: [0..150]. Default: 45 for Video CD 1.0/1.1/2.0, otherwise 0." ) ); + +} + + +K3bVcdBurnDialog::~K3bVcdBurnDialog() +{} + +void K3bVcdBurnDialog::setupAdvancedTab() +{ + QWidget * w = new QWidget( this ); + + // ---------------------------------------------------- generic group ---- + m_groupGeneric = new QGroupBox( 5, Qt::Vertical, i18n( "Generic" ), w ); + + m_checkPbc = new QCheckBox( i18n( "Playback Control (PBC)" ), m_groupGeneric ); + m_checkSegmentFolder = new QCheckBox( i18n( "SEGMENT Folder must always be present" ), m_groupGeneric ); + m_checkRelaxedAps = new QCheckBox( i18n( "Relaxed aps" ), m_groupGeneric ); + m_checkUpdateScanOffsets = new QCheckBox( i18n( "Update scan offsets" ), m_groupGeneric ); + m_checkUpdateScanOffsets->setEnabled( false ); + + + // -------------------------------------------- gaps & margins group ---- + m_groupGaps = new QGroupBox( 0, Qt::Vertical, i18n( "Gaps" ), w ); + m_groupGaps->layout() ->setSpacing( spacingHint() ); + m_groupGaps->layout() ->setMargin( marginHint() ); + + QGridLayout* groupGapsLayout = new QGridLayout( m_groupGaps->layout() ); + groupGapsLayout->setAlignment( Qt::AlignTop ); + + m_checkGaps = new QCheckBox( i18n( "Customize gaps and margins" ), m_groupGaps ); + + m_labelPreGapLeadout = new QLabel( i18n( "Leadout pre gap (0..300):" ), m_groupGaps, "labelPreGapLeadout" ); + m_spinPreGapLeadout = new QSpinBox( m_groupGaps, "m_spinPreGapLeadout" ); + m_spinPreGapLeadout->setMinValue( 0 ); + m_spinPreGapLeadout->setMaxValue( 300 ); + + m_labelPreGapTrack = new QLabel( i18n( "Track pre gap (0..300):" ), m_groupGaps, "labelPreGapTrack" ); + m_spinPreGapTrack = new QSpinBox( m_groupGaps, "m_spinPreGapTrack" ); + m_spinPreGapTrack->setMinValue( 0 ); + m_spinPreGapTrack->setMaxValue( 300 ); + + m_labelFrontMarginTrack = new QLabel( i18n( "Track front margin (0..150):" ), m_groupGaps, "labelFrontMarginTrack" ); + m_spinFrontMarginTrack = new QSpinBox( m_groupGaps, "m_spinFrontMarginTrack" ); + m_spinFrontMarginTrack->setMinValue( 0 ); + m_spinFrontMarginTrack->setMaxValue( 150 ); + m_spinFrontMarginTrackSVCD = new QSpinBox( m_groupGaps, "m_spinFrontMarginTrackSVCD" ); + m_spinFrontMarginTrackSVCD->setMinValue( 0 ); + m_spinFrontMarginTrackSVCD->setMaxValue( 150 ); + m_spinFrontMarginTrackSVCD->setHidden( true ); + + m_labelRearMarginTrack = new QLabel( i18n( "Track rear margin (0..150):" ), m_groupGaps, "labelRearMarginTrack" ); + m_spinRearMarginTrack = new QSpinBox( m_groupGaps, "m_spinRearMarginTrack" ); + m_spinRearMarginTrack->setMinValue( 0 ); + m_spinRearMarginTrack->setMaxValue( 150 ); + m_spinRearMarginTrackSVCD = new QSpinBox( m_groupGaps, "m_spinRearMarginTrackSVCD" ); + m_spinRearMarginTrackSVCD->setMinValue( 0 ); + m_spinRearMarginTrackSVCD->setMaxValue( 150 ); + m_spinRearMarginTrackSVCD->setHidden( true ); + + groupGapsLayout->addMultiCellWidget( m_checkGaps, 1, 1, 0, 4 ); + groupGapsLayout->addWidget( m_labelPreGapLeadout, 2, 0 ); + groupGapsLayout->addWidget( m_spinPreGapLeadout, 2, 1 ); + groupGapsLayout->addWidget( m_labelPreGapTrack, 2, 3 ); + groupGapsLayout->addWidget( m_spinPreGapTrack, 2, 4 ); + + groupGapsLayout->addWidget( m_labelFrontMarginTrack, 3, 0 ); + groupGapsLayout->addWidget( m_spinFrontMarginTrack, 3, 1 ); + groupGapsLayout->addWidget( m_spinFrontMarginTrackSVCD, 3, 1 ); + groupGapsLayout->addWidget( m_labelRearMarginTrack, 3, 3 ); + groupGapsLayout->addWidget( m_spinRearMarginTrack, 3, 4 ); + groupGapsLayout->addWidget( m_spinRearMarginTrackSVCD, 3, 4 ); + + groupGapsLayout->setRowStretch( 4, 0 ); + + groupGapsLayout->addMultiCellWidget( m_checkGaps, 1, 1, 0, 4 ); + groupGapsLayout->addWidget( m_labelPreGapLeadout, 2, 0 ); + groupGapsLayout->addWidget( m_spinPreGapLeadout, 2, 1 ); + groupGapsLayout->addWidget( m_labelPreGapTrack, 2, 3 ); + groupGapsLayout->addWidget( m_spinPreGapTrack, 2, 4 ); + + groupGapsLayout->addWidget( m_labelFrontMarginTrack, 3, 0 ); + groupGapsLayout->addWidget( m_spinFrontMarginTrack, 3, 1 ); + groupGapsLayout->addWidget( m_spinFrontMarginTrackSVCD, 3, 1 ); + groupGapsLayout->addWidget( m_labelRearMarginTrack, 3, 3 ); + groupGapsLayout->addWidget( m_spinRearMarginTrack, 3, 4 ); + groupGapsLayout->addWidget( m_spinRearMarginTrackSVCD, 3, 4 ); + + groupGapsLayout->setRowStretch( 4, 0 ); + groupGapsLayout->addMultiCellWidget( m_checkGaps, 1, 1, 0, 4 ); + groupGapsLayout->addWidget( m_labelPreGapLeadout, 2, 0 ); + groupGapsLayout->addWidget( m_spinPreGapLeadout, 2, 1 ); + groupGapsLayout->addWidget( m_labelPreGapTrack, 2, 3 ); + groupGapsLayout->addWidget( m_spinPreGapTrack, 2, 4 ); + + groupGapsLayout->addWidget( m_labelFrontMarginTrack, 3, 0 ); + groupGapsLayout->addWidget( m_spinFrontMarginTrack, 3, 1 ); + groupGapsLayout->addWidget( m_spinFrontMarginTrackSVCD, 3, 1 ); + groupGapsLayout->addWidget( m_labelRearMarginTrack, 3, 3 ); + groupGapsLayout->addWidget( m_spinRearMarginTrack, 3, 4 ); + groupGapsLayout->addWidget( m_spinRearMarginTrackSVCD, 3, 4 ); + + groupGapsLayout->setRowStretch( 4, 0 ); + groupGapsLayout->addMultiCellWidget( m_checkGaps, 1, 1, 0, 4 ); + groupGapsLayout->addWidget( m_labelPreGapLeadout, 2, 0 ); + groupGapsLayout->addWidget( m_spinPreGapLeadout, 2, 1 ); + groupGapsLayout->addWidget( m_labelPreGapTrack, 2, 3 ); + groupGapsLayout->addWidget( m_spinPreGapTrack, 2, 4 ); + + groupGapsLayout->addWidget( m_labelFrontMarginTrack, 3, 0 ); + groupGapsLayout->addWidget( m_spinFrontMarginTrack, 3, 1 ); + groupGapsLayout->addWidget( m_spinFrontMarginTrackSVCD, 3, 1 ); + groupGapsLayout->addWidget( m_labelRearMarginTrack, 3, 3 ); + groupGapsLayout->addWidget( m_spinRearMarginTrack, 3, 4 ); + groupGapsLayout->addWidget( m_spinRearMarginTrackSVCD, 3, 4 ); + + groupGapsLayout->setRowStretch( 4, 0 ); + + // ------------------------------------------------------- misc group ---- + m_groupMisc = new QGroupBox( 0, Qt::Vertical, i18n( "Misc" ), w ); + m_groupMisc->layout() ->setSpacing( spacingHint() ); + m_groupMisc->layout() ->setMargin( marginHint() ); + + QGridLayout* groupMiscLayout = new QGridLayout( m_groupMisc->layout() ); + groupMiscLayout->setAlignment( Qt::AlignTop ); + + m_labelRestriction = new QLabel( i18n( "Restriction category (0..3):" ), m_groupMisc, "m_labelRestriction" ); + m_spinRestriction = new QSpinBox( m_groupMisc, "m_spinRestriction" ); + m_spinRestriction->setMinValue( 0 ); + m_spinRestriction->setMaxValue( 3 ); + + groupMiscLayout->addWidget( m_labelRestriction, 1, 0 ); + groupMiscLayout->addMultiCellWidget( m_spinRestriction, 1, 1, 1, 4 ); + groupMiscLayout->setRowStretch( 2, 0 ); + + // ---------------------------------------------------------------------- + QGridLayout* grid = new QGridLayout( w ); + grid->setMargin( marginHint() ); + grid->setSpacing( spacingHint() ); + grid->addWidget( m_groupGeneric, 0, 0 ); + grid->addWidget( m_groupGaps, 1, 0 ); + grid->addWidget( m_groupMisc, 2, 0 ); + + addPage( w, i18n( "Advanced" ) ); +} + +void K3bVcdBurnDialog::setupVideoCdTab() +{ + QWidget * w = new QWidget( this ); + + // ---------------------------------------------------- Format group ---- + m_groupVcdFormat = new QButtonGroup( 4, Qt::Vertical, i18n( "Type" ), w ); + m_radioVcd11 = new QRadioButton( i18n( "VideoCD 1.1" ), m_groupVcdFormat ); + m_radioVcd20 = new QRadioButton( i18n( "VideoCD 2.0" ), m_groupVcdFormat ); + m_radioSvcd10 = new QRadioButton( i18n( "Super-VideoCD" ), m_groupVcdFormat ); + m_radioHqVcd10 = new QRadioButton( i18n( "HQ-VideoCD" ), m_groupVcdFormat ); + m_groupVcdFormat->setExclusive( true ); + + // ---------------------------------------------------- Options group --- + + m_groupOptions = new QGroupBox( 5, Qt::Vertical, i18n( "Settings" ), w ); + m_checkAutoDetect = new QCheckBox( i18n( "Autodetect VideoCD type" ), m_groupOptions ); + + m_checkNonCompliant = new QCheckBox( i18n( "Enable broken SVCD mode" ), m_groupOptions ); + // Only available on SVCD Type + m_checkNonCompliant->setEnabled( false ); + m_checkNonCompliant->setChecked( false ); + + m_checkVCD30interpretation = new QCheckBox( i18n( "Enable %1 track interpretation" ).arg( "VCD 3.0" ), m_groupOptions ); + // Only available on SVCD Type + m_checkVCD30interpretation->setEnabled( false ); + m_checkVCD30interpretation->setChecked( false ); + + m_check2336 = new QCheckBox( i18n( "Use 2336 byte sectors" ), m_groupOptions ); + + m_checkCdiSupport = new QCheckBox( i18n( "Enable CD-i support" ), m_groupOptions ); + + // ------------------------------------------------- CD-i Application --- + m_groupCdi = new QGroupBox( 4, Qt::Vertical, i18n( "VideoCD on CD-i" ), w ); + m_editCdiCfg = new QMultiLineEdit( m_groupCdi, "m_editCdiCfg" ); + m_editCdiCfg->setFrameShape( QTextEdit::NoFrame ); + + // ---------------------------------------------------------------------- + QGridLayout* grid = new QGridLayout( w ); + grid->setMargin( marginHint() ); + grid->setSpacing( spacingHint() ); + grid->addMultiCellWidget( m_groupVcdFormat, 0, 1, 0, 0 ); + grid->addWidget( m_groupOptions, 0, 1 ); + grid->addWidget( m_groupCdi, 1, 1 ); + + addPage( w, i18n( "Settings" ) ); +} + +void K3bVcdBurnDialog::setupLabelTab() +{ + QWidget * w = new QWidget( this ); + + // ---------------------------------------------------------------------- + // noEdit + QLabel* labelSystemId = new QLabel( i18n( "System:" ), w, "labelSystemId" ); + QLabel* labelApplicationId = new QLabel( i18n( "Application:" ), w, "labelApplicationId" ); + QLabel* labelInfoSystemId = new QLabel( vcdDoc() ->vcdOptions() ->systemId(), w, "labelInfoSystemId" ); + QLabel* labelInfoApplicationId = new QLabel( vcdDoc() ->vcdOptions() ->applicationId(), w, "labelInfoApplicationId" ); + + labelInfoSystemId->setFrameShape( QLabel::LineEditPanel ); + labelInfoSystemId->setFrameShadow( QLabel::Sunken ); + + labelInfoApplicationId->setFrameShape( QLabel::LineEditPanel ); + labelInfoApplicationId->setFrameShadow( QLabel::Sunken ); + QToolTip::add + ( labelInfoApplicationId, i18n( "ISO application id for VideoCD" ) ); + + // ---------------------------------------------------------------------- + + QLabel* labelVolumeId = new QLabel( i18n( "&Volume name:" ), w, "labelVolumeId" ); + QLabel* labelAlbumId = new QLabel( i18n( "Volume &set name:" ), w, "labelAlbumId" ); + QLabel* labelVolumeCount = new QLabel( i18n( "Volume set s&ize:" ), w, "labelVolumeCount" ); + QLabel* labelVolumeNumber = new QLabel( i18n( "Volume set &number:" ), w, "labelVolumeNumber" ); + QLabel* labelPublisher = new QLabel( i18n( "&Publisher:" ), w, "labelPublisher" ); + + + m_editVolumeId = new QLineEdit( w, "m_editVolumeId" ); + m_editAlbumId = new QLineEdit( w, "m_editAlbumId" ); + m_spinVolumeNumber = new QSpinBox( w, "m_editVolumeNumber" ); + m_spinVolumeCount = new QSpinBox( w, "m_editVolumeCount" ); + m_editPublisher = new QLineEdit( w, "m_editPublisher" ); + + // only ISO646 d-Characters + m_editVolumeId->setValidator( K3bValidators::iso646Validator( K3bValidators::Iso646_d, true, m_editVolumeId ) ); + m_editAlbumId->setValidator( K3bValidators::iso646Validator( K3bValidators::Iso646_d, true, m_editVolumeId ) ); + + m_editVolumeId->setMaxLength( 32 ); + m_editAlbumId->setMaxLength( 16 ); + // only ISO646 a-Characters + m_editPublisher->setValidator( K3bValidators::iso646Validator( K3bValidators::Iso646_a, true, m_editVolumeId ) ); + m_editPublisher->setMaxLength( 128 ); + + m_spinVolumeNumber->setMinValue( 1 ); + m_spinVolumeNumber->setMaxValue( 1 ); + m_spinVolumeCount->setMinValue( 1 ); + + QFrame* line = new QFrame( w ); + line->setFrameShape( QFrame::HLine ); + line->setFrameShadow( QFrame::Sunken ); + line->setFrameShape( QFrame::HLine ); + + + // ---------------------------------------------------------------------- + QGridLayout* grid = new QGridLayout( w ); + grid->setMargin( marginHint() ); + grid->setSpacing( spacingHint() ); + + grid->addWidget( labelVolumeId, 1, 0 ); + grid->addMultiCellWidget( m_editVolumeId, 1, 1, 1, 3 ); + grid->addWidget( labelAlbumId, 2, 0 ); + grid->addMultiCellWidget( m_editAlbumId, 2, 2, 1, 3 ); + + grid->addWidget( labelVolumeCount, 3, 0 ); + grid->addWidget( m_spinVolumeCount, 3, 1 ); + grid->addWidget( labelVolumeNumber, 3, 2 ); + grid->addWidget( m_spinVolumeNumber, 3, 3 ); + + grid->addWidget( labelPublisher, 4, 0 ); + grid->addMultiCellWidget( m_editPublisher, 4, 4, 1, 3 ); + + grid->addMultiCellWidget( line, 5, 5, 0, 3 ); + + grid->addWidget( labelSystemId, 6, 0 ); + grid->addMultiCellWidget( labelInfoSystemId, 6, 6, 1, 3 ); + grid->addWidget( labelApplicationId, 7, 0 ); + grid->addMultiCellWidget( labelInfoApplicationId, 7, 7, 1, 3 ); + + // grid->addRowSpacing( 5, 15 ); + grid->setRowStretch( 8, 1 ); + + // buddies + labelVolumeId->setBuddy( m_editVolumeId ); + labelPublisher->setBuddy( m_editPublisher ); + labelAlbumId->setBuddy( m_editAlbumId ); + + labelVolumeCount->setBuddy( m_spinVolumeCount ); + labelVolumeNumber->setBuddy( m_spinVolumeNumber ); + + // tab order + setTabOrder( m_editVolumeId, m_editAlbumId ); + setTabOrder( m_editAlbumId, m_spinVolumeCount ); + setTabOrder( m_spinVolumeCount, m_spinVolumeNumber ); + setTabOrder( m_spinVolumeNumber, m_editPublisher ); + + addPage( w, i18n( "Volume Descriptor" ) ); +} + + +void K3bVcdBurnDialog::slotStartClicked() +{ + + if ( QFile::exists( vcdDoc() ->vcdImage() ) ) { + if ( KMessageBox::warningContinueCancel( this, i18n( "Do you want to overwrite %1" ).arg( vcdDoc() ->vcdImage() ), i18n( "File Exists" ), i18n("Overwrite") ) + != KMessageBox::Continue ) + return ; + } + + K3bProjectBurnDialog::slotStartClicked(); +} + + +void K3bVcdBurnDialog::loadK3bDefaults() +{ + K3bVcdOptions o = K3bVcdOptions::defaults(); + + m_writingModeWidget->setWritingMode( K3b::WRITING_MODE_AUTO ); + m_checkSimulate->setChecked( false ); + m_checkRemoveBufferFiles->setChecked( true ); + m_checkOnlyCreateImage->setChecked( false ); + + m_checkAutoDetect->setChecked( o.AutoDetect() ); + m_groupVcdFormat->setDisabled( o.AutoDetect() ); + + m_check2336->setChecked( o.Sector2336() ); + m_checkNonCompliant->setChecked( o.NonCompliantMode() ); + m_checkVCD30interpretation->setChecked( o.VCD30interpretation() ); + m_spinVolumeCount->setValue( o.volumeCount() ); + m_spinVolumeNumber->setMaxValue( o.volumeCount() ); + m_spinVolumeNumber->setValue( o.volumeNumber() ); + + + // to not use i18n for this, so user can not use unsupported letters in her language pack + if ( m_radioSvcd10->isChecked() ) { + m_checkCdiSupport->setEnabled( false ); + m_checkCdiSupport->setChecked( false ); + m_checkUpdateScanOffsets->setEnabled( true ); + m_editVolumeId->setText( "SUPER_VIDEOCD" ); + } else if ( m_radioHqVcd10->isChecked() ) { + m_checkCdiSupport->setEnabled( false ); + m_checkCdiSupport->setChecked( false ); + m_checkUpdateScanOffsets->setEnabled( true ); + m_editVolumeId->setText( "HQ_VIDEOCD" ); + } else { + m_checkCdiSupport->setEnabled( true ); + m_checkCdiSupport->setChecked( o.CdiSupport() ); + m_groupCdi->setEnabled( o.CdiSupport() ); + m_checkUpdateScanOffsets->setEnabled( false ); + m_editVolumeId->setText( "VIDEOCD" ); + } + + m_editPublisher->setText( o.publisher() ); + m_editAlbumId->setText( o.albumId() ); + + m_checkPbc->setChecked( o.PbcEnabled() ); + m_checkSegmentFolder->setChecked( o.SegmentFolder() ); + m_checkRelaxedAps->setChecked( o.RelaxedAps() ); + m_checkUpdateScanOffsets->setChecked( o.UpdateScanOffsets() ); + m_spinRestriction->setValue( o.Restriction() ); + + m_checkGaps->setChecked( o.UseGaps() ); + m_spinPreGapLeadout->setValue( o.PreGapLeadout() ); + m_spinPreGapTrack->setValue( o.PreGapTrack() ); + m_spinFrontMarginTrack->setValue( o.FrontMarginTrack() ); + m_spinRearMarginTrack->setValue( o.RearMarginTrack() ); + m_spinFrontMarginTrackSVCD->setValue( o.FrontMarginTrackSVCD() ); + m_spinRearMarginTrackSVCD->setValue( o.RearMarginTrackSVCD() ); + + loadDefaultCdiConfig(); +} + +void K3bVcdBurnDialog::saveSettings() +{ + K3bProjectBurnDialog::saveSettings(); + + // set VolumeID if empty + setVolumeID(); + + doc() ->setTempDir( m_tempDirSelectionWidget->tempPath() ); + doc() ->setOnTheFly( false ); + + // save image file & path (.bin) + vcdDoc() ->setVcdImage( m_tempDirSelectionWidget->tempPath() + "/" + m_editVolumeId->text() + ".bin" ); + + vcdDoc() ->setVcdType( m_groupVcdFormat->id( m_groupVcdFormat->selected() ) ); + + vcdDoc() ->vcdOptions() ->setVolumeId( m_editVolumeId->text() ); + vcdDoc() ->vcdOptions() ->setPublisher( m_editPublisher->text() ); + vcdDoc() ->vcdOptions() ->setAlbumId( m_editAlbumId->text() ); + + vcdDoc() ->vcdOptions() ->setAutoDetect( m_checkAutoDetect->isChecked() ); + vcdDoc() ->vcdOptions() ->setNonCompliantMode( m_checkNonCompliant->isChecked() ); + vcdDoc() ->vcdOptions() ->setVCD30interpretation( m_checkVCD30interpretation->isChecked() ); + vcdDoc() ->vcdOptions() ->setSector2336( m_check2336->isChecked() ); + + vcdDoc() ->vcdOptions() ->setCdiSupport( m_checkCdiSupport->isChecked() ); + // vcdDoc() ->setOnlyCreateImages( m_checkOnlyCreateImage->isChecked() ); + + vcdDoc() ->vcdOptions() ->setVolumeNumber( m_spinVolumeNumber->value() ); + vcdDoc() ->vcdOptions() ->setVolumeCount( m_spinVolumeCount->value() ); + + vcdDoc() ->vcdOptions() ->setPbcEnabled( m_checkPbc->isChecked() ); + if ( m_checkPbc->isChecked() ) + vcdDoc() -> setPbcTracks(); + + vcdDoc() ->vcdOptions() ->setSegmentFolder( m_checkSegmentFolder->isChecked() ); + vcdDoc() ->vcdOptions() ->setRelaxedAps( m_checkRelaxedAps->isChecked() ); + vcdDoc() ->vcdOptions() ->setUpdateScanOffsets( m_checkUpdateScanOffsets->isChecked() ); + vcdDoc() ->vcdOptions() ->setRestriction( m_spinRestriction->value() ); + + vcdDoc() ->vcdOptions() ->setUseGaps( m_checkGaps->isChecked() ); + vcdDoc() ->vcdOptions() ->setPreGapLeadout( m_spinPreGapLeadout->value() ); + vcdDoc() ->vcdOptions() ->setPreGapTrack( m_spinPreGapTrack->value() ); + vcdDoc() ->vcdOptions() ->setFrontMarginTrack( m_spinFrontMarginTrack->value() ); + vcdDoc() ->vcdOptions() ->setRearMarginTrack( m_spinRearMarginTrack->value() ); + vcdDoc() ->vcdOptions() ->setFrontMarginTrackSVCD( m_spinFrontMarginTrackSVCD->value() ); + vcdDoc() ->vcdOptions() ->setRearMarginTrackSVCD( m_spinRearMarginTrackSVCD->value() ); + + if ( m_editCdiCfg->edited() ) + saveCdiConfig(); +} + + +void K3bVcdBurnDialog::readSettings() +{ + K3bProjectBurnDialog::readSettings(); + + m_checkNonCompliant->setEnabled( false ); + m_checkVCD30interpretation->setEnabled( false ); + + // read vcdType + switch ( ( ( K3bVcdDoc* ) doc() ) ->vcdType() ) { + case K3bVcdDoc::VCD11: + m_radioVcd11->setChecked( true ); + break; + case K3bVcdDoc::VCD20: + m_radioVcd20->setChecked( true ); + break; + case K3bVcdDoc::SVCD10: + m_radioSvcd10->setChecked( true ); + m_checkNonCompliant->setEnabled( true ); + m_checkVCD30interpretation->setEnabled( true ); + break; + case K3bVcdDoc::HQVCD: + m_radioHqVcd10->setChecked( true ); + break; + default: + m_radioVcd20->setChecked( true ); + break; + } + + m_spinVolumeCount->setValue( vcdDoc() ->vcdOptions() ->volumeCount() ); + m_spinVolumeNumber->setMaxValue( vcdDoc() ->vcdOptions() ->volumeCount() ); + m_spinVolumeNumber->setValue( vcdDoc() ->vcdOptions() ->volumeNumber() ); + + m_checkAutoDetect->setChecked( vcdDoc() ->vcdOptions() ->AutoDetect() ); + m_groupVcdFormat->setDisabled( vcdDoc() ->vcdOptions() ->AutoDetect() ); + + m_check2336->setChecked( vcdDoc() ->vcdOptions() ->Sector2336() ); + + m_checkCdiSupport->setEnabled( false ); + m_checkCdiSupport->setChecked( false ); + m_groupCdi->setEnabled( false ); + + if ( m_radioSvcd10->isChecked() ) { + m_checkNonCompliant->setChecked( vcdDoc() ->vcdOptions() ->NonCompliantMode() ); + m_checkUpdateScanOffsets->setEnabled( true ); + m_checkVCD30interpretation->setChecked( vcdDoc() ->vcdOptions() ->VCD30interpretation() ); + } else if ( m_radioHqVcd10->isChecked() ) { + // NonCompliant only for SVCD + m_checkNonCompliant->setChecked( false ); + m_checkNonCompliant->setEnabled( false ); + m_checkUpdateScanOffsets->setEnabled( false ); + m_checkVCD30interpretation->setChecked( false ); + m_checkVCD30interpretation->setEnabled( false ); + } else { + // NonCompliant only for SVCD + m_checkNonCompliant->setChecked( false ); + m_checkNonCompliant->setEnabled( false ); + m_checkVCD30interpretation->setChecked( false ); + m_checkUpdateScanOffsets->setEnabled( false ); + m_checkVCD30interpretation->setEnabled( false ); + // CD-I only for VCD and CD-i application was found :) + if ( vcdDoc() ->vcdOptions() ->checkCdiFiles() ) { + m_checkCdiSupport->setEnabled( true ); + m_checkCdiSupport->setChecked( vcdDoc() ->vcdOptions() ->CdiSupport() ); + } + } + + // set VolumeID if empty + setVolumeID(); + // m_editVolumeId->setText( vcdDoc() ->vcdOptions() ->volumeId() ); + m_editPublisher->setText( vcdDoc() ->vcdOptions() ->publisher() ); + m_editAlbumId->setText( vcdDoc() ->vcdOptions() ->albumId() ); + + m_checkPbc->setChecked( vcdDoc() ->vcdOptions() ->PbcEnabled() ); + m_checkSegmentFolder->setChecked( vcdDoc() ->vcdOptions() ->SegmentFolder() ); + m_checkRelaxedAps->setChecked( vcdDoc() ->vcdOptions() ->RelaxedAps() ); + m_checkUpdateScanOffsets->setChecked( vcdDoc() ->vcdOptions() ->UpdateScanOffsets() ); + m_spinRestriction->setValue( vcdDoc() ->vcdOptions() ->Restriction() ); + + m_checkGaps->setChecked( vcdDoc() ->vcdOptions() ->UseGaps() ); + slotGapsChecked( m_checkGaps->isChecked() ) ; + m_spinPreGapLeadout->setValue( vcdDoc() ->vcdOptions() ->PreGapLeadout() ); + m_spinPreGapTrack->setValue( vcdDoc() ->vcdOptions() ->PreGapTrack() ); + m_spinFrontMarginTrack->setValue( vcdDoc() ->vcdOptions() ->FrontMarginTrack() ); + m_spinRearMarginTrack->setValue( vcdDoc() ->vcdOptions() ->RearMarginTrack() ); + m_spinFrontMarginTrackSVCD->setValue( vcdDoc() ->vcdOptions() ->FrontMarginTrackSVCD() ); + m_spinRearMarginTrackSVCD->setValue( vcdDoc() ->vcdOptions() ->RearMarginTrackSVCD() ); + + if ( !doc() ->tempDir().isEmpty() ) + m_tempDirSelectionWidget->setTempPath( doc() ->tempDir() ); + + loadCdiConfig(); +} + +void K3bVcdBurnDialog::loadUserDefaults( KConfigBase* c ) +{ + K3bProjectBurnDialog::loadUserDefaults( c ); + + K3bVcdOptions o = K3bVcdOptions::load( c ); + + m_checkAutoDetect->setChecked( o.AutoDetect() ); + m_check2336->setChecked( o.Sector2336() ); + + m_checkCdiSupport->setChecked( false ); + m_checkCdiSupport->setEnabled( false ); + m_groupCdi->setEnabled( false ); + + if ( m_radioSvcd10->isChecked() ) { + m_checkNonCompliant->setChecked( o.NonCompliantMode() ); + m_checkVCD30interpretation->setChecked( o.VCD30interpretation() ); + } else { + m_checkNonCompliant->setChecked( false ); + m_checkNonCompliant->setEnabled( false ); + m_checkVCD30interpretation->setChecked( false ); + m_checkVCD30interpretation->setEnabled( false ); + if ( vcdDoc() ->vcdOptions() ->checkCdiFiles() ) { + m_checkCdiSupport->setEnabled( true ); + m_checkCdiSupport->setChecked( o.CdiSupport() ); + } + } + + m_spinVolumeCount->setValue( o.volumeCount() ); + m_spinVolumeNumber->setMaxValue( o.volumeCount() ); + m_spinVolumeNumber->setValue( o.volumeNumber() ); + + m_editVolumeId->setText( o.volumeId() ); + m_editPublisher->setText( o.publisher() ); + m_editAlbumId->setText( o.albumId() ); + m_checkPbc->setChecked( o.PbcEnabled() ); + m_checkSegmentFolder->setChecked( o.SegmentFolder() ); + m_checkRelaxedAps->setChecked( o.RelaxedAps() ); + m_checkUpdateScanOffsets->setChecked( o.UpdateScanOffsets() ); + m_spinRestriction->setValue( o.Restriction() ); + + m_checkGaps->setChecked( o.UseGaps() ); + m_spinPreGapLeadout->setValue( o.PreGapLeadout() ); + m_spinPreGapTrack->setValue( o.PreGapTrack() ); + m_spinFrontMarginTrack->setValue( o.FrontMarginTrack() ); + m_spinRearMarginTrack->setValue( o.RearMarginTrack() ); + m_spinFrontMarginTrackSVCD->setValue( o.FrontMarginTrackSVCD() ); + m_spinRearMarginTrackSVCD->setValue( o.RearMarginTrackSVCD() ); + + loadCdiConfig(); +} + + +void K3bVcdBurnDialog::saveUserDefaults( KConfigBase* c ) +{ + K3bProjectBurnDialog::saveUserDefaults( c ); + + K3bVcdOptions o; + + o.setVolumeId( m_editVolumeId->text() ); + o.setPublisher( m_editPublisher->text() ); + o.setAlbumId( m_editAlbumId->text() ); + o.setAutoDetect( m_checkAutoDetect->isChecked() ); + o.setNonCompliantMode( m_checkNonCompliant->isChecked() ); + o.setVCD30interpretation( m_checkVCD30interpretation->isChecked() ); + o.setSector2336( m_check2336->isChecked() ); + o.setVolumeCount( m_spinVolumeCount->value() ); + o.setVolumeNumber( m_spinVolumeNumber->value() ); + o.setCdiSupport( m_checkCdiSupport->isChecked() ); + o.setPbcEnabled( m_checkPbc->isChecked() ); + o.setSegmentFolder( m_checkSegmentFolder->isChecked() ); + o.setRelaxedAps( m_checkRelaxedAps->isChecked() ); + o.setUpdateScanOffsets( m_checkUpdateScanOffsets->isChecked() ); + o.setRestriction( m_spinRestriction->value() ); + o.setUseGaps( m_checkGaps->isChecked() ); + o.setPreGapLeadout( m_spinPreGapLeadout->value() ); + o.setPreGapTrack( m_spinPreGapTrack->value() ); + o.setFrontMarginTrack( m_spinFrontMarginTrack->value() ); + o.setRearMarginTrack( m_spinRearMarginTrack->value() ); + o.setFrontMarginTrackSVCD( m_spinFrontMarginTrackSVCD->value() ); + o.setRearMarginTrackSVCD( m_spinRearMarginTrackSVCD->value() ); + + o.save( c ); + + saveCdiConfig(); +} + +void K3bVcdBurnDialog::saveCdiConfig() +{ + + QString filename = locateLocal( "appdata", "cdi/cdi_vcd.cfg" ); + if ( QFile::exists( filename ) ) + QFile::remove + ( filename ); + + QFile cdi( filename ); + if ( !cdi.open( IO_WriteOnly ) ) + return ; + + QTextStream s( &cdi ); + int i = m_editCdiCfg->numLines(); + + for ( int j = 0; j < i; j++ ) + s << QString( "%1" ).arg( m_editCdiCfg->textLine( j ) ) << "\n"; + + cdi.close(); + + m_editCdiCfg->setEdited( false ); +} + +void K3bVcdBurnDialog::loadCdiConfig() +{ + QString filename = locateLocal( "appdata", "cdi/cdi_vcd.cfg" ); + if ( QFile::exists( filename ) ) { + QFile cdi( filename ); + if ( !cdi.open( IO_ReadOnly ) ) { + loadDefaultCdiConfig(); + return ; + } + + QTextStream s( &cdi ); + + m_editCdiCfg->clear(); + + while ( !s.atEnd() ) + m_editCdiCfg->insertLine( s.readLine() ); + + cdi.close(); + m_editCdiCfg->setEdited( false ); + m_editCdiCfg->setCursorPosition( 0, 0, false ); + m_groupCdi->setEnabled( m_checkCdiSupport->isChecked() ); + } else + loadDefaultCdiConfig(); + +} + +void K3bVcdBurnDialog::loadDefaultCdiConfig() +{ + QString filename = locate( "data", "k3b/cdi/cdi_vcd.cfg" ); + if ( QFile::exists( filename ) ) { + QFile cdi( filename ); + if ( !cdi.open( IO_ReadOnly ) ) { + m_checkCdiSupport->setChecked( false ); + m_checkCdiSupport->setEnabled( false ); + return ; + } + + QTextStream s( &cdi ); + + m_editCdiCfg->clear(); + + while ( !s.atEnd() ) + m_editCdiCfg->insertLine( s.readLine() ); + + cdi.close(); + m_editCdiCfg->setEdited( false ); + m_editCdiCfg->setCursorPosition( 0, 0, false ); + m_groupCdi->setEnabled( m_checkCdiSupport->isChecked() ); + } +} + +void K3bVcdBurnDialog::setVolumeID() +{ + if ( m_editVolumeId->text().length() < 1 ) { + if ( m_radioSvcd10->isChecked() ) + m_editVolumeId->setText( "SUPER_VIDEOCD" ); + else if ( m_radioHqVcd10->isChecked() ) + m_editVolumeId->setText( "HQ_VIDEOCD" ); + else + m_editVolumeId->setText( "VIDEOCD" ); + } +} + +void K3bVcdBurnDialog::slotSpinVolumeCount() +{ + m_spinVolumeNumber->setMaxValue( m_spinVolumeCount->value() ); +} + +void K3bVcdBurnDialog::slotVcdTypeClicked( int i ) +{ + + switch ( i ) { + case 0: + // vcd 1.1 no support for version 3.x. + // v4 work also for vcd 1.1 but without CD-i menus. + // Do anybody use vcd 1.1 with cd-i???? + m_checkCdiSupport->setEnabled( vcdDoc() ->vcdOptions() ->checkCdiFiles() ); + m_checkCdiSupport->setChecked( false ); + + m_checkNonCompliant->setEnabled( false ); + m_checkNonCompliant->setChecked( false ); + m_checkVCD30interpretation->setEnabled( false ); + m_checkVCD30interpretation->setChecked( false ); + m_checkUpdateScanOffsets->setEnabled( false ); + m_checkUpdateScanOffsets->setChecked( false ); + break; + case 1: + //vcd 2.0 + m_checkCdiSupport->setEnabled( vcdDoc() ->vcdOptions() ->checkCdiFiles() ); + m_groupCdi->setEnabled( m_checkCdiSupport->isChecked() ); + + m_checkNonCompliant->setEnabled( false ); + m_checkNonCompliant->setChecked( false ); + m_checkVCD30interpretation->setEnabled( false ); + m_checkVCD30interpretation->setChecked( false ); + m_checkUpdateScanOffsets->setEnabled( false ); + m_checkUpdateScanOffsets->setChecked( false ); + break; + case 2: + //svcd 1.0 + m_checkCdiSupport->setEnabled( false ); + m_checkCdiSupport->setChecked( false ); + m_groupCdi->setEnabled( false ); + + m_checkNonCompliant->setEnabled( true ); + m_checkVCD30interpretation->setEnabled( true ); + m_checkUpdateScanOffsets->setEnabled( true ); + break; + case 3: + //hqvcd 1.0 + m_checkCdiSupport->setEnabled( false ); + m_checkCdiSupport->setChecked( false ); + m_groupCdi->setEnabled( false ); + + m_checkNonCompliant->setEnabled( false ); + m_checkNonCompliant->setChecked( false ); + m_checkVCD30interpretation->setEnabled( false ); + m_checkVCD30interpretation->setChecked( false ); + m_checkUpdateScanOffsets->setEnabled( true ); + break; + } + + MarginChecked( m_checkGaps->isChecked() ); + +} + +void K3bVcdBurnDialog::slotGapsChecked( bool b ) +{ + m_labelPreGapLeadout->setEnabled( b ); + m_spinPreGapLeadout->setEnabled( b ); + m_labelPreGapTrack->setEnabled( b ); + m_spinPreGapTrack->setEnabled( b ); + MarginChecked( b ); +} + +void K3bVcdBurnDialog::MarginChecked( bool b ) +{ + if ( m_radioSvcd10->isChecked() || m_radioHqVcd10->isChecked() ) { + m_spinFrontMarginTrack->setHidden( true ); + m_spinFrontMarginTrackSVCD->setHidden( false ); + m_spinRearMarginTrack->setHidden( true ); + m_spinRearMarginTrackSVCD->setHidden( false ); + } else { + m_spinFrontMarginTrack->setHidden( false ); + m_spinFrontMarginTrackSVCD->setHidden( true ); + m_spinRearMarginTrack->setHidden( false ); + m_spinRearMarginTrackSVCD->setHidden( true ); + } + + m_labelFrontMarginTrack->setEnabled( b ); + m_spinFrontMarginTrack->setEnabled( b ); + m_spinFrontMarginTrackSVCD->setEnabled( b ); + + m_labelRearMarginTrack->setEnabled( b ); + m_spinRearMarginTrack->setEnabled( b ); + m_spinRearMarginTrackSVCD->setEnabled( b ); + +} + +void K3bVcdBurnDialog::slotCdiSupportChecked( bool b ) +{ + m_groupCdi->setEnabled( b ); +} + +void K3bVcdBurnDialog::slotAutoDetect( bool b ) +{ + if ( b ) { + m_groupVcdFormat->setButton( vcdDoc() ->vcdOptions() ->mpegVersion() ); + slotVcdTypeClicked( vcdDoc() ->vcdOptions() ->mpegVersion() ); + } + + m_groupVcdFormat->setDisabled( b ); + +} + +void K3bVcdBurnDialog::toggleAll() +{ + K3bProjectBurnDialog::toggleAll(); + + m_writingModeWidget->setSupportedModes( K3b::DAO ); + m_checkRemoveBufferFiles->setDisabled( m_checkOnlyCreateImage->isChecked() ); +} + +#include "k3bvcdburndialog.moc" diff --git a/src/projects/k3bvcdburndialog.h b/src/projects/k3bvcdburndialog.h new file mode 100644 index 0000000..6f199a9 --- /dev/null +++ b/src/projects/k3bvcdburndialog.h @@ -0,0 +1,142 @@ +/* +* +* $Id: k3bvcdburndialog.h 619556 2007-01-03 17:38:12Z trueg $ +* Copyright (C) 2003-2004 Christian Kvasny <chris@k3b.org> +* +* This file is part of the K3b project. +* Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> +* +* 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 2 of the License, or +* (at your option) any later version. +* See the file "COPYING" for the exact licensing terms. +*/ + +#ifndef K3BVCDBURNDIALOG_H +#define K3BVCDBURNDIALOG_H + +#include "k3bprojectburndialog.h" +#include <qmultilineedit.h> + +class QCheckBox; +class QGroupBox; +class QButtonGroup; +class QSpinBox; +class QRadioButton; +class QLabel; +class QLineEdit; +class QMultiLineEdit; +class QToolButton; +class K3bWriterSelectionWidget; +class K3bTempDirSelectionWidget; +class K3bVcdDoc; +class K3bVcdOptions; + +class K3bVcdBurnDialog : public K3bProjectBurnDialog +{ + Q_OBJECT + + public: + K3bVcdBurnDialog( K3bVcdDoc* doc, QWidget *parent = 0, const char *name = 0, bool modal = true ); + ~K3bVcdBurnDialog(); + + K3bVcdDoc* vcdDoc() const + { + return m_vcdDoc; + } + + protected: + void setupAdvancedTab(); + void setupVideoCdTab(); + void setupLabelTab(); + void saveSettings(); + void readSettings(); + + void loadK3bDefaults(); + void loadUserDefaults( KConfigBase* ); + void saveUserDefaults( KConfigBase* ); + + // ----------------------------------------------------------- + // the video-cd-tab + // ----------------------------------------------------------- + + QButtonGroup* m_groupVcdFormat; + QRadioButton* m_radioVcd11; + QRadioButton* m_radioVcd20; + QRadioButton* m_radioSvcd10; + QRadioButton* m_radioHqVcd10; + + QGroupBox* m_groupOptions; + QCheckBox* m_checkAutoDetect; + QCheckBox* m_checkNonCompliant; + QCheckBox* m_checkVCD30interpretation; + QCheckBox* m_check2336; + + // CD-i + QGroupBox* m_groupCdi; + QCheckBox* m_checkCdiSupport; + QMultiLineEdit* m_editCdiCfg; + + + // ----------------------------------------------------------- + // the video-label-tab + // ----------------------------------------------------------- + + QLineEdit* m_editVolumeId; + QLineEdit* m_editPublisher; + QLineEdit* m_editAlbumId; + + QSpinBox* m_spinVolumeCount; + QSpinBox* m_spinVolumeNumber; + + // ----------------------------------------------------------- + // the advanced-tab + // ----------------------------------------------------------- + + QGroupBox* m_groupGeneric; + QGroupBox* m_groupGaps; + QGroupBox* m_groupMisc; + + QCheckBox* m_checkPbc; + QCheckBox* m_checkSegmentFolder; + QCheckBox* m_checkRelaxedAps; + QCheckBox* m_checkUpdateScanOffsets; + QCheckBox* m_checkGaps; + + QSpinBox* m_spinRestriction; + QSpinBox* m_spinPreGapLeadout; + QSpinBox* m_spinPreGapTrack; + QSpinBox* m_spinFrontMarginTrack; + QSpinBox* m_spinRearMarginTrack; + QSpinBox* m_spinFrontMarginTrackSVCD; + QSpinBox* m_spinRearMarginTrackSVCD; + + QLabel* m_labelRestriction; + QLabel* m_labelPreGapLeadout; + QLabel* m_labelPreGapTrack; + QLabel* m_labelFrontMarginTrack; + QLabel* m_labelRearMarginTrack; + + // ----------------------------------------------------------- + + private: + K3bVcdDoc* m_vcdDoc; + void setVolumeID( ); + void MarginChecked( bool ); + void saveCdiConfig(); + void loadCdiConfig(); + void loadDefaultCdiConfig(); + void toggleAll(); + + protected slots: + void slotStartClicked(); + + void slotGapsChecked( bool ); + void slotSpinVolumeCount(); + void slotVcdTypeClicked( int ); + void slotCdiSupportChecked( bool ); + void slotAutoDetect( bool ); +}; + +#endif diff --git a/src/projects/k3bvcdlistview.cpp b/src/projects/k3bvcdlistview.cpp new file mode 100644 index 0000000..f61863b --- /dev/null +++ b/src/projects/k3bvcdlistview.cpp @@ -0,0 +1,271 @@ +/* +* +* $Id: k3bvcdlistview.cpp 628165 2007-01-29 11:01:22Z trueg $ +* Copyright (C) 2003-2004 Christian Kvasny <chris@k3b.org> +* +* This file is part of the K3b project. +* Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> +* +* 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 2 of the License, or +* (at your option) any later version. +* See the file "COPYING" for the exact licensing terms. +*/ + +#include <qheader.h> +#include <qtimer.h> +#include <qdragobject.h> +#include <qpoint.h> +#include <qptrlist.h> +#include <qstringlist.h> +#include <qevent.h> +#include <qpainter.h> +#include <qfontmetrics.h> + +#include <kiconloader.h> +#include <kurl.h> +#include <kurldrag.h> +#include <klocale.h> +#include <kaction.h> +#include <kpopupmenu.h> +#include <kdialog.h> + +// K3b Includes +#include "k3bvcdlistview.h" +#include "k3bvcdlistviewitem.h" +#include "k3bvcdtrack.h" +#include "k3bvcdtrackdialog.h" +#include "k3bvcddoc.h" +#include <k3bview.h> + +K3bVcdListView::K3bVcdListView( K3bView* view, K3bVcdDoc* doc, QWidget *parent, const char *name ) + : K3bListView( parent, name ), m_doc( doc ), m_view( view ) +{ + setAcceptDrops( true ); + setDropVisualizer( true ); + setAllColumnsShowFocus( true ); + setDragEnabled( true ); + setSelectionModeExt( KListView::Extended ); + setItemsMovable( false ); + + setNoItemText( i18n( "Use drag'n'drop to add MPEG video files to the project." ) + "\n" + + i18n( "After that press the burn button to write the CD." ) ); + + setSorting( 0 ); + + setupActions(); + setupPopupMenu(); + + setupColumns(); + header() ->setClickEnabled( false ); + + connect( this, SIGNAL( dropped( KListView*, QDropEvent*, QListViewItem* ) ), + this, SLOT( slotDropped( KListView*, QDropEvent*, QListViewItem* ) ) ); + connect( this, SIGNAL( contextMenu( KListView*, QListViewItem*, const QPoint& ) ), + this, SLOT( showPopupMenu( KListView*, QListViewItem*, const QPoint& ) ) ); + connect( this, SIGNAL( doubleClicked( QListViewItem*, const QPoint&, int ) ), + this, SLOT( showPropertiesDialog() ) ); + + connect( m_doc, SIGNAL( changed() ), this, SLOT( slotUpdateItems() ) ); + connect( m_doc, SIGNAL( trackRemoved( K3bVcdTrack* ) ), this, SLOT( slotTrackRemoved( K3bVcdTrack* ) ) ); + + slotUpdateItems(); +} + +K3bVcdListView::~K3bVcdListView() +{} + +void K3bVcdListView::setupColumns() +{ + addColumn( i18n( "No." ) ); + addColumn( i18n( "Title" ) ); + addColumn( i18n( "Type" ) ); + addColumn( i18n( "Resolution" ) ); + addColumn( i18n( "High Resolution" ) ); + addColumn( i18n( "Framerate" ) ); + addColumn( i18n( "Muxrate" ) ); + addColumn( i18n( "Duration" ) ); + addColumn( i18n( "File Size" ) ); + addColumn( i18n( "Filename" ) ); +} + + +void K3bVcdListView::setupActions() +{ + m_actionCollection = new KActionCollection( this ); + m_actionProperties = new KAction( i18n( "Properties" ), "misc", 0, this, SLOT( showPropertiesDialog() ), actionCollection() ); + m_actionRemove = new KAction( i18n( "Remove" ), "editdelete", Key_Delete, this, SLOT( slotRemoveTracks() ), actionCollection() ); + + // disabled by default + m_actionRemove->setEnabled( false ); +} + + +void K3bVcdListView::setupPopupMenu() +{ + m_popupMenu = new KPopupMenu( this, "VcdViewPopupMenu" ); + m_actionRemove->plug( m_popupMenu ); + m_popupMenu->insertSeparator(); + m_actionProperties->plug( m_popupMenu ); + m_popupMenu->insertSeparator(); + m_view->actionCollection() ->action( "project_burn" ) ->plug( m_popupMenu ); +} + + +bool K3bVcdListView::acceptDrag( QDropEvent* e ) const +{ + // the first is for built-in item moving, the second for dropping urls + return ( KListView::acceptDrag( e ) || KURLDrag::canDecode( e ) ); +} + + +QDragObject* K3bVcdListView::dragObject() +{ + QPtrList<QListViewItem> list = selectedItems(); + + if ( list.isEmpty() ) + return 0; + + QPtrListIterator<QListViewItem> it( list ); + KURL::List urls; + + for ( ; it.current(); ++it ) + urls.append( KURL( ( ( K3bVcdListViewItem* ) it.current() ) ->vcdTrack() ->absPath() ) ); + + return KURLDrag::newDrag( urls, viewport() ); +} + + +void K3bVcdListView::slotDropped( KListView*, QDropEvent* e, QListViewItem* after ) +{ + if ( !e->isAccepted() ) + return ; + + int pos; + if ( after == 0L ) + pos = 0; + else + pos = ( ( K3bVcdListViewItem* ) after ) ->vcdTrack() ->index() + 1; + + if ( e->source() == viewport() ) { + QPtrList<QListViewItem> sel = selectedItems(); + QPtrListIterator<QListViewItem> it( sel ); + K3bVcdTrack* trackAfter = ( after ? ( ( K3bVcdListViewItem* ) after ) ->vcdTrack() : 0 ); + while ( it.current() ) { + K3bVcdTrack * track = ( ( K3bVcdListViewItem* ) it.current() ) ->vcdTrack(); + m_doc->moveTrack( track, trackAfter ); + trackAfter = track; + ++it; + } + } else { + KURL::List urls; + KURLDrag::decode( e, urls ); + + m_doc->addTracks( urls, pos ); + } + + // now grab that focus + setFocus(); +} + + +void K3bVcdListView::insertItem( QListViewItem* item ) +{ + KListView::insertItem( item ); + + // make sure at least one item is selected + if ( selectedItems().isEmpty() ) { + setSelected( firstChild(), true ); + } +} + +void K3bVcdListView::showPopupMenu( KListView*, QListViewItem* _item, const QPoint& _point ) +{ + if ( _item ) { + m_actionRemove->setEnabled( true ); + } else { + m_actionRemove->setEnabled( false ); + } + + m_popupMenu->popup( _point ); +} + +void K3bVcdListView::showPropertiesDialog() +{ + QPtrList<K3bVcdTrack> selected = selectedTracks(); + if ( !selected.isEmpty() && selected.count() == 1 ) { + QPtrList<K3bVcdTrack> tracks = *m_doc->tracks(); + K3bVcdTrackDialog d( m_doc, tracks, selected, this ); + if ( d.exec() ) { + repaint(); + } + } else { + m_view->slotProperties(); + } +} + +QPtrList<K3bVcdTrack> K3bVcdListView::selectedTracks() +{ + QPtrList<K3bVcdTrack> selectedTracks; + QPtrList<QListViewItem> selectedVI( selectedItems() ); + for ( QListViewItem * item = selectedVI.first(); item != 0; item = selectedVI.next() ) { + K3bVcdListViewItem * vcdItem = dynamic_cast<K3bVcdListViewItem*>( item ); + if ( vcdItem ) { + selectedTracks.append( vcdItem->vcdTrack() ); + } + } + + return selectedTracks; +} + + +void K3bVcdListView::slotRemoveTracks() +{ + QPtrList<K3bVcdTrack> selected = selectedTracks(); + if ( !selected.isEmpty() ) { + + for ( K3bVcdTrack * track = selected.first(); track != 0; track = selected.next() ) { + m_doc->removeTrack( track ); + } + } + + if ( m_doc->numOfTracks() == 0 ) { + m_actionRemove->setEnabled( false ); + } +} + + +void K3bVcdListView::slotTrackRemoved( K3bVcdTrack* track ) +{ + QListViewItem * viewItem = m_itemMap[ track ]; + m_itemMap.remove( track ); + delete viewItem; +} + + +void K3bVcdListView::slotUpdateItems() +{ + // iterate through all doc-tracks and test if we have a listItem, if not, create one + K3bVcdTrack * track = m_doc->first(); + K3bVcdTrack* lastTrack = 0; + while ( track != 0 ) { + if ( !m_itemMap.contains( track ) ) + m_itemMap.insert( track, new K3bVcdListViewItem( track, this, m_itemMap[ lastTrack ] ) ); + + lastTrack = track; + track = m_doc->next(); + } + + if ( m_doc->numOfTracks() > 0 ) { + m_actionRemove->setEnabled( true ); + } else { + m_actionRemove->setEnabled( false ); + } + + sort(); // This is so lame! + + header()->setShown( m_doc->numOfTracks() > 0 ); +} + +#include "k3bvcdlistview.moc" diff --git a/src/projects/k3bvcdlistview.h b/src/projects/k3bvcdlistview.h new file mode 100644 index 0000000..71d22d7 --- /dev/null +++ b/src/projects/k3bvcdlistview.h @@ -0,0 +1,90 @@ +/* +* +* $Id: k3bvcdlistview.h 619556 2007-01-03 17:38:12Z trueg $ +* Copyright (C) 2003-2004 Christian Kvasny <chris@k3b.org> +* +* This file is part of the K3b project. +* Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> +* +* 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 2 of the License, or +* (at your option) any later version. +* See the file "COPYING" for the exact licensing terms. +*/ + +#ifndef K3BVCDLISTVIEW_H +#define K3BVCDLISTVIEW_H + + +#include <k3blistview.h> + +#include <qmap.h> + +class QDragEnterEvent; +class QDragObject; +class QDropEvent; +class QTimer; +class KPopupMenu; +class KAction; +class K3bVcdDoc; +class K3bView; +class K3bVcdTrack; +class KActionCollection; +class K3bVcdListViewItem; +class QPainter; + + +class K3bVcdListView : public K3bListView +{ + Q_OBJECT + + public: + K3bVcdListView( K3bView*, K3bVcdDoc*, QWidget *parent = 0, const char *name = 0 ); + ~K3bVcdListView(); + + /** + * reimplemented from KListView + */ + void insertItem( QListViewItem* ); + + KActionCollection* actionCollection() const + { + return m_actionCollection; + } + + QPtrList<K3bVcdTrack> selectedTracks(); + + signals: + void lengthReady(); + + private: + void setupColumns(); + void setupPopupMenu(); + void setupActions(); + + K3bVcdDoc* m_doc; + K3bView* m_view; + + KAction* m_actionProperties; + KAction* m_actionRemove; + KActionCollection* m_actionCollection; + + KPopupMenu* m_popupMenu; + + QMap<K3bVcdTrack*, K3bVcdListViewItem*> m_itemMap; + + private slots: + void slotDropped( KListView*, QDropEvent* e, QListViewItem* after ); + void slotUpdateItems(); + void showPopupMenu( KListView*, QListViewItem* item, const QPoint& ); + void showPropertiesDialog(); + void slotRemoveTracks(); + void slotTrackRemoved( K3bVcdTrack* ); + + protected: + bool acceptDrag( QDropEvent* e ) const; + QDragObject* dragObject(); +}; + +#endif diff --git a/src/projects/k3bvcdlistviewitem.cpp b/src/projects/k3bvcdlistviewitem.cpp new file mode 100644 index 0000000..02df525 --- /dev/null +++ b/src/projects/k3bvcdlistviewitem.cpp @@ -0,0 +1,129 @@ +/* +* +* $Id: k3bvcdlistviewitem.cpp 619556 2007-01-03 17:38:12Z trueg $ +* Copyright (C) 2003-2004 Christian Kvasny <chris@k3b.org> +* +* This file is part of the K3b project. +* Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> +* +* 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 2 of the License, or +* (at your option) any later version. +* See the file "COPYING" for the exact licensing terms. +*/ + +#include <kio/global.h> +#include <kiconloader.h> + + +// K3b Includes +#include "k3bvcdlistviewitem.h" +#include "k3bvcdtrack.h" +#include <k3bglobals.h> + +K3bVcdListViewItem::K3bVcdListViewItem( K3bVcdTrack* track, K3bListView* parent ) + : K3bListViewItem( parent ), m_track( track ) +{ + setEditor( 1, LINE ); + animate(); +} + +K3bVcdListViewItem::K3bVcdListViewItem( K3bVcdTrack* track, K3bListView* parent, QListViewItem* after ) + : K3bListViewItem( parent, after ), m_track( track ) +{ + setEditor( 1, LINE ); + animate(); +} + + +K3bVcdListViewItem::~K3bVcdListViewItem() +{} + +QString K3bVcdListViewItem::text( int i ) const +{ + // + // We add two spaces after all strings (except the once renamable) + // to increase readability + // + + switch ( i ) { + case 0: + return QString::number( m_track->index() + 1 ).rightJustify( 2, ' ' ) + " "; + case 1: + return m_track->title(); + case 2: + // track mpegtype + return m_track->mpegTypeS() + " "; + case 3: + // track mpegsize + return m_track->resolution() + " "; + case 4: + // track low mpegsize for MPEG1 Stills + return m_track->highresolution() + " "; + case 5: + // track mpegfps + return m_track->video_frate() + " "; + case 6: + // track mpegmbps + return QString::number( m_track->muxrate() ) + " "; + case 7: + // track mpegduration + return m_track->duration() + " "; + case 8: + // track size + return KIO::convertSize( m_track->size() ) + " "; + case 9: + // filename + return m_track->fileName(); + + default: + return KListViewItem::text( i ); + } +} + +void K3bVcdListViewItem::setText( int col, const QString& text ) +{ + if ( col == 1 ) { + // this is the title field + m_track->setTitle( text ); + } + + KListViewItem::setText( col, text ); +} + + +QString K3bVcdListViewItem::key( int, bool ) const +{ + QString num = QString::number( m_track->index() ); + if ( num.length() == 1 ) + return "00" + num; + else if ( num.length() == 2 ) + return "0" + num; + + return num; +} + +bool K3bVcdListViewItem::animate() +{ + bool animate = false; + + switch ( m_track->mpegType() ) { + case 0: // MPEG_MOTION + setPixmap( 2, ( SmallIcon( "video" ) ) ); + break; + case 1: // MPEG_STILL + setPixmap( 2, ( SmallIcon( "image" ) ) ); + break; + case 2: // MPEG_AUDIO + setPixmap( 2, ( SmallIcon( "sound" ) ) ); + break; + + default: + setPixmap( 2, ( SmallIcon( "video" ) ) ); + break; + } + + + return animate; +} diff --git a/src/projects/k3bvcdlistviewitem.h b/src/projects/k3bvcdlistviewitem.h new file mode 100644 index 0000000..0101850 --- /dev/null +++ b/src/projects/k3bvcdlistviewitem.h @@ -0,0 +1,50 @@ +/* +* +* $Id: k3bvcdlistviewitem.h 619556 2007-01-03 17:38:12Z trueg $ +* Copyright (C) 2003-2004 Christian Kvasny <chris@k3b.org> +* +* This file is part of the K3b project. +* Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> +* +* 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 2 of the License, or +* (at your option) any later version. +* See the file "COPYING" for the exact licensing terms. +*/ + +#ifndef K3BVCDLISTVIEWITEM_H +#define K3BVCDLISTVIEWITEM_H + +#include <k3blistview.h> + +class K3bVcdTrack; + +class K3bVcdListViewItem : public K3bListViewItem +{ + + public: + K3bVcdListViewItem( K3bVcdTrack* track, K3bListView* parent ); + K3bVcdListViewItem( K3bVcdTrack* track, K3bListView* parent, QListViewItem* after ); + ~K3bVcdListViewItem(); + + /** reimplemented from QListViewItem */ + QString text( int i ) const; + + /** reimplemented from QListViewItem */ + void setText( int col, const QString& text ); + + /** reimplemented from QListViewItem */ + QString key( int column, bool a ) const; + bool animate(); + + K3bVcdTrack* vcdTrack() + { + return m_track; + } + + private: + K3bVcdTrack* m_track; +}; + +#endif diff --git a/src/projects/k3bvcdtrackdialog.cpp b/src/projects/k3bvcdtrackdialog.cpp new file mode 100644 index 0000000..06588b8 --- /dev/null +++ b/src/projects/k3bvcdtrackdialog.cpp @@ -0,0 +1,802 @@ +/* +* +* $Id: k3bvcdtrackdialog.cpp 619556 2007-01-03 17:38:12Z trueg $ +* Copyright (C) 2003-2004 Christian Kvasny <chris@k3b.org> +* +* This file is part of the K3b project. +* Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> +* +* 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 2 of the License, or +* (at your option) any later version. +* See the file "COPYING" for the exact licensing terms. +*/ + +// Qt Includes +#include <qbuttongroup.h> +#include <qcheckbox.h> +#include <qcombobox.h> +#include <qframe.h> +#include <qgroupbox.h> +#include <qhbox.h> +#include <qlineedit.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qmultilineedit.h> +#include <qpixmap.h> +#include <qradiobutton.h> +#include <qtable.h> +#include <qtooltip.h> +#include <qwhatsthis.h> + +// Kde Includes +#include <kiconloader.h> +#include <kio/global.h> +#include <klocale.h> +#include <kmimetype.h> +#include <knuminput.h> +#include <kurl.h> + +// K3b Includes +#include "k3bvcdtrackdialog.h" +#include "k3bvcdtrack.h" +#include <kcutlabel.h> +#include <k3bmsf.h> +#include <k3bglobals.h> +#include <k3bcutcombobox.h> + + +K3bVcdTrackDialog::K3bVcdTrackDialog( K3bVcdDoc* _doc, QPtrList<K3bVcdTrack>& tracks, QPtrList<K3bVcdTrack>& selectedTracks, QWidget* parent, const char* name ) + : KDialogBase( KDialogBase::Plain, i18n( "Video Track Properties" ), KDialogBase::Ok | KDialogBase::Cancel | KDialogBase::Apply, + KDialogBase::Ok, parent, name ) +{ + prepareGui(); + + setupPbcTab(); + setupPbcKeyTab(); + setupVideoTab(); + setupAudioTab(); + + m_tracks = tracks; + m_selectedTracks = selectedTracks; + m_vcdDoc = _doc; + m_numkeysmap.clear(); + + if ( !m_selectedTracks.isEmpty() ) { + + K3bVcdTrack * selectedTrack = m_selectedTracks.first(); + + m_displayFileName->setText( selectedTrack->fileName() ); + m_displayLength->setText( selectedTrack->duration() ); + m_displaySize->setText( KIO::convertSize( selectedTrack->size() ) ); + m_muxrate->setText( i18n( "%1 bit/s" ).arg( selectedTrack->muxrate() ) ); + + if ( selectedTrack->isSegment() ) + m_labelMimeType->setPixmap( SmallIcon( "image", KIcon::SizeMedium ) ); + else + m_labelMimeType->setPixmap( SmallIcon( "video", KIcon::SizeMedium ) ); + + fillGui(); + } +} + +K3bVcdTrackDialog::~K3bVcdTrackDialog() +{} + +void K3bVcdTrackDialog::slotOk() +{ + slotApply(); + done( 0 ); +} + +void K3bVcdTrackDialog::setPbcTrack( K3bVcdTrack* selected, K3bCutComboBox* box, int which ) +{ + // TODO: Unset Userdefined on default settings + kdDebug() << QString( "K3bVcdTrackDialog::setPbcTrack: currentItem = %1, count = %2" ).arg( box->currentItem() ).arg( m_tracks.count() ) << endl; + + int count = m_tracks.count(); + + if ( selected->getPbcTrack( which ) == m_tracks.at( box->currentItem() ) ) { + if ( selected->getNonPbcTrack( which ) == ( int ) ( box->currentItem() - count ) ) { + kdDebug() << "K3bVcdTrackDialog::setPbcTrack: not changed, return" << endl; + return ; + } + } + + if ( selected->getPbcTrack( which ) ) + selected->getPbcTrack( which ) ->delFromRevRefList( selected ); + + if ( box->currentItem() > count - 1 ) { + selected->setPbcTrack( which ); + selected->setPbcNonTrack( which, box->currentItem() - count ); + } else { + selected->setPbcTrack( which, m_tracks.at( box->currentItem() ) ); + m_tracks.at( box->currentItem() ) ->addToRevRefList( selected ); + } + + selected->setUserDefined( which, true ); +} + +void K3bVcdTrackDialog::slotApply() +{ + // track set + K3bVcdTrack * selectedTrack = m_selectedTracks.first(); + + setPbcTrack( selectedTrack, m_pbc_previous, K3bVcdTrack::PREVIOUS ); + setPbcTrack( selectedTrack, m_pbc_next, K3bVcdTrack::NEXT ); + setPbcTrack( selectedTrack, m_pbc_return, K3bVcdTrack::RETURN ); + setPbcTrack( selectedTrack, m_pbc_default, K3bVcdTrack::DEFAULT ); + setPbcTrack( selectedTrack, m_comboAfterTimeout, K3bVcdTrack::AFTERTIMEOUT ); + + selectedTrack->setPlayTime( m_spin_times->value() ); + selectedTrack->setWaitTime( m_spin_waittime->value() ); + selectedTrack->setReactivity( m_check_reactivity->isChecked() ); + selectedTrack->setPbcNumKeys( m_check_usekeys->isChecked() ); + selectedTrack->setPbcNumKeysUserdefined( m_check_overwritekeys->isChecked() ); + + // global set + VcdOptions() ->setPbcEnabled( m_check_pbc->isChecked() ); + + // define numeric keys + selectedTrack->delDefinedNumKey(); + + if ( m_check_overwritekeys->isChecked() ) { + QListViewItemIterator it( m_list_keys ); + int skiped = 0; + int startkey = 0; + while ( it.current() ) { + if ( it.current() ->text( 1 ).isEmpty() ) { + skiped++; + } else { + + if ( startkey > 0 ) + for ( ; skiped > 0; skiped-- ) + kdDebug() << "Key " << it.current() ->text( 0 ).toInt() - skiped << " Playing: " << displayName( selectedTrack ) << " (normaly none)" << endl; + else { + skiped = 0; + startkey = it.current() ->text( 0 ).toInt(); + } + + QMap<QString, K3bVcdTrack*>::Iterator mit; + mit = m_numkeysmap.find( it.current() ->text( 1 ) ); + if ( mit != m_numkeysmap.end() ) + if ( mit.data() ) { + selectedTrack->setDefinedNumKey( it.current() ->text( 0 ).toInt(), mit.data() ); + kdDebug() << "Key " << it.current() ->text( 0 ).toInt() << " Playing: " << it.current() ->text( 1 ) << "Track: " << mit.data() << endl; + } else { + selectedTrack->setDefinedNumKey( it.current() ->text( 0 ).toInt(), 0L ); + kdDebug() << "Key " << it.current() ->text( 0 ).toInt() << " Playing: " << it.current() ->text( 1 ) << endl; + } + } + ++it; + } + } else { + selectedTrack->setDefinedNumKey( 1, selectedTrack ); + kdDebug() << "Key 1" << " Playing: (default) " << displayName( selectedTrack ) << "Track: " << selectedTrack << endl; + } +} + +void K3bVcdTrackDialog::fillGui() +{ + K3bVcdTrack * selectedTrack = m_selectedTracks.first(); + + m_mpegver_video->setText( selectedTrack->mpegTypeS() ); + m_rate_video->setText( selectedTrack->video_bitrate() ); + m_chromaformat_video->setText( selectedTrack->video_chroma() ); + m_format_video->setText( selectedTrack->video_format() ); + m_highresolution_video->setText( selectedTrack->highresolution() ); + m_resolution_video->setText( selectedTrack->resolution() ); + + m_mpegver_audio->setText( selectedTrack->mpegTypeS( true ) ); + m_rate_audio->setText( selectedTrack->audio_bitrate() ); + + m_sampling_frequency_audio->setText( selectedTrack->audio_sampfreq() ); + m_mode_audio->setText( selectedTrack->audio_mode() ); + m_copyright_audio->setText( selectedTrack->audio_copyright() ); + + fillPbcGui(); + + + QToolTip::add + ( m_pbc_previous, i18n( "May also look like | << on the remote control. " ) ); + QToolTip::add + ( m_pbc_next, i18n( "May also look like >> | on the remote control." ) ); + QToolTip::add + ( m_pbc_return, i18n( "This key may be mapped to the STOP key." ) ); + QToolTip::add + ( m_pbc_default, i18n( "This key is usually mapped to the > or PLAY key." ) ); + QToolTip::add + ( m_comboAfterTimeout, i18n( "Target to be jumped to on time-out of <wait>." ) ); + QToolTip::add + ( m_check_reactivity, i18n( "Delay reactivity of keys." ) ); + QToolTip::add + ( m_check_pbc, i18n( "Playback control, PBC, is available for Video CD 2.0 and Super Video CD 1.0 disc formats." ) ); + QToolTip::add + ( m_check_usekeys, i18n( "Activate the use of numeric keys." ) ); + QToolTip::add + ( m_check_overwritekeys, i18n( "Overwrite default numeric keys." ) ); + QToolTip::add + ( m_list_keys, i18n( "Numeric keys." ) ); + QToolTip::add + ( m_spin_times, i18n( "Times to repeat the playback of 'play track'." ) ); + QToolTip::add + ( m_spin_waittime, i18n( "Time in seconds to wait after playback of 'play track'." ) ); + + QWhatsThis::add + ( m_comboAfterTimeout, i18n( "<p>Target to be jumped to on time-out of <wait>." + "<p>If omitted (and <wait> is not set to an infinite time) one of the targets is selected at random." ) ); + QWhatsThis::add + ( m_check_reactivity, i18n( "<p>When reactivity is set to delayed, it is recommended that the length of the referenced 'play track' is not more than 5 seconds." + "<p>The recommended setting for a play item consisting of one still picture and no audio is to loop once and have a delayed reactivity." ) ); + QWhatsThis::add + ( m_check_pbc, i18n( "<p>Playback control, PBC, is available for Video CD 2.0 and Super Video CD 1.0 disc formats." + "<p>PBC allows control of the playback of play items and the possibility of interaction with the user through the remote control or some other input device available." ) ); + QWhatsThis::add + ( m_check_usekeys, i18n( "These are actually pseudo keys, representing the numeric keys 0, 1, ..., 9." ) ); + QWhatsThis::add + ( m_check_overwritekeys, i18n( "<p>If numeric keys enabled, you can overwrite the default settings." ) ); + QWhatsThis::add + ( m_spin_times, i18n( "<p>Times to repeat the playback of 'play track'." + "<p>The reactivity attribute controls whether the playback of 'play track' is finished, thus delayed, before executing user triggered action or an immediate jump is performed." + "<p>After the specified number of repetitions have completed, the <wait> time begins to count down, unless set to an infinite wait time." + "<p>If this element is omitted, a default of `1' is used, i.e. the 'play track' will be displayed once." ) ); + QWhatsThis::add + ( m_spin_waittime, i18n( "Time in seconds to wait after playback of 'play track' before triggering the <timeout> action (unless the user triggers some action before time ran up)." ) ); + +} + +void K3bVcdTrackDialog::fillPbcGui() +{ + K3bVcdTrack * selectedTrack = m_selectedTracks.first(); + // add tracktitles to combobox + int iPrevious = -1; + int iNext = -1; + int iReturn = -1; + int iDefault = -1; + int iAfterTimeOut = -1; + + K3bVcdTrack* track; + K3bListViewItem* item; + + m_numkeysmap.insert( "", 0L ); + m_numkeysmap.insert( displayName( selectedTrack ) , selectedTrack ); + + for ( track = m_tracks.first(); track; track = m_tracks.next() ) { + QPixmap pm; + if ( track->isSegment() ) + pm = SmallIcon( "image" ); + else + pm = SmallIcon( "video" ); + + QString s = displayName( track ); + if ( track != selectedTrack ) // donot insert selectedTrack, it was as "ItSelf" inserted to the begin of map + m_numkeysmap.insert( s, track ); + + m_pbc_previous->insertItem( pm, s ); + if ( track == selectedTrack->getPbcTrack( K3bVcdTrack::PREVIOUS ) ) + iPrevious = m_pbc_previous->count() - 1; + + m_pbc_next->insertItem( pm, s ); + if ( track == selectedTrack->getPbcTrack( K3bVcdTrack::NEXT ) ) + iNext = m_pbc_next->count() - 1; + + m_pbc_return->insertItem( pm, s ); + if ( track == selectedTrack->getPbcTrack( K3bVcdTrack::RETURN ) ) + iReturn = m_pbc_return->count() - 1; + + m_pbc_default->insertItem( pm, s ); + if ( track == selectedTrack->getPbcTrack( K3bVcdTrack::DEFAULT ) ) + iDefault = m_pbc_default->count() - 1; + + m_comboAfterTimeout->insertItem( pm, s ); + if ( track == selectedTrack->getPbcTrack( K3bVcdTrack::AFTERTIMEOUT ) ) + iAfterTimeOut = m_comboAfterTimeout->count() - 1; + + } + + // add Event Disabled + QPixmap pmDisabled = SmallIcon( "stop" ); + QString txtDisabled = i18n( "Event Disabled" ); + m_pbc_previous->insertItem( pmDisabled, txtDisabled ); + m_pbc_next->insertItem( pmDisabled, txtDisabled ); + m_pbc_return->insertItem( pmDisabled, txtDisabled ); + m_pbc_default->insertItem( pmDisabled, txtDisabled ); + m_comboAfterTimeout->insertItem( pmDisabled, txtDisabled ); + + // add VideoCD End + QPixmap pmEnd = SmallIcon( "cdrom_unmount" ); + QString txtEnd = i18n( "VideoCD END" ); + m_pbc_previous->insertItem( pmEnd, txtEnd ); + m_pbc_next->insertItem( pmEnd, txtEnd ); + m_pbc_return->insertItem( pmEnd, txtEnd ); + m_pbc_default->insertItem( pmEnd, txtEnd ); + m_comboAfterTimeout->insertItem( pmEnd, txtEnd ); + m_numkeysmap.insert( txtEnd, 0L ); + + for ( int i = 99; i > 0; i-- ) { + item = new K3bListViewItem( m_list_keys, QString::number( i ) + " ", "" ); + item->setEditor( 1, K3bListViewItem::COMBO , m_numkeysmap.keys() ); + } + + int count = m_tracks.count(); + + if ( iPrevious < 0 ) + m_pbc_previous->setCurrentItem( count + selectedTrack->getNonPbcTrack( K3bVcdTrack::PREVIOUS ) ); + else + m_pbc_previous->setCurrentItem( iPrevious ); + + if ( iNext < 0 ) + m_pbc_next->setCurrentItem( count + selectedTrack->getNonPbcTrack( K3bVcdTrack::NEXT ) ); + else + m_pbc_next->setCurrentItem( iNext ); + + if ( iReturn < 0 ) + m_pbc_return->setCurrentItem( count + selectedTrack->getNonPbcTrack( K3bVcdTrack::RETURN ) ); + else + m_pbc_return->setCurrentItem( iReturn ); + + if ( iDefault < 0 ) + m_pbc_default->setCurrentItem( count + selectedTrack->getNonPbcTrack( K3bVcdTrack::DEFAULT ) ); + else + m_pbc_default->setCurrentItem( iDefault ); + + if ( iAfterTimeOut < 0 ) + m_comboAfterTimeout->setCurrentItem( count + selectedTrack->getNonPbcTrack( K3bVcdTrack::AFTERTIMEOUT ) ); + else + m_comboAfterTimeout->setCurrentItem( iAfterTimeOut ); + + + m_spin_waittime->setValue( selectedTrack->getWaitTime() ); + m_spin_times->setValue( selectedTrack->getPlayTime() ); + + m_check_reactivity->setChecked( selectedTrack->Reactivity() ); + m_check_pbc->setChecked( VcdOptions() ->PbcEnabled() ); + + m_check_usekeys->setChecked( selectedTrack->PbcNumKeys() ); + m_check_overwritekeys->setChecked( selectedTrack->PbcNumKeysUserdefined() ); + + m_mainTabbed->setTabEnabled( m_widgetnumkeys, m_check_usekeys->isChecked() && m_check_pbc->isChecked() ); + + setDefinedNumKeys(); +} + +void K3bVcdTrackDialog::prepareGui() +{ + QFrame * frame = plainPage(); + + QGridLayout* mainLayout = new QGridLayout( frame ); + mainLayout->setSpacing( spacingHint() ); + mainLayout->setMargin( 0 ); + + m_mainTabbed = new QTabWidget( frame ); + + /////////////////////////////////////////////////// + // FILE-INFO BOX + /////////////////////////////////////////////////// + QGroupBox* groupFileInfo = new QGroupBox( 0, Qt::Vertical, i18n( "File Info" ), frame, "groupFileInfo" ); + groupFileInfo->layout() ->setSpacing( 0 ); + groupFileInfo->layout() ->setMargin( 0 ); + + QGridLayout* groupFileInfoLayout = new QGridLayout( groupFileInfo->layout() ); + groupFileInfoLayout->setAlignment( Qt::AlignTop ); + groupFileInfoLayout->setSpacing( spacingHint() ); + groupFileInfoLayout->setMargin( marginHint() ); + + m_labelMimeType = new QLabel( groupFileInfo, "m_labelMimeType" ); + + m_displayFileName = new KCutLabel( groupFileInfo ); + m_displayFileName->setText( i18n( "Filename" ) ); + m_displayFileName->setAlignment( int( QLabel::AlignTop | QLabel::AlignLeft ) ); + + QLabel* labelSize = new QLabel( i18n( "Size:" ), groupFileInfo, "labelSize" ); + QLabel* labelLength = new QLabel( i18n( "Length:" ), groupFileInfo, "labelLength" ); + QLabel* labelMuxrate = new QLabel( i18n( "Muxrate:" ), groupFileInfo, "labelMuxrate" ); + + m_displaySize = new QLabel( groupFileInfo, "m_displaySize" ); + m_displaySize->setText( "0.0 MB" ); + m_displaySize->setAlignment( int( QLabel::AlignVCenter | QLabel::AlignRight ) ); + + m_displayLength = new QLabel( groupFileInfo, "m_displayLength" ); + m_displayLength->setText( "0:0:0" ); + m_displayLength->setAlignment( int( QLabel::AlignVCenter | QLabel::AlignRight ) ); + + m_muxrate = new QLabel( groupFileInfo, "m_muxrate" ); + m_muxrate->setText( i18n( "%1 bit/s" ).arg( 0 ) ); + m_muxrate->setAlignment( int( QLabel::AlignVCenter | QLabel::AlignRight ) ); + + QFrame* fileInfoLine = new QFrame( groupFileInfo ); + fileInfoLine->setFrameStyle( QFrame::HLine | QFrame::Sunken ); + + groupFileInfoLayout->addWidget( m_labelMimeType, 0, 0 ); + groupFileInfoLayout->addMultiCellWidget( m_displayFileName, 0, 1, 1, 1 ); + groupFileInfoLayout->addMultiCellWidget( fileInfoLine, 2, 2, 0, 1 ); + groupFileInfoLayout->addWidget( labelLength, 3, 0 ); + groupFileInfoLayout->addWidget( labelSize, 4, 0 ); + groupFileInfoLayout->addWidget( labelMuxrate, 5, 0 ); + groupFileInfoLayout->addWidget( m_displayLength, 3, 1 ); + groupFileInfoLayout->addWidget( m_displaySize, 4, 1 ); + groupFileInfoLayout->addWidget( m_muxrate, 5, 1 ); + + groupFileInfoLayout->setRowStretch( 6, 1 ); + groupFileInfoLayout->setColStretch( 1, 1 ); + + QFont f( m_displayLength->font() ); + f.setBold( true ); + m_displayLength->setFont( f ); + m_displaySize->setFont( f ); + m_muxrate->setFont( f ); + /////////////////////////////////////////////////// + + mainLayout->addWidget( groupFileInfo, 0, 0 ); + mainLayout->addWidget( m_mainTabbed, 0, 1 ); + + // mainLayout->setColStretch( 0, 1 ); + +} + +void K3bVcdTrackDialog::setupPbcTab() +{ + // ///////////////////////////////////////////////// + // Playback Control TAB + // ///////////////////////////////////////////////// + QWidget * w = new QWidget( m_mainTabbed ); + + QGridLayout* grid = new QGridLayout( w ); + grid->setAlignment( Qt::AlignTop ); + grid->setSpacing( spacingHint() ); + grid->setMargin( marginHint() ); + + + ////////////////////////////////////////////////////////////////////////////////////////// + QGroupBox* groupOptions = new QGroupBox( 3, Qt::Vertical, i18n( "Settings" ), w ); + groupOptions->layout() ->setSpacing( spacingHint() ); + groupOptions->layout() ->setMargin( marginHint() ); + + m_check_pbc = new QCheckBox( i18n( "Enable playback control (for the whole CD)" ), groupOptions, "m_check_pbc" ); + + m_check_usekeys = new QCheckBox( i18n( "Use numeric keys" ), groupOptions, "m_check_usekeys" ); + m_check_usekeys->setEnabled( false ); + + m_check_reactivity = new QCheckBox( i18n( "Reactivity delayed to the end of playing track" ), groupOptions, "m_check_reactivity" ); + m_check_reactivity->setEnabled( false ); + + ////////////////////////////////////////////////////////////////////////////////////////// + m_groupPlay = new QGroupBox( 0, Qt::Vertical, i18n( "Playing" ), w ); + m_groupPlay->layout() ->setSpacing( spacingHint() ); + m_groupPlay->layout() ->setMargin( marginHint() ); + + QGridLayout* groupPlayLayout = new QGridLayout( m_groupPlay->layout() ); + groupPlayLayout->setAlignment( Qt::AlignTop ); + + QLabel* labelPlaying = new QLabel( i18n( "Playing track" ) , m_groupPlay, "labelPlaying" ); + + m_spin_times = new QSpinBox( m_groupPlay, "m_spin_times" ); + m_spin_times->setValue( 1 ); + m_spin_times->setSuffix( i18n( " time(s)" ) ); + m_spin_times->setSpecialValueText( i18n( "forever" ) ); + + ////////////////////////////////////////////////////////////////////////////////////////// + m_labelWait = new QLabel( i18n( "then wait" ), m_groupPlay, "m_labelWait" ); + m_spin_waittime = new QSpinBox( m_groupPlay, "m_spinSeconds" ); + m_spin_waittime->setMinValue( -1 ); + m_spin_waittime->setValue( 0 ); + // m_spin_waittime->setEnabled( false ); + m_spin_waittime->setSuffix( i18n( " seconds" ) ); + m_spin_waittime->setSpecialValueText( i18n( "infinite" ) ); + + m_labelAfterTimeout = new QLabel( i18n( "after timeout playing" ), m_groupPlay, "m_labelTimeout" ); + // m_labelAfterTimeout->setEnabled( false ); + m_comboAfterTimeout = new K3bCutComboBox( K3bCutComboBox::SQUEEZE, m_groupPlay, "m_comboAfterTimeout" ); + // m_comboAfterTimeout->setEnabled( false ); + + groupPlayLayout->addWidget( labelPlaying, 1, 0 ); + groupPlayLayout->addWidget( m_spin_times, 1, 1 ); + groupPlayLayout->addWidget( m_labelWait, 1, 2 ); + groupPlayLayout->addWidget( m_spin_waittime, 1, 3 ); + groupPlayLayout->addMultiCellWidget( m_labelAfterTimeout, 2, 2, 1, 3 ); + groupPlayLayout->addMultiCellWidget( m_comboAfterTimeout, 3, 3, 1, 3 ); + + ////////////////////////////////////////////////////////////////////////////////////////// + m_groupPbc = new QGroupBox( 0, Qt::Vertical, i18n( "Key Pressed Interaction" ), w ); + m_groupPbc->layout() ->setSpacing( spacingHint() ); + m_groupPbc->layout() ->setMargin( marginHint() ); + + QGridLayout* groupPbcLayout = new QGridLayout( m_groupPbc->layout() ); + groupPbcLayout->setAlignment( Qt::AlignTop ); + + QLabel* labelPbc_previous = new QLabel( i18n( "Previous:" ), m_groupPbc, "labelPbc_previous" ); + QLabel* labelPbc_next = new QLabel( i18n( "Next:" ), m_groupPbc, "labelPbc_next" ); + QLabel* labelPbc_return = new QLabel( i18n( "Return:" ), m_groupPbc, "labelPbc_return" ); + QLabel* labelPbc_default = new QLabel( i18n( "Default:" ), m_groupPbc, "labelPbc_default" ); + + m_pbc_previous = new K3bCutComboBox( K3bCutComboBox::SQUEEZE, m_groupPbc, "m_pbc_previous" ); + m_pbc_next = new K3bCutComboBox( K3bCutComboBox::SQUEEZE, m_groupPbc, "m_pbc_next" ); + m_pbc_return = new K3bCutComboBox( K3bCutComboBox::SQUEEZE, m_groupPbc, "m_pbc_return" ); + m_pbc_default = new K3bCutComboBox( K3bCutComboBox::SQUEEZE, m_groupPbc, "m_pbc_default" ); + + groupPbcLayout->addWidget( labelPbc_previous, 1, 0 ); + groupPbcLayout->addMultiCellWidget( m_pbc_previous, 1, 1, 1, 3 ); + + groupPbcLayout->addWidget( labelPbc_next, 2, 0 ); + groupPbcLayout->addMultiCellWidget( m_pbc_next, 2, 2, 1, 3 ); + + groupPbcLayout->addWidget( labelPbc_return, 3, 0 ); + groupPbcLayout->addMultiCellWidget( m_pbc_return, 3, 3, 1, 3 ); + + groupPbcLayout->addWidget( labelPbc_default, 4, 0 ); + groupPbcLayout->addMultiCellWidget( m_pbc_default, 4, 4, 1, 3 ); + + + grid->addWidget( groupOptions, 0, 0 ); + grid->addWidget( m_groupPlay, 1, 0 ); + grid->addWidget( m_groupPbc, 2, 0 ); + + grid->setRowStretch( 9, 1 ); + + m_mainTabbed->addTab( w, i18n( "Playback Control" ) ); + + m_groupPlay->setEnabled( false ); + m_groupPbc->setEnabled( false ); + + connect( m_check_pbc, SIGNAL( toggled( bool ) ), this, SLOT( slotPbcToggled( bool ) ) ); + connect( m_spin_times, SIGNAL( valueChanged( int ) ), this, SLOT( slotPlayTimeChanged( int ) ) ); + connect( m_spin_waittime, SIGNAL( valueChanged( int ) ), this, SLOT( slotWaitTimeChanged( int ) ) ); + connect( m_check_usekeys, SIGNAL( toggled( bool ) ), this, SLOT( slotUseKeysToggled( bool ) ) ); +} + +void K3bVcdTrackDialog::setupPbcKeyTab() +{ + // ///////////////////////////////////////////////// + // Playback Control Numeric Key's TAB + // ///////////////////////////////////////////////// + m_widgetnumkeys = new QWidget( m_mainTabbed ); + + QGridLayout* grid = new QGridLayout( m_widgetnumkeys ); + grid->setAlignment( Qt::AlignTop ); + grid->setSpacing( spacingHint() ); + grid->setMargin( marginHint() ); + + m_groupKey = new QGroupBox( 3, Qt::Vertical, i18n( "Numeric Keys" ), m_widgetnumkeys ); + m_groupKey->setEnabled( false ); + m_groupKey->layout() ->setSpacing( spacingHint() ); + m_groupKey->layout() ->setMargin( marginHint() ); + + m_list_keys = new K3bListView( m_groupKey, "m_list_keys" ); + m_list_keys->setAllColumnsShowFocus( true ); + m_list_keys->setDoubleClickForEdit( false ); + m_list_keys->setColumnAlignment( 0, Qt::AlignRight ); + m_list_keys->setSelectionMode( QListView::NoSelection ); + m_list_keys->setSorting( -1 ); + m_list_keys->addColumn( i18n( "Key" ) ); + m_list_keys->addColumn( i18n( "Playing" ) ); + m_list_keys->setResizeMode( QListView::LastColumn ); + m_check_overwritekeys = new QCheckBox( i18n( "Overwrite default assignment" ), m_widgetnumkeys, "m_check_overwritekeys" ); + + grid->addWidget( m_groupKey, 1, 0 ); + grid->addWidget( m_check_overwritekeys, 2, 0 ); + + m_mainTabbed->addTab( m_widgetnumkeys, i18n( "Numeric Keys" ) ); + + connect( m_check_overwritekeys, SIGNAL( toggled( bool ) ), this, SLOT( slotGroupkeyToggled( bool ) ) ); + +} + +void K3bVcdTrackDialog::setupAudioTab() +{ + // ///////////////////////////////////////////////// + // AUDIO TAB + // ///////////////////////////////////////////////// + QWidget * w = new QWidget( m_mainTabbed ); + + QGridLayout* grid = new QGridLayout( w ); + grid->setAlignment( Qt::AlignTop ); + grid->setSpacing( spacingHint() ); + grid->setMargin( marginHint() ); + + QLabel* labelMpegVer_Audio = new QLabel( i18n( "Type:" ), w, "labelMpegVer_Audio" ); + QLabel* labelRate_Audio = new QLabel( i18n( "Rate:" ), w, "labelRate_Audio" ); + QLabel* labelSampling_Frequency_Audio = new QLabel( i18n( "Sampling frequency:" ), w, "labelSampling_Frequency_Audio" ); + QLabel* labelMode_Audio = new QLabel( i18n( "Mode:" ), w, "labelMode_Audio" ); + QLabel* labelCopyright_Audio = new QLabel( i18n( "Copyright:" ), w, "labelCopyright_Audio" ); + + m_mpegver_audio = new QLabel( w, "m_mpegver_audio" ); + m_rate_audio = new QLabel( w, "m_rate_audio" ); + m_sampling_frequency_audio = new QLabel( w, "m_sampling_frequency_audio" ); + m_mode_audio = new QLabel( w, "m_mode_audio" ); + m_copyright_audio = new QLabel( w, "m_copyright_audio" ); + + m_mpegver_audio->setFrameShape( QLabel::LineEditPanel ); + m_rate_audio->setFrameShape( QLabel::LineEditPanel ); + m_sampling_frequency_audio->setFrameShape( QLabel::LineEditPanel ); + m_mode_audio->setFrameShape( QLabel::LineEditPanel ); + m_copyright_audio->setFrameShape( QLabel::LineEditPanel ); + + m_mpegver_audio->setFrameShadow( QLabel::Sunken ); + m_rate_audio->setFrameShadow( QLabel::Sunken ); + m_sampling_frequency_audio->setFrameShadow( QLabel::Sunken ); + m_mode_audio->setFrameShadow( QLabel::Sunken ); + m_copyright_audio->setFrameShadow( QLabel::Sunken ); + + grid->addWidget( labelMpegVer_Audio, 1, 0 ); + grid->addMultiCellWidget( m_mpegver_audio, 1, 1, 1, 4 ); + + grid->addWidget( labelRate_Audio, 2, 0 ); + grid->addMultiCellWidget( m_rate_audio, 2, 2, 1, 4 ); + + grid->addWidget( labelSampling_Frequency_Audio, 3, 0 ); + grid->addMultiCellWidget( m_sampling_frequency_audio, 3, 3, 1, 4 ); + + grid->addWidget( labelMode_Audio, 4, 0 ); + grid->addMultiCellWidget( m_mode_audio, 4, 4, 1, 4 ); + + grid->addWidget( labelCopyright_Audio, 5, 0 ); + grid->addMultiCellWidget( m_copyright_audio, 5, 5, 1, 4 ); + + grid->setRowStretch( 9, 4 ); + + m_mainTabbed->addTab( w, i18n( "Audio" ) ); + +} + +void K3bVcdTrackDialog::setupVideoTab() +{ + // ///////////////////////////////////////////////// + // VIDEO TAB + // ///////////////////////////////////////////////// + QWidget * w = new QWidget( m_mainTabbed ); + + QGridLayout* grid = new QGridLayout( w ); + grid->setAlignment( Qt::AlignTop ); + grid->setSpacing( spacingHint() ); + grid->setMargin( marginHint() ); + + QLabel* labelMpegVer_Video = new QLabel( i18n( "Type:" ), w, "labelMpegVer_Video" ); + QLabel* labelRate_Video = new QLabel( i18n( "Rate:" ), w, "labelRate_Video" ); + QLabel* labelChromaFormat_Video = new QLabel( i18n( "Chroma format:" ), w, "labelChromaFormat_Video" ); + QLabel* labelFormat_Video = new QLabel( i18n( "Video format:" ), w, "labelFormat_Video" ); + QLabel* labelResolution_Video = new QLabel( i18n( "Resolution:" ), w, "labelSize_Video" ); + QLabel* labelHighResolution_Video = new QLabel( i18n( "High resolution:" ), w, "labelHighResolution_Video" ); + + m_mpegver_video = new QLabel( w, "m_mpegver_video" ); + m_rate_video = new QLabel( w, "m_rate_video" ); + m_chromaformat_video = new QLabel( w, "m_chromaformat_video" ); + m_format_video = new QLabel( w, "m_format_video" ); + m_resolution_video = new QLabel( w, "m_resolution_video" ); + m_highresolution_video = new QLabel( w, "m_highresolution_video" ); + + m_mpegver_video->setFrameShape( QLabel::LineEditPanel ); + m_rate_video->setFrameShape( QLabel::LineEditPanel ); + m_chromaformat_video->setFrameShape( QLabel::LineEditPanel ); + m_format_video->setFrameShape( QLabel::LineEditPanel ); + m_resolution_video->setFrameShape( QLabel::LineEditPanel ); + m_highresolution_video->setFrameShape( QLabel::LineEditPanel ); + + m_mpegver_video->setFrameShadow( QLabel::Sunken ); + m_rate_video->setFrameShadow( QLabel::Sunken ); + m_chromaformat_video->setFrameShadow( QLabel::Sunken ); + m_format_video->setFrameShadow( QLabel::Sunken ); + m_resolution_video->setFrameShadow( QLabel::Sunken ); + m_highresolution_video->setFrameShadow( QLabel::Sunken ); + + grid->addWidget( labelMpegVer_Video, 1, 0 ); + grid->addMultiCellWidget( m_mpegver_video, 1, 1, 1, 4 ); + + grid->addWidget( labelRate_Video, 2, 0 ); + grid->addMultiCellWidget( m_rate_video, 2, 2, 1, 4 ); + + grid->addWidget( labelChromaFormat_Video, 3, 0 ); + grid->addMultiCellWidget( m_chromaformat_video, 3, 3, 1, 4 ); + + grid->addWidget( labelFormat_Video, 4, 0 ); + grid->addMultiCellWidget( m_format_video, 4, 4, 1, 4 ); + + grid->addWidget( labelResolution_Video, 5, 0 ); + grid->addMultiCellWidget( m_resolution_video, 5, 5, 1, 4 ); + + grid->addWidget( labelHighResolution_Video, 6, 0 ); + grid->addMultiCellWidget( m_highresolution_video, 6, 6, 1, 4 ); + + grid->setRowStretch( 9, 4 ); + + m_mainTabbed->addTab( w, i18n( "Video" ) ); +} + +void K3bVcdTrackDialog::setDefinedNumKeys( ) +{ + K3bVcdTrack * selectedTrack = m_selectedTracks.first(); + if ( !m_check_overwritekeys->isChecked() ) { + + selectedTrack->delDefinedNumKey(); + selectedTrack->setDefinedNumKey( 1, selectedTrack ); + + } + + QListViewItemIterator it( m_list_keys ); + QMap<int, K3bVcdTrack*> definedkeysmap = selectedTrack->DefinedNumKey(); + + while ( it.current() ) { + int itemId = it.current() ->text( 0 ).toInt(); + + QMap<int, K3bVcdTrack*>::const_iterator keyit = definedkeysmap.find( itemId ); + + if ( keyit != definedkeysmap.end() ) { + if ( keyit.data() ) { + if ( m_tracks.findRef( keyit.data() ) >= 0 ) { + it.current() ->setText( 1 , displayName( keyit.data() ) ) ; + } else { + it.current() ->setText( 1 , "" ) ; + selectedTrack->delDefinedNumKey( keyit.key() ); + } + } else { + it.current() ->setText( 1 , i18n( "VideoCD END" ) ) ; + } + } else { + it.current() ->setText( 1 , "" ) ; + } + ++it; + } +} + +QString K3bVcdTrackDialog::displayName( K3bVcdTrack * track ) +{ + if ( track == m_selectedTracks.first() ) + return i18n( "ItSelf" ); + + if ( track->isSegment() ) + return i18n( "Segment-%1 - %2" ).arg( QString::number( track->index() + 1 ).rightJustify( 3, '0' ) ).arg( track->title() ); + + return i18n( "Sequence-%1 - %2" ).arg( QString::number( track->index() + 1 ).rightJustify( 3, '0' ) ).arg( track->title() ); +} + +void K3bVcdTrackDialog::slotPlayTimeChanged( int value ) +{ + if ( value == 0 ) { + m_labelWait->setEnabled( false ); + m_spin_waittime->setEnabled( false ); + m_labelAfterTimeout->setEnabled( false ); + m_comboAfterTimeout->setEnabled( false ); + } else { + m_labelWait->setEnabled( true ); + m_spin_waittime->setEnabled( true ); + if ( m_spin_waittime->value() > -1 ) { + m_labelAfterTimeout->setEnabled( true ); + m_comboAfterTimeout->setEnabled( true ); + } + } +} + +void K3bVcdTrackDialog::slotWaitTimeChanged( int value ) +{ + if ( value < 0 || !m_labelWait->isEnabled() ) { + m_labelAfterTimeout->setEnabled( false ); + m_comboAfterTimeout->setEnabled( false ); + } else { + m_labelAfterTimeout->setEnabled( true ); + m_comboAfterTimeout->setEnabled( true ); + } +} + +void K3bVcdTrackDialog::slotPbcToggled( bool b ) +{ + m_groupPlay->setEnabled( b ); + m_groupPbc->setEnabled( b ); + m_check_usekeys->setEnabled( b ); + slotUseKeysToggled( b && m_check_usekeys->isChecked() ); + m_check_reactivity->setEnabled( b ); + if ( b ) + slotWaitTimeChanged( m_spin_waittime->value() ); +} + +void K3bVcdTrackDialog::slotUseKeysToggled( bool b ) +{ + m_mainTabbed->setTabEnabled( m_widgetnumkeys, b ); +} + +void K3bVcdTrackDialog::slotGroupkeyToggled( bool b ) +{ + m_groupKey->setEnabled( b ); + setDefinedNumKeys(); +} + +#include "k3bvcdtrackdialog.moc" diff --git a/src/projects/k3bvcdtrackdialog.h b/src/projects/k3bvcdtrackdialog.h new file mode 100644 index 0000000..3b62c35 --- /dev/null +++ b/src/projects/k3bvcdtrackdialog.h @@ -0,0 +1,123 @@ +/* +* +* $Id: k3bvcdtrackdialog.h 619556 2007-01-03 17:38:12Z trueg $ +* Copyright (C) 2003-2004 Christian Kvasny <chris@k3b.org> +* +* This file is part of the K3b project. +* Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> +* +* 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 2 of the License, or +* (at your option) any later version. +* See the file "COPYING" for the exact licensing terms. +*/ + +#ifndef K3BVCDTRACKDIALOG_H +#define K3BVCDTRACKDIALOG_H + +#include <kdialogbase.h> +#include <qptrlist.h> +#include <qtabwidget.h> + +#include <k3bvcddoc.h> +#include <k3blistview.h> + +class K3bVcdTrack; +class QLabel; +class QCheckBox; +class QComboBox; +class QGroupBox; +class QRadioButton; +class QButtonGroup; +class KCutLabel; +class K3bCutComboBox; + + +class K3bVcdTrackDialog : public KDialogBase +{ + Q_OBJECT + + public: + K3bVcdTrackDialog( K3bVcdDoc*, QPtrList<K3bVcdTrack>& tracks, QPtrList<K3bVcdTrack>& selectedTracks, QWidget* parent = 0, const char* name = 0 ); + ~K3bVcdTrackDialog(); + + protected slots: + void slotOk(); + void slotApply(); + + private slots: + void slotPlayTimeChanged( int ); + void slotWaitTimeChanged( int ); + void slotPbcToggled( bool ); + void slotUseKeysToggled( bool ); + void slotGroupkeyToggled( bool ); + + + private: + K3bVcdDoc* m_vcdDoc; + QPtrList<K3bVcdTrack> m_tracks; + QPtrList<K3bVcdTrack> m_selectedTracks; + QMap<QString, K3bVcdTrack*> m_numkeysmap; + QTabWidget* m_mainTabbed; + + KCutLabel* m_displayFileName; + QLabel* m_labelMimeType; + QLabel* m_displaySize; + QLabel* m_displayLength; + QLabel* m_muxrate; + + QLabel* m_mpegver_audio; + QLabel* m_rate_audio; + QLabel* m_sampling_frequency_audio; + QLabel* m_mode_audio; + QLabel* m_copyright_audio; + + QLabel* m_mpegver_video; + QLabel* m_rate_video; + QLabel* m_chromaformat_video; + QLabel* m_format_video; + QLabel* m_resolution_video; + QLabel* m_highresolution_video; + + QLabel* m_labelAfterTimeout; + QLabel* m_labelWait; + + QGroupBox* m_groupPlay; + QGroupBox* m_groupPbc; + QGroupBox* m_groupKey; + QWidget* m_widgetnumkeys; + + K3bCutComboBox* m_pbc_previous; + K3bCutComboBox* m_pbc_next; + K3bCutComboBox* m_pbc_return; + K3bCutComboBox* m_pbc_default; + K3bCutComboBox* m_comboAfterTimeout; + + QCheckBox* m_check_reactivity; + QCheckBox* m_check_pbc; + QCheckBox* m_check_usekeys; + QCheckBox* m_check_overwritekeys; + K3bListView* m_list_keys; + + QSpinBox* m_spin_times; + QSpinBox* m_spin_waittime; + + void prepareGui(); + void setupPbcTab(); + void setupPbcKeyTab(); + void setupAudioTab(); + void setupVideoTab(); + void fillGui(); + void fillPbcGui(); + + void setPbcTrack( K3bVcdTrack*, K3bCutComboBox*, int ); + void setDefinedNumKeys( ); + QString displayName( K3bVcdTrack* ); + K3bVcdOptions* VcdOptions() + { + return m_vcdDoc->vcdOptions(); + } +}; + +#endif diff --git a/src/projects/k3bvcdview.cpp b/src/projects/k3bvcdview.cpp new file mode 100644 index 0000000..d8984d4 --- /dev/null +++ b/src/projects/k3bvcdview.cpp @@ -0,0 +1,74 @@ +/* +* +* $Id: k3bvcdview.cpp 619556 2007-01-03 17:38:12Z trueg $ +* Copyright (C) 2003-2004 Christian Kvasny <chris@k3b.org> +* +* This file is part of the K3b project. +* Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> +* +* 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 2 of the License, or +* (at your option) any later version. +* See the file "COPYING" for the exact licensing terms. +*/ + +// QT-includes +#include <qlayout.h> +#include <qstring.h> + + +// KDE-includes +#include <klocale.h> +#include <kapplication.h> +#include <kdebug.h> +#include <kmessagebox.h> + +// K3b Includes +#include "k3bvcdview.h" +#include "k3bvcddoc.h" +#include "k3bvcdlistview.h" +#include "k3bvcdburndialog.h" +#include <k3bfillstatusdisplay.h> +#include <k3bexternalbinmanager.h> +#include <k3bcore.h> + + +K3bVcdView::K3bVcdView( K3bVcdDoc* pDoc, QWidget* parent, const char *name ) + : K3bView( pDoc, parent, name ) +{ + m_doc = pDoc; + + // --- setup GUI --------------------------------------------------- + + m_vcdlist = new K3bVcdListView( this, pDoc, this ); + setMainWidget( m_vcdlist ); + fillStatusDisplay() ->showSize(); + + connect( m_vcdlist, SIGNAL( lengthReady() ), fillStatusDisplay(), SLOT( update() ) ); + connect( m_doc, SIGNAL( newTracks() ), fillStatusDisplay(), SLOT( update() ) ); +} + +K3bVcdView::~K3bVcdView() +{} + + +K3bProjectBurnDialog* K3bVcdView::newBurnDialog( QWidget * parent, const char * name ) +{ + return new K3bVcdBurnDialog( m_doc, parent, name, true ); +} + + +void K3bVcdView::init() +{ + if( !k3bcore->externalBinManager()->foundBin( "vcdxbuild" ) ) { + kdDebug() << "(K3bVcdView) could not find vcdxbuild executable" << endl; + KMessageBox::information( this, + i18n( "Could not find VcdImager executable. " + "To create VideoCD's you must install VcdImager >= 0.7.12. " + "You can find this on your distribution disks or download " + "it from http://www.vcdimager.org" ) ); + } +} + +#include "k3bvcdview.moc" diff --git a/src/projects/k3bvcdview.h b/src/projects/k3bvcdview.h new file mode 100644 index 0000000..77ad292 --- /dev/null +++ b/src/projects/k3bvcdview.h @@ -0,0 +1,55 @@ +/* +* +* $Id: k3bvcdview.h 619556 2007-01-03 17:38:12Z trueg $ +* Copyright (C) 2003-2004 Christian Kvasny <chris@k3b.org> +* +* This file is part of the K3b project. +* Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> +* +* 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 2 of the License, or +* (at your option) any later version. +* See the file "COPYING" for the exact licensing terms. +*/ + +#ifndef K3BVCDVIEW_H +#define K3BVCDVIEW_H + +#include <qstringlist.h> +#include <qptrlist.h> + +// K3b Includes +#include <k3bview.h> + +class K3bVcdListView; +class K3bVcdListViewItem; +class QWidget; +class K3bVcdDoc; +class K3bVcdTrack; +class QListViewItem; +class KListView; +class K3bVcdBurnDialog; +class K3bProjectBurnDialog; + + +class K3bVcdView : public K3bView +{ + Q_OBJECT + + public: + K3bVcdView( K3bVcdDoc* pDoc, QWidget* parent, const char *name = 0 ); + ~K3bVcdView(); + + protected: + K3bProjectBurnDialog* newBurnDialog( QWidget* parent = 0, const char* name = 0 ); + + void init(); + + private: + K3bVcdDoc* m_doc; + + K3bVcdListView* m_vcdlist; +}; + +#endif diff --git a/src/projects/k3bvideodvdburndialog.cpp b/src/projects/k3bvideodvdburndialog.cpp new file mode 100644 index 0000000..22626df --- /dev/null +++ b/src/projects/k3bvideodvdburndialog.cpp @@ -0,0 +1,198 @@ +/* + * + * $Id: k3bvideodvdburndialog.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bvideodvdburndialog.h" +#include "k3bvideodvddoc.h" + +#include <k3bdevice.h> +#include <k3bwriterselectionwidget.h> +#include <k3btempdirselectionwidget.h> +#include <k3bcore.h> +#include <k3bwritingmodewidget.h> +#include <k3bglobals.h> +#include <k3bdataimagesettingswidget.h> +#include <k3bisooptions.h> +#include <k3bstdguiitems.h> +#include <k3bglobalsettings.h> + +#include <kconfig.h> +#include <klocale.h> +#include <kio/global.h> +#include <kmessagebox.h> + +#include <qlayout.h> +#include <qcheckbox.h> +#include <qgroupbox.h> +#include <qlabel.h> +#include <qtooltip.h> +#include <qwhatsthis.h> + + +K3bVideoDvdBurnDialog::K3bVideoDvdBurnDialog( K3bVideoDvdDoc* doc, QWidget *parent, const char *name, bool modal ) + : K3bProjectBurnDialog( doc, parent, name, modal, true ), + m_doc( doc ) +{ + prepareGui(); + + setTitle( i18n("Video DVD Project"), i18n("Size: %1").arg( KIO::convertSize(doc->size()) ) ); + + // for now we just put the verify checkbox on the main page... + m_checkVerify = K3bStdGuiItems::verifyCheckBox( m_optionGroup ); + m_optionGroupLayout->addWidget( m_checkVerify ); + + QSpacerItem* spacer = new QSpacerItem( 20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding ); + m_optionGroupLayout->addItem( spacer ); + + // create image settings tab + m_imageSettingsWidget = new K3bDataImageSettingsWidget( this ); + m_imageSettingsWidget->showFileSystemOptions( false ); + + addPage( m_imageSettingsWidget, i18n("Filesystem") ); + + m_tempDirSelectionWidget->setSelectionMode( K3bTempDirSelectionWidget::FILE ); + + QString path = m_doc->tempDir(); + if( path.isEmpty() ) { + path = K3b::defaultTempPath(); + if( m_doc->isoOptions().volumeID().isEmpty() ) + path.append( "image.iso" ); + else + path.append( m_doc->isoOptions().volumeID() + ".iso" ); + } + m_tempDirSelectionWidget->setTempPath( path ); +} + + +K3bVideoDvdBurnDialog::~K3bVideoDvdBurnDialog() +{ +} + + +void K3bVideoDvdBurnDialog::saveSettings() +{ + K3bProjectBurnDialog::saveSettings(); + + // save iso image settings + K3bIsoOptions o = m_doc->isoOptions(); + m_imageSettingsWidget->save( o ); + m_doc->setIsoOptions( o ); + + // save image file path + m_doc->setTempDir( m_tempDirSelectionWidget->tempPath() ); + + m_doc->setVerifyData( m_checkVerify->isChecked() ); +} + + +void K3bVideoDvdBurnDialog::readSettings() +{ + K3bProjectBurnDialog::readSettings(); + + if( !doc()->tempDir().isEmpty() ) + m_tempDirSelectionWidget->setTempPath( doc()->tempDir() ); + else + m_tempDirSelectionWidget->setTempPath( K3b::defaultTempPath() + doc()->name() + ".iso" ); + + m_checkVerify->setChecked( m_doc->verifyData() ); + + m_imageSettingsWidget->load( m_doc->isoOptions() ); + + // in case overburn is enabled we allow some made up max size + // before we force a DL medium + if( doc()->size() > 4700372992LL && + ( !k3bcore->globalSettings()->overburn() || + doc()->size() > 4900000000LL ) ) + m_writerSelectionWidget->setWantedMediumType( K3bDevice::MEDIA_WRITABLE_DVD_DL ); + else + m_writerSelectionWidget->setWantedMediumType( K3bDevice::MEDIA_WRITABLE_DVD ); + + toggleAll(); +} + + +void K3bVideoDvdBurnDialog::toggleAll() +{ + K3bProjectBurnDialog::toggleAll(); + + if( m_checkSimulate->isChecked() || m_checkOnlyCreateImage->isChecked() ) { + m_checkVerify->setChecked(false); + m_checkVerify->setEnabled(false); + } + else + m_checkVerify->setEnabled(true); +} + + +void K3bVideoDvdBurnDialog::loadK3bDefaults() +{ + K3bProjectBurnDialog::loadK3bDefaults(); + + m_imageSettingsWidget->load( K3bIsoOptions::defaults() ); + m_checkVerify->setChecked( false ); + + toggleAll(); +} + + +void K3bVideoDvdBurnDialog::loadUserDefaults( KConfigBase* c ) +{ + K3bProjectBurnDialog::loadUserDefaults( c ); + + K3bIsoOptions o = K3bIsoOptions::load( c ); + m_imageSettingsWidget->load( o ); + + m_checkVerify->setChecked( c->readBoolEntry( "verify data", false ) ); + + toggleAll(); +} + + +void K3bVideoDvdBurnDialog::saveUserDefaults( KConfigBase* c ) +{ + K3bProjectBurnDialog::saveUserDefaults(c); + + K3bIsoOptions o; + m_imageSettingsWidget->save( o ); + o.save( c ); + + c->writeEntry( "verify data", m_checkVerify->isChecked() ); +} + + +void K3bVideoDvdBurnDialog::slotStartClicked() +{ + if( m_checkOnlyCreateImage->isChecked() || + m_checkCacheImage->isChecked() ) { + QFileInfo fi( m_tempDirSelectionWidget->tempPath() ); + if( fi.isDir() ) + m_tempDirSelectionWidget->setTempPath( fi.filePath() + "/image.iso" ); + + if( QFile::exists( m_tempDirSelectionWidget->tempPath() ) ) { + if( KMessageBox::warningContinueCancel( this, + i18n("Do you want to overwrite %1?").arg(m_tempDirSelectionWidget->tempPath()), + i18n("File Exists"), i18n("Overwrite") ) + == KMessageBox::Continue ) { + // delete the file here to avoid problems with free space in K3bProjectBurnDialog::slotStartClicked + QFile::remove( m_tempDirSelectionWidget->tempPath() ); + } + else + return; + } + } + + K3bProjectBurnDialog::slotStartClicked(); +} + +#include "k3bvideodvdburndialog.moc" diff --git a/src/projects/k3bvideodvdburndialog.h b/src/projects/k3bvideodvdburndialog.h new file mode 100644 index 0000000..0dbbe58 --- /dev/null +++ b/src/projects/k3bvideodvdburndialog.h @@ -0,0 +1,55 @@ +/* + * + * $Id: k3bvideodvdburndialog.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_VIDEODVD_BURNDIALOG_H_ +#define _K3B_VIDEODVD_BURNDIALOG_H_ + +#include "k3bprojectburndialog.h" + + +class K3bVideoDvdDoc; +class K3bDataImageSettingsWidget; +class QCheckBox; + + +class K3bVideoDvdBurnDialog : public K3bProjectBurnDialog +{ + Q_OBJECT + + public: + K3bVideoDvdBurnDialog( K3bVideoDvdDoc*, QWidget *parent = 0, const char *name = 0, bool modal = true ); + ~K3bVideoDvdBurnDialog(); + + protected slots: + void slotStartClicked(); + void saveSettings(); + void readSettings(); + + protected: + void loadK3bDefaults(); + void loadUserDefaults( KConfigBase* ); + void saveUserDefaults( KConfigBase* ); + void toggleAll(); + + private: + K3bDataImageSettingsWidget* m_imageSettingsWidget; + + QCheckBox* m_checkVerify; + + K3bVideoDvdDoc* m_doc; +}; + +#endif diff --git a/src/projects/k3bvideodvdview.cpp b/src/projects/k3bvideodvdview.cpp new file mode 100644 index 0000000..277beac --- /dev/null +++ b/src/projects/k3bvideodvdview.cpp @@ -0,0 +1,84 @@ +/* + * + * $Id: k3bvideodvdview.cpp 644513 2007-03-20 09:07:44Z trueg $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bvideodvdview.h" +#include "k3bvideodvddoc.h" +#include "k3bvideodvdburndialog.h" +#include "k3bdatadirtreeview.h" +#include "k3bdatafileview.h" +#include "k3bdataurladdingdialog.h" +#include <k3bfillstatusdisplay.h> +#include <k3bdatafileview.h> +#include <k3btoolbox.h> +#include <k3bprojectplugin.h> + +#include <klocale.h> +#include <kmessagebox.h> +#include <kactioncollection.h> + +#include <qsplitter.h> + + +K3bVideoDvdView::K3bVideoDvdView( K3bVideoDvdDoc* doc, QWidget *parent, const char *name ) + : K3bView( doc, parent, name ), + m_doc(doc) +{ + fillStatusDisplay()->showDvdSizes(true); + + // --- setup GUI --------------------------------------------------- + QSplitter* mainSplitter = new QSplitter( this ); + m_dataDirTree = new K3bDataDirTreeView( this, doc, mainSplitter ); + m_dataFileView = new K3bDataFileView( this, m_dataDirTree, doc, mainSplitter ); + m_dataDirTree->setFileView( m_dataFileView ); + setMainWidget( mainSplitter ); + + connect( m_dataFileView, SIGNAL(dirSelected(K3bDirItem*)), m_dataDirTree, SLOT(setCurrentDir(K3bDirItem*)) ); + + m_dataDirTree->checkForNewItems(); + m_dataFileView->checkForNewItems(); + + addPluginButtons( K3bProjectPlugin::VIDEO_DVD ); +} + + +K3bVideoDvdView::~K3bVideoDvdView() +{ +} + + +K3bProjectBurnDialog* K3bVideoDvdView::newBurnDialog( QWidget* parent, const char* name ) +{ + return new K3bVideoDvdBurnDialog( m_doc, parent, name, true ); +} + + +void K3bVideoDvdView::init() +{ + KMessageBox::information( this, + i18n("Be aware that you need to provide the complete Video DVD filestructure. " + "K3b does not support video transcoding and preparation of video object " + "files yet. That means you need to already have the VTS_X_YY.VOB " + "and VTS_X_YY.IFO files."), + i18n("K3b Video DVD Restrictions"), + "video_dvd_restrictions" ); +} + + +void K3bVideoDvdView::addUrls( const KURL::List& urls ) +{ + K3bDataUrlAddingDialog::addUrls( urls, m_dataFileView->currentDir() ); +} + +#include "k3bvideodvdview.moc" diff --git a/src/projects/k3bvideodvdview.h b/src/projects/k3bvideodvdview.h new file mode 100644 index 0000000..1125ac4 --- /dev/null +++ b/src/projects/k3bvideodvdview.h @@ -0,0 +1,48 @@ +/* + * + * $Id: k3bvideodvdview.h 644513 2007-03-20 09:07:44Z trueg $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_VIDEO_DVDVIEW_H_ +#define _K3B_VIDEO_DVDVIEW_H_ + +#include <k3bview.h> + +class K3bVideoDvdDoc; +class K3bDataDirTreeView; +class K3bDataFileView; + + +class K3bVideoDvdView : public K3bView +{ + Q_OBJECT + + public: + K3bVideoDvdView( K3bVideoDvdDoc* doc, QWidget *parent = 0, const char *name = 0 ); + ~K3bVideoDvdView(); + + void addUrls( const KURL::List& ); + + protected: + virtual K3bProjectBurnDialog* newBurnDialog( QWidget* parent = 0, const char* name = 0 ); + + void init(); + + private: + K3bVideoDvdDoc* m_doc; + K3bDataDirTreeView* m_dataDirTree; + K3bDataFileView* m_dataFileView; +}; + +#endif diff --git a/src/projects/k3bview.cpp b/src/projects/k3bview.cpp new file mode 100644 index 0000000..0809f59 --- /dev/null +++ b/src/projects/k3bview.cpp @@ -0,0 +1,176 @@ +/* + * + * $Id: k3bview.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +// include files for Qt +#include <qlayout.h> +#include <qtoolbutton.h> +#include <qtooltip.h> +#include <qwhatsthis.h> +#include <qptrlist.h> +#include <qtoolbutton.h> + +#include <kaction.h> +#include <kiconloader.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kdebug.h> + +// application specific includes +#include "k3bview.h" +#include "k3bdoc.h" +#include "k3bfillstatusdisplay.h" +#include "k3bprojectburndialog.h" +#include "k3bprojectplugindialog.h" +#include <k3btoolbox.h> +#include <k3bpluginmanager.h> +#include <k3bprojectplugin.h> +#include <k3bcore.h> + + +K3bView::K3bView( K3bDoc* pDoc, QWidget *parent, const char* name ) + : QWidget( parent, name ), + m_doc( pDoc ) +{ + QGridLayout* grid = new QGridLayout( this ); + + m_toolBox = new K3bToolBox( this, "toolbox" ); + m_fillStatusDisplay = new K3bFillStatusDisplay( m_doc, this ); + + grid->addMultiCellWidget( m_toolBox, 0, 0, 0, 1 ); + grid->addMultiCellWidget( m_fillStatusDisplay, 2, 2, 0, 1 ); + // grid->addWidget( m_buttonBurn, 2, 1 ); + grid->setRowStretch( 1, 1 ); + grid->setColStretch( 0, 1 ); + grid->setSpacing( 5 ); + grid->setMargin( 2 ); + + KAction* burnAction = new KAction( i18n("&Burn"), "cdburn", CTRL + Key_B, this, SLOT(slotBurn()), + actionCollection(), "project_burn"); + burnAction->setToolTip( i18n("Open the burn dialog for the current project") ); + KAction* propAction = new KAction( i18n("&Properties"), "edit", CTRL + Key_P, this, SLOT(slotProperties()), + actionCollection(), "project_properties"); + propAction->setToolTip( i18n("Open the properties dialog") ); + + m_toolBox->addButton( burnAction, true ); + m_toolBox->addSeparator(); + + // this is just for testing (or not?) + // most likely every project type will have it's rc file in the future + setXML( "<!DOCTYPE kpartgui SYSTEM \"kpartgui.dtd\">" + "<kpartgui name=\"k3bproject\" version=\"1\">" + "<MenuBar>" + " <Menu name=\"project\"><text>&Project</text>" + " <Action name=\"project_burn\"/>" + " <Action name=\"project_properties\"/>" + " </Menu>" + "</MenuBar>" + "</kpartgui>", true ); +} + +K3bView::~K3bView() +{ +} + + +void K3bView::setMainWidget( QWidget* w ) +{ + static_cast<QGridLayout*>(layout())->addMultiCellWidget( w, 1, 1, 0, 1 ); +} + + +void K3bView::slotBurn() +{ + if( m_doc->numOfTracks() == 0 || m_doc->size() == 0 ) { + KMessageBox::information( this, i18n("Please add files to your project first."), + i18n("No Data to Burn"), QString::null, false ); + } + else { + K3bProjectBurnDialog* dlg = newBurnDialog( this ); + if( dlg ) { + dlg->execBurnDialog(true); + delete dlg; + } + else { + kdDebug() << "(K3bDoc) Error: no burndialog available." << endl; + } + } +} + + +void K3bView::slotProperties() +{ + K3bProjectBurnDialog* dlg = newBurnDialog( this ); + if( dlg ) { + dlg->execBurnDialog(false); + delete dlg; + } + else { + kdDebug() << "(K3bDoc) Error: no burndialog available." << endl; + } +} + + +// KActionCollection* K3bView::actionCollection() const +// { +// return m_actionCollection; +// } + + +void K3bView::addPluginButtons( int projectType ) +{ + QPtrList<K3bPlugin> pl = k3bcore->pluginManager()->plugins( "ProjectPlugin" ); + for( QPtrListIterator<K3bPlugin> it( pl ); *it; ++it ) { + K3bProjectPlugin* pp = dynamic_cast<K3bProjectPlugin*>( *it ); + if( pp && (pp->type() & projectType) ) { + QToolButton* button = toolBox()->addButton( pp->text(), + pp->icon(), + pp->toolTip(), + pp->whatsThis(), + this, + SLOT(slotPluginButtonClicked()) ); + m_plugins.insert( static_cast<void*>(button), pp ); + } + } +} + + +void K3bView::slotPluginButtonClicked() +{ + QObject* o = const_cast<QObject*>(sender()); + if( K3bProjectPlugin* p = m_plugins[static_cast<void*>(o)] ) { + if( p->hasGUI() ) { + K3bProjectPluginDialog dlg( p, doc(), this ); + dlg.exec(); + } + else + p->activate( doc(), this ); + } +} + + +void K3bView::addUrl( const KURL& url ) +{ + KURL::List urls(url); + addUrls( urls ); +} + + +void K3bView::addUrls( const KURL::List& urls ) +{ + doc()->addUrls( urls ); +} + +#include "k3bview.moc" diff --git a/src/projects/k3bview.h b/src/projects/k3bview.h new file mode 100644 index 0000000..2bd8266 --- /dev/null +++ b/src/projects/k3bview.h @@ -0,0 +1,112 @@ +/* + * + * $Id: k3bview.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BVIEW_H +#define K3BVIEW_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +// include files for Qt +#include <qwidget.h> +#include <qptrdict.h> + +#include <kxmlguiclient.h> +#include <kurl.h> + +class K3bDoc; +class KActionCollection; +class K3bFillStatusDisplay; +class K3bProjectBurnDialog; +class K3bToolBox; +class K3bProjectPlugin; + + +/** + * + */ +class K3bView : public QWidget, public KXMLGUIClient +{ + Q_OBJECT + + public: + /** + * + */ + K3bView( K3bDoc* pDoc, QWidget* parent, const char *name = 0 ); + virtual ~K3bView(); + + /** + * returns a pointer to the document connected to the view + * @deprecated use doc() + */ + K3bDoc* getDocument() const { return m_doc; } + K3bDoc* doc() const { return m_doc; } + + void setMainWidget( QWidget* ); + + public slots: + /** + * Default impl. brings up the burnDialog via newBurnDialog() with writing + */ + virtual void slotBurn(); + + /** + * Default impl. brings up the burnDialog via newBurnDialog() without writing + */ + virtual void slotProperties(); + + /** + * Add an url to the doc. The default implementation simply calls + * addUrls. + */ + virtual void addUrl( const KURL& ); + + /** + * Add urls to the doc. The default implementation calls doc()->addUrls. + */ + virtual void addUrls( const KURL::List& ); + + protected: + /** + * Protected since the BurnDialog is not part of the API. + */ + virtual K3bProjectBurnDialog* newBurnDialog( QWidget* = 0, const char* = 0 ) = 0; + + /** + * Call this to add the projectplugin buttons to the toolbox. It is not called + * automatically to make it possible to add other buttons before. + * + * @param projectType the type of the project (@see K3bProjectPlugin) + */ + void addPluginButtons( int projectType ); + + K3bFillStatusDisplay* fillStatusDisplay() const { return m_fillStatusDisplay; } + K3bToolBox* toolBox() const { return m_toolBox; } + + private slots: + void slotPluginButtonClicked(); + + private: + K3bDoc* m_doc; + K3bFillStatusDisplay* m_fillStatusDisplay; + K3bToolBox* m_toolBox; + + QPtrDict<K3bProjectPlugin> m_plugins; +}; + +#endif // K3BVIEW_H diff --git a/src/projects/kostore/Makefile.am b/src/projects/kostore/Makefile.am new file mode 100644 index 0000000..d99ae86 --- /dev/null +++ b/src/projects/kostore/Makefile.am @@ -0,0 +1,11 @@ + +KDE_CXXFLAGS = $(USE_RTTI) +noinst_LTLIBRARIES = libkostore.la +INCLUDES = $(all_includes) + +####### Files + +libkostore_la_LIBADD = $(LIB_KIO) +libkostore_la_SOURCES = koStore.cc koZipStore.cc koStoreBase.cc +#libkostore_la_LDFLAGS = $(all_libraries) -version-info 3:0:0 $(KDE_LDFLAGS) -no-undefined +#include_HEADERS = koStore.h diff --git a/src/projects/kostore/README.k3b b/src/projects/kostore/README.k3b new file mode 100644 index 0000000..dbf4db1 --- /dev/null +++ b/src/projects/kostore/README.k3b @@ -0,0 +1,2 @@ +This is a stripped down version of the KoStore lib from Koffice. +It only contains the Zip backend. diff --git a/src/projects/kostore/SPEC b/src/projects/kostore/SPEC new file mode 100644 index 0000000..e72286a --- /dev/null +++ b/src/projects/kostore/SPEC @@ -0,0 +1,122 @@ +------------------------------------------------------------------------------- +- - +- KOffice Storage Format Specification - Version 2.3 - +- - +- by Werner, last changed: 20020306 by Werner Trobin - +- - +- History : - +- Version 1.0 : binary store - +- Version 2.0 : tar.gz store - +- Version 2.1 : cleaned up - +- version 2.2 : shaheed Put each part into its own directory to allow - +- one filter to easily embed the results of another - +- and also to have its own documentinfo etc. - +- Added description of naming convention. - +- Version 2.3 : werner Allow the usage of relative links. It is now - +- possible to refer to any "embedded" image or part - +- via a plain relative URL as you all know it. - +- - +------------------------------------------------------------------------------- + +The purpose of this document is to define a common KOffice Storage Structure. +Torben, Reggie, and all the others agreed on storing embedded KOffice Parts +and binary data (e.g. pictures, movies, sounds) via a simple tar.gz-structure. +The support class for the tar format is kdelibs/kio/ktar.*, written by Torben +and finished by David. + +The obvious benefits of this type of storage are: + - It's 100% non- proprietary as it uses only the already available formats + (XML, pictures, tar.gz, ...) and tools (tar, gzip). + - It enables anybody to edit the document directly; for instance, to update + an image (faster than launching the application), or to write scripts + that generate KOffice documents ! :) + - It is also easy to write an import filter for any other office-suite + application out there by reading the tar.gz file and extracting the XML out + of it (at the worst, the user can extract the XML file by himself, but then + the import loses embedded Parts and pictures). + +The tar.gz format also generates much smaller files than the old binary +store, since everything's gzipped. + +Name of the KOffice Files +------------------------- + +As some people suggested, using a "tgz"-ending is confusing; it's been dropped. +Instead, we use the "normal" endings like ".kwd", ".ksp", ".kpr", etc. To recognize +KOffice documents without a proper extension David Faure <faure@kde.org> +added some magic numbers to the gzip header (to see what I'm talking about +please use the "file" command on a KOffice document or see +http://lists.kde.org/?l=koffice-devel&m=98609092618214&w=2); + +External Structure +------------------ + +Here is a simple example to demonstrate the structure of a KOffice document. +Assume you have to write a lab-report. You surely will have some text, the +readings, some formulas and a few pictures (e.g. circuit diagram,...). +The main document will be a KWord-file. In this file you embed some KSpread- +tables, some KChart-diagramms, the KFormulas, and some picture-frames. You save +the document as "lab-report.kwd". Here is what the contents of the +tar.gz file will look like : + +lab-report.kwd: +--------------- +maindoc.xml -- The main XML file containing the KWord document. +documentinfo.xml -- Author and other "metadata" for KWord document. +pictures/ -- Pictures embedded in the main KWord document. +pictures/picture0.jpg +pictures/picture1.bmp +cliparts/ -- Cliparts embedded in the main KWord document. +cliparts/clipart0.wmf +part0/maindoc.xml -- for instance a KSpread embedded table. +part0/documentinfo.xml -- Author and other "metadata" for KSpread table. +part0/part1/maindoc.xml -- say a KChart diagram within the KSpread table. +part1/maindoc.xml -- say a KChart diagram. +part2/maindoc.xml -- why not a KIllustrator drawing. +part2/pictures/ -- Pictures embedded in the KIllustrator document. +part2/pictures/picture0.jpg +part2/pictures/picture1.bmp +part2/cliparts/ -- Cliparts embedded in the KIllustrator document. +part2/cliparts/clipart0.wmf +... + +Internal Name +------------- + +- Absolute references: + The API provided by this specification does not require application writers + or filter writers to know the details of the external structure: + + tar:/documentinfo.xml is saved as documentinfo.xml + tar:/0 is saved as part0/maindoc.xml + tar:/0/documentinfo.xml is saved as part0/documentinfo.xml + tar:/0/1 is saved as part0/part1/maindoc.xml + tar:/0/1/pictures/picture0.png + is saved as part0/part1/pictures/picture0.png + tar:/Table1/0 is saved as Table1/part0/maindoc.xml + + Note that this is the structure as of version 2.2 of this specification. + The only other format shipped with KDE2.0 is converted (on reading) to look + like this through the services of the "Internal Name". + + If the document does not contain any other Parts or pictures, then the + maindoc.xml and documentinfo.xml files are tarred and gzipped alone, + and saved with the proper extension (.kwd for KWord, .ksp for KSpread, + etc.). + The plan is to use relative paths everywhere, so please try not to use + absolute paths unless neccessary. + +- Relative references: + To allow parts to be self-contained, and to ease the work of filter + developers version 2.3 features relative links within the storage. + This means that the KoStore now has a "state" as in "there is something + like a current directory". You can specify a link like + "pictures/picture0.png" and depending on the current directory this will + be mapped to some absolute path. The surrounding code has to ensure that + the current path is maintained correctly, but due to that we can get rid + of the ugly prefix thingy. + + +Thank you for your attention, +Werner <trobin@kde.org> and David <faure@kde.org> +(edited by Chris Lee <lee@azsites.com> for grammer, spelling, and formatting) diff --git a/src/projects/kostore/koStore.cc b/src/projects/kostore/koStore.cc new file mode 100644 index 0000000..5e7fd06 --- /dev/null +++ b/src/projects/kostore/koStore.cc @@ -0,0 +1,629 @@ +// -*- c-basic-offset: 2 -*- +/* This file is part of the KDE project + Copyright (C) 1998, 1999 Torben Weis <weis@kde.org> + Copyright (C) 2000-2002 David Faure <faure@kde.org>, Werner Trobin <trobin@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <stdio.h> +#include <assert.h> +#include <stdlib.h> + +#include "koStore.h" +//#include "koTarStore.h" +#include "koZipStore.h" +//#include "koDirectoryStore.h" + +#include <qfileinfo.h> +#include <qfile.h> +#include <qdir.h> + +#include <kurl.h> +#include <kdebug.h> +#include <kdeversion.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kio/netaccess.h> + +//#define DefaultFormat KoStore::Tar +#define DefaultFormat KoStore::Zip + +const int KoStore::s_area = 30002; + +KoStore::Backend KoStore::determineBackend( QIODevice* dev ) +{ + unsigned char buf[5]; + if ( dev->readBlock( (char *)buf, 4 ) < 4 ) + return DefaultFormat; // will create a "bad" store (bad()==true) + if ( buf[0] == 0037 && buf[1] == 0213 ) // gzip -> tar.gz + return Tar; + if ( buf[0] == 'P' && buf[1] == 'K' && buf[2] == 3 && buf[3] == 4 ) + return Zip; + return DefaultFormat; // fallback +} + +KoStore* KoStore::createStore( const QString& fileName, Mode mode, const QCString & appIdentification, Backend backend ) +{ + if ( backend == Auto ) { + if ( mode == KoStore::Write ) + backend = DefaultFormat; + else + { + QFileInfo inf( fileName ); + if ( inf.isDir() ) + backend = Directory; + else + { + QFile file( fileName ); + if ( file.open( IO_ReadOnly ) ) + backend = determineBackend( &file ); + else + backend = DefaultFormat; // will create a "bad" store (bad()==true) + } + } + } + switch ( backend ) + { +// case Tar: +// return new KoTarStore( fileName, mode, appIdentification ); + case Zip: + return new KoZipStore( fileName, mode, appIdentification ); +// case Directory: +// return new KoDirectoryStore( fileName /* should be a dir name.... */, mode ); + default: + kdWarning(s_area) << "Unsupported backend requested for KoStore : " << backend << endl; + return 0L; + } +} + +KoStore* KoStore::createStore( QIODevice *device, Mode mode, const QCString & appIdentification, Backend backend ) +{ + if ( backend == Auto ) + { + if ( mode == KoStore::Write ) + backend = DefaultFormat; + else { + if ( device->open( IO_ReadOnly ) ) { + backend = determineBackend( device ); + device->close(); + } + } + } + switch ( backend ) + { +// case Tar: +// return new KoTarStore( device, mode, appIdentification ); +// case Directory: +// kdError(s_area) << "Can't create a Directory store for a memory buffer!" << endl; + // fallback + case Zip: + return new KoZipStore( device, mode, appIdentification ); + default: + kdWarning(s_area) << "Unsupported backend requested for KoStore : " << backend << endl; + return 0L; + } +} + +KoStore* KoStore::createStore( QWidget* window, const KURL& url, Mode mode, const QCString & appIdentification, Backend backend ) +{ + if ( url.isLocalFile() ) + return createStore(url.path(), mode, appIdentification, backend ); + + QString tmpFile; + if ( mode == KoStore::Write ) + { + if ( backend == Auto ) + backend = DefaultFormat; + } + else + { + const bool downloaded = + KIO::NetAccess::download( url, tmpFile, window ); + + if (!downloaded) + { + kdError(s_area) << "Could not download file!" << endl; + backend = DefaultFormat; // will create a "bad" store (bad()==true) + } + else if ( backend == Auto ) + { + QFile file( tmpFile ); + if ( file.open( IO_ReadOnly ) ) + { + backend = determineBackend( &file ); + file.close(); + } + } + } + switch ( backend ) + { +// case Tar: +// return new KoTarStore( window, url, tmpFile, mode, appIdentification ); + case Zip: + return new KoZipStore( window, url, tmpFile, mode, appIdentification ); + default: + kdWarning(s_area) << "Unsupported backend requested for KoStore (KURL) : " << backend << endl; + KMessageBox::sorry( window, + i18n("The directory mode is not supported for remote locations."), + i18n("KOffice Storage")); + return 0L; + } +} + +namespace { + const char* const ROOTPART = "root"; + const char* const MAINNAME = "maindoc.xml"; +} + +bool KoStore::init( Mode _mode ) +{ + d = 0; + m_bIsOpen = false; + m_mode = _mode; + m_stream = 0; + + // Assume new style names. + m_namingVersion = NAMING_VERSION_2_2; + return true; +} + +KoStore::~KoStore() +{ + delete m_stream; +} + +bool KoStore::open( const QString & _name ) +{ + // This also converts from relative to absolute, i.e. merges the currentPath() + m_sName = toExternalNaming( _name ); + + if ( m_bIsOpen ) + { + kdWarning(s_area) << "KoStore: File is already opened" << endl; + //return KIO::ERR_INTERNAL; + return false; + } + + if ( m_sName.length() > 512 ) + { + kdError(s_area) << "KoStore: Filename " << m_sName << " is too long" << endl; + //return KIO::ERR_MALFORMED_URL; + return false; + } + + if ( m_mode == Write ) + { + kdDebug(s_area) << "KoStore: opening for writing '" << m_sName << "'" << endl; + if ( m_strFiles.findIndex( m_sName ) != -1 ) // just check if it's there + { + kdWarning(s_area) << "KoStore: Duplicate filename " << m_sName << endl; + //return KIO::ERR_FILE_ALREADY_EXIST; + return false; + } + + m_strFiles.append( m_sName ); + + m_iSize = 0; + if ( !openWrite( m_sName ) ) + return false; + } + else if ( m_mode == Read ) + { + kdDebug(s_area) << "Opening for reading '" << m_sName << "'" << endl; + if ( !openRead( m_sName ) ) + return false; + } + else + //return KIO::ERR_UNSUPPORTED_ACTION; + return false; + + m_bIsOpen = true; + return true; +} + +bool KoStore::isOpen() const +{ + return m_bIsOpen; +} + +bool KoStore::close() +{ + kdDebug(s_area) << "KoStore: Closing" << endl; + + if ( !m_bIsOpen ) + { + kdWarning(s_area) << "KoStore: You must open before closing" << endl; + //return KIO::ERR_INTERNAL; + return false; + } + + bool ret = m_mode == Write ? closeWrite() : closeRead(); + + delete m_stream; + m_stream = 0L; + m_bIsOpen = false; + return ret; +} + +QIODevice* KoStore::device() const +{ + if ( !m_bIsOpen ) + kdWarning(s_area) << "KoStore: You must open before asking for a device" << endl; + if ( m_mode != Read ) + kdWarning(s_area) << "KoStore: Can not get device from store that is opened for writing" << endl; + return m_stream; +} + +QByteArray KoStore::read( unsigned long int max ) +{ + QByteArray data; // Data is a QArray<char> + + if ( !m_bIsOpen ) + { + kdWarning(s_area) << "KoStore: You must open before reading" << endl; + data.resize( 0 ); + return data; + } + if ( m_mode != Read ) + { + kdError(s_area) << "KoStore: Can not read from store that is opened for writing" << endl; + data.resize( 0 ); + return data; + } + + if ( m_stream->atEnd() ) + { + data.resize( 0 ); + return data; + } + + if ( max > m_iSize - m_stream->at() ) + max = m_iSize - m_stream->at(); + if ( max == 0 ) + { + data.resize( 0 ); + return data; + } + + char *p = new char[ max ]; + m_stream->readBlock( p, max ); + + data.setRawData( p, max ); + return data; +} + +Q_LONG KoStore::write( const QByteArray& data ) +{ + return write( data.data(), data.size() ); // see below +} + +Q_LONG KoStore::read( char *_buffer, Q_ULONG _len ) +{ + if ( !m_bIsOpen ) + { + kdError(s_area) << "KoStore: You must open before reading" << endl; + return -1; + } + if ( m_mode != Read ) + { + kdError(s_area) << "KoStore: Can not read from store that is opened for writing" << endl; + return -1; + } + + if ( m_stream->atEnd() ) + return 0; + + if ( _len > m_iSize - m_stream->at() ) + _len = m_iSize - m_stream->at(); + if ( _len == 0 ) + return 0; + + return m_stream->readBlock( _buffer, _len ); +} + +Q_LONG KoStore::write( const char* _data, Q_ULONG _len ) +{ + if ( _len == 0L ) return 0; + + if ( !m_bIsOpen ) + { + kdError(s_area) << "KoStore: You must open before writing" << endl; + return 0L; + } + if ( m_mode != Write ) + { + kdError(s_area) << "KoStore: Can not write to store that is opened for reading" << endl; + return 0L; + } + + int nwritten = m_stream->writeBlock( _data, _len ); + Q_ASSERT( nwritten == (int)_len ); + m_iSize += nwritten; + + return nwritten; +} + +QIODevice::Offset KoStore::size() const +{ + if ( !m_bIsOpen ) + { + kdWarning(s_area) << "KoStore: You must open before asking for a size" << endl; + return static_cast<QIODevice::Offset>(-1); + } + if ( m_mode != Read ) + { + kdWarning(s_area) << "KoStore: Can not get size from store that is opened for writing" << endl; + return static_cast<QIODevice::Offset>(-1); + } + return m_iSize; +} + +bool KoStore::enterDirectory( const QString& directory ) +{ + //kdDebug(s_area) << "KoStore::enterDirectory " << directory << endl; + int pos; + bool success = true; + QString tmp( directory ); + + while ( ( pos = tmp.find( '/' ) ) != -1 && + ( success = enterDirectoryInternal( tmp.left( pos ) ) ) ) + tmp = tmp.mid( pos + 1 ); + + if ( success && !tmp.isEmpty() ) + return enterDirectoryInternal( tmp ); + return success; +} + +bool KoStore::leaveDirectory() +{ + if ( m_currentPath.isEmpty() ) + return false; + + m_currentPath.pop_back(); + + return enterAbsoluteDirectory( expandEncodedDirectory( currentPath() ) ); +} + +QString KoStore::currentDirectory() const +{ + return expandEncodedDirectory( currentPath() ); +} + +QString KoStore::currentPath() const +{ + QString path; + QStringList::ConstIterator it = m_currentPath.begin(); + QStringList::ConstIterator end = m_currentPath.end(); + for ( ; it != end; ++it ) { + path += *it; + path += '/'; + } + return path; +} + +void KoStore::pushDirectory() +{ + m_directoryStack.push( currentPath() ); +} + +void KoStore::popDirectory() +{ + m_currentPath.clear(); + enterAbsoluteDirectory( QString::null ); + enterDirectory( m_directoryStack.pop() ); +} + +bool KoStore::addLocalFile( const QString &fileName, const QString &destName ) +{ + QFileInfo fi( fileName ); + uint size = fi.size(); + QFile file( fileName ); + if ( !file.open( IO_ReadOnly )) + { + return false; + } + + if ( !open ( destName ) ) + { + return false; + } + + QByteArray data ( 8 * 1024 ); + + uint total = 0; + for ( int block = 0; ( block = file.readBlock ( data.data(), data.size() ) ) > 0; total += block ) + { + data.resize(block); + if ( write( data ) != block ) + return false; + data.resize(8*1024); + } + Q_ASSERT( total == size ); + + close(); + file.close(); + + return true; +} + +bool KoStore::extractFile ( const QString &srcName, const QString &fileName ) +{ + if ( !open ( srcName ) ) + return false; + + QFile file( fileName ); + + if( !file.open ( IO_WriteOnly ) ) + { + close(); + return false; + } + + QByteArray data ( 8 * 1024 ); + uint total = 0; + for( int block = 0; ( block = read ( data.data(), data.size() ) ) > 0; total += block ) + { + file.writeBlock ( data.data(), block ); + } + + if( size() != static_cast<QIODevice::Offset>(-1) ) + Q_ASSERT( total == size() ); + + file.close(); + close(); + + return true; +} + +QStringList KoStore::addLocalDirectory( const QString &dirPath, const QString &destName ) +{ + QString dot = "."; + QString dotdot = ".."; + QStringList content; + + QDir dir(dirPath); + if ( !dir.exists() ) + return 0; + + QStringList files = dir.entryList(); + for ( QStringList::Iterator it = files.begin(); it != files.end(); ++it ) + { + if ( *it != dot && *it != dotdot ) + { + QString currentFile = dirPath + "/" + *it; + QString dest = destName.isEmpty() ? *it : (destName + "/" + *it); + + QFileInfo fi ( currentFile ); + if ( fi.isFile() ) + { + addLocalFile ( currentFile, dest ); + content.append(dest); + } + else if ( fi.isDir() ) + { + content += addLocalDirectory ( currentFile, dest ); + } + } + } + + return content; +} + + +bool KoStore::at( QIODevice::Offset pos ) +{ + return m_stream->at( pos ); +} + +QIODevice::Offset KoStore::at() const +{ + return m_stream->at(); +} + +bool KoStore::atEnd() const +{ + return m_stream->atEnd(); +} + +// See the specification for details of what this function does. +QString KoStore::toExternalNaming( const QString & _internalNaming ) const +{ + if ( _internalNaming == ROOTPART ) + return expandEncodedDirectory( currentPath() ) + MAINNAME; + + QString intern; + if ( _internalNaming.startsWith( "tar:/" ) ) // absolute reference + intern = _internalNaming.mid( 5 ); // remove protocol + else + intern = currentPath() + _internalNaming; + + return expandEncodedPath( intern ); +} + +QString KoStore::expandEncodedPath( QString intern ) const +{ + if ( m_namingVersion == NAMING_VERSION_RAW ) + return intern; + + QString result; + int pos; + + if ( ( pos = intern.findRev( '/', -1 ) ) != -1 ) { + result = expandEncodedDirectory( intern.left( pos ) ) + '/'; + intern = intern.mid( pos + 1 ); + } + + // Now process the filename. If the first character is numeric, we have + // a main document. + if ( QChar(intern.at(0)).isDigit() ) + { + // If this is the first part name, check if we have a store with + // old-style names. + if ( ( m_namingVersion == NAMING_VERSION_2_2 ) && + ( m_mode == Read ) && + ( fileExists( result + "part" + intern + ".xml" ) ) ) + m_namingVersion = NAMING_VERSION_2_1; + + if ( m_namingVersion == NAMING_VERSION_2_1 ) + result = result + "part" + intern + ".xml"; + else + result = result + "part" + intern + "/" + MAINNAME; + } + else + result += intern; + return result; +} + +QString KoStore::expandEncodedDirectory( QString intern ) const +{ + if ( m_namingVersion == NAMING_VERSION_RAW ) + return intern; + + QString result; + int pos; + while ( ( pos = intern.find( '/' ) ) != -1 ) { + if ( QChar(intern.at(0)).isDigit() ) + result += "part"; + result += intern.left( pos + 1 ); // copy numbers (or "pictures") + "/" + intern = intern.mid( pos + 1 ); // remove the dir we just processed + } + + if ( QChar(intern.at(0)).isDigit() ) + result += "part"; + result += intern; + return result; +} + +bool KoStore::enterDirectoryInternal( const QString& directory ) +{ + if ( enterRelativeDirectory( expandEncodedDirectory( directory ) ) ) + { + m_currentPath.append( directory ); + return true; + } + return false; +} + +void KoStore::disallowNameExpansion( void ) +{ + m_namingVersion = NAMING_VERSION_RAW; +} + +bool KoStore::hasFile( const QString& fileName ) const +{ + return fileExists( toExternalNaming( currentPath() + fileName ) ); +} diff --git a/src/projects/kostore/koStore.h b/src/projects/kostore/koStore.h new file mode 100644 index 0000000..a22c5f3 --- /dev/null +++ b/src/projects/kostore/koStore.h @@ -0,0 +1,384 @@ +// -*- c-basic-offset: 2 -*- +/* This file is part of the KDE project + Copyright (C) 1998, 1999 David Faure <faure@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __koStore_h_ +#define __koStore_h_ + +#include <qstring.h> +#include <qstringlist.h> +#include <qiodevice.h> +#include <qvaluestack.h> +//#include <koffice_export.h> +#include <kdemacros.h> + +#define KOSTORE_EXPORT KDE_EXPORT + +class QWidget; + +class KURL; + +/** + * Saves and loads KOffice documents using various backends. Currently supported + * backends are ZIP, tar and directory. + * We call a "store" the file on the hard disk (the one the users sees) + * and call a "file" a file inside the store. + */ +class KoStore +{ +public: + + enum Mode { Read, Write }; + enum Backend { Auto, Tar, Zip, Directory }; + + /** + * Open a store (i.e. the representation on disk of a KOffice document). + * + * @param fileName the name of the file to open + * @param mode if KoStore::Read, open an existing store to read it. + * if KoStore::Write, create or replace a store. + * @param backend the backend to use for the data storage. + * Auto means automatically-determined for reading, + * and the current format (now Zip) for writing. + * + * @param appIdentification the application's mimetype, + * to be written in the file for "mime-magic" identification. + * Only meaningful if mode is Write, and if backend!=Directory. + */ + static KoStore* createStore( const QString& fileName, Mode mode, const QCString & appIdentification = "", Backend backend = Auto ); + + /** + * Create a store for any kind of QIODevice: file, memory buffer... + * KoStore will take care of opening the QIODevice. + * This method doesn't support the Directory store! + */ + static KoStore* createStore( QIODevice *device, Mode mode, const QCString & appIdentification = "", Backend backend = Auto ); + + /** + * Open a store (i.e. the representation on disk of a KOffice document). + * + * @param window associated window (for the progress bar dialog and authentication) + * @param url URL of the file to open + * @param mode if KoStore::Read, open an existing store to read it. + * if KoStore::Write, create or replace a store. + * @param backend the backend to use for the data storage. + * Auto means automatically-determined for reading, + * and the current format (now Zip) for writing. + * + * @param appIdentification the application's mimetype, + * to be written in the file for "mime-magic" identification. + * Only meaningful if mode is Write, and if backend!=Directory. + * + * If the file is remote, the backend Directory cannot be used! + * + * @since 1.4 + * @bug saving not completely implemented (fixed temporary file) + */ + static KoStore* createStore( QWidget* window, const KURL& url, Mode mode, const QCString & appIdentification = "", Backend backend = Auto ); + + /** + * Destroys the store (i.e. closes the file on the hard disk) + */ + virtual ~KoStore(); + + /** + * Open a new file inside the store + * @param name The filename, internal representation ("root", "tar:/0"... ). + * If the tar:/ prefix is missing it's assumed to be a relative URI. + * @return true on success. + */ + bool open( const QString & name ); + + /** + * Check whether a file inside the store is currently opened with open(), + * ready to be read or written. + * @return true if a file is currently opened. + */ + bool isOpen() const; + + /** + * Close the file inside the store + * @return true on success. + */ + bool close(); + + /** + * Get a device for reading a file from the store directly + * (slightly faster than read() calls) + * You need to call @ref open first, and @ref close afterwards. + */ + QIODevice* device() const; + + /** + * Read data from the currently opened file. You can also use the streams + * for this. + */ + QByteArray read( unsigned long int max ); + + /** + * Write data into the currently opened file. You can also use the streams + * for this. + */ + Q_LONG write( const QByteArray& _data ); + + /** + * Read data from the currently opened file. You can also use the streams + * for this. + * @return size of data read, -1 on error + */ + Q_LONG read( char *_buffer, Q_ULONG _len ); + + /** + * Write data into the currently opened file. You can also use the streams + * for this. + */ + virtual Q_LONG write( const char* _data, Q_ULONG _len ); + + /** + * @return the size of the currently opened file, -1 on error. + * Can be used as an argument for the read methods, for instance + */ + QIODevice::Offset size() const; + + /** + * @return true if an error occurred + */ + bool bad() const { return !m_bGood; } // :) + + /** + * @return the mode used when opening, read or write + */ + Mode mode() const { return m_mode; } + + /** + * Enters one or multiple directories. In Read mode this actually + * checks whether the specified directories exist and returns false + * if they don't. In Write mode we don't create the directory, we + * just use the "current directory" to generate the absolute path + * if you pass a relative path (one not starting with tar:/) when + * opening a stream. + * Note: Operates on internal names + */ + bool enterDirectory( const QString& directory ); + + /** + * Leaves a directory. Equivalent to "cd .." + * @return true on success, false if we were at the root already to + * make it possible to "loop to the root" + */ + bool leaveDirectory(); + + /** + * Returns the current path including a trailing slash. + * Note: Returns a path in "internal name" style + */ + QString currentPath() const; + + /** + * Returns the current directory. + * Note: Returns a path in "internal name" style + */ + QString currentDirectory() const; + + + /** + * Stacks the current directory. Restore the current path using + * @ref popDirectory . + */ + void pushDirectory(); + + /** + * Restores the previously pushed directory. No-op if the stack is + * empty. + */ + void popDirectory(); + + /** + * @return true if the given file exists in the current directory, + * i.e. if open(fileName) will work. + */ + bool hasFile( const QString& fileName ) const; + + /** + * Imports a local file into a store + * @param fileName file on hard disk + * @param destName file in the store + */ + bool addLocalFile( const QString &fileName, const QString &destName ); + + /** + * Imports a local directory + * @param dirPath path to the directory on a disk + * @param dest path in the store where the directory should get saved + * @return the directory index + */ + QStringList addLocalDirectory( const QString &dirPath, const QString &dest ); + + + /** + * Extracts a file out of the store + * @param srcName file in the store + * @param fileName file on a disk + */ + bool extractFile( const QString &srcName, const QString &fileName ); + + //@{ + /// See QIODevice + bool at( QIODevice::Offset pos ); + QIODevice::Offset at() const; + bool atEnd() const; + //@} + + /** + * Do not expand file and directory names + * Useful when using KoStore on non-KOffice files. + * (This method should be called just after the constructor) + */ + void disallowNameExpansion( void ); + +protected: + + KoStore() {} + + /** + * Init store - called by constructor. + * @return true on success + */ + virtual bool init( Mode mode ); + /** + * Open the file @p name in the store, for writing + * On success, this method must set m_stream to a stream in which we can write. + * @param name "absolute path" (in the archive) to the file to open + * @return true on success + */ + virtual bool openWrite( const QString& name ) = 0; + /** + * Open the file @p name in the store, for reading. + * On success, this method must set m_stream to a stream from which we can read, + * as well as setting m_iSize to the size of the file. + * @param name "absolute path" (in the archive) to the file to open + * @return true on success + */ + virtual bool openRead( const QString& name ) = 0; + + /** + * @return true on success + */ + virtual bool closeRead() = 0; + /** + * @return true on success + */ + virtual bool closeWrite() = 0; + + /** + * Enter a subdirectory of the current directory. + * The directory might not exist yet in Write mode. + */ + virtual bool enterRelativeDirectory( const QString& dirName ) = 0; + /** + * Enter a directory where we've been before. + * It is guaranteed to always exist. + */ + virtual bool enterAbsoluteDirectory( const QString& path ) = 0; + + /** + * Check if a file exists inside the store. + * @param absPath the absolute path inside the store, i.e. not relative to the current directory + */ + virtual bool fileExists( const QString& absPath ) const = 0; + +private: + static Backend determineBackend( QIODevice* dev ); + + /** + * Conversion routine + * @param _internalNaming name used internally : "root", "tar:/0", ... + * @return the name used in the file, more user-friendly ("maindoc.xml", + * "part0/maindoc.xml", ...) + * Examples: + * + * tar:/0 is saved as part0/maindoc.xml + * tar:/0/1 is saved as part0/part1/maindoc.xml + * tar:/0/1/pictures/picture0.png is saved as part0/part1/pictures/picture0.png + * + * see specification (koffice/lib/store/SPEC) for details. + */ + QString toExternalNaming( const QString & _internalNaming ) const; + + /** + * Expands a full path name for a stream (directories+filename) + */ + QString expandEncodedPath( QString intern ) const; + + /** + * Expands only directory names(!) + * Needed for the path handling code, as we only operate on internal names + */ + QString expandEncodedDirectory( QString intern ) const; + + mutable enum + { + NAMING_VERSION_2_1, + NAMING_VERSION_2_2, + NAMING_VERSION_RAW ///< Never expand file and directory names + } m_namingVersion; + + /** + * Enter *one* single directory. Nothing like foo/bar/bleh allowed. + * Performs some checking when in Read mode + */ + bool enterDirectoryInternal( const QString& directory ); + +protected: + + Mode m_mode; + + /// Store the filenames (with full path inside the archive) when writing, to avoid duplicates + QStringList m_strFiles; + + /// The "current directory" (path) + QStringList m_currentPath; + + /// Used to push/pop directories to make it easy to save/restore the state + QValueStack<QString> m_directoryStack; + + /// Current filename (between an open() and a close()) + QString m_sName; + /// Current size of the file named m_sName + QIODevice::Offset m_iSize; + + /// The stream for the current read or write operation + QIODevice * m_stream; + + bool m_bIsOpen; + /// Must be set by the constructor. + bool m_bGood; + + static const int s_area; + +private: + KoStore( const KoStore& store ); ///< don't copy + KoStore& operator=( const KoStore& store ); ///< don't assign + + class Private; + Private * d; + +}; + +#endif diff --git a/src/projects/kostore/koStoreBase.cc b/src/projects/kostore/koStoreBase.cc new file mode 100644 index 0000000..a9cc63e --- /dev/null +++ b/src/projects/kostore/koStoreBase.cc @@ -0,0 +1,29 @@ +// +/* This file is part of the KDE project + Copyright 2004 Nicolas GOUTTE <goutte@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include "koStoreBase.h" + +KoStoreBase::KoStoreBase(void) : m_fileMode(Local), m_window(0) +{ +} + +KoStoreBase::~KoStoreBase(void) +{ +} diff --git a/src/projects/kostore/koStoreBase.h b/src/projects/kostore/koStoreBase.h new file mode 100644 index 0000000..0987577 --- /dev/null +++ b/src/projects/kostore/koStoreBase.h @@ -0,0 +1,51 @@ +// +/* This file is part of the KDE project + Copyright 2004 Nicolas GOUTTE <goutte@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef KOSTORE_BASE_H +#define KOSTORE_BASE_H + +#include <kurl.h> + +#include "koStore.h" + +/** + * Helper class for KoStore (mainly for remote file support) + * @since 1.4 + */ +class KoStoreBase : public KoStore +{ +public: + KoStoreBase(void); + virtual ~KoStoreBase(void); +public: + enum FileMode { /*Bad=0,*/ Local=1, RemoteRead, RemoteWrite }; + +protected: + /** + * original URL of the remote file + * (undefined for a local file) + */ + KURL m_url; + FileMode m_fileMode; + QString m_localFileName; + QWidget* m_window; +}; + +#endif //KOSTORE_BASE_H diff --git a/src/projects/kostore/koStoreDevice.h b/src/projects/kostore/koStoreDevice.h new file mode 100644 index 0000000..b245d60 --- /dev/null +++ b/src/projects/kostore/koStoreDevice.h @@ -0,0 +1,88 @@ +/* This file is part of the KDE project + Copyright (C) 2000 David Faure <faure@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef koStoreDevice_h +#define koStoreDevice_h + +#include "koStore.h" + +/** + * This class implements a QIODevice around KoStore, so that + * it can be used to create a QDomDocument from it, to be written or read + * using QDataStream or to be written using QTextStream + */ +class KoStoreDevice : public QIODevice +{ +public: + /// Note: KoStore::open() should be called before calling this. + KoStoreDevice( KoStore * store ) : m_store(store) { + setType( IO_Direct ); + } + ~KoStoreDevice() {} + + bool open( int m ) { + if ( m & IO_ReadOnly ) + return ( m_store->mode() == KoStore::Read ); + if ( m & IO_WriteOnly ) + return ( m_store->mode() == KoStore::Write ); + return false; + } + void close() { } + void flush() { } + + Offset size() const { + if ( m_store->mode() == KoStore::Read ) + return m_store->size(); + else + return 0xffffffff; + } + + virtual Q_LONG readBlock( char *data, Q_ULONG maxlen ) { return m_store->read(data, maxlen); } + virtual Q_LONG writeBlock( const char *data, Q_ULONG len ) { return m_store->write( data, len ); } + // Not virtual, only to uncover shadow + Q_LONG writeBlock( const QByteArray& data ) { return QIODevice::writeBlock( data ); } + + int getch() { + char c[2]; + if ( m_store->read(c, 1) == -1) + return -1; + else + return c[0]; + } + int putch( int _c ) { + char c[2]; + c[0] = _c; + c[1] = 0; + if (m_store->write( c, 1 ) == 1) + return _c; + else + return -1; + } + int ungetch( int ) { return -1; } // unsupported + + // See QIODevice + virtual bool at( Offset pos ) { return m_store->at(pos); } + virtual Offset at() const { return m_store->at(); } + virtual bool atEnd() const { return m_store->atEnd(); } + +protected: + KoStore * m_store; +}; + +#endif diff --git a/src/projects/kostore/koZipStore.cc b/src/projects/kostore/koZipStore.cc new file mode 100644 index 0000000..ed3fec4 --- /dev/null +++ b/src/projects/kostore/koZipStore.cc @@ -0,0 +1,237 @@ +/* This file is part of the KDE project + Copyright (C) 2000-2002 David Faure <faure@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include "koZipStore.h" + +#include <qbuffer.h> + +#include <kzip.h> +#include <kdebug.h> +#include <kdeversion.h> +#include <kurl.h> +#include <kio/netaccess.h> +#if ! KDE_IS_VERSION( 3, 4, 1 ) +#include <qdir.h> +#include <qfileinfo.h> +#endif + +KoZipStore::KoZipStore( const QString & _filename, Mode _mode, const QCString & appIdentification ) +{ + kdDebug(s_area) << "KoZipStore Constructor filename = " << _filename + << " mode = " << int(_mode) + << " mimetype = " << appIdentification << endl; + + m_pZip = new KZip( _filename ); + +#if ! KDE_IS_VERSION( 3, 4, 1 ) + // Workaround for KZip KSaveFile double deletion in kdelibs-3.4, + // when trying to write to a non-writable directory. + QDir dir( QFileInfo( _filename ).dir() ); + if (_mode == Write && !QFileInfo( dir.path() ).isWritable() ) + { + kdWarning(s_area) << dir.path() << " isn't writable" << endl; + m_bGood = false; + m_currentDir = 0; + KoStore::init( _mode ); + } + else +#endif + { + m_bGood = init( _mode, appIdentification ); // open the zip file and init some vars + } +} + +KoZipStore::KoZipStore( QIODevice *dev, Mode mode, const QCString & appIdentification ) +{ + m_pZip = new KZip( dev ); + m_bGood = init( mode, appIdentification ); +} + +KoZipStore::KoZipStore( QWidget* window, const KURL & _url, const QString & _filename, Mode _mode, const QCString & appIdentification ) +{ + kdDebug(s_area) << "KoZipStore Constructor url" << _url.prettyURL() + << " filename = " << _filename + << " mode = " << int(_mode) + << " mimetype = " << appIdentification << endl; + + m_url = _url; + m_window = window; + + if ( _mode == KoStore::Read ) + { + m_fileMode = KoStoreBase::RemoteRead; + m_localFileName = _filename; + + } + else + { + m_fileMode = KoStoreBase::RemoteWrite; + m_localFileName = "/tmp/kozip"; // ### FIXME with KTempFile + } + + m_pZip = new KZip( m_localFileName ); + m_bGood = init( _mode, appIdentification ); // open the zip file and init some vars +} + +KoZipStore::~KoZipStore() +{ + kdDebug(s_area) << "KoZipStore::~KoZipStore" << endl; + m_pZip->close(); + delete m_pZip; + + // Now we have still some job to do for remote files. + if ( m_fileMode == KoStoreBase::RemoteRead ) + { + KIO::NetAccess::removeTempFile( m_localFileName ); + } + else if ( m_fileMode == KoStoreBase::RemoteWrite ) + { + KIO::NetAccess::upload( m_localFileName, m_url, m_window ); + // ### FIXME: delete temp file + } +} + +bool KoZipStore::init( Mode _mode, const QCString& appIdentification ) +{ + KoStore::init( _mode ); + m_currentDir = 0; + bool good = m_pZip->open( _mode == Write ? IO_WriteOnly : IO_ReadOnly ); + + if ( good && _mode == Read ) + good = m_pZip->directory() != 0; + else if ( good && _mode == Write ) + { + //kdDebug(s_area) << "KoZipStore::init writing mimetype " << appIdentification << endl; + + m_pZip->setCompression( KZip::NoCompression ); + m_pZip->setExtraField( KZip::NoExtraField ); + // Write identification + (void)m_pZip->writeFile( "mimetype", "", "", appIdentification.length(), appIdentification.data() ); + m_pZip->setCompression( KZip::DeflateCompression ); + // We don't need the extra field in KOffice - so we leave it as "no extra field". + } + return good; +} + +bool KoZipStore::openWrite( const QString& name ) +{ +#if 0 + // Prepare memory buffer for writing + m_byteArray.resize( 0 ); + m_stream = new QBuffer( m_byteArray ); + m_stream->open( IO_WriteOnly ); + return true; +#endif + m_stream = 0L; // Don't use! + return m_pZip->prepareWriting( name, "", "" /*m_pZip->rootDir()->user(), m_pZip->rootDir()->group()*/, 0 ); +} + +bool KoZipStore::openRead( const QString& name ) +{ + const KArchiveEntry * entry = m_pZip->directory()->entry( name ); + if ( entry == 0L ) + { + //kdWarning(s_area) << "Unknown filename " << name << endl; + //return KIO::ERR_DOES_NOT_EXIST; + return false; + } + if ( entry->isDirectory() ) + { + kdWarning(s_area) << name << " is a directory !" << endl; + //return KIO::ERR_IS_DIRECTORY; + return false; + } + // Must cast to KZipFileEntry, not only KArchiveFile, because device() isn't virtual! + const KZipFileEntry * f = static_cast<const KZipFileEntry *>(entry); + delete m_stream; + m_stream = f->device(); + m_iSize = f->size(); + return true; +} + +Q_LONG KoZipStore::write( const char* _data, Q_ULONG _len ) +{ + if ( _len == 0L ) return 0; + //kdDebug(s_area) << "KoZipStore::write " << _len << endl; + + if ( !m_bIsOpen ) + { + kdError(s_area) << "KoStore: You must open before writing" << endl; + return 0L; + } + if ( m_mode != Write ) + { + kdError(s_area) << "KoStore: Can not write to store that is opened for reading" << endl; + return 0L; + } + + m_iSize += _len; + if ( m_pZip->writeData( _data, _len ) ) // writeData returns a bool! + return _len; + return 0L; +} + +bool KoZipStore::closeWrite() +{ + kdDebug(s_area) << "Wrote file " << m_sName << " into ZIP archive. size " + << m_iSize << endl; + return m_pZip->doneWriting( m_iSize ); +#if 0 + if ( !m_pZip->writeFile( m_sName , "user", "group", m_iSize, m_byteArray.data() ) ) + kdWarning( s_area ) << "Failed to write " << m_sName << endl; + m_byteArray.resize( 0 ); // save memory + return true; +#endif +} + +bool KoZipStore::enterRelativeDirectory( const QString& dirName ) +{ + if ( m_mode == Read ) { + if ( !m_currentDir ) { + m_currentDir = m_pZip->directory(); // initialize + Q_ASSERT( m_currentPath.isEmpty() ); + } + const KArchiveEntry *entry = m_currentDir->entry( dirName ); + if ( entry && entry->isDirectory() ) { + m_currentDir = dynamic_cast<const KArchiveDirectory*>( entry ); + return m_currentDir != 0; + } + return false; + } + else // Write, no checking here + return true; +} + +bool KoZipStore::enterAbsoluteDirectory( const QString& path ) +{ + if ( path.isEmpty() ) + { + m_currentDir = 0; + return true; + } + m_currentDir = dynamic_cast<const KArchiveDirectory*>( m_pZip->directory()->entry( path ) ); + Q_ASSERT( m_currentDir ); + return m_currentDir != 0; +} + +bool KoZipStore::fileExists( const QString& absPath ) const +{ + const KArchiveEntry *entry = m_pZip->directory()->entry( absPath ); + return entry && entry->isFile(); +} diff --git a/src/projects/kostore/koZipStore.h b/src/projects/kostore/koZipStore.h new file mode 100644 index 0000000..e87f5e4 --- /dev/null +++ b/src/projects/kostore/koZipStore.h @@ -0,0 +1,61 @@ +/* This file is part of the KDE project + Copyright (C) 2002 David Faure <faure@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef koZipStore_h +#define koZipStore_h + +#include "koStoreBase.h" + +class KZip; +class KArchiveDirectory; +class KURL; + +class KoZipStore : public KoStoreBase +{ +public: + KoZipStore( const QString & _filename, Mode _mode, const QCString & appIdentification ); + KoZipStore( QIODevice *dev, Mode mode, const QCString & appIdentification ); + /** + * KURL-constructor + * @todo saving not completely implemented (fixed temporary file) + * @since 1.4 + */ + KoZipStore( QWidget* window, const KURL& _url, const QString & _filename, Mode _mode, const QCString & appIdentification ); + ~KoZipStore(); + + virtual Q_LONG write( const char* _data, Q_ULONG _len ); +protected: + virtual bool init( Mode _mode, const QCString& appIdentification ); + virtual bool openWrite( const QString& name ); + virtual bool openRead( const QString& name ); + virtual bool closeWrite(); + virtual bool closeRead() { return true; } + virtual bool enterRelativeDirectory( const QString& dirName ); + virtual bool enterAbsoluteDirectory( const QString& path ); + virtual bool fileExists( const QString& absPath ) const; + + /// The archive + KZip * m_pZip; + + /** In "Read" mode this pointer is pointing to the + current directory in the archive to speed up the verification process */ + const KArchiveDirectory* m_currentDir; +}; + +#endif diff --git a/src/rip/Makefile.am b/src/rip/Makefile.am new file mode 100644 index 0000000..da023c7 --- /dev/null +++ b/src/rip/Makefile.am @@ -0,0 +1,32 @@ +if include_videodvdrip +VIDEODVDRIPDIR = videodvd +VIDEODVDRIPLIB = videodvd/libvideodvdrip.la +endif + +AM_CPPFLAGS = -I$(srcdir)/../../libk3b/core \ + -I$(srcdir)/../../libk3b/cddb \ + -I$(srcdir)/../../libk3bdevice \ + -I$(srcdir)/../../libk3b/plugin \ + -I$(srcdir)/../../libk3b/tools \ + -I$(srcdir)/../../libk3b/projects \ + -I$(srcdir)/../../libk3b/projects/audiocd \ + -I$(srcdir)/../../libk3b/cddb \ + -I$(srcdir)/../../libk3b/jobs/ \ + -I$(srcdir)/.. \ + -I$(srcdir)/../projects \ + $(all_includes) + +METASOURCES = AUTO + +noinst_LTLIBRARIES = librip.la +librip_la_LIBADD = $(VIDEODVDRIPLIB) + +librip_la_SOURCES = base_k3baudiorippingoptionwidget.ui \ + base_k3bcddbpatternwidget.ui k3bpatternparser.cpp k3baudiorippingdialog.cpp \ + k3baudioripthread.cpp k3baudiocdview.cpp k3bcddbpatternwidget.cpp \ + k3bvideocdinfo.cpp k3bvideocdview.cpp k3bvideocdrip.cpp \ + k3bvideocdrippingdialog.cpp k3bcuefilewriter.cpp k3baudioconvertingoptionwidget.cpp \ + k3baudiocdlistview.cpp k3baudioprojectconvertingdialog.cpp \ + k3baudioprojectconvertingthread.cpp k3baudioripjob.cpp + +SUBDIRS = $(VIDEODVDRIPDIR) \ No newline at end of file diff --git a/src/rip/base_k3baudiorippingoptionwidget.ui b/src/rip/base_k3baudiorippingoptionwidget.ui new file mode 100644 index 0000000..04355b4 --- /dev/null +++ b/src/rip/base_k3baudiorippingoptionwidget.ui @@ -0,0 +1,282 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>base_K3bAudioRippingOptionWidget</class> +<author>Sebastian Trueg</author> +<widget class="QWidget"> + <property name="name"> + <cstring>Form1</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>436</width> + <height>182</height> + </rect> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QGroupBox" row="0" column="0"> + <property name="name"> + <cstring>groupBox2</cstring> + </property> + <property name="title"> + <string>Filetype</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KComboBox"> + <property name="name"> + <cstring>m_comboFileType</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>1</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="QToolButton"> + <property name="name"> + <cstring>m_buttonConfigurePlugin</cstring> + </property> + <property name="text"> + <string>...</string> + </property> + <property name="toolTip" stdset="0"> + <string>Configure Plugin</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QGroupBox" row="0" column="1" rowspan="2" colspan="1"> + <property name="name"> + <cstring>groupBox3</cstring> + </property> + <property name="title"> + <string>Options</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_checkCreatePlaylist</cstring> + </property> + <property name="text"> + <string>Create m&3u playlist</string> + </property> + <property name="toolTip" stdset="0"> + <string>Create playlist for the ripped files</string> + </property> + <property name="whatsThis" stdset="0"> + <string><p>If this option is checked K3b will create a playlist of the ripped files +which can be used with programs like xmms or noatun. +<p>You may use the special strings to give the playlist a unique filename.</string> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout6</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer1_2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>16</height> + </size> + </property> + </spacer> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_checkPlaylistRelative</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>&Use relative paths</string> + </property> + <property name="toolTip" stdset="0"> + <string>Use relative paths instead of absolute</string> + </property> + <property name="whatsThis" stdset="0"> + <string><p>If this option is checked, the entries in the playlist will be relative to its location. +<p>Example: If your playlist is located in <em>/home/myself/music</em> and +your audio files are in <em>/home/myself/music/cool</em>; then the entries in the +playlist will look something like: <em>cool/track1.ogg</em>.</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_checkSingleFile</cstring> + </property> + <property name="text"> + <string>Create si&ngle file</string> + </property> + <property name="toolTip" stdset="0"> + <string>Rip all tracks to a single file</string> + </property> + <property name="whatsThis" stdset="0"> + <string><p>If this option is checked K3b will create only one +audio file no matter how many tracks are ripped. This +file will contain all tracks one after the other. +<p>This might be useful to rip a live album or a radio play. +<p><b>Caution:</b> The file will have the name of the first track.</string> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout6_2</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer1_2_2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>16</height> + </size> + </property> + </spacer> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_checkWriteCueFile</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Write &cue file</string> + </property> + <property name="toolTip" stdset="0"> + <string>Write a cuefile</string> + </property> + <property name="whatsThis" stdset="0"> + <string><p>If this option is checked K3b will create a CDRWIN cue file which allows to easily write a copy of the audio CD on other systems.</string> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + <widget class="QGroupBox" row="1" column="0"> + <property name="name"> + <cstring>groupBox1</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>1</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>Target Folder</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Free space in directory:</string> + </property> + </widget> + <widget class="KURLRequester" row="0" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>m_editBaseDir</cstring> + </property> + </widget> + <widget class="QLabel" row="1" column="1"> + <property name="name"> + <cstring>m_labelFreeSpace</cstring> + </property> + <property name="text"> + <string>-</string> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>textLabel1_2</cstring> + </property> + <property name="text"> + <string>Space needed:</string> + </property> + </widget> + <widget class="QLabel" row="2" column="1"> + <property name="name"> + <cstring>m_labelNeededSpace</cstring> + </property> + <property name="text"> + <string>-</string> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + </grid> + </widget> + </grid> +</widget> +<customwidgets> +</customwidgets> +<connections> + <connection> + <sender>m_checkCreatePlaylist</sender> + <signal>toggled(bool)</signal> + <receiver>m_checkPlaylistRelative</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>m_checkSingleFile</sender> + <signal>toggled(bool)</signal> + <receiver>m_checkWriteCueFile</receiver> + <slot>setEnabled(bool)</slot> + </connection> +</connections> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kurlrequester.h</includehint> + <includehint>kpushbutton.h</includehint> +</includehints> +</UI> diff --git a/src/rip/base_k3bcddbpatternwidget.ui b/src/rip/base_k3bcddbpatternwidget.ui new file mode 100644 index 0000000..cafaa5d --- /dev/null +++ b/src/rip/base_k3bcddbpatternwidget.ui @@ -0,0 +1,180 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>base_K3bCddbPatternWidget</class> +<widget class="QWidget"> + <property name="name"> + <cstring>base_K3bPatternOptionTab</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>344</width> + <height>139</height> + </rect> + </property> + <property name="caption"> + <string>Ripping Pattern</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QLayoutWidget" row="3" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>layout8</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_checkBlankReplace</cstring> + </property> + <property name="text"> + <string>Replace all blan&ks with:</string> + </property> + </widget> + <widget class="KLineEdit"> + <property name="name"> + <cstring>m_editBlankReplace</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>_</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Playlist pattern:</string> + </property> + </widget> + <widget class="KComboBox" row="1" column="1"> + <property name="name"> + <cstring>m_comboPlaylistPattern</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>1</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="editable"> + <bool>true</bool> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Ripped files pattern:</string> + </property> + </widget> + <widget class="KComboBox" row="0" column="1"> + <property name="name"> + <cstring>m_comboFilenamePattern</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>1</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="editable"> + <bool>true</bool> + </property> + <property name="toolTip" stdset="0"> + <string>Insert your custom pattern here</string> + </property> + </widget> + <widget class="QLayoutWidget" row="2" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>layout2</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>31</width> + <height>2</height> + </size> + </property> + </spacer> + <widget class="KURLLabel"> + <property name="name"> + <cstring>m_specialStringsLabel</cstring> + </property> + <property name="text"> + <string>See special strings</string> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + <widget class="KURLLabel"> + <property name="name"> + <cstring>m_conditionalInclusionLabel</cstring> + </property> + <property name="text"> + <string>About conditional inclusion</string> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + </hbox> + </widget> + </grid> +</widget> +<customwidgets> +</customwidgets> +<connections> + <connection> + <sender>m_checkBlankReplace</sender> + <signal>toggled(bool)</signal> + <receiver>m_editBlankReplace</receiver> + <slot>setEnabled(bool)</slot> + </connection> +</connections> +<tabstops> + <tabstop>m_comboFilenamePattern</tabstop> + <tabstop>m_comboPlaylistPattern</tabstop> + <tabstop>m_checkBlankReplace</tabstop> + <tabstop>m_editBlankReplace</tabstop> +</tabstops> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kurllabel.h</includehint> + <includehint>kurllabel.h</includehint> +</includehints> +</UI> diff --git a/src/rip/k3baudiocdlistview.cpp b/src/rip/k3baudiocdlistview.cpp new file mode 100644 index 0000000..b5f8566 --- /dev/null +++ b/src/rip/k3baudiocdlistview.cpp @@ -0,0 +1,66 @@ +/* + * + * $Id: k3baudiocdlistview.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3baudiocdlistview.h" +#include "k3baudiocdview.h" + +#include <klocale.h> + +#include <qheader.h> +#include <qtooltip.h> + + +K3bAudioCdListView::K3bAudioCdListView( K3bAudioCdView* view, QWidget* parent, const char* name ) + : K3bListView( parent, name ), + m_view(view) +{ + setFullWidth(true); + setSorting(-1); + setAllColumnsShowFocus( true ); + setSelectionModeExt( Extended ); + setDragEnabled( true ); + addColumn( "" ); + addColumn( "" ); + addColumn( i18n("Artist") ); + addColumn( i18n("Title") ); + addColumn( i18n("Length") ); + addColumn( i18n("Size") ); + + setDoubleClickForEdit( true ); + + header()->setClickEnabled(false); + setColumnWidthMode( 0, QListView::Manual ); + setColumnWidth( 0, 20 ); + header()->setResizeEnabled( false,0 ); + + setColumnAlignment( 4, Qt::AlignHCenter ); + + QToolTip::add( viewport(), i18n("Check the tracks that should be ripped") ); +} + + +K3bAudioCdListView::~K3bAudioCdListView() +{ +} + + +QDragObject* K3bAudioCdListView::dragObject() +{ + return m_view->dragObject(); +} + + +#include "k3baudiocdlistview.moc" + diff --git a/src/rip/k3baudiocdlistview.h b/src/rip/k3baudiocdlistview.h new file mode 100644 index 0000000..1ce4a90 --- /dev/null +++ b/src/rip/k3baudiocdlistview.h @@ -0,0 +1,45 @@ +/* + * + * $Id: k3baudiocdlistview.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_AUDIO_CD_LISTVIEW_H_ +#define _K3B_AUDIO_CD_LISTVIEW_H_ + +#include <k3blistview.h> + +class QDragObject; +class K3bAudioCdView; + +/** + * Internally used by K3bAudioCdView + */ +class K3bAudioCdListView : public K3bListView +{ + Q_OBJECT + + public: + K3bAudioCdListView( K3bAudioCdView*, QWidget* parent = 0, const char* name = 0 ); + ~K3bAudioCdListView(); + + protected: + /** + * @reimpl from KListView + */ + QDragObject* dragObject(); + + private: + K3bAudioCdView* m_view; +}; + +#endif diff --git a/src/rip/k3baudiocdview.cpp b/src/rip/k3baudiocdview.cpp new file mode 100644 index 0000000..d225922 --- /dev/null +++ b/src/rip/k3baudiocdview.cpp @@ -0,0 +1,631 @@ +/* + * + * $Id: k3baudiocdview.cpp 624215 2007-01-16 19:10:03Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3baudiocdview.h" +#include "k3baudiorippingdialog.h" +#include "k3baudiocdlistview.h" + +#include <k3bpassivepopup.h> +#include <k3btoc.h> +#include <k3bdiskinfo.h> +#include <k3bdevicehandler.h> +#include <k3blistview.h> +#include <k3bcddbresult.h> +#include <k3bmsf.h> +#include <k3bcddb.h> +#include <k3bcddbquery.h> +#include <k3btoolbox.h> +#include <kcutlabel.h> +#include <k3bstdguiitems.h> +#include <k3bapplication.h> +#include <k3bthememanager.h> +#include <k3baudiocdtrackdrag.h> +#include <k3bthemedlabel.h> + +#include <klocale.h> +#include <kdebug.h> +#include <kiconloader.h> +#include <kaction.h> +#include <kstdaction.h> +#include <kmessagebox.h> +#include <kconfig.h> +#include <klineedit.h> +#include <kcombobox.h> +#include <kstandarddirs.h> +#include <kdialogbase.h> + +#include <qlayout.h> +#include <qheader.h> +#include <qlabel.h> +#include <qframe.h> +#include <qspinbox.h> +#include <qfont.h> +#include <qdragobject.h> + + + + +class K3bAudioCdView::AudioTrackViewItem : public K3bCheckListViewItem +{ +public: + AudioTrackViewItem( QListView* parent, + QListViewItem* after, + int _trackNumber, + const K3b::Msf& length) + : K3bCheckListViewItem( parent, after ) { + + setText( 1, QString::number(_trackNumber).rightJustify( 2, ' ' ) ); + setText( 3, i18n("Track %1").arg(_trackNumber) ); + setText( 4, " " + length.toString() + " " ); + setText( 5, " " + KIO::convertSize( length.audioBytes() ) + " " ); + + trackNumber = _trackNumber; + + setEditor( 2, LINE ); + setEditor( 3, LINE ); + + setChecked(true); + } + + void setup() { + K3bCheckListViewItem::setup(); + + setHeight( height() + 4 ); + } + + int trackNumber; + + void updateCddbData( const K3bCddbResultEntry& entry ) { + setText( 2, entry.artists[trackNumber-1] ); + setText( 3, entry.titles[trackNumber-1] ); + } +}; + + +K3bAudioCdView::K3bAudioCdView( QWidget* parent, const char *name ) + : K3bMediaContentsView( true, + K3bMedium::CONTENT_AUDIO, + K3bDevice::MEDIA_CD_ALL, + K3bDevice::STATE_INCOMPLETE|K3bDevice::STATE_COMPLETE, + parent, name ) +{ + QGridLayout* mainGrid = new QGridLayout( mainWidget() ); + + // toolbox + // ---------------------------------------------------------------------------------- + QHBoxLayout* toolBoxLayout = new QHBoxLayout( 0, 0, 0, "toolBoxLayout" ); + m_toolBox = new K3bToolBox( mainWidget() ); + toolBoxLayout->addWidget( m_toolBox ); + QSpacerItem* spacer = new QSpacerItem( 10, 10, QSizePolicy::Expanding, QSizePolicy::Minimum ); + toolBoxLayout->addItem( spacer ); + m_labelLength = new QLabel( mainWidget() ); + m_labelLength->setAlignment( int( QLabel::AlignVCenter | QLabel::AlignRight ) ); + toolBoxLayout->addWidget( m_labelLength ); + + + // the track view + // ---------------------------------------------------------------------------------- + m_trackView = new K3bAudioCdListView( this, mainWidget() ); + + connect( m_trackView, SIGNAL(itemRenamed(QListViewItem*, const QString&, int)), + this, SLOT(slotItemRenamed(QListViewItem*, const QString&, int)) ); + connect( m_trackView, SIGNAL(contextMenu(KListView*, QListViewItem*, const QPoint&)), + this, SLOT(slotContextMenu(KListView*, QListViewItem*, const QPoint&)) ); +// connect( m_trackView, SIGNAL(selectionChanged(QListViewItem*)), +// this, SLOT(slotTrackSelectionChanged(QListViewItem*)) ); + + mainGrid->addLayout( toolBoxLayout, 0, 0 ); + mainGrid->addWidget( m_trackView, 1, 0 ); + + + m_cddb = new K3bCddb( this ); + + connect( m_cddb, SIGNAL(queryFinished(int)), + this, SLOT(slotCddbQueryFinished(int)) ); + + initActions(); + // slotTrackSelectionChanged(0); + + setLeftPixmap( K3bTheme::MEDIA_LEFT ); + setRightPixmap( K3bTheme::MEDIA_AUDIO ); + + m_busyInfoLabel = new K3bThemedLabel( i18n("Searching for Artist information..."), this ); + m_busyInfoLabel->setFrameStyle( QFrame::Box|QFrame::Plain ); + m_busyInfoLabel->setMargin( 6 ); + m_busyInfoLabel->hide(); +} + + +K3bAudioCdView::~K3bAudioCdView() +{ +} + + +void K3bAudioCdView::reloadMedium() +{ + m_toc = medium().toc(); + m_device = medium().device(); + + // initialize cddb info for editing + m_cddbInfo = K3bCddbResultEntry(); + m_cddbInfo.discid = QString::number( medium().toc().discId(), 16 ); + + for( int i = 0; i < (int)m_toc.count(); ++i ) { + m_cddbInfo.titles.append(""); + m_cddbInfo.artists.append(""); + m_cddbInfo.extInfos.append(""); + } + + m_trackView->clear(); + showBusyLabel(true); + + // create a listviewItem for every audio track + int index = 1; + for( K3bDevice::Toc::const_iterator it = m_toc.begin(); + it != m_toc.end(); ++it ) { + + // for now skip data tracks since we are not able to rip them to iso + if( (*it).type() == K3bTrack::AUDIO ) { + K3b::Msf length( (*it).length() ); + (void)new AudioTrackViewItem( m_trackView, + m_trackView->lastItem(), + index, + length ); + } + + index++; + } + + m_cdText = medium().cdText(); + + // simulate a cddb entry with the cdtext data + m_cddbInfo.cdTitle = m_cdText.title(); + m_cddbInfo.cdArtist = m_cdText.performer(); + m_cddbInfo.cdExtInfo = m_cdText.message(); + + for( unsigned int i = 0; i < m_cdText.count(); ++i ) { + m_cddbInfo.titles[i] = m_cdText[i].title(); + m_cddbInfo.artists[i] = m_cdText[i].performer(); + m_cddbInfo.extInfos[i] = m_cdText[i].message(); + } + + updateDisplay(); + + KConfig* c = k3bcore->config(); + c->setGroup("Cddb"); + bool useCddb = ( c->readBoolEntry( "use local cddb query", true ) || + c->readBoolEntry( "use remote cddb", false ) ); + + if( useCddb && + ( m_cdText.isEmpty() || + KMessageBox::questionYesNo( this, + i18n("Found Cd-Text. Do you want to use it instead of querying CDDB?"), + i18n("Found Cd-Text"), + i18n("Use CD-Text"), + i18n("Query CDDB"), + "prefereCdTextOverCddb" ) == KMessageBox::No ) ) + queryCddb(); + else + showBusyLabel(false); +} + + +void K3bAudioCdView::initActions() +{ + m_actionCollection = new KActionCollection( this ); + + KAction* actionSelectAll = new KAction( i18n("Check All"), 0, 0, this, + SLOT(slotCheckAll()), actionCollection(), + "check_all" ); + KAction* actionDeselectAll = new KAction( i18n("Uncheck All"), 0, 0, this, + SLOT(slotUncheckAll()), actionCollection(), + "uncheck_all" ); + KAction* actionSelect = new KAction( i18n("Check Track"), 0, 0, this, + SLOT(slotSelect()), actionCollection(), + "select_track" ); + KAction* actionDeselect = new KAction( i18n("Uncheck Track"), 0, 0, this, + SLOT(slotDeselect()), actionCollection(), + "deselect_track" ); + KAction* actionEditTrackCddbInfo = new KAction( i18n("Edit Track cddb Info"), "edit", 0, this, + SLOT(slotEditTrackCddb()), actionCollection(), + "edit_track_cddb" ); + KAction* actionEditAlbumCddbInfo = new KAction( i18n("Edit Album cddb Info"), "edit", 0, this, + SLOT(slotEditAlbumCddb()), actionCollection(), + "edit_album_cddb" ); + + KAction* actionStartRip = new KAction( i18n("Start Ripping"), "cddarip", 0, this, + SLOT(startRip()), actionCollection(), "start_rip" ); + + KAction* actionQueryCddb = new KAction( i18n("Query cddb"), "reload", 0, this, + SLOT(queryCddb()), actionCollection(), "query_cddb" ); + + KAction* actionSaveCddbLocally = new KAction( i18n("Save Cddb Entry Locally"), "filesave", 0, this, + SLOT(slotSaveCddbLocally()), actionCollection(), "save_cddb_local" ); + + // TODO: set the actions tooltips and whatsthis infos + + // setup the popup menu + m_popupMenu = new KActionMenu( actionCollection(), "popup_menu" ); + KAction* separator = new KActionSeparator( actionCollection(), "separator" ); + m_popupMenu->insert( actionSelect ); + m_popupMenu->insert( actionDeselect ); + m_popupMenu->insert( actionSelectAll ); + m_popupMenu->insert( actionDeselectAll ); + m_popupMenu->insert( separator ); + m_popupMenu->insert( actionEditTrackCddbInfo ); + m_popupMenu->insert( actionEditAlbumCddbInfo ); + m_popupMenu->insert( separator ); + m_popupMenu->insert( actionStartRip ); + + // setup the toolbox + m_toolBox->addButton( actionStartRip, true ); + m_toolBox->addSpacing(); + m_toolBox->addButton( actionQueryCddb ); + m_toolBox->addButton( actionSaveCddbLocally ); + m_toolBox->addButton( actionEditTrackCddbInfo ); + m_toolBox->addButton( actionEditAlbumCddbInfo ); +} + + +void K3bAudioCdView::slotContextMenu( KListView*, QListViewItem*, const QPoint& p ) +{ + m_popupMenu->popup(p); +} + + +void K3bAudioCdView::slotItemRenamed( QListViewItem* item, const QString& str, int col ) +{ + AudioTrackViewItem* a = (AudioTrackViewItem*)item; + if( col == 2 ) + m_cddbInfo.artists[a->trackNumber-1] = str; + else if( col == 3 ) + m_cddbInfo.titles[a->trackNumber-1] = str; + else if( col == 6 ) + m_cddbInfo.extInfos[a->trackNumber-1] = str; +} + + +void K3bAudioCdView::slotTrackSelectionChanged( QListViewItem* item ) +{ + actionCollection()->action("edit_track_cddb")->setEnabled( item != 0 ); + actionCollection()->action("select_track")->setEnabled( item != 0 ); + actionCollection()->action("deselect_track")->setEnabled( item != 0 ); +} + + +void K3bAudioCdView::startRip() +{ + QValueList<int> trackNumbers; + for( QListViewItemIterator it( m_trackView ); it.current(); ++it ) { + AudioTrackViewItem* a = (AudioTrackViewItem*)it.current(); + if( a->isChecked() ) + trackNumbers.append( a->trackNumber ); + } + + if( trackNumbers.count() == 0 ) { + KMessageBox::error( this, i18n("Please select the tracks to rip."), + i18n("No Tracks Selected") ); + } + else { + K3bAudioRippingDialog rip( m_toc, + m_device, + m_cddbInfo, + trackNumbers, + this ); + rip.exec(); + } +} + + +void K3bAudioCdView::slotEditTrackCddb() +{ + QPtrList<QListViewItem> items( m_trackView->selectedItems() ); + if( !items.isEmpty() ) { + AudioTrackViewItem* a = static_cast<AudioTrackViewItem*>(items.first()); + + KDialogBase d( this, "trackCddbDialog", true, i18n("Cddb Track %1").arg(a->trackNumber), + KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok, true); + QWidget* w = new QWidget( &d ); + + KLineEdit* editTitle = new KLineEdit( m_cddbInfo.titles[a->trackNumber-1], w ); + KLineEdit* editArtist = new KLineEdit( m_cddbInfo.artists[a->trackNumber-1], w ); + KLineEdit* editExtInfo = new KLineEdit( m_cddbInfo.extInfos[a->trackNumber-1], w ); + QFrame* line = new QFrame( w ); + line->setFrameShape( QFrame::HLine ); + line->setFrameShadow( QFrame::Sunken ); + + QGridLayout* grid = new QGridLayout( w ); + grid->setSpacing( KDialog::spacingHint() ); + + grid->addWidget( new QLabel( i18n("Title:"), w ), 0, 0 ); + grid->addWidget( editTitle, 0, 1 ); + grid->addMultiCellWidget( line, 1, 1, 0, 1 ); + grid->addWidget( new QLabel( i18n("Artist:"), w ), 2, 0 ); + grid->addWidget( editArtist, 2, 1 ); + grid->addWidget( new QLabel( i18n("Extra info:"), w ), 3, 0 ); + grid->addWidget( editExtInfo, 3, 1 ); + grid->setRowStretch( 4, 1 ); + + d.setMainWidget(w); + d.resize( QMAX( QMAX(d.sizeHint().height(), d.sizeHint().width()), 300), d.sizeHint().height() ); + + if( d.exec() == QDialog::Accepted ) { + m_cddbInfo.titles[a->trackNumber-1] = editTitle->text(); + m_cddbInfo.artists[a->trackNumber-1] = editArtist->text(); + m_cddbInfo.extInfos[a->trackNumber-1] = editExtInfo->text(); + a->updateCddbData( m_cddbInfo ); + } + } +} + + +void K3bAudioCdView::slotEditAlbumCddb() +{ + KDialogBase d( this, "trackCddbDialog", true, i18n("Album Cddb"), + KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok, true); + QWidget* w = new QWidget( &d ); + + KLineEdit* editTitle = new KLineEdit( m_cddbInfo.cdTitle, w ); + KLineEdit* editArtist = new KLineEdit( m_cddbInfo.cdArtist, w ); + KLineEdit* editExtInfo = new KLineEdit( m_cddbInfo.cdExtInfo, w ); + KLineEdit* editGenre = new KLineEdit( m_cddbInfo.genre, w ); + QSpinBox* spinYear = new QSpinBox( 0, 9999, 1, w ); + spinYear->setValue( m_cddbInfo.year ); + QFrame* line = new QFrame( w ); + line->setFrameShape( QFrame::HLine ); + line->setFrameShadow( QFrame::Sunken ); + KComboBox* comboCat = new KComboBox( w ); + comboCat->insertStringList( K3bCddbQuery::categories() ); + + // set the category + for( int i = 0; i < comboCat->count(); ++i ) + if( comboCat->text(i) == m_cddbInfo.category ) { + comboCat->setCurrentItem(i); + break; + } + + QGridLayout* grid = new QGridLayout( w ); + grid->setSpacing( KDialog::spacingHint() ); + + grid->addWidget( new QLabel( i18n("Title:"), w ), 0, 0 ); + grid->addWidget( editTitle, 0, 1 ); + grid->addMultiCellWidget( line, 1, 1, 0, 1 ); + grid->addWidget( new QLabel( i18n("Artist:"), w ), 2, 0 ); + grid->addWidget( editArtist, 2, 1 ); + grid->addWidget( new QLabel( i18n("Extra info:"), w ), 3, 0 ); + grid->addWidget( editExtInfo, 3, 1 ); + grid->addWidget( new QLabel( i18n("Genre:"), w ), 4, 0 ); + grid->addWidget( editGenre, 4, 1 ); + grid->addWidget( new QLabel( i18n("Year:"), w ), 5, 0 ); + grid->addWidget( spinYear, 5, 1 ); + grid->addWidget( new QLabel( i18n("Category:"), w ), 6, 0 ); + grid->addWidget( comboCat, 6, 1 ); + grid->setRowStretch( 7, 1 ); + + d.setMainWidget(w); + d.resize( QMAX( QMAX(d.sizeHint().height(), d.sizeHint().width()), 300), d.sizeHint().height() ); + + if( d.exec() == QDialog::Accepted ) { + m_cddbInfo.cdTitle = editTitle->text(); + m_cddbInfo.cdArtist = editArtist->text(); + m_cddbInfo.cdExtInfo = editExtInfo->text(); + m_cddbInfo.category = comboCat->currentText(); + m_cddbInfo.genre = editGenre->text(); + m_cddbInfo.year = spinYear->value(); + + updateDisplay(); + } +} + + +void K3bAudioCdView::queryCddb() +{ + KConfig* c = k3bcore->config(); + c->setGroup("Cddb"); + + m_cddb->readConfig( c ); + + if( c->readBoolEntry( "use local cddb query", true ) || + c->readBoolEntry( "use remote cddb", false ) ) { + + showBusyLabel(true); + + m_cddb->query( m_toc ); + } +} + + +void K3bAudioCdView::slotCddbQueryFinished( int error ) +{ + if( error == K3bCddbQuery::SUCCESS ) { + m_cddbInfo = m_cddb->result(); + + // save the entry locally + KConfig* c = k3bcore->config(); + c->setGroup( "Cddb" ); + if( c->readBoolEntry( "save cddb entries locally", true ) ) + m_cddb->saveEntry( m_cddbInfo ); + + updateDisplay(); + } + else if( error == K3bCddbQuery::NO_ENTRY_FOUND ) { + if( !KConfigGroup( k3bcore->config(), "Cddb" ).readBoolEntry( "use remote cddb", false ) ) + K3bPassivePopup::showPopup( i18n("<p>No CDDB entry found. Enable remote CDDB queries in the K3b settings to get access " + "to more entries through the internet."), i18n("CDDB") ); + else + K3bPassivePopup::showPopup( i18n("No CDDB entry found."), i18n("CDDB") ); + } + else if( error != K3bCddbQuery::CANCELED ) { + K3bPassivePopup::showPopup( m_cddb->errorString(), i18n("CDDB Error") ); + } + + enableInteraction(true); +} + + +void K3bAudioCdView::slotSaveCddbLocally() +{ + // check if the minimal info has been inserted + if( m_cddbInfo.category.isEmpty() ) { + KMessageBox::sorry( this, i18n("Please set the category before saving.") ); + return; + } + + if( m_cddbInfo.cdTitle.isEmpty() || m_cddbInfo.cdArtist.isEmpty() ) { + KMessageBox::sorry( this, i18n("Please set CD artist and title before saving.") ); + return; + } + + bool missingTitle = false; + bool missingArtist = false; + bool allTrackArtistsEmpty = true; + for( unsigned int i = 0; i < m_cddbInfo.titles.count(); ++i ) { + if( m_cddbInfo.titles[i].isEmpty() ) + missingTitle = true; + if( m_cddbInfo.artists[i].isEmpty() ) + missingArtist = true; + if( !m_cddbInfo.artists[i].isEmpty() ) + allTrackArtistsEmpty = false; + } + + if( missingTitle || + ( missingArtist && !allTrackArtistsEmpty ) ) { + KMessageBox::sorry( this, i18n("Please set at least artist and title on all tracks before saving.") ); + return; + } + + // make sure the data gets updated (bad design like a lot in the cddb stuff! :( + m_cddbInfo.rawData.truncate(0); + + KConfig* c = k3bcore->config(); + c->setGroup("Cddb"); + + m_cddb->readConfig( c ); + + m_cddb->saveEntry( m_cddbInfo ); + K3bPassivePopup::showPopup( i18n("Saved entry (%1) in category %2.") + .arg(m_cddbInfo.discid) + .arg(m_cddbInfo.category), + i18n("CDDB") ); +} + + +void K3bAudioCdView::slotCheckAll() +{ + for( QListViewItemIterator it( m_trackView ); it.current(); ++it ) + ((AudioTrackViewItem*)it.current())->setChecked(true); +} + +void K3bAudioCdView::slotUncheckAll() +{ + for( QListViewItemIterator it( m_trackView ); it.current(); ++it ) + ((AudioTrackViewItem*)it.current())->setChecked(false); +} + +void K3bAudioCdView::slotSelect() +{ + QPtrList<QListViewItem> items( m_trackView->selectedItems() ); + for( QPtrListIterator<QListViewItem> it( items ); + it.current(); ++it ) + static_cast<AudioTrackViewItem*>(it.current())->setChecked(true); +} + +void K3bAudioCdView::slotDeselect() +{ + QPtrList<QListViewItem> items( m_trackView->selectedItems() ); + for( QPtrListIterator<QListViewItem> it( items ); + it.current(); ++it ) + static_cast<AudioTrackViewItem*>(it.current())->setChecked(false); +} + +void K3bAudioCdView::updateDisplay() +{ + // update the listview + for( QListViewItemIterator it( m_trackView ); it.current(); ++it ) { + AudioTrackViewItem* item = (AudioTrackViewItem*)it.current(); + item->updateCddbData( m_cddbInfo ); + } + + if( !m_cddbInfo.cdTitle.isEmpty() ) { + QString s = m_cddbInfo.cdTitle; + if( !m_cddbInfo.cdArtist.isEmpty() ) + s += " (" + m_cddbInfo.cdArtist + ")"; + setTitle( s ); + } + else + setTitle( i18n("Audio CD") ); + + m_labelLength->setText( i18n("1 track (%1)", + "%n tracks (%1)", + m_toc.count()).arg(K3b::Msf(m_toc.length()).toString()) ); +} + + +void K3bAudioCdView::showBusyLabel( bool b ) +{ + if( !b ) { + actionCollection()->action( "start_rip" )->setEnabled( true ); + m_trackView->setEnabled( true ); + m_busyInfoLabel->hide(); + } + else { + // the themed label is a cut label, thus its size hint is + // based on the cut text, we force it to be full + m_busyInfoLabel->resize( width(), height() ); + m_busyInfoLabel->resize( m_busyInfoLabel->sizeHint() ); + int x = (width() - m_busyInfoLabel->width())/2; + int y = (height() - m_busyInfoLabel->height())/2; + QRect r( QPoint( x, y ), m_busyInfoLabel->size() ); + m_busyInfoLabel->setGeometry( r ); + m_busyInfoLabel->show(); + + m_trackView->setEnabled( false ); + enableInteraction( false ); + } +} + + +void K3bAudioCdView::enableInteraction( bool b ) +{ + // we leave the track view enabled in default disabled mode + // since drag'n'drop to audio projects does not need an inserted CD + actionCollection()->action( "start_rip" )->setEnabled( b ); + if( b ) + showBusyLabel( false ); +} + + +QDragObject* K3bAudioCdView::dragObject() +{ + QPtrList<QListViewItem> items = m_trackView->selectedItems(); + QValueList<int> tracks; + for( QPtrListIterator<QListViewItem> it( items ); + it.current(); ++it ) + tracks.append( static_cast<AudioTrackViewItem*>(it.current())->trackNumber ); + + if( !items.isEmpty() ) { + QDragObject* drag = new K3bAudioCdTrackDrag( m_toc, + tracks, + m_cddbInfo, + m_device, + this ); + drag->setPixmap( m_trackView->createDragPixmap( items ) ); + return drag; + } + else + return 0; +} + +#include "k3baudiocdview.moc" diff --git a/src/rip/k3baudiocdview.h b/src/rip/k3baudiocdview.h new file mode 100644 index 0000000..257a0f5 --- /dev/null +++ b/src/rip/k3baudiocdview.h @@ -0,0 +1,107 @@ +/* + * + * $Id: k3baudiocdview.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_AUDIOCD_VIEW_H_ +#define _K3B_AUDIOCD_VIEW_H_ + +#include <k3bmediacontentsview.h> +#include <k3bmedium.h> + +#include <k3btoc.h> +#include <k3bcddbresult.h> +#include <k3bcdtext.h> + +class K3bListView; +class KListView; +class QListViewItem; +class QPoint; +class KActionCollection; +class KActionMenu; +class K3bCddb; +class QLabel; +class K3bToolBox; +class QDragObject; + + +namespace K3bDevice { + class Device; +} + + +class K3bAudioCdView : public K3bMediaContentsView +{ + Q_OBJECT + + public: + K3bAudioCdView( QWidget* parent = 0, const char * name = 0 ); + ~K3bAudioCdView(); + + KActionCollection* actionCollection() const { return m_actionCollection; } + + /** + * internal + */ + QDragObject* dragObject(); + + public slots: + void queryCddb(); + + private slots: + void slotContextMenu( KListView*, QListViewItem*, const QPoint& ); + void slotItemRenamed( QListViewItem*, const QString&, int ); + void slotCddbQueryFinished( int ); + void slotTrackSelectionChanged( QListViewItem* ); + void slotSaveCddbLocally(); + + void slotEditTrackCddb(); + void slotEditAlbumCddb(); + void startRip(); + void slotCheckAll(); + void slotUncheckAll(); + void slotSelect(); + void slotDeselect(); + + private: + void reloadMedium(); + + void initActions(); + void updateDisplay(); + void enableInteraction( bool ); + void showBusyLabel( bool ); + + K3bDevice::Toc m_toc; + K3bDevice::Device* m_device; + + K3bCddbResultEntry m_cddbInfo; + + KActionCollection* m_actionCollection; + KActionMenu* m_popupMenu; + + K3bListView* m_trackView; + K3bToolBox* m_toolBox; + QLabel* m_labelLength; + + class AudioTrackViewItem; + + K3bCddb* m_cddb; + + K3bDevice::CdText m_cdText; + + QLabel* m_busyInfoLabel; +}; + + +#endif diff --git a/src/rip/k3baudioconvertingoptionwidget.cpp b/src/rip/k3baudioconvertingoptionwidget.cpp new file mode 100644 index 0000000..a044dc5 --- /dev/null +++ b/src/rip/k3baudioconvertingoptionwidget.cpp @@ -0,0 +1,266 @@ +/* + * + * $Id: k3baudioconvertingoptionwidget.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3baudioconvertingoptionwidget.h" + +#include <k3bpluginmanager.h> +#include <k3baudioencoder.h> +#include <k3bcore.h> +#include <k3bglobals.h> + +#include <kcombobox.h> +#include <kurlrequester.h> +#include <kio/global.h> +#include <kconfig.h> +#include <klocale.h> +#include <kiconloader.h> + +#include <qintdict.h> +#include <qmap.h> +#include <qlabel.h> +#include <qtimer.h> +#include <qtoolbutton.h> +#include <qcheckbox.h> + + + +class K3bAudioConvertingOptionWidget::Private +{ +public: + QIntDict<K3bAudioEncoder> encoderMap; + QMap<int, QString> extensionMap; + + QTimer freeSpaceUpdateTimer; + + KIO::filesize_t neededSize; + + int getDefaultFormat() { + // we prefere formats in this order: + // 1. ogg + // 2. mp3 + // 3. flac + // 4. wave + int ogg = -1; + int mp3 = -1; + int flac = -1; + for( QMap<int, QString>::const_iterator it = extensionMap.constBegin(); + it != extensionMap.constEnd(); ++it ) { + if( it.data() == "ogg" ) + ogg = it.key(); + else if( it.data() == "mp3" ) + mp3 = it.key(); + else if( it.data() == "flac" ) + flac = it.key(); + } + + if( ogg > -1 ) + return ogg; + else if( mp3 > -1 ) + return mp3; + else if( flac > -1 ) + return flac; + else + return 0; + } +}; + + +K3bAudioConvertingOptionWidget::K3bAudioConvertingOptionWidget( QWidget* parent, const char* name ) + : base_K3bAudioRippingOptionWidget( parent, name ) +{ + d = new Private(); + + connect( m_editBaseDir, SIGNAL(textChanged(const QString&)), + this, SLOT(slotUpdateFreeTempSpace()) ); + connect( m_comboFileType, SIGNAL(activated(int)), + this, SLOT(slotEncoderChanged()) ); + connect( &d->freeSpaceUpdateTimer, SIGNAL(timeout()), + this, SLOT(slotUpdateFreeTempSpace()) ); + connect( m_checkCreatePlaylist, SIGNAL(toggled(bool)), this, SIGNAL(changed()) ); + connect( m_checkSingleFile, SIGNAL(toggled(bool)), this, SIGNAL(changed()) ); + connect( m_checkWriteCueFile, SIGNAL(toggled(bool)), this, SIGNAL(changed()) ); + connect( m_comboFileType, SIGNAL(activated(int)), this, SIGNAL(changed()) ); + connect( m_editBaseDir, SIGNAL(textChanged(const QString&)), this, SIGNAL(changed()) ); + connect( m_buttonConfigurePlugin, SIGNAL(clicked()), this, SLOT(slotConfigurePlugin()) ); + + m_editBaseDir->setMode( KFile::Directory | KFile::ExistingOnly | KFile::LocalOnly ); + m_buttonConfigurePlugin->setIconSet( SmallIconSet( "gear" ) ); + + // FIXME: see if sox and the sox encoder are installed and if so do not put the internal wave + // writer in the list of encoders. + + d->encoderMap.clear(); + d->extensionMap.clear(); + m_comboFileType->clear(); + m_comboFileType->insertItem( i18n("Wave") ); + d->extensionMap[0] = "wav"; + + // check the available encoding plugins + QPtrList<K3bPlugin> fl = k3bcore->pluginManager()->plugins( "AudioEncoder" ); + for( QPtrListIterator<K3bPlugin> it( fl ); it.current(); ++it ) { + K3bAudioEncoder* f = (K3bAudioEncoder*)it.current(); + QStringList exL = f->extensions(); + + for( QStringList::const_iterator exIt = exL.begin(); + exIt != exL.end(); ++exIt ) { + d->extensionMap.insert( m_comboFileType->count(), *exIt ); + d->encoderMap.insert( m_comboFileType->count(), f ); + m_comboFileType->insertItem( f->fileTypeComment(*exIt) ); + } + } + + // refresh every 2 seconds + d->freeSpaceUpdateTimer.start(2000); + slotUpdateFreeTempSpace(); +} + + +K3bAudioConvertingOptionWidget::~K3bAudioConvertingOptionWidget() +{ + delete d; +} + + +QString K3bAudioConvertingOptionWidget::baseDir() const +{ + return m_editBaseDir->url(); +} + + +void K3bAudioConvertingOptionWidget::setBaseDir( const QString& path ) +{ + m_editBaseDir->setURL( path ); +} + + +void K3bAudioConvertingOptionWidget::setNeededSize( KIO::filesize_t size ) +{ + d->neededSize = size; + if( size > 0 ) + m_labelNeededSpace->setText( KIO::convertSize( size ) ); + else + m_labelNeededSpace->setText( i18n("unknown") ); + + slotUpdateFreeTempSpace(); +} + + +void K3bAudioConvertingOptionWidget::slotConfigurePlugin() +{ + // 0 for wave + K3bAudioEncoder* encoder = d->encoderMap[m_comboFileType->currentItem()]; + if( encoder ) + k3bcore->pluginManager()->execPluginDialog( encoder, this ); +} + + +void K3bAudioConvertingOptionWidget::slotUpdateFreeTempSpace() +{ + QString path = m_editBaseDir->url(); + + if( !QFile::exists( path ) ) + path.truncate( path.findRev('/') ); + + unsigned long size, avail; + if( K3b::kbFreeOnFs( path, size, avail ) ) { + m_labelFreeSpace->setText( KIO::convertSizeFromKB(avail) ); + if( avail < d->neededSize/1024 ) + m_labelNeededSpace->setPaletteForegroundColor( Qt::red ); + else + m_labelNeededSpace->setPaletteForegroundColor( paletteForegroundColor() ); + } + else { + m_labelFreeSpace->setText("-"); + m_labelNeededSpace->setPaletteForegroundColor( paletteForegroundColor() ); + } +} + + +void K3bAudioConvertingOptionWidget::slotEncoderChanged() +{ + // 0 for wave + m_buttonConfigurePlugin->setEnabled( d->encoderMap[m_comboFileType->currentItem()] != 0 ); +} + + +K3bAudioEncoder* K3bAudioConvertingOptionWidget::encoder() const +{ + return d->encoderMap[m_comboFileType->currentItem()]; // 0 for wave +} + + +QString K3bAudioConvertingOptionWidget::extension() const +{ + return d->extensionMap[m_comboFileType->currentItem()]; +} + + +void K3bAudioConvertingOptionWidget::loadDefaults() +{ + m_editBaseDir->setURL( QDir::homeDirPath() ); + m_checkSingleFile->setChecked( false ); + m_checkWriteCueFile->setChecked( false ); + m_comboFileType->setCurrentItem( d->getDefaultFormat() ); + m_checkCreatePlaylist->setChecked(false); + m_checkPlaylistRelative->setChecked(false); + + slotEncoderChanged(); +} + + +void K3bAudioConvertingOptionWidget::loadConfig( KConfigBase* c ) +{ + m_editBaseDir->setURL( c->readPathEntry( "last ripping directory", QDir::homeDirPath() ) ); + + m_checkSingleFile->setChecked( c->readBoolEntry( "single_file", false ) ); + m_checkWriteCueFile->setChecked( c->readBoolEntry( "write_cue_file", false ) ); + + m_checkCreatePlaylist->setChecked( c->readBoolEntry( "create_playlist", false ) ); + m_checkPlaylistRelative->setChecked( c->readBoolEntry( "relative_path_in_playlist", false ) ); + + QString filetype = c->readEntry( "filetype", d->extensionMap[d->getDefaultFormat()] ); + if( filetype == "wav" ) + m_comboFileType->setCurrentItem(0); + else { + for( QMap<int, QString>::iterator it = d->extensionMap.begin(); + it != d->extensionMap.end(); ++it ) { + if( it.data() == filetype ) { + m_comboFileType->setCurrentItem( it.key() ); + break; + } + } + } + + slotEncoderChanged(); +} + + +void K3bAudioConvertingOptionWidget::saveConfig( KConfigBase* c ) +{ + c->writePathEntry( "last ripping directory", m_editBaseDir->url() ); + + c->writeEntry( "single_file", m_checkSingleFile->isChecked() ); + c->writeEntry( "write_cue_file", m_checkWriteCueFile->isChecked() ); + + c->writeEntry( "create_playlist", m_checkCreatePlaylist->isChecked() ); + c->writeEntry( "relative_path_in_playlist", m_checkPlaylistRelative->isChecked() ); + + if( d->extensionMap.contains(m_comboFileType->currentItem()) ) + c->writeEntry( "filetype", d->extensionMap[m_comboFileType->currentItem()] ); + else + c->writeEntry( "filetype", "wav" ); +} + +#include "k3baudioconvertingoptionwidget.moc" diff --git a/src/rip/k3baudioconvertingoptionwidget.h b/src/rip/k3baudioconvertingoptionwidget.h new file mode 100644 index 0000000..ff4cd45 --- /dev/null +++ b/src/rip/k3baudioconvertingoptionwidget.h @@ -0,0 +1,74 @@ +/* + * + * $Id: k3baudioconvertingoptionwidget.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_AUDIO_CONVERTING_OPTION_WIDGET_H_ +#define _K3B_AUDIO_CONVERTING_OPTION_WIDGET_H_ + +#include "base_k3baudiorippingoptionwidget.h" + +#include <qcheckbox.h> +#include <kio/global.h> + +class K3bAudioEncoder; +class KConfigBase; + + +/** + * Internally used by K3bAudioConvertingDialog + */ +class K3bAudioConvertingOptionWidget : public base_K3bAudioRippingOptionWidget +{ + Q_OBJECT + + public: + K3bAudioConvertingOptionWidget( QWidget* parent, const char* name = 0 ); + ~K3bAudioConvertingOptionWidget(); + + void setBaseDir( const QString& path ); + + void setNeededSize( KIO::filesize_t ); + + /** + * @returns 0 if wave is selected + */ + K3bAudioEncoder* encoder() const; + QString extension() const; + + QString baseDir() const; + + bool createPlaylist() const { return m_checkCreatePlaylist->isChecked(); } + bool playlistRelativePath() const { return m_checkPlaylistRelative->isChecked(); } + bool createSingleFile() const { return m_checkSingleFile->isChecked(); } + bool createCueFile() const { return m_checkWriteCueFile->isChecked(); } + + public slots: + void loadDefaults(); + void loadConfig( KConfigBase* ); + void saveConfig( KConfigBase* ); + + signals: + void changed(); + + private slots: + void slotConfigurePlugin(); + void slotUpdateFreeTempSpace(); + void slotEncoderChanged(); + + private: + class Private; + Private* d; +}; + +#endif diff --git a/src/rip/k3baudioprojectconvertingdialog.cpp b/src/rip/k3baudioprojectconvertingdialog.cpp new file mode 100644 index 0000000..8a3eadc --- /dev/null +++ b/src/rip/k3baudioprojectconvertingdialog.cpp @@ -0,0 +1,371 @@ +/* + * + * $Id: k3baudioprojectconvertingdialog.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3baudioprojectconvertingdialog.h" +#include "k3baudioprojectconvertingthread.h" +#include "k3bpatternparser.h" +#include "k3bcddbpatternwidget.h" +#include "k3baudioconvertingoptionwidget.h" + +#include <k3baudiodoc.h> +#include <k3baudioview.h> +#include <k3baudiotrackplayer.h> +#include <k3baudiotrack.h> +#include <k3bjobprogressdialog.h> +#include <k3bcore.h> +#include <k3bglobals.h> +#include <k3blistview.h> +#include <k3baudioencoder.h> +#include <k3bthreadjob.h> + +#include <kcombobox.h> +#include <klocale.h> +#include <kconfig.h> +#include <klistview.h> +#include <kurlrequester.h> +#include <kfiledialog.h> +#include <kio/global.h> +#include <kdebug.h> +#include <kmessagebox.h> + +#include <qgroupbox.h> +#include <qheader.h> +#include <qcheckbox.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qdir.h> +#include <qstringlist.h> +#include <qtabwidget.h> + + + +class K3bAudioProjectConvertingDialog::Private +{ +public: + Private() { + } + + QValueVector<QString> filenames; + QString playlistFilename; + QString cueFilename; +}; + + +K3bAudioProjectConvertingDialog::K3bAudioProjectConvertingDialog( K3bAudioDoc* doc, QWidget *parent, const char *name ) + : K3bInteractionDialog( parent, name, + QString::null, + QString::null, + START_BUTTON|CANCEL_BUTTON, + START_BUTTON, + "Audio Project Converting" ), // config group + m_doc(doc) +{ + d = new Private(); + + setupGui(); + + setTitle( i18n("Audio Project Conversion"), + i18n("1 track (%1)", "%n tracks (%1)", + m_doc->numOfTracks()).arg(m_doc->length().toString()) ); + + refresh(); +} + + +K3bAudioProjectConvertingDialog::~K3bAudioProjectConvertingDialog() +{ + delete d; +} + + +void K3bAudioProjectConvertingDialog::setupGui() +{ + QWidget *frame = mainWidget(); + QGridLayout* Form1Layout = new QGridLayout( frame ); + Form1Layout->setSpacing( KDialog::spacingHint() ); + Form1Layout->setMargin( 0 ); + + m_viewTracks = new K3bListView( frame, "m_viewTracks" ); + m_viewTracks->addColumn(i18n( "Filename (relative to base directory)") ); + m_viewTracks->addColumn(i18n( "Length") ); + m_viewTracks->addColumn(i18n( "File Size") ); + m_viewTracks->setSorting(-1); + m_viewTracks->setAllColumnsShowFocus(true); + m_viewTracks->setFullWidth(true); + + QTabWidget* mainTab = new QTabWidget( frame ); + + m_optionWidget = new K3bAudioConvertingOptionWidget( mainTab ); + mainTab->addTab( m_optionWidget, i18n("Settings") ); + + + // setup filename pattern page + // ------------------------------------------------------------------------------------------- + m_patternWidget = new K3bCddbPatternWidget( mainTab ); + mainTab->addTab( m_patternWidget, i18n("File Naming") ); + connect( m_patternWidget, SIGNAL(changed()), this, SLOT(refresh()) ); + + Form1Layout->addWidget( m_viewTracks, 0, 0 ); + Form1Layout->addWidget( mainTab, 1, 0 ); + Form1Layout->setRowStretch( 0, 1 ); + + connect( m_optionWidget, SIGNAL(changed()), this, SLOT(refresh()) ); +} + + +void K3bAudioProjectConvertingDialog::slotStartClicked() +{ + // make sure we have the tracks just for ourselves + static_cast<K3bAudioView*>(m_doc->view())->player()->stop(); + + // check if all filenames differ + if( d->filenames.count() > 1 ) { + bool differ = true; + // the most stupid version to compare but most cds have about 12 tracks + // that's a size where algorithms do not need any optimization! ;) + for( unsigned int i = 0; i < d->filenames.count(); ++i ) { + for( unsigned int j = i+1; j < d->filenames.count(); ++j ) + if( d->filenames[i] == d->filenames[j] ) { + differ = false; + break; + } + } + + if( !differ ) { + KMessageBox::sorry( this, i18n("Please check the naming pattern. All filenames need to be unique.") ); + return; + } + } + + // check if we need to overwrite some files... + QListViewItemIterator it( m_viewTracks ); + QStringList filesToOverwrite; + for( unsigned int i = 0; i < d->filenames.count(); ++i ) { + if( QFile::exists( d->filenames[i] ) ) + filesToOverwrite.append( d->filenames[i] ); + } + + if( m_optionWidget->createPlaylist() && QFile::exists( d->playlistFilename ) ) + filesToOverwrite.append( d->playlistFilename ); + + if( !filesToOverwrite.isEmpty() ) + if( KMessageBox::warningContinueCancelList( this, + i18n("Do you want to overwrite these files?"), + filesToOverwrite, + i18n("Files Exist"), i18n("Overwrite") ) == KMessageBox::Cancel ) + return; + + + // just generate a fake m_tracks list for now so we can keep most of the methods + // like they are in K3bAudioRipThread. This way future combination is easier + QValueVector<QPair<int, QString> > tracksToRip; + int i = 0; + K3bAudioTrack* track = m_doc->firstTrack(); + while( track ) { + tracksToRip.append( qMakePair( i+1, d->filenames[(m_optionWidget->createSingleFile() ? 0 : i)] ) ); + ++i; + track = track->next(); + } + + K3bAudioEncoder* encoder = m_optionWidget->encoder(); + + K3bAudioProjectConvertingThread* thread = new K3bAudioProjectConvertingThread( m_doc ); + thread->setCddbEntry( createCddbEntryFromDoc( m_doc ) ); + thread->setTracksToRip( tracksToRip ); + thread->setSingleFile( m_optionWidget->createSingleFile() ); + thread->setWriteCueFile( m_optionWidget->createCueFile() ); + thread->setEncoder( encoder ); + thread->setWritePlaylist( m_optionWidget->createPlaylist() ); + thread->setPlaylistFilename( d->playlistFilename ); + thread->setUseRelativePathInPlaylist( m_optionWidget->playlistRelativePath() ); + if( encoder ) + thread->setFileType( m_optionWidget->extension() ); + + K3bJobProgressDialog progressDialog( parentWidget() ); + + K3bThreadJob job( thread, &progressDialog, this ); + + hide(); + progressDialog.startJob(&job); + + delete thread; + + close(); +} + + +void K3bAudioProjectConvertingDialog::refresh() +{ + m_viewTracks->clear(); + d->filenames.clear(); + + // FIXME: this is bad and needs to be improved + // create a cddb entry from the doc to use in the patternparser + K3bCddbResultEntry cddbEntry = createCddbEntryFromDoc( m_doc ); + + QString baseDir = K3b::prepareDir( m_optionWidget->baseDir() ); + + QString extension = m_optionWidget->extension(); + + KIO::filesize_t overallSize = 0; + + if( m_optionWidget->createSingleFile() ) { + QString filename; + long long filesize = 0; + if( m_optionWidget->encoder() == 0 ) { + filesize = m_doc->length().audioBytes() + 44; + } + else { + filesize = m_optionWidget->encoder()->fileSize( extension, m_doc->length() ); + } + + if( filesize > 0 ) + overallSize = filesize; + + filename = K3bPatternParser::parsePattern( cddbEntry, 1, + m_patternWidget->filenamePattern(), + m_patternWidget->replaceBlanks(), + m_patternWidget->blankReplaceString() ); + + + (void)new KListViewItem( m_viewTracks, + m_viewTracks->lastItem(), + filename + "." + extension, + m_doc->length().toString(), + filesize < 0 ? i18n("unknown") : KIO::convertSize( filesize ) ); + + d->filenames.append( K3b::fixupPath( baseDir + "/" + filename + "." + extension ) ); + + if( m_optionWidget->createCueFile() ) { + d->cueFilename = K3b::fixupPath( baseDir + "/" + filename + ".cue" ); + (void)new KListViewItem( m_viewTracks, + m_viewTracks->lastItem(), + filename + ".cue", + "-", + "-", + i18n("Cue-file") ); + } + } + else { + K3bAudioTrack* track = m_doc->firstTrack(); + unsigned int i = 1; + while( track ) { + long long filesize = 0; + if( m_optionWidget->encoder() == 0 ) { + filesize = track->length().audioBytes() + 44; + } + else { + filesize = m_optionWidget->encoder()->fileSize( extension, track->length() ); + } + + if( filesize > 0 ) + overallSize += filesize; + + QString filename = K3bPatternParser::parsePattern( cddbEntry, i, + m_patternWidget->filenamePattern(), + m_patternWidget->replaceBlanks(), + m_patternWidget->blankReplaceString() ) + "." + extension; + + (void)new KListViewItem( m_viewTracks, + m_viewTracks->lastItem(), + filename, + track->length().toString(), + filesize < 0 ? i18n("unknown") : KIO::convertSize( filesize ) ); + + d->filenames.append( K3b::fixupPath( baseDir + "/" + filename ) ); + + track = track->next(); + ++i; + } + } + + // create playlist item + if( m_optionWidget->createPlaylist() ) { + QString filename = K3bPatternParser::parsePattern( cddbEntry, 1, + m_patternWidget->playlistPattern(), + m_patternWidget->replaceBlanks(), + m_patternWidget->blankReplaceString() ) + ".m3u"; + + (void)new KListViewItem( m_viewTracks, + m_viewTracks->lastItem(), + filename, + "-", + "-", + i18n("Playlist") ); + + d->playlistFilename = K3b::fixupPath( baseDir + "/" + filename ); + } + + if( overallSize > 0 ) + m_optionWidget->setNeededSize( overallSize ); + else + m_optionWidget->setNeededSize( 0 ); +} + + +void K3bAudioProjectConvertingDialog::setBaseDir( const QString& path ) +{ + m_optionWidget->setBaseDir( path ); +} + + +void K3bAudioProjectConvertingDialog::loadK3bDefaults() +{ + m_optionWidget->loadDefaults(); + m_patternWidget->loadDefaults(); + + refresh(); +} + +void K3bAudioProjectConvertingDialog::loadUserDefaults( KConfigBase* c ) +{ + m_optionWidget->loadConfig( c ); + m_patternWidget->loadConfig( c ); + + refresh(); +} + + +void K3bAudioProjectConvertingDialog::saveUserDefaults( KConfigBase* c ) +{ + m_optionWidget->saveConfig( c ); + m_patternWidget->saveConfig( c ); +} + + +K3bCddbResultEntry K3bAudioProjectConvertingDialog::createCddbEntryFromDoc( K3bAudioDoc* doc ) +{ + K3bCddbResultEntry e; + + // global + e.cdTitle = doc->title(); + e.cdArtist = doc->artist(); + e.cdExtInfo = doc->cdTextMessage(); + + // tracks + K3bAudioTrack* track = doc->firstTrack(); + while( track ) { + e.titles.append( track->title() ); + e.artists.append( track->artist() ); + e.extInfos.append( track->cdTextMessage() ); + + track = track->next(); + } + + return e; +} + +#include "k3baudioprojectconvertingdialog.moc" diff --git a/src/rip/k3baudioprojectconvertingdialog.h b/src/rip/k3baudioprojectconvertingdialog.h new file mode 100644 index 0000000..1816ea2 --- /dev/null +++ b/src/rip/k3baudioprojectconvertingdialog.h @@ -0,0 +1,78 @@ +/* + * + * $Id: k3baudioprojectconvertingdialog.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_AUDIO_PROJECT_CONVERTING_DIALOG_H_ +#define _K3B_AUDIO_PROJECT_CONVERTING_DIALOG_H_ + +#include <k3binteractiondialog.h> +#include <k3bmsf.h> + +#include <qstringlist.h> + + +class K3bListView; +class QCheckBox; +class QSpinBox; +class QComboBox; +class K3bCddbPatternWidget; +class QToolButton; +class K3bAudioConvertingOptionWidget; +class K3bCddbResultEntry; +class K3bAudioConvertingJob; +class K3bJobHandler; +class K3bAudioDoc; + + +/** + *@author Sebastian Trueg + */ +class K3bAudioProjectConvertingDialog : public K3bInteractionDialog +{ + Q_OBJECT + + public: + K3bAudioProjectConvertingDialog( K3bAudioDoc*, QWidget *parent = 0, const char *name = 0 ); + ~K3bAudioProjectConvertingDialog(); + + void setBaseDir( const QString& path ); + + public slots: + void refresh(); + + protected: + void loadK3bDefaults(); + void loadUserDefaults( KConfigBase* ); + void saveUserDefaults( KConfigBase* ); + + private: + K3bCddbPatternWidget* m_patternWidget; + K3bAudioConvertingOptionWidget* m_optionWidget; + + K3bListView* m_viewTracks; + K3bAudioDoc* m_doc; + + void setupGui(); + + static K3bCddbResultEntry createCddbEntryFromDoc( K3bAudioDoc* ); + + class Private; + Private* d; + + private slots: + void slotStartClicked(); +}; + +#endif diff --git a/src/rip/k3baudioprojectconvertingthread.cpp b/src/rip/k3baudioprojectconvertingthread.cpp new file mode 100644 index 0000000..8c175fb --- /dev/null +++ b/src/rip/k3baudioprojectconvertingthread.cpp @@ -0,0 +1,459 @@ +/* + * + * $Id: k3baudioprojectconvertingthread.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3baudioprojectconvertingthread.h" +#include "k3bpatternparser.h" + +#include <k3bjob.h> +#include <k3baudiodoc.h> +#include <k3baudiotrack.h> +#include <k3baudioencoder.h> +#include <k3bwavefilewriter.h> +#include "k3bcuefilewriter.h" + +#include <k3bglobals.h> + +#include <qfile.h> +#include <qtimer.h> + +#include <kdebug.h> +#include <klocale.h> +#include <kstandarddirs.h> + + + + +class K3bAudioProjectConvertingThread::Private +{ +public: + Private() + : encoder(0), + waveFileWriter(0), + canceled(false) { + } + + // the index of the currently ripped track in m_tracks + int currentTrackIndex; + long long overallBytesRead; + long long overallBytesToRead; + + K3bAudioEncoder* encoder; + K3bWaveFileWriter* waveFileWriter; + + bool canceled; + + QString fileType; +}; + + +K3bAudioProjectConvertingThread::K3bAudioProjectConvertingThread( K3bAudioDoc* doc ) + : K3bThread(), + m_doc(doc) +{ + d = new Private(); +} + + +K3bAudioProjectConvertingThread::~K3bAudioProjectConvertingThread() +{ + delete d->waveFileWriter; + delete d; +} + + +void K3bAudioProjectConvertingThread::setFileType( const QString& t ) +{ + d->fileType = t; +} + + +void K3bAudioProjectConvertingThread::setEncoder( K3bAudioEncoder* f ) +{ + d->encoder = f; +} + + +void K3bAudioProjectConvertingThread::init() +{ + d->canceled = false; +} + + +void K3bAudioProjectConvertingThread::run() +{ + emitStarted(); + emitNewTask( i18n("Converting Audio Tracks") ); + + if( !d->encoder ) + if( !d->waveFileWriter ) + d->waveFileWriter = new K3bWaveFileWriter(); + + + d->overallBytesRead = 0; + d->overallBytesToRead = m_doc->length().audioBytes(); + + if( m_singleFile ) { + QString& filename = m_tracks[0].second; + + QString dir = filename.left( filename.findRev("/") ); + if( !KStandardDirs::makeDir( dir ) ) { + emitInfoMessage( i18n("Unable to create directory %1").arg(dir), K3bJob::ERROR ); + emitFinished(false); + return; + } + + // initialize + bool isOpen = true; + if( d->encoder ) { + if( isOpen = d->encoder->openFile( d->fileType, filename, m_doc->length() ) ) { + // here we use cd Title and Artist + d->encoder->setMetaData( K3bAudioEncoder::META_TRACK_ARTIST, m_cddbEntry.cdArtist ); + d->encoder->setMetaData( K3bAudioEncoder::META_TRACK_TITLE, m_cddbEntry.cdTitle ); + d->encoder->setMetaData( K3bAudioEncoder::META_TRACK_COMMENT, m_cddbEntry.cdExtInfo ); + d->encoder->setMetaData( K3bAudioEncoder::META_ALBUM_ARTIST, m_cddbEntry.cdArtist ); + d->encoder->setMetaData( K3bAudioEncoder::META_ALBUM_TITLE, m_cddbEntry.cdTitle ); + d->encoder->setMetaData( K3bAudioEncoder::META_ALBUM_COMMENT, m_cddbEntry.cdExtInfo ); + d->encoder->setMetaData( K3bAudioEncoder::META_YEAR, QString::number(m_cddbEntry.year) ); + d->encoder->setMetaData( K3bAudioEncoder::META_GENRE, m_cddbEntry.genre ); + } + else + emitInfoMessage( d->encoder->lastErrorString(), K3bJob::ERROR ); + } + else { + isOpen = d->waveFileWriter->open( filename ); + } + + if( !isOpen ) { + emitInfoMessage( i18n("Unable to open '%1' for writing.").arg(filename), K3bJob::ERROR ); + emitFinished(false); + return; + } + + emitInfoMessage( i18n("Converting to single file '%1'.").arg(filename), K3bJob::INFO ); + } + + bool success = true; + K3bAudioTrack* track = m_doc->firstTrack(); + unsigned int i = 0; + while( track ) { + d->currentTrackIndex = i; + if( !convertTrack( track, m_singleFile ? m_tracks[0].second : m_tracks[i].second ) ) { + success = false; + break; + } + + emitInfoMessage( i18n("Successfully converted track %1.").arg(i+1), K3bJob::INFO ); + + track = track->next(); + ++i; + } + + if( m_singleFile ) { + if( d->encoder ) + d->encoder->closeFile(); + else + d->waveFileWriter->close(); + } + + if( !d->canceled && success && m_writePlaylist ) { + success = success && writePlaylist(); + } + + if( !d->canceled && success && m_writeCueFile && m_singleFile ) { + success = success && writeCueFile(); + } + + if( d->canceled ) { + if( d->currentTrackIndex >= 0 && d->currentTrackIndex < (int)m_tracks.count() ) { + if( QFile::exists( m_tracks[d->currentTrackIndex].second ) ) { + QFile::remove( m_tracks[d->currentTrackIndex].second ); + emitInfoMessage( i18n("Removed partial file '%1'.").arg(m_tracks[d->currentTrackIndex].second), K3bJob::INFO ); + } + } + + emitCanceled(); + emitFinished(false); + } + else + emitFinished(success); +} + + +bool K3bAudioProjectConvertingThread::convertTrack( K3bAudioTrack* track, const QString& filename ) +{ + QString dir = filename.left( filename.findRev("/") ); + if( !KStandardDirs::makeDir( dir ) ) { + emitInfoMessage( i18n("Unable to create directory %1").arg(dir), K3bJob::ERROR ); + return false; + } + + // initialize + bool isOpen = true; + if( !m_singleFile ) { + if( d->encoder ) { + if( isOpen = d->encoder->openFile( d->fileType, + filename, + track->length() ) ) { + + d->encoder->setMetaData( K3bAudioEncoder::META_TRACK_ARTIST, m_cddbEntry.artists[d->currentTrackIndex] ); + d->encoder->setMetaData( K3bAudioEncoder::META_TRACK_TITLE, m_cddbEntry.titles[d->currentTrackIndex] ); + d->encoder->setMetaData( K3bAudioEncoder::META_TRACK_COMMENT, m_cddbEntry.extInfos[d->currentTrackIndex] ); + d->encoder->setMetaData( K3bAudioEncoder::META_TRACK_NUMBER, QString::number(d->currentTrackIndex+1).rightJustify( 2, '0' ) ); + d->encoder->setMetaData( K3bAudioEncoder::META_ALBUM_ARTIST, m_cddbEntry.cdArtist ); + d->encoder->setMetaData( K3bAudioEncoder::META_ALBUM_TITLE, m_cddbEntry.cdTitle ); + d->encoder->setMetaData( K3bAudioEncoder::META_ALBUM_COMMENT, m_cddbEntry.cdExtInfo ); + d->encoder->setMetaData( K3bAudioEncoder::META_YEAR, QString::number(m_cddbEntry.year) ); + d->encoder->setMetaData( K3bAudioEncoder::META_GENRE, m_cddbEntry.genre ); + } + else + emitInfoMessage( d->encoder->lastErrorString(), K3bJob::ERROR ); + } + else { + isOpen = d->waveFileWriter->open( filename ); + } + + if( !isOpen ) { + emitInfoMessage( i18n("Unable to open '%1' for writing.").arg(filename), K3bJob::ERROR ); + return false; + } + } + + + if( !m_cddbEntry.artists[d->currentTrackIndex].isEmpty() && + !m_cddbEntry.titles[d->currentTrackIndex].isEmpty() ) + emitNewSubTask( i18n("Converting track %1 (%2 - %3)") + .arg(d->currentTrackIndex+1) + .arg(m_cddbEntry.artists[d->currentTrackIndex]) + .arg(m_cddbEntry.titles[d->currentTrackIndex]) ); + else + emitNewSubTask( i18n("Converting track %1").arg(d->currentTrackIndex+1) ); + + + // do the conversion + // ---------------------- + + char buffer[10*1024]; + const int bufferLength = 10*1024; + int readLength = 0; + long long readFile = 0; + track->seek(0); + while( !d->canceled && ( readLength = track->read( buffer, bufferLength ) ) > 0 ) { + + if( d->encoder ) { + // the tracks produce big endian samples + // so we need to swap the bytes here + char b; + for( int i = 0; i < bufferLength-1; i+=2 ) { + b = buffer[i]; + buffer[i] = buffer[i+1]; + buffer[i+1] = b; + } + + if( d->encoder->encode( buffer, readLength ) < 0 ) { + kdDebug() << "(K3bAudioProjectConvertingThread) error while encoding." << endl; + emitInfoMessage( d->encoder->lastErrorString(), K3bJob::ERROR ); + emitInfoMessage( i18n("Error while encoding track %1.").arg(d->currentTrackIndex+1), K3bJob::ERROR ); + return false; + } + } + else { + d->waveFileWriter->write( buffer, + readLength, + K3bWaveFileWriter::BigEndian ); + } + + d->overallBytesRead += readLength; + readFile += readLength; + emitSubPercent( 100*readFile/track->size() ); + emitPercent( 100*d->overallBytesRead/d->overallBytesToRead ); + } + + if( !m_singleFile ) { + if( d->encoder ) + d->encoder->closeFile(); + else + d->waveFileWriter->close(); + } + + return ( readLength == 0 ); +} + + +void K3bAudioProjectConvertingThread::cancel() +{ + d->canceled = true; +} + + +bool K3bAudioProjectConvertingThread::writePlaylist() +{ + // this is an absolut path so there is always a "/" + QString playlistDir = m_playlistFilename.left( m_playlistFilename.findRev( "/" ) ); + + if( !KStandardDirs::makeDir( playlistDir ) ) { + emitInfoMessage( i18n("Unable to create directory %1").arg(playlistDir), K3bJob::ERROR ); + return false; + } + + emitInfoMessage( i18n("Writing playlist to %1.").arg( m_playlistFilename ), K3bJob::INFO ); + + QFile f( m_playlistFilename ); + if( f.open( IO_WriteOnly ) ) { + QTextStream t( &f ); + + // format descriptor + t << "#EXTM3U" << endl; + + // now write the entries (or the entry if m_singleFile) + if( m_singleFile ) { + // extra info + t << "#EXTINF:" << m_doc->length().lba() << ","; + if( !m_cddbEntry.cdArtist.isEmpty() && !m_cddbEntry.cdTitle.isEmpty() ) + t << m_cddbEntry.cdArtist << " - " << m_cddbEntry.cdTitle << endl; + else + t << m_tracks[0].second.mid(m_tracks[0].second.findRev("/") + 1, + m_tracks[0].second.length() - m_tracks[0].second.findRev("/") - 5) + << endl; // filename without extension + + // filename + if( m_relativePathInPlaylist ) + t << findRelativePath( m_tracks[0].second, playlistDir ) + << endl; + else + t << m_tracks[0].second << endl; + } + else { + for( unsigned int i = 0; i < m_tracks.count(); ++i ) { + int trackIndex = m_tracks[i].first-1; + + // extra info + t << "#EXTINF:" << m_doc->length().totalFrames()/75 << ","; + + if( !m_cddbEntry.artists[trackIndex].isEmpty() && !m_cddbEntry.titles[trackIndex].isEmpty() ) + t << m_cddbEntry.artists[trackIndex] << " - " << m_cddbEntry.titles[trackIndex] << endl; + else + t << m_tracks[i].second.mid(m_tracks[i].second.findRev("/") + 1, + m_tracks[i].second.length() + - m_tracks[i].second.findRev("/") - 5) + << endl; // filename without extension + + // filename + if( m_relativePathInPlaylist ) + t << findRelativePath( m_tracks[i].second, playlistDir ) + << endl; + else + t << m_tracks[i].second << endl; + } + } + + return ( t.device()->status() == IO_Ok ); + } + else { + emitInfoMessage( i18n("Unable to open '%1' for writing.").arg(m_playlistFilename), K3bJob::ERROR ); + kdDebug() << "(K3bAudioProjectConvertingThread) could not open file " << m_playlistFilename << " for writing." << endl; + return false; + } +} + + +bool K3bAudioProjectConvertingThread::writeCueFile() +{ + K3bCueFileWriter cueWriter; + + // create a new toc and cd-text + K3bDevice::Toc toc; + K3bDevice::CdText text; + text.setPerformer( m_cddbEntry.cdArtist ); + text.setTitle( m_cddbEntry.cdTitle ); + text.reserve( m_tracks.count() ); + K3b::Msf currentSector; + K3bAudioTrack* track = m_doc->firstTrack(); + int trackNum = 1; + while( track ) { + + K3bDevice::Track newTrack( currentSector, (currentSector+=track->length()) - 1, K3bDevice::Track::AUDIO ); + toc.append( newTrack ); + + K3bDevice::TrackCdText trackText; + trackText.setPerformer( m_cddbEntry.artists[trackNum-1] ); + trackText.setTitle( m_cddbEntry.titles[trackNum-1] ); + text.append( trackText ); + + track = track->next(); + ++trackNum; + } + + cueWriter.setData( toc ); + cueWriter.setCdText( text ); + + + // we always use a relative filename here + QString imageFile = m_tracks[0].second.section( '/', -1 ); + cueWriter.setImage( imageFile, ( d->fileType.isEmpty() ? QString("WAVE") : d->fileType ) ); + + // use the same base name as the image file + QString cueFile = m_tracks[0].second; + cueFile.truncate( cueFile.findRev(".") ); + cueFile += ".cue"; + + emitInfoMessage( i18n("Writing cue file to %1.").arg(cueFile), K3bJob::INFO ); + + return cueWriter.save( cueFile ); +} + + +QString K3bAudioProjectConvertingThread::findRelativePath( const QString& absPath, const QString& baseDir ) +{ + QString baseDir_ = K3b::prepareDir( K3b::fixupPath(baseDir) ); + QString path = K3b::fixupPath( absPath ); + + // both paths have an equal beginning. That's just how it's configured by K3b + int pos = baseDir_.find( "/" ); + int oldPos = pos; + while( pos != -1 && path.left( pos+1 ) == baseDir_.left( pos+1 ) ) { + oldPos = pos; + pos = baseDir_.find( "/", pos+1 ); + } + + // now the paths are equal up to oldPos, so that's how "deep" we go + path = path.mid( oldPos+1 ); + baseDir_ = baseDir_.mid( oldPos+1 ); + int numberOfDirs = baseDir_.contains( '/' ); + for( int i = 0; i < numberOfDirs; ++i ) + path.prepend( "../" ); + + return path; +} + + +QString K3bAudioProjectConvertingThread::jobDescription() const +{ + if( m_cddbEntry.cdTitle.isEmpty() ) + return i18n("Converting Audio Tracks"); + else + return i18n("Converting Audio Tracks From '%1'").arg(m_cddbEntry.cdTitle); +} + +QString K3bAudioProjectConvertingThread::jobDetails() const +{ + if( d->encoder ) + return i18n("1 track (encoding to %1)", + "%n tracks (encoding to %1)", + m_tracks.count() ).arg(d->encoder->fileTypeComment(d->fileType)); + else + return i18n("1 track", "%n tracks", m_doc->numOfTracks() ); +} + diff --git a/src/rip/k3baudioprojectconvertingthread.h b/src/rip/k3baudioprojectconvertingthread.h new file mode 100644 index 0000000..aeda217 --- /dev/null +++ b/src/rip/k3baudioprojectconvertingthread.h @@ -0,0 +1,101 @@ +/* + * + * $Id: k3baudioprojectconvertingthread.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3B_AUDIO_PROJECT_CONVERTING_THREAD_H +#define K3B_AUDIO_PROJECT_CONVERTING_THREAD_H + +#include <k3bthread.h> +#include <qobject.h> +#include <qvaluevector.h> +#include <qpair.h> + +#include <k3bcddbresult.h> + + +class K3bAudioEncoder; +class K3bAudioDoc; +class K3bAudioTrack; + + +class K3bAudioProjectConvertingThread : public K3bThread +{ + public: + K3bAudioProjectConvertingThread( K3bAudioDoc* ); + ~K3bAudioProjectConvertingThread(); + + QString jobDescription() const; + QString jobDetails() const; + + void setSingleFile( bool b ) { m_singleFile = b; } + + void setCddbEntry( const K3bCddbResultEntry& e ) { m_cddbEntry = e; } + + // if 0 (default) wave files are created + void setEncoder( K3bAudioEncoder* f ); + + /** + * Used for encoders that support multiple formats + */ + void setFileType( const QString& ); + + /** + * 1 is the first track + */ + void setTracksToRip( const QValueVector<QPair<int, QString> >& t ) { m_tracks = t; } + + void setWritePlaylist( bool b ) { m_writePlaylist = b; } + void setPlaylistFilename( const QString& s ) { m_playlistFilename = s; } + void setUseRelativePathInPlaylist( bool b ) { m_relativePathInPlaylist = b; } + void setWriteCueFile( bool b ) { m_writeCueFile = b; } + + /** + * \reimplemented from K3bThread + */ + void init(); + + void cancel(); + + private: + /** reimplemented from QThread. Does the work */ + void run(); + + bool convertTrack( K3bAudioTrack*, const QString& filename ); + bool writePlaylist(); + bool writeCueFile(); + + /** + * Finds a relative path from baseDir to absPath + */ + QString findRelativePath( const QString& absPath, const QString& baseDir ); + + K3bCddbResultEntry m_cddbEntry; + + bool m_singleFile; + bool m_writePlaylist; + bool m_relativePathInPlaylist; + QString m_playlistFilename; + + bool m_writeCueFile; + + QValueVector<QPair<int, QString> > m_tracks; + + K3bAudioDoc* m_doc; + + class Private; + Private* d; +}; + +#endif diff --git a/src/rip/k3baudioripjob.cpp b/src/rip/k3baudioripjob.cpp new file mode 100644 index 0000000..ef520e1 --- /dev/null +++ b/src/rip/k3baudioripjob.cpp @@ -0,0 +1,77 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3baudioripjob.h" +#include "k3baudioripthread.h" + +#include <k3bthreadjob.h> +#include <k3bcore.h> + +#include <kdebug.h> +#include <klocale.h> + + +K3bAudioRipJob::K3bAudioRipJob( K3bJobHandler* hdl, QObject* parent ) + : K3bJob( hdl, parent ) +{ + m_thread = new K3bAudioRipThread(); + m_threadJob = new K3bThreadJob( m_thread, this, this ); + connectSubJob( m_threadJob, + SLOT(slotRippingFinished(bool)), + SIGNAL(newTask(const QString&)), + SIGNAL(newSubTask(const QString&)), + SIGNAL(percent(int)), + SIGNAL(subPercent(int)) ); +} + + +K3bAudioRipJob::~K3bAudioRipJob() +{ +} + + +QString K3bAudioRipJob::jobDescription() const +{ + return m_thread->jobDescription(); +} + + +QString K3bAudioRipJob::jobDetails() const +{ + return m_thread->jobDetails(); +} + + +void K3bAudioRipJob::start() +{ + jobStarted(); + k3bcore->blockDevice( m_thread->m_device ); + m_threadJob->start(); +} + + +void K3bAudioRipJob::cancel() +{ + m_threadJob->cancel(); +} + + +void K3bAudioRipJob::slotRippingFinished( bool success ) +{ + k3bcore->unblockDevice( m_thread->m_device ); + jobFinished( success ); +} + +#include "k3baudioripjob.moc" diff --git a/src/rip/k3baudioripjob.h b/src/rip/k3baudioripjob.h new file mode 100644 index 0000000..adf47f3 --- /dev/null +++ b/src/rip/k3baudioripjob.h @@ -0,0 +1,71 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_AUDIORIP_JOB_H_ +#define _K3B_AUDIORIP_JOB_H_ + +#include <k3bjob.h> + +#include "k3baudioripthread.h" +#include <k3bdevice.h> +#include <k3bcddbresult.h> +#include <k3baudioencoder.h> + +#include <qvaluevector.h> + +class K3bInterferingSystemsHandler; +class K3bThreadJob; + + +class K3bAudioRipJob : public K3bJob +{ + Q_OBJECT + + public: + K3bAudioRipJob( K3bJobHandler* hdl, QObject* parent ); + ~K3bAudioRipJob(); + + QString jobDescription() const; + QString jobDetails() const; + + public slots: + void start(); + void cancel(); + + void setDevice( K3bDevice::Device* dev ) { m_thread->setDevice( dev ); } + void setCddbEntry( const K3bCddbResultEntry& entry ) { m_thread->setCddbEntry( entry ); } + void setTracksToRip( const QValueVector<QPair<int, QString> >& tracksToRip ) { m_thread->setTracksToRip( tracksToRip ); } + void setParanoiaMode( int mode ) { m_thread->setParanoiaMode( mode ); } + void setMaxRetries( int retries ) { m_thread->setMaxRetries( retries ); } + void setNeverSkip( bool neverSkip ) { m_thread->setNeverSkip( neverSkip ); } + void setSingleFile( bool singleFile ) { m_thread->setSingleFile( singleFile ); } + void setWriteCueFile( bool cue ) { m_thread->setWriteCueFile( cue ); } + void setEncoder( K3bAudioEncoder* encoder ) { m_thread->setEncoder( encoder ); } + void setWritePlaylist( bool playlist ) { m_thread->setWritePlaylist( playlist ); } + void setPlaylistFilename( const QString& filename ) { m_thread->setPlaylistFilename( filename ); } + void setUseRelativePathInPlaylist( bool relative ) { m_thread->setUseRelativePathInPlaylist( relative ); } + void setUseIndex0( bool index0 ) { m_thread->setUseIndex0( index0 ); } + void setFileType( const QString& filetype ) { m_thread->setFileType( filetype ); } + + private slots: + void slotRippingFinished( bool ); + + private: + K3bInterferingSystemsHandler* m_interferingSystemsHandler; + K3bThreadJob* m_threadJob; + K3bAudioRipThread* m_thread; +}; + +#endif diff --git a/src/rip/k3baudiorippingdialog.cpp b/src/rip/k3baudiorippingdialog.cpp new file mode 100644 index 0000000..693230f --- /dev/null +++ b/src/rip/k3baudiorippingdialog.cpp @@ -0,0 +1,470 @@ +/* + * + * $Id: k3baudiorippingdialog.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3baudiorippingdialog.h" +#include "k3baudioripjob.h" +#include "k3bpatternparser.h" +#include "k3bcddbpatternwidget.h" +#include "k3baudioconvertingoptionwidget.h" + +#include <k3bjobprogressdialog.h> +#include <k3bcore.h> +#include <k3bglobals.h> +#include <k3btrack.h> +#include <k3bstdguiitems.h> +#include <k3bfilesysteminfo.h> +#include <k3bpluginmanager.h> +#include <k3baudioencoder.h> + +#include <kcombobox.h> +#include <klocale.h> +#include <kapplication.h> +#include <kconfig.h> +#include <klistview.h> +#include <kurlrequester.h> +#include <kfiledialog.h> +#include <kio/global.h> +#include <kiconloader.h> +#include <kstdguiitem.h> +#include <kdebug.h> +#include <kmessagebox.h> +#include <kurllabel.h> + +#include <qgroupbox.h> +#include <qheader.h> +#include <qcheckbox.h> +#include <qlabel.h> +#include <qpushbutton.h> +#include <qlayout.h> +#include <qvariant.h> +#include <qtooltip.h> +#include <qwhatsthis.h> +#include <qdir.h> +#include <qstringlist.h> +#include <qmessagebox.h> +#include <qfont.h> +#include <qhbox.h> +#include <qtoolbutton.h> +#include <qtabwidget.h> +#include <qspinbox.h> +#include <qptrlist.h> +#include <qintdict.h> +#include <qpair.h> +#include <qvalidator.h> + + +class K3bAudioRippingDialog::Private +{ +public: + Private() { + } + + QValueVector<QString> filenames; + QString playlistFilename; + K3bFileSystemInfo fsInfo; +}; + + +K3bAudioRippingDialog::K3bAudioRippingDialog(const K3bDevice::Toc& toc, + K3bDevice::Device* device, + const K3bCddbResultEntry& entry, + const QValueList<int>& tracks, + QWidget *parent, const char *name ) + : K3bInteractionDialog( parent, name, + QString::null, + QString::null, + START_BUTTON|CANCEL_BUTTON, + START_BUTTON, + "Audio Ripping" ), // config group + m_toc( toc ), + m_device( device ), + m_cddbEntry( entry ), + m_trackNumbers( tracks ) +{ + d = new Private(); + + setupGui(); + setupContextHelp(); + + K3b::Msf length; + for( QValueList<int>::const_iterator it = m_trackNumbers.begin(); + it != m_trackNumbers.end(); ++it ) { + length += m_toc[*it-1].length(); + } + setTitle( i18n("CD Ripping"), + i18n("1 track (%1)", "%n tracks (%1)", + m_trackNumbers.count()).arg(length.toString()) ); +} + + +K3bAudioRippingDialog::~K3bAudioRippingDialog() +{ + delete d; +} + + +void K3bAudioRippingDialog::setupGui() +{ + QWidget *frame = mainWidget(); + QGridLayout* Form1Layout = new QGridLayout( frame ); + Form1Layout->setSpacing( KDialog::spacingHint() ); + Form1Layout->setMargin( 0 ); + + m_viewTracks = new KListView( frame, "m_viewTracks" ); + m_viewTracks->addColumn(i18n( "Filename") ); + m_viewTracks->addColumn(i18n( "Length") ); + m_viewTracks->addColumn(i18n( "File Size") ); + m_viewTracks->addColumn(i18n( "Type") ); + m_viewTracks->setSorting(-1); + m_viewTracks->setAllColumnsShowFocus(true); + m_viewTracks->setFullWidth(true); + + QTabWidget* mainTab = new QTabWidget( frame ); + + m_optionWidget = new K3bAudioConvertingOptionWidget( mainTab ); + mainTab->addTab( m_optionWidget, i18n("Settings") ); + + + // setup filename pattern page + // ------------------------------------------------------------------------------------------- + m_patternWidget = new K3bCddbPatternWidget( mainTab ); + mainTab->addTab( m_patternWidget, i18n("File Naming") ); + connect( m_patternWidget, SIGNAL(changed()), this, SLOT(refresh()) ); + + + // setup advanced page + // ------------------------------------------------------------------------------------------- + QWidget* advancedPage = new QWidget( mainTab ); + QGridLayout* advancedPageLayout = new QGridLayout( advancedPage ); + advancedPageLayout->setMargin( marginHint() ); + advancedPageLayout->setSpacing( spacingHint() ); + mainTab->addTab( advancedPage, i18n("Advanced") ); + + m_comboParanoiaMode = K3bStdGuiItems::paranoiaModeComboBox( advancedPage ); + m_spinRetries = new QSpinBox( advancedPage ); + m_checkIgnoreReadErrors = new QCheckBox( i18n("Ignore read errors"), advancedPage ); + m_checkUseIndex0 = new QCheckBox( i18n("Don't read pregaps"), advancedPage ); + + advancedPageLayout->addWidget( new QLabel( i18n("Paranoia mode:"), advancedPage ), 0, 0 ); + advancedPageLayout->addWidget( m_comboParanoiaMode, 0, 1 ); + advancedPageLayout->addWidget( new QLabel( i18n("Read retries:"), advancedPage ), 1, 0 ); + advancedPageLayout->addWidget( m_spinRetries, 1, 1 ); + advancedPageLayout->addMultiCellWidget( m_checkIgnoreReadErrors, 2, 2, 0, 1 ); + advancedPageLayout->addMultiCellWidget( m_checkUseIndex0, 3, 3, 0, 1 ); + advancedPageLayout->setRowStretch( 4, 1 ); + advancedPageLayout->setColStretch( 2, 1 ); + + // ------------------------------------------------------------------------------------------- + + + Form1Layout->addWidget( m_viewTracks, 0, 0 ); + Form1Layout->addWidget( mainTab, 1, 0 ); + Form1Layout->setRowStretch( 0, 1 ); + + setStartButtonText( i18n( "Start Ripping" ), i18n( "Starts copying the selected tracks") ); + + connect( m_checkUseIndex0, SIGNAL(toggled(bool)), this, SLOT(refresh()) ); + connect( m_optionWidget, SIGNAL(changed()), this, SLOT(refresh()) ); +} + + +void K3bAudioRippingDialog::setupContextHelp() +{ + QToolTip::add( m_spinRetries, i18n("Maximal number of read retries") ); + QWhatsThis::add( m_spinRetries, i18n("<p>This specifies the maximum number of retries to " + "read a sector of audio data from the cd. After that " + "K3b will either skip the sector if the <em>Ignore Read Errors</em> " + "option is enabled or stop the process.") ); + QToolTip::add( m_checkUseIndex0, i18n("Do not read the pregaps at the end of every track") ); + QWhatsThis::add( m_checkUseIndex0, i18n("<p>If this option is checked K3b will not rip the audio " + "data in the pregaps. Most audio tracks contain an empty " + "pregap which does not belong to the track itself.</p>" + "<p>Although the default behaviour of nearly all ripping " + "software is to include the pregaps for most CDs it makes more " + "sense to ignore them. When creating a K3b audio project you " + "will regenerate these pregaps anyway.</p>") ); +} + + +void K3bAudioRippingDialog::init() +{ + refresh(); +} + + +void K3bAudioRippingDialog::slotStartClicked() +{ + // check if all filenames differ + if( d->filenames.count() > 1 ) { + bool differ = true; + // the most stupid version to compare but most cds have about 12 tracks + // that's a size where algorithms do not need any optimization! ;) + for( unsigned int i = 0; i < d->filenames.count(); ++i ) { + for( unsigned int j = i+1; j < d->filenames.count(); ++j ) + if( d->filenames[i] == d->filenames[j] ) { + differ = false; + break; + } + } + + if( !differ ) { + KMessageBox::sorry( this, i18n("Please check the naming pattern. All filenames need to be unique.") ); + return; + } + } + + // check if we need to overwrite some files... + QListViewItemIterator it( m_viewTracks ); + QStringList filesToOverwrite; + for( unsigned int i = 0; i < d->filenames.count(); ++i ) { + if( QFile::exists( d->filenames[i] ) ) + filesToOverwrite.append( d->filenames[i] ); + } + + if( m_optionWidget->createPlaylist() && QFile::exists( d->playlistFilename ) ) + filesToOverwrite.append( d->playlistFilename ); + + if( !filesToOverwrite.isEmpty() ) + if( KMessageBox::questionYesNoList( this, + i18n("Do you want to overwrite these files?"), + filesToOverwrite, + i18n("Files Exist"), i18n("Overwrite"), KStdGuiItem::cancel() ) == KMessageBox::No ) + return; + + + // prepare list of tracks to rip + QValueVector<QPair<int, QString> > tracksToRip; + unsigned int i = 0; + for( QValueList<int>::const_iterator trackIt = m_trackNumbers.begin(); + trackIt != m_trackNumbers.end(); ++trackIt ) { + tracksToRip.append( qMakePair( *trackIt, d->filenames[(m_optionWidget->createSingleFile() ? 0 : i)] ) ); + ++i; + } + + K3bJobProgressDialog ripDialog( parentWidget(), "Ripping" ); + + K3bAudioEncoder* encoder = m_optionWidget->encoder(); + K3bAudioRipJob* job = new K3bAudioRipJob( &ripDialog, this ); + job->setDevice( m_device ); + job->setCddbEntry( m_cddbEntry ); + job->setTracksToRip( tracksToRip ); + job->setParanoiaMode( m_comboParanoiaMode->currentText().toInt() ); + job->setMaxRetries( m_spinRetries->value() ); + job->setNeverSkip( !m_checkIgnoreReadErrors->isChecked() ); + job->setSingleFile( m_optionWidget->createSingleFile() ); + job->setWriteCueFile( m_optionWidget->createCueFile() ); + job->setEncoder( encoder ); + job->setWritePlaylist( m_optionWidget->createPlaylist() ); + job->setPlaylistFilename( d->playlistFilename ); + job->setUseRelativePathInPlaylist( m_optionWidget->playlistRelativePath() ); + job->setUseIndex0( m_checkUseIndex0->isChecked() ); + if( encoder ) + job->setFileType( m_optionWidget->extension() ); + + hide(); + ripDialog.startJob(job); + + kdDebug() << "(K3bAudioRippingDialog) deleting ripjob." << endl; + delete job; + + close(); +} + + +void K3bAudioRippingDialog::refresh() +{ + m_viewTracks->clear(); + d->filenames.clear(); + + QString baseDir = K3b::prepareDir( m_optionWidget->baseDir() ); + d->fsInfo.setPath( baseDir ); + + KIO::filesize_t overallSize = 0; + + if( m_optionWidget->createSingleFile() ) { + long length = 0; + for( QValueList<int>::const_iterator it = m_trackNumbers.begin(); + it != m_trackNumbers.end(); ++it ) { + length += ( m_checkUseIndex0->isChecked() + ? m_toc[*it-1].realAudioLength().lba() + : m_toc[*it-1].length().lba() ); + } + + QString filename; + QString extension; + long long fileSize = 0; + if( m_optionWidget->encoder() == 0 ) { + extension = "wav"; + fileSize = length * 2352 + 44; + } + else { + extension = m_optionWidget->extension(); + fileSize = m_optionWidget->encoder()->fileSize( extension, length ); + } + + if( fileSize > 0 ) + overallSize = fileSize; + + if( (int)m_cddbEntry.titles.count() >= 1 ) { + filename = K3bPatternParser::parsePattern( m_cddbEntry, 1, + m_patternWidget->filenamePattern(), + m_patternWidget->replaceBlanks(), + m_patternWidget->blankReplaceString() ); + } + else { + filename = i18n("Album"); + } + + filename = d->fsInfo.fixupPath( filename ); + + (void)new KListViewItem( m_viewTracks, + m_viewTracks->lastItem(), + filename + "." + extension, + K3b::Msf(length).toString(), + fileSize < 0 ? i18n("unknown") : KIO::convertSize( fileSize ), + i18n("Audio") ); + d->filenames.append( baseDir + "/" + filename + "." + extension ); + + if( m_optionWidget->createCueFile() ) + (void)new KListViewItem( m_viewTracks, + m_viewTracks->lastItem(), + filename + ".cue", + "-", + "-", + i18n("Cue-file") ); + } + else { + for( QValueList<int>::const_iterator it = m_trackNumbers.begin(); + it != m_trackNumbers.end(); ++it ) { + int index = *it - 1; + + QString extension; + long long fileSize = 0; + K3b::Msf trackLength = ( m_checkUseIndex0->isChecked() + ? m_toc[index].realAudioLength() + : m_toc[index].length() ); + if( m_optionWidget->encoder() == 0 ) { + extension = "wav"; + fileSize = trackLength.audioBytes() + 44; + } + else { + extension = m_optionWidget->extension(); + fileSize = m_optionWidget->encoder()->fileSize( extension, trackLength ); + } + + if( fileSize > 0 ) + overallSize += fileSize; + + if( m_toc[index].type() == K3bTrack::DATA ) { + extension = ".iso"; + continue; // TODO: find out how to rip the iso data + } + + + QString filename; + + if( (int)m_cddbEntry.titles.count() >= *it ) { + filename = K3bPatternParser::parsePattern( m_cddbEntry, *it, + m_patternWidget->filenamePattern(), + m_patternWidget->replaceBlanks(), + m_patternWidget->blankReplaceString() ) + "." + extension; + } + else { + filename = i18n("Track%1").arg( QString::number( *it ).rightJustify( 2, '0' ) ) + "." + extension; + } + + filename = d->fsInfo.fixupPath( filename ); + + (void)new KListViewItem( m_viewTracks, + m_viewTracks->lastItem(), + filename, + trackLength.toString(), + fileSize < 0 ? i18n("unknown") : KIO::convertSize( fileSize ), + (m_toc[index].type() == K3bTrack::AUDIO ? i18n("Audio") : i18n("Data") ) ); + + d->filenames.append( baseDir + "/" + filename ); + } + } + + // create playlist item + if( m_optionWidget->createPlaylist() ) { + QString filename = K3bPatternParser::parsePattern( m_cddbEntry, 1, + m_patternWidget->playlistPattern(), + m_patternWidget->replaceBlanks(), + m_patternWidget->blankReplaceString() ) + ".m3u"; + + (void)new KListViewItem( m_viewTracks, + m_viewTracks->lastItem(), + filename, + "-", + "-", + i18n("Playlist") ); + + d->playlistFilename = d->fsInfo.fixupPath( baseDir + "/" + filename ); + } + + if( overallSize > 0 ) + m_optionWidget->setNeededSize( overallSize ); + else + m_optionWidget->setNeededSize( 0 ); +} + + +void K3bAudioRippingDialog::setStaticDir( const QString& path ) +{ + m_optionWidget->setBaseDir( path ); +} + + +void K3bAudioRippingDialog::loadK3bDefaults() +{ + m_comboParanoiaMode->setCurrentItem( 0 ); + m_spinRetries->setValue(5); + m_checkIgnoreReadErrors->setChecked( true ); + m_checkUseIndex0->setChecked( false ); + + m_optionWidget->loadDefaults(); + m_patternWidget->loadDefaults(); + + refresh(); +} + +void K3bAudioRippingDialog::loadUserDefaults( KConfigBase* c ) +{ + m_comboParanoiaMode->setCurrentItem( c->readNumEntry( "paranoia_mode", 0 ) ); + m_spinRetries->setValue( c->readNumEntry( "read_retries", 5 ) ); + m_checkIgnoreReadErrors->setChecked( !c->readBoolEntry( "never_skip", true ) ); + m_checkUseIndex0->setChecked( c->readBoolEntry( "use_index0", false ) ); + + m_optionWidget->loadConfig( c ); + m_patternWidget->loadConfig( c ); + + refresh(); +} + +void K3bAudioRippingDialog::saveUserDefaults( KConfigBase* c ) +{ + c->writeEntry( "paranoia_mode", m_comboParanoiaMode->currentText().toInt() ); + c->writeEntry( "read_retries", m_spinRetries->value() ); + c->writeEntry( "never_skip", !m_checkIgnoreReadErrors->isChecked() ); + c->writeEntry( "use_index0", m_checkUseIndex0->isChecked() ); + + m_optionWidget->saveConfig( c ); + m_patternWidget->saveConfig( c ); +} + + +#include "k3baudiorippingdialog.moc" diff --git a/src/rip/k3baudiorippingdialog.h b/src/rip/k3baudiorippingdialog.h new file mode 100644 index 0000000..83fe0dc --- /dev/null +++ b/src/rip/k3baudiorippingdialog.h @@ -0,0 +1,92 @@ +/* + * + * $Id: k3baudiorippingdialog.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_AUDIO_RIPPING_DIALOG_H_ +#define _K3B_AUDIO_RIPPING_DIALOG_H_ + +#include <k3binteractiondialog.h> + +#include <qstringlist.h> + +#include <k3bcddbquery.h> + +namespace K3bDevice { + class Device; + class Toc; +} + + +class KListView; +class QCheckBox; +class QSpinBox; +class QComboBox; +class K3bCddbPatternWidget; +class QToolButton; +class K3bAudioConvertingOptionWidget; + + +/** + *@author Sebastian Trueg + */ +class K3bAudioRippingDialog : public K3bInteractionDialog +{ + Q_OBJECT + + public: + K3bAudioRippingDialog( const K3bDevice::Toc&, + K3bDevice::Device*, + const K3bCddbResultEntry&, + const QValueList<int>&, + QWidget *parent = 0, const char *name = 0 ); + ~K3bAudioRippingDialog(); + + void setStaticDir( const QString& path ); + + public slots: + void refresh(); + void init(); + + private: + K3bDevice::Toc m_toc; + K3bDevice::Device* m_device; + K3bCddbResultEntry m_cddbEntry; + QValueList<int> m_trackNumbers; + + KListView* m_viewTracks; + + QComboBox* m_comboParanoiaMode; + QSpinBox* m_spinRetries; + QCheckBox* m_checkIgnoreReadErrors; + QCheckBox* m_checkUseIndex0; + + K3bCddbPatternWidget* m_patternWidget; + K3bAudioConvertingOptionWidget* m_optionWidget; + + void setupGui(); + void setupContextHelp(); + + void loadK3bDefaults(); + void loadUserDefaults( KConfigBase* ); + void saveUserDefaults( KConfigBase* ); + + class Private; + Private* d; + + private slots: + void slotStartClicked(); +}; + +#endif diff --git a/src/rip/k3baudioripthread.cpp b/src/rip/k3baudioripthread.cpp new file mode 100644 index 0000000..8a5a6e9 --- /dev/null +++ b/src/rip/k3baudioripthread.cpp @@ -0,0 +1,602 @@ +/* + * + * $Id: k3baudioripthread.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3baudioripthread.h" +#include "k3bpatternparser.h" + +#include <k3bcdparanoialib.h> +#include <k3bjob.h> +#include <k3baudioencoder.h> +#include <k3bwavefilewriter.h> +#include <k3bglobalsettings.h> +#include <k3bcore.h> +#include "k3bcuefilewriter.h" + +#include <k3bdevice.h> +#include <k3btoc.h> +#include <k3btrack.h> +#include <k3bglobals.h> + +#include <qfile.h> +#include <qfileinfo.h> +#include <qtimer.h> + +#include <kdebug.h> +#include <klocale.h> +#include <kstandarddirs.h> + + + + +class K3bAudioRipThread::Private +{ +public: + Private() + : paranoiaRetries(5), + neverSkip(false), + encoder(0), + waveFileWriter(0), + paranoiaLib(0), + canceled(false) { + } + + // the index of the currently ripped track in m_tracks + int currentTrackIndex; + long overallSectorsRead; + long overallSectorsToRead; + + int paranoiaMode; + int paranoiaRetries; + int neverSkip; + + K3bAudioEncoder* encoder; + K3bWaveFileWriter* waveFileWriter; + + K3bCdparanoiaLib* paranoiaLib; + + bool canceled; + + K3bDevice::Toc toc; + + QString fileType; +}; + + +K3bAudioRipThread::K3bAudioRipThread() + : QObject(), + K3bThread(), + m_device(0), + m_useIndex0(false) +{ + d = new Private(); +} + + +K3bAudioRipThread::~K3bAudioRipThread() +{ + delete d->waveFileWriter; + delete d->paranoiaLib; + delete d; +} + + +void K3bAudioRipThread::setFileType( const QString& t ) +{ + d->fileType = t; +} + + +void K3bAudioRipThread::setParanoiaMode( int mode ) +{ + d->paranoiaMode = mode; +} + + +void K3bAudioRipThread::setMaxRetries( int r ) +{ + d->paranoiaRetries = r; +} + + +void K3bAudioRipThread::setNeverSkip( bool b ) +{ + d->neverSkip = b; +} + + +void K3bAudioRipThread::setEncoder( K3bAudioEncoder* f ) +{ + d->encoder = f; +} + + +void K3bAudioRipThread::run() +{ + emitStarted(); + emitNewTask( i18n("Extracting Digital Audio") ); + + if( !d->paranoiaLib ) { + d->paranoiaLib = K3bCdparanoiaLib::create(); + } + + if( !d->paranoiaLib ) { + emitInfoMessage( i18n("Could not load libcdparanoia."), K3bJob::ERROR ); + emitFinished(false); + return; + } + + // try to open the device + if( !m_device ) { + emitFinished(false); + return; + } + + m_device->block(true); + + emitInfoMessage( i18n("Reading CD table of contents."), K3bJob::INFO ); + d->toc = m_device->readToc(); + + if( !d->paranoiaLib->initParanoia( m_device, d->toc ) ) { + emitInfoMessage( i18n("Could not open device %1").arg(m_device->blockDeviceName()), + K3bJob::ERROR ); + m_device->block(false); + + // check if we have write access to the generic device + if( m_device->interfaceType() == K3bDevice::SCSI && + !m_device->genericDevice().isEmpty() && + !QFileInfo( m_device->genericDevice() ).isWritable() ) + emitInfoMessage( i18n("You need write access to %1").arg( m_device->genericDevice() ), K3bJob::ERROR ); + + emitFinished(false); + return; + } + d->paranoiaLib->setParanoiaMode( d->paranoiaMode ); + d->paranoiaLib->setNeverSkip( d->neverSkip ); + d->paranoiaLib->setMaxRetries( d->paranoiaRetries ); + + + if( !d->encoder ) + if( !d->waveFileWriter ) { + d->waveFileWriter = new K3bWaveFileWriter(); + } + + + if( m_useIndex0 ) { + emitNewSubTask( i18n("Searching index 0 for all tracks") ); + m_device->indexScan( d->toc ); + } + + + d->canceled = false; + d->overallSectorsRead = 0; + d->overallSectorsToRead = 0; + for( unsigned int i = 0; i < m_tracks.count(); ++i ) { + if( m_useIndex0 ) + d->overallSectorsToRead += d->toc[m_tracks[i].first-1].realAudioLength().lba(); + else + d->overallSectorsToRead += d->toc[m_tracks[i].first-1].length().lba(); + } + + + if( m_singleFile ) { + QString& filename = m_tracks[0].second; + + QString dir = filename.left( filename.findRev("/") ); + if( !KStandardDirs::makeDir( dir, 0777 ) ) { + d->paranoiaLib->close(); + emitInfoMessage( i18n("Unable to create directory %1").arg(dir), K3bJob::ERROR ); + m_device->block(false); + emitFinished(false); + return; + } + + // initialize + bool isOpen = true; + if( d->encoder ) { + if( isOpen = d->encoder->openFile( d->fileType, filename, d->overallSectorsToRead ) ) { + // here we use cd Title and Artist + d->encoder->setMetaData( K3bAudioEncoder::META_TRACK_ARTIST, m_cddbEntry.cdArtist ); + d->encoder->setMetaData( K3bAudioEncoder::META_TRACK_TITLE, m_cddbEntry.cdTitle ); + d->encoder->setMetaData( K3bAudioEncoder::META_TRACK_COMMENT, m_cddbEntry.cdExtInfo ); + d->encoder->setMetaData( K3bAudioEncoder::META_ALBUM_ARTIST, m_cddbEntry.cdArtist ); + d->encoder->setMetaData( K3bAudioEncoder::META_ALBUM_TITLE, m_cddbEntry.cdTitle ); + d->encoder->setMetaData( K3bAudioEncoder::META_ALBUM_COMMENT, m_cddbEntry.cdExtInfo ); + d->encoder->setMetaData( K3bAudioEncoder::META_YEAR, QString::number(m_cddbEntry.year) ); + d->encoder->setMetaData( K3bAudioEncoder::META_GENRE, m_cddbEntry.genre ); + } + else + emitInfoMessage( d->encoder->lastErrorString(), K3bJob::ERROR ); + } + else { + isOpen = d->waveFileWriter->open( filename ); + } + + if( !isOpen ) { + d->paranoiaLib->close(); + emitInfoMessage( i18n("Unable to open '%1' for writing.").arg(filename), K3bJob::ERROR ); + m_device->block(false); + emitFinished(false); + return; + } + + emitInfoMessage( i18n("Ripping to single file '%1'.").arg(filename), K3bJob::INFO ); + } + + emitInfoMessage( i18n("Starting digital audio extraction (ripping)."), K3bJob::INFO ); + + bool success = true; + for( unsigned int i = 0; i < m_tracks.count(); ++i ) { + d->currentTrackIndex = i; + if( !ripTrack( m_tracks[i].first, m_singleFile ? m_tracks[0].second : m_tracks[i].second ) ) { + success = false; + break; + } + } + + if( m_singleFile ) { + if( d->encoder ) + d->encoder->closeFile(); + else + d->waveFileWriter->close(); + + if( success && !d->canceled ) { + QString& filename = m_tracks[0].second; + emitInfoMessage( i18n("Successfully ripped to %2.").arg(filename), K3bJob::INFO ); + } + } + + if( !d->canceled && m_writePlaylist ) { + success = success && writePlaylist(); + } + + if( !d->canceled && m_writeCueFile && m_singleFile ) { + if( !m_useIndex0 ) { + emitNewSubTask( i18n("Searching index 0 for all tracks") ); + m_device->indexScan( d->toc ); + } + success = success && writeCueFile(); + } + + d->paranoiaLib->close(); + m_device->block(false); + + if( d->canceled ) { + emitCanceled(); + emitFinished(false); + } + else { + if( k3bcore->globalSettings()->ejectMedia() ) + m_device->eject(); + + emitFinished(success); + } +} + + +bool K3bAudioRipThread::ripTrack( int track, const QString& filename ) +{ + const K3bTrack& tt = d->toc[track-1]; + + long endSec = ( (m_useIndex0 && tt.index0() > 0) + ? tt.firstSector().lba() + tt.index0().lba() - 1 + : tt.lastSector().lba() ); + + if( d->paranoiaLib->initReading( tt.firstSector().lba(), endSec ) ) { + + long trackSectorsRead = 0; + + QString dir = filename.left( filename.findRev("/") ); + if( !KStandardDirs::makeDir( dir, 0777 ) ) { + emitInfoMessage( i18n("Unable to create directory %1").arg(dir), K3bJob::ERROR ); + return false; + } + + // initialize + bool isOpen = true; + if( !m_singleFile ) { + if( d->encoder ) { + if( isOpen = d->encoder->openFile( d->fileType, + filename, + m_useIndex0 ? d->toc[track-1].realAudioLength() : d->toc[track-1].length() ) ) { + + d->encoder->setMetaData( K3bAudioEncoder::META_TRACK_ARTIST, m_cddbEntry.artists[track-1] ); + d->encoder->setMetaData( K3bAudioEncoder::META_TRACK_TITLE, m_cddbEntry.titles[track-1] ); + d->encoder->setMetaData( K3bAudioEncoder::META_TRACK_COMMENT, m_cddbEntry.extInfos[track-1] ); + d->encoder->setMetaData( K3bAudioEncoder::META_TRACK_NUMBER, QString::number(track).rightJustify( 2, '0' ) ); + d->encoder->setMetaData( K3bAudioEncoder::META_ALBUM_ARTIST, m_cddbEntry.cdArtist ); + d->encoder->setMetaData( K3bAudioEncoder::META_ALBUM_TITLE, m_cddbEntry.cdTitle ); + d->encoder->setMetaData( K3bAudioEncoder::META_ALBUM_COMMENT, m_cddbEntry.cdExtInfo ); + d->encoder->setMetaData( K3bAudioEncoder::META_YEAR, QString::number(m_cddbEntry.year) ); + d->encoder->setMetaData( K3bAudioEncoder::META_GENRE, m_cddbEntry.genre ); + } + else + emitInfoMessage( d->encoder->lastErrorString(), K3bJob::ERROR ); + } + else { + isOpen = d->waveFileWriter->open( filename ); + } + + if( !isOpen ) { + emitInfoMessage( i18n("Unable to open '%1' for writing.").arg(filename), K3bJob::ERROR ); + return false; + } + } + + if( !m_cddbEntry.artists[track-1].isEmpty() && + !m_cddbEntry.titles[track-1].isEmpty() ) + emitNewSubTask( i18n("Ripping track %1 (%2 - %3)").arg(track).arg(m_cddbEntry.artists[track-1]).arg(m_cddbEntry.titles[track-1]) ); + else + emitNewSubTask( i18n("Ripping track %1").arg(track) ); + + int status; + while( 1 ) { + if( d->canceled ) { + cleanupAfterCancellation(); + return false; + } + + char* buf = d->paranoiaLib->read( &status ); + if( status == K3bCdparanoiaLib::S_OK ) { + if( buf == 0 ) { + if( m_singleFile ) + emitInfoMessage( i18n("Successfully ripped track %1.").arg(track), K3bJob::INFO ); + else + emitInfoMessage( i18n("Successfully ripped track %1 to %2.").arg(track).arg(filename), K3bJob::INFO ); + + if( !m_singleFile ) { + if( d->encoder ) + d->encoder->closeFile(); + else + d->waveFileWriter->close(); + } + + return true; + } + else { + if( d->encoder ) { + if( d->encoder->encode( buf, + CD_FRAMESIZE_RAW ) < 0 ) { + kdDebug() << "(K3bAudioRipThread) error while encoding." << endl; + emitInfoMessage( d->encoder->lastErrorString(), K3bJob::ERROR ); + emitInfoMessage( i18n("Error while encoding track %1.").arg(track), K3bJob::ERROR ); + return false; + } + } + else + d->waveFileWriter->write( buf, + CD_FRAMESIZE_RAW, + K3bWaveFileWriter::LittleEndian ); + + trackSectorsRead++; + d->overallSectorsRead++; + emitSubPercent( 100*trackSectorsRead/d->toc[track-1].length().lba() ); + emitPercent( 100*d->overallSectorsRead/d->overallSectorsToRead ); + } + } + else { + emitInfoMessage( i18n("Unrecoverable error while ripping track %1.").arg(track), K3bJob::ERROR ); + return false; + } + } + return true; + } + else { + emitInfoMessage( i18n("Error while initializing audio ripping."), K3bJob::ERROR ); + return false; + } +} + + +void K3bAudioRipThread::cancel() +{ + d->canceled = true; + + // what if paranoia is stuck in paranoia_read? + // we need to terminate in that case + // wait for 1 second. I the thread still is working terminate it + // and trigger the finished slot manually + emitInfoMessage( i18n("Cancellation could take a while..."), K3bJob::INFO ); + QTimer::singleShot( 1000, this, SLOT(slotCheckIfThreadStillRunning()) ); +} + + +void K3bAudioRipThread::slotCheckIfThreadStillRunning() +{ + if( running() ) { + d->paranoiaLib->close(); + m_device->block(false); + + // this could happen if the thread is stuck in paranoia_read + // because of an unreadable cd + terminate(); + cleanupAfterCancellation(); + emitCanceled(); + emitFinished(false); + } +} + + +// this needs to be called if the thread was killed due to a hung paranoia_read +void K3bAudioRipThread::cleanupAfterCancellation() +{ + if( d->currentTrackIndex >= 0 && d->currentTrackIndex < (int)m_tracks.count() ) { + if( QFile::exists( m_tracks[d->currentTrackIndex].second ) ) { + QFile::remove( m_tracks[d->currentTrackIndex].second ); + emitInfoMessage( i18n("Removed partial file '%1'.").arg(m_tracks[d->currentTrackIndex].second), K3bJob::INFO ); + } + } +} + + +bool K3bAudioRipThread::writePlaylist() +{ + // this is an absolut path so there is always a "/" + QString playlistDir = m_playlistFilename.left( m_playlistFilename.findRev( "/" ) ); + + if( !KStandardDirs::makeDir( playlistDir ) ) { + emitInfoMessage( i18n("Unable to create directory %1").arg(playlistDir), K3bJob::ERROR ); + return false; + } + + emitInfoMessage( i18n("Writing playlist to %1.").arg( m_playlistFilename ), K3bJob::INFO ); + + QFile f( m_playlistFilename ); + if( f.open( IO_WriteOnly ) ) { + QTextStream t( &f ); + + // format descriptor + t << "#EXTM3U" << endl; + + // now write the entries (or the entry if m_singleFile) + if( m_singleFile ) { + // extra info + t << "#EXTINF:" << d->overallSectorsToRead/75 << ","; + if( !m_cddbEntry.cdArtist.isEmpty() && !m_cddbEntry.cdTitle.isEmpty() ) + t << m_cddbEntry.cdArtist << " - " << m_cddbEntry.cdTitle << endl; + else + t << m_tracks[0].second.mid(m_tracks[0].second.findRev("/") + 1, + m_tracks[0].second.length() - m_tracks[0].second.findRev("/") - 5) + << endl; // filename without extension + + // filename + if( m_relativePathInPlaylist ) + t << findRelativePath( m_tracks[0].second, playlistDir ) + << endl; + else + t << m_tracks[0].second << endl; + } + else { + for( unsigned int i = 0; i < m_tracks.count(); ++i ) { + int trackIndex = m_tracks[i].first-1; + + // extra info + t << "#EXTINF:" << d->toc[trackIndex].length().totalFrames()/75 << ","; + + if( !m_cddbEntry.artists[trackIndex].isEmpty() && !m_cddbEntry.titles[trackIndex].isEmpty() ) + t << m_cddbEntry.artists[trackIndex] << " - " << m_cddbEntry.titles[trackIndex] << endl; + else + t << m_tracks[i].second.mid(m_tracks[i].second.findRev("/") + 1, + m_tracks[i].second.length() + - m_tracks[i].second.findRev("/") - 5) + << endl; // filename without extension + + // filename + if( m_relativePathInPlaylist ) + t << findRelativePath( m_tracks[i].second, playlistDir ) + << endl; + else + t << m_tracks[i].second << endl; + } + } + + return ( t.device()->status() == IO_Ok ); + } + else { + emitInfoMessage( i18n("Unable to open '%1' for writing.").arg(m_playlistFilename), K3bJob::ERROR ); + kdDebug() << "(K3bAudioRipThread) could not open file " << m_playlistFilename << " for writing." << endl; + return false; + } +} + + +bool K3bAudioRipThread::writeCueFile() +{ + K3bCueFileWriter cueWriter; + + // create a new toc and cd-text + K3bDevice::Toc toc; + K3bDevice::CdText text; + text.setPerformer( m_cddbEntry.cdArtist ); + text.setTitle( m_cddbEntry.cdTitle ); + text.reserve( m_tracks.count() ); + K3b::Msf currentSector; + for( unsigned int i = 0; i < m_tracks.count(); ++i ) { + int trackNum = m_tracks[i].first; + + const K3bDevice::Track& oldTrack = d->toc[trackNum-1]; + K3bDevice::Track newTrack( oldTrack ); + newTrack.setFirstSector( currentSector ); + newTrack.setLastSector( (currentSector+=oldTrack.length()) - 1 ); + toc.append( newTrack ); + + K3bDevice::TrackCdText trackText; + trackText.setPerformer( m_cddbEntry.artists[trackNum-1] ); + trackText.setTitle( m_cddbEntry.titles[trackNum-1] ); + text.append( trackText ); + } + + cueWriter.setData( toc ); + cueWriter.setCdText( text ); + + + // we always use a relative filename here + QString imageFile = m_tracks[0].second.section( '/', -1 ); + cueWriter.setImage( imageFile, ( d->fileType.isEmpty() ? QString("WAVE") : d->fileType ) ); + + // use the same base name as the image file + QString cueFile = m_tracks[0].second; + cueFile.truncate( cueFile.findRev(".") ); + cueFile += ".cue"; + + emitInfoMessage( i18n("Writing cue file to %1.").arg(cueFile), K3bJob::INFO ); + + return cueWriter.save( cueFile ); +} + + +QString K3bAudioRipThread::findRelativePath( const QString& absPath, const QString& baseDir ) +{ + QString baseDir_ = K3b::prepareDir( K3b::fixupPath(baseDir) ); + QString path = K3b::fixupPath( absPath ); + + // both paths have an equal beginning. That's just how it's configured by K3b + int pos = baseDir_.find( "/" ); + int oldPos = pos; + while( pos != -1 && path.left( pos+1 ) == baseDir_.left( pos+1 ) ) { + oldPos = pos; + pos = baseDir_.find( "/", pos+1 ); + } + + // now the paths are equal up to oldPos, so that's how "deep" we go + path = path.mid( oldPos+1 ); + baseDir_ = baseDir_.mid( oldPos+1 ); + int numberOfDirs = baseDir_.contains( '/' ); + for( int i = 0; i < numberOfDirs; ++i ) + path.prepend( "../" ); + + return path; +} + + +QString K3bAudioRipThread::jobDescription() const +{ + if( m_cddbEntry.cdTitle.isEmpty() ) + return i18n("Ripping Audio Tracks"); + else + return i18n("Ripping Audio Tracks From '%1'").arg(m_cddbEntry.cdTitle); +} + +QString K3bAudioRipThread::jobDetails() const +{ + if( d->encoder ) + return i18n("1 track (encoding to %1)", + "%n tracks (encoding to %1)", + m_tracks.count() ).arg(d->encoder->fileTypeComment(d->fileType)); + else + return i18n("1 track", "%n tracks", m_tracks.count() ); +} + +#include "k3baudioripthread.moc" diff --git a/src/rip/k3baudioripthread.h b/src/rip/k3baudioripthread.h new file mode 100644 index 0000000..93d600f --- /dev/null +++ b/src/rip/k3baudioripthread.h @@ -0,0 +1,117 @@ +/* + * + * $Id: k3baudioripthread.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3B_AUDIO_RIP_THREAD_H +#define K3B_AUDIO_RIP_THREAD_H + +#include <k3bthread.h> +#include <qobject.h> +#include <qvaluevector.h> +#include <qpair.h> + +#include <k3bcddbquery.h> + + +class K3bAudioEncoder; +class K3bCdparanoiaLib; +namespace K3bDevice { + class Device; +} + + +class K3bAudioRipThread : public QObject, public K3bThread +{ + Q_OBJECT + + public: + K3bAudioRipThread(); + ~K3bAudioRipThread(); + + QString jobDescription() const; + QString jobDetails() const; + + // paranoia settings + void setParanoiaMode( int mode ); + void setMaxRetries( int r ); + void setNeverSkip( bool b ); + + void setSingleFile( bool b ) { m_singleFile = b; } + + void setUseIndex0( bool b ) { m_useIndex0 = b; } + + void setDevice( K3bDevice::Device* dev ) { m_device = dev; } + + void setCddbEntry( const K3bCddbResultEntry& e ) { m_cddbEntry = e; } + + // if 0 (default) wave files are created + void setEncoder( K3bAudioEncoder* f ); + + /** + * Used for encoders that support multiple formats + */ + void setFileType( const QString& ); + + /** + * 1 is the first track + */ + void setTracksToRip( const QValueVector<QPair<int, QString> >& t ) { m_tracks = t; } + + void setWritePlaylist( bool b ) { m_writePlaylist = b; } + void setPlaylistFilename( const QString& s ) { m_playlistFilename = s; } + void setUseRelativePathInPlaylist( bool b ) { m_relativePathInPlaylist = b; } + void setWriteCueFile( bool b ) { m_writeCueFile = b; } + + void cancel(); + + private slots: + void slotCheckIfThreadStillRunning(); + + private: + /** reimplemented from QThread. Does the work */ + void run(); + + bool ripTrack( int track, const QString& filename ); + void cleanupAfterCancellation(); + bool writePlaylist(); + bool writeCueFile(); + + /** + * Finds a relative path from baseDir to absPath + */ + QString findRelativePath( const QString& absPath, const QString& baseDir ); + + K3bCddbResultEntry m_cddbEntry; + K3bDevice::Device* m_device; + + bool m_bUsePattern; + bool m_singleFile; + bool m_useIndex0; + + bool m_writePlaylist; + bool m_relativePathInPlaylist; + QString m_playlistFilename; + + bool m_writeCueFile; + + QValueVector<QPair<int, QString> > m_tracks; + + friend class K3bAudioRipJob; + + class Private; + Private* d; +}; + +#endif diff --git a/src/rip/k3bcddbpatternwidget.cpp b/src/rip/k3bcddbpatternwidget.cpp new file mode 100644 index 0000000..9cea4d5 --- /dev/null +++ b/src/rip/k3bcddbpatternwidget.cpp @@ -0,0 +1,175 @@ +/* + * + * $Id: k3bcddbpatternwidget.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bcddbpatternwidget.h" + +#include <kconfig.h> +#include <klocale.h> +#include <kcombobox.h> +#include <klineedit.h> +#include <kurllabel.h> +#include <kdebug.h> + +#include <qregexp.h> +#include <qvalidator.h> +#include <qwhatsthis.h> +#include <qcheckbox.h> +#include <qlayout.h> + + +K3bCddbPatternWidget::K3bCddbPatternWidget( QWidget* parent, const char* name ) + : base_K3bCddbPatternWidget( parent, name ) +{ + // fix the layout + ((QGridLayout*)layout())->setRowStretch( 4, 1 ); + + // setup validators + // there can never be one of the following characters in both dir and filename: + // * ? " + // additional the filename can never contain a slash / + // and the dir should never start with a slash since it should always be a relative path + + QRegExpValidator* dirValidator = new QRegExpValidator( QRegExp( "[^/][^?\\*\\\"]*" ), this ); + m_comboFilenamePattern->setValidator( dirValidator ); + m_comboPlaylistPattern->setValidator( dirValidator ); + m_editBlankReplace->setValidator( dirValidator ); + + // default pattern + m_comboFilenamePattern->insertItem( i18n("%A - %T/%n - !a='%A'{%a - }%t") ); + m_comboFilenamePattern->insertItem( i18n( "%{albumartist} - %{albumtitle}/%{number} - %{artist} - %{title}" ) ); + m_comboFilenamePattern->insertItem( i18n( "%{genre}/%{albumartist} - %{albumtitle}/Track%{number}" ) ); + m_comboFilenamePattern->insertItem( i18n( "music/ripped-tracks/%a - %t" ) ); + + m_comboPlaylistPattern->insertItem( i18n( "%{albumartist} - %{albumtitle}" ) ); + m_comboPlaylistPattern->insertItem( i18n( "Playlist" ) ); + m_comboPlaylistPattern->insertItem( i18n( "playlists/%{albumartist}/%{albumtitle }" ) ); + + connect( m_comboFilenamePattern, SIGNAL(textChanged(const QString&)), + this, SIGNAL(changed()) ); + connect( m_comboPlaylistPattern, SIGNAL(textChanged(const QString&)), + this, SIGNAL(changed()) ); + connect( m_editBlankReplace, SIGNAL(textChanged(const QString&)), + this, SIGNAL(changed()) ); + connect( m_checkBlankReplace, SIGNAL(toggled(bool)), + this, SIGNAL(changed()) ); + connect( m_specialStringsLabel, SIGNAL(leftClickedURL()), + this, SLOT(slotSeeSpecialStrings()) ); + connect( m_conditionalInclusionLabel, SIGNAL(leftClickedURL()), + this, SLOT(slotSeeConditionalInclusion()) ); +} + + +K3bCddbPatternWidget::~K3bCddbPatternWidget() +{ +} + + +QString K3bCddbPatternWidget::filenamePattern() const +{ + return m_comboFilenamePattern->currentText(); +} + + +QString K3bCddbPatternWidget::playlistPattern() const +{ + return m_comboPlaylistPattern->currentText(); +} + + +QString K3bCddbPatternWidget::blankReplaceString() const +{ + return m_editBlankReplace->text(); +} + + +bool K3bCddbPatternWidget::replaceBlanks() const +{ + return m_checkBlankReplace->isChecked(); +} + + +void K3bCddbPatternWidget::loadConfig( KConfigBase* c ) +{ + m_comboPlaylistPattern->setEditText( c->readEntry( "playlist pattern", m_comboPlaylistPattern->text(0) ) ); + m_comboFilenamePattern->setEditText( c->readEntry( "filename pattern", m_comboFilenamePattern->text(0) ) ); + m_checkBlankReplace->setChecked( c->readBoolEntry( "replace blanks", false ) ); + m_editBlankReplace->setText( c->readEntry( "blank replace string", "_" ) ); +} + + +void K3bCddbPatternWidget::saveConfig( KConfigBase* c ) +{ + c->writeEntry( "playlist pattern", m_comboPlaylistPattern->currentText() ); + c->writeEntry( "filename pattern", m_comboFilenamePattern->currentText() ); + c->writeEntry( "replace blanks", m_checkBlankReplace->isChecked() ); + c->writeEntry( "blank replace string", m_editBlankReplace->text() ); +} + + +void K3bCddbPatternWidget::loadDefaults() +{ + m_comboPlaylistPattern->setEditText( m_comboPlaylistPattern->text(0) ); + m_comboFilenamePattern->setEditText( m_comboFilenamePattern->text(0) ); + m_checkBlankReplace->setChecked( false ); + m_editBlankReplace->setText( "_" ); +} + + +void K3bCddbPatternWidget::slotSeeSpecialStrings() +{ + QWhatsThis::display( i18n( "<p><b>Pattern special strings:</b>" + "<p>The following strings will be replaced with their respective meaning in every " + "track name.<br>" + "<em>Hint:</em> %A differs from %a only on soundtracks or compilations." + "<p><table border=\"0\">" + "<tr><td></td><td><em>Meaning</em></td><td><em>Alternatives</em></td></tr>" + "<tr><td>%a</td><td>artist of the track</td><td>%{a} or %{artist}</td></tr>" + "<tr><td>%t</td><td>title of the track</td><td>%{t} or %{title}</td></tr>" + "<tr><td>%n</td><td>track number</td><td>%{n} or %{number}</td></tr>" + "<tr><td>%y</td><td>year of the CD</td><td>%{y} or %{year}</td></tr>" + "<tr><td>%c</td><td>extended track information</td><td>%{c} or %{comment}</td></tr>" + "<tr><td>%g</td><td>genre of the CD</td><td>%{g} or %{genre}</td></tr>" + "<tr><td>%A</td><td>album artist</td><td>%{A} or %{albumartist}</td></tr>" + "<tr><td>%T</td><td>album title</td><td>%{T} or %{albumtitle}</td></tr>" + "<tr><td>%C</td><td>extended CD information</td><td>%{C} or %{albumcomment}</td></tr>" + "<tr><td>%d</td><td>current date</td><td>%{d} or %{date}</td></tr>" + "</table>") ); +} + +void K3bCddbPatternWidget::slotSeeConditionalInclusion() +{ + QWhatsThis::display( i18n( "<p><b>Conditional inclusion:</b>" + "<p>These patterns make it possible to selectively include texts, " + "depending on the value of CDDB entries. You can choose only to " + "include or exclude texts if one of the entries is empty, " + "or if it has a specific value. Examples:" + "<ul>" + "<li>@T{TEXT} includes TEXT if the album title is specified" + "<li>!T{TEXT} includes TEXT if the album title is not specified" + "<li>@C=\'Soundtrack\'{TEXT} includes TEXT if the CD's extended " + "information is named Soundtrack" + "<li>!C=\'Soundtrack\'{TEXT} includes TEXT if the CD's extended " + "information is anything else but Soundtrack" + "<li>It is also possible to include special strings in texts and conditions, " + "e.g. !a='%A'{%a} only includes the title's artist information " + "if it does not differ from the album artist." + "</ul>" + "<p>Conditional includes make use of the same characters as the special " + "strings, which means that the X in @X{...} can be one character out of " + "[atnycgATCd]." ) ); +} + +#include "k3bcddbpatternwidget.moc" + diff --git a/src/rip/k3bcddbpatternwidget.h b/src/rip/k3bcddbpatternwidget.h new file mode 100644 index 0000000..928b95b --- /dev/null +++ b/src/rip/k3bcddbpatternwidget.h @@ -0,0 +1,51 @@ +/* + * + * $Id: k3bcddbpatternwidget.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_CDDB_PATTERN_WIDGET_H_ +#define _K3B_CDDB_PATTERN_WIDGET_H_ + +#include "base_k3bcddbpatternwidget.h" + +class KConfigBase; + + +class K3bCddbPatternWidget : public base_K3bCddbPatternWidget +{ + Q_OBJECT + + public: + K3bCddbPatternWidget( QWidget* parent = 0, const char* name = 0 ); + ~K3bCddbPatternWidget(); + + QString filenamePattern() const; + QString playlistPattern() const; + QString blankReplaceString() const; + bool replaceBlanks() const; + + signals: + void changed(); + + public slots: + void loadConfig( KConfigBase* ); + void saveConfig( KConfigBase* ); + void loadDefaults(); + + private slots: + void slotSeeSpecialStrings(); + void slotSeeConditionalInclusion(); +}; + +#endif diff --git a/src/rip/k3bcuefilewriter.cpp b/src/rip/k3bcuefilewriter.cpp new file mode 100644 index 0000000..087002d --- /dev/null +++ b/src/rip/k3bcuefilewriter.cpp @@ -0,0 +1,91 @@ +/* + * + * $Id: k3bcuefilewriter.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bcuefilewriter.h" + +#include <k3btrack.h> +#include <k3bmsf.h> +#include <k3bcore.h> +#include <k3bversion.h> + +#include <qfile.h> +#include <qtextstream.h> +#include <qdatetime.h> + + +K3bCueFileWriter::K3bCueFileWriter() +{ +} + + +bool K3bCueFileWriter::save( const QString& filename ) +{ + QFile f( filename ); + + if( !f.open( IO_WriteOnly ) ) { + kdDebug() << "(K3bCueFileWriter) could not open file " << f.name() << endl; + return false; + } + + QTextStream s( &f ); + + return save( s ); +} + + +bool K3bCueFileWriter::save( QTextStream& t ) +{ + t << "REM Cue file written by K3b " << k3bcore->version() << endl + << endl; + + if( !m_cdText.isEmpty() ) { + t << "PERFORMER \"" << m_cdText.performer() << "\"" << endl; + t << "TITLE \"" << m_cdText.title() << "\"" << endl; + } + + t << "FILE \"" << m_image << "\" " << m_dataType.upper() << endl; + + // the tracks + unsigned int i = 0; + for( K3bDevice::Toc::const_iterator it = m_toc.begin(); + it != m_toc.end(); ++it ) { + + const K3bDevice::Track& track = *it; + + t << " TRACK " << QString::number(i+1).rightJustify( 2, '0' ) << " AUDIO" << endl; + + if( m_cdText.count() > i && !m_cdText[i].isEmpty() ) { + t << " PERFORMER \"" << m_cdText[i].performer() << "\"" << endl; + t << " TITLE \"" << m_cdText[i].title() << "\"" << endl; + } + + // + // the pregap is part of the current track like in toc files + // and not part of the last track as on the CD + // + if( i > 0 ) { + --it; + if( (*it).index0() > 0 ) + t << " INDEX 00 " << ((*it).firstSector() + (*it).index0()).toString() << endl; + ++it; + } + t << " INDEX 01 " << track.firstSector().toString() << endl; + // TODO: add additional indices + + i++; + } + + return ( t.device()->status() == IO_Ok ); +} diff --git a/src/rip/k3bcuefilewriter.h b/src/rip/k3bcuefilewriter.h new file mode 100644 index 0000000..88f7ffe --- /dev/null +++ b/src/rip/k3bcuefilewriter.h @@ -0,0 +1,54 @@ +/* + * + * $Id: k3bcuefilewriter.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_CUE_FILE_WRITER_H_ +#define _K3B_CUE_FILE_WRITER_H_ + +#include <qtextstream.h> +#include <qstringlist.h> + +#include <k3btoc.h> +#include <k3bcdtext.h> + +namespace K3bDevice { + class TrackCdText; +} + +/** + * Write a CDRWIN cue file. + * For now this writer only supports audio CDs + * for usage in the K3b audio CD ripper. + */ + +class K3bCueFileWriter +{ + public: + K3bCueFileWriter(); + + bool save( QTextStream& ); + bool save( const QString& filename ); + + void setData( const K3bDevice::Toc& toc ) { m_toc = toc; } + void setCdText( const K3bDevice::CdText& text ) { m_cdText = text; } + void setImage( const QString& name, const QString& type ) { m_image = name; m_dataType = type; } + + private: + K3bDevice::Toc m_toc; + K3bDevice::CdText m_cdText; + QString m_image; + QString m_dataType; +}; + +#endif diff --git a/src/rip/k3bpatternparser.cpp b/src/rip/k3bpatternparser.cpp new file mode 100644 index 0000000..8ba04e6 --- /dev/null +++ b/src/rip/k3bpatternparser.cpp @@ -0,0 +1,305 @@ +/* + * + * $Id: k3bpatternparser.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * Copyright (C) 2004-2005 Jakob Petsovits <jpetso@gmx.at> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3bpatternparser.h" + +#include <qregexp.h> +#include <qdatetime.h> +#include <qvaluestack.h> + +#include <kglobal.h> +#include <klocale.h> + + +QString K3bPatternParser::parsePattern( const K3bCddbResultEntry& entry, + unsigned int trackNumber, + const QString& pattern, + bool replace, + const QString& replaceString ) +{ + if( entry.titles.count() < trackNumber ) + return ""; + + QString dir, s; + char c = ' '; // contains the character representation of a special string + unsigned int len; // length of the current special string + + + for( unsigned int i = 0; i < pattern.length(); ++i ) { + + if( pattern[i] == '%' ) { + + if( i + 1 < pattern.length() ) { + len = 2; + + if( pattern[i+1] != '{' ) { // strings like %a + c = pattern[i+1]; + } + else if( i + 3 >= pattern.length() ) { // too short to contain a %{*} string + c = ' '; + } + else { // long enough to contain %{*} + + if( pattern[i+3] == '}' ) { // strings like %{a} + c = pattern[i+2]; + len = 4; + } + else { // strings like %{artist}, or anything like %{* + + while( i + len - 1 < pattern.length() ) { + ++len; + + if( pattern[i + len - 1] == '%' ) { // don't touch other special strings + c = ' '; + --len; + break; + } + else if( pattern[i + len - 1] == '}' ) { + s = pattern.mid( i + 2, len - 3 ); + + if( s == "title" ) { + c = TITLE; + } + else if( s == "artist" ) { + c = ARTIST; + } + else if( s == "number" ) { + c = NUMBER; + } + else if( s == "comment" ) { + c = COMMENT; + } + else if( s == "year" ) { + c = YEAR; + } + else if( s == "genre" ) { + c = GENRE; + } + else if( s == "albumtitle" ) { + c = ALBUMTITLE; + } + else if( s == "albumartist" ) { + c = ALBUMARTIST; + } + else if( s == "albumcomment" ) { + c = ALBUMCOMMENT; + } + else if( s == "date" ) { + c = DATE; + } + else { // no valid pattern in here, don't replace anything + c = ' '; + } + break; // finished parsing %{* string + } + } // end of while(...) + + } // end of %{* strings + + } // end of if( long enough to contain %{*} ) + + switch( c ) { + case ARTIST: + s = entry.artists[trackNumber-1]; + s.replace( '/', '_' ); + s.replace( '*', '_' ); + s.replace( '}', '*' ); // for conditional inclusion + dir.append( s.isEmpty() + ? i18n("unknown") + QString(" %1").arg(trackNumber) + : s ); + break; + case TITLE: + s = entry.titles[trackNumber-1]; + s.replace( '/', '_' ); + s.replace( '*', '_' ); + s.replace( '}', '*' ); + dir.append( s.isEmpty() + ? i18n("Track %1").arg(trackNumber) + : s ); + break; + case NUMBER: + dir.append( QString::number(trackNumber).rightJustify( 2, '0' ) ); + break; + case YEAR: + dir.append( QString::number( entry.year ) ); + break; + case COMMENT: + s = entry.extInfos[trackNumber-1]; + s.replace( '/', '_' ); + s.replace( '*', '_' ); + s.replace( '}', '*' ); + dir.append( s ); + break; + case GENRE: + s = ( entry.genre.isEmpty() ? entry.category : entry.genre ); + s.replace( '/', '_' ); + s.replace( '*', '_' ); + s.replace( '}', '*' ); + dir.append( s ); + break; + case ALBUMARTIST: + dir.append( entry.cdArtist.isEmpty() + ? i18n("unknown") : entry.cdArtist ); + break; + case ALBUMTITLE: + s = entry.cdTitle; + s.replace( '/', '_' ); + s.replace( '*', '_' ); + s.replace( '}', '*' ); + dir.append( s.isEmpty() + ? i18n("unknown") : s ); + break; + case ALBUMCOMMENT: + s = entry.cdExtInfo; + s.replace( '/', '_' ); + s.replace( '*', '_' ); + s.replace( '}', '*' ); + dir.append( s ); // I think it makes more sense to allow empty comments + break; + case DATE: + dir.append( KGlobal::locale()->formatDate( QDate::currentDate() ) ); + break; + default: + dir.append( pattern.mid(i, len) ); + break; + } + i += len - 1; + } + else { // end of pattern + dir.append( "%" ); + } + } + else { + dir.append( pattern[i] ); + } + } + + + + // /* delete line comment to comment out + // the following part: Conditional Inclusion + + QValueStack<int> offsetStack; + QString inclusion; + bool isIncluded; + + static QRegExp conditionrx( "^[@|!][atyegrmx](?:='.*')?\\{" ); + conditionrx.setMinimal( TRUE ); + + for( unsigned int i = 0; i < dir.length(); ++i ) { + + offsetStack.push( + conditionrx.search(dir, i, QRegExp::CaretAtOffset) ); + + if( offsetStack.top() == -1 ) { + offsetStack.pop(); + } + else { + i += conditionrx.matchedLength() - 1; + continue; + } + + if( dir[i] == '}' && !offsetStack.isEmpty() ) { + + int offset = offsetStack.pop(); + int length = i - offset + 1; + + switch( (QChar) dir[offset+1] ) { + case ARTIST: + s = entry.artists[trackNumber-1]; + break; + case TITLE: + s = entry.titles[trackNumber-1]; + break; + case NUMBER: + s = QString::number( trackNumber ); + break; + case YEAR: + s = QString::number( entry.year ); + break; + case COMMENT: + s = entry.extInfos[trackNumber-1]; + break; + case GENRE: + s = ( entry.genre.isEmpty() ? entry.category : entry.genre ); + break; + case ALBUMARTIST: + s = entry.cdArtist; + break; + case ALBUMTITLE: + s = entry.cdTitle; + break; + case ALBUMCOMMENT: + s = entry.cdExtInfo; + break; + case DATE: + s = KGlobal::locale()->formatDate( QDate::currentDate() ); + break; + default: // we must never get here, + break; // all choices should be covered + } + + if( dir[offset+2] == '{' ) { // no string matching, e.g. ?y{text} + switch( (QChar) dir[offset+1] ) { + case YEAR: + isIncluded = (s != "0"); + break; + default: + isIncluded = !s.isEmpty(); + break; + } + inclusion = dir.mid( offset + 3, length - 4 ); + } + else { // with string matching, e.g. ?y='2004'{text} + + // Be aware that there might be ' in the condition text + int endOfCondition = dir.find( '{', offset+4 )-1; + QString condition = dir.mid( offset+4, + endOfCondition - (offset+4) ); + + isIncluded = (s == condition); + inclusion = dir.mid( endOfCondition+2, + i - (endOfCondition+2) ); + } + + if( dir[offset] == '!' ) + isIncluded = !isIncluded; + // Leave it when it's '@'. + + dir.replace( offset, length, ( isIncluded ? inclusion : QString("") ) ); + + if( isIncluded == TRUE ) + i -= length - inclusion.length(); + else + i = offset - 1; // start next loop at offset + + continue; + + } // end of replace (at closing bracket '}') + + } // end of conditional inclusion for(...) + + // end of Conditional Inclusion */ + + + dir.replace( '*', '}' ); // bring the brackets back, if there were any + + if( replace ) + dir.replace( QRegExp( "\\s" ), replaceString ); + + return dir; +} diff --git a/src/rip/k3bpatternparser.h b/src/rip/k3bpatternparser.h new file mode 100644 index 0000000..88a725d --- /dev/null +++ b/src/rip/k3bpatternparser.h @@ -0,0 +1,52 @@ +/* + * + * $Id: k3bpatternparser.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef K3BPATTERNPARSER_H +#define K3BPATTERNPARSER_H + +#include <qstring.h> + +#include <k3bcddbquery.h> + + +/** + *@author Sebastian Trueg + */ +class K3bPatternParser +{ + public: + static QString parsePattern( const K3bCddbResultEntry& entry, + unsigned int trackNumber, + const QString& pattern, + bool replace = false, + const QString& replaceString = "_" ); + + private: + enum { + TITLE = 't', + ARTIST = 'a', + NUMBER = 'n', + COMMENT = 'c', + YEAR = 'y', + GENRE = 'g', + ALBUMTITLE = 'T', + ALBUMARTIST = 'A', + ALBUMCOMMENT = 'C', + DATE = 'd' + }; +}; + +#endif diff --git a/src/rip/k3bvideocdinfo.cpp b/src/rip/k3bvideocdinfo.cpp new file mode 100644 index 0000000..ac30d40 --- /dev/null +++ b/src/rip/k3bvideocdinfo.cpp @@ -0,0 +1,247 @@ +/* +* +* $Id: k3bvideocdinfo.cpp 619556 2007-01-03 17:38:12Z trueg $ +* Copyright (C) 2003 Christian Kvasny <chris@k3b.org> +* +* This file is part of the K3b project. +* Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> +* +* 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 2 of the License, or +* (at your option) any later version. +* See the file "COPYING" for the exact licensing terms. +*/ + + + +#include <qstring.h> +#include <qvaluelist.h> +#include <qstringlist.h> +#include <qtimer.h> +#include <qdom.h> + +#include <klocale.h> +#include <kconfig.h> +#include <kdebug.h> + +#include "k3bvideocdinfo.h" + +#include <k3bprocess.h> +#include <k3bexternalbinmanager.h> + + +K3bVideoCdInfo::K3bVideoCdInfo( QObject* parent, const char* name ) + : QObject( parent, name ) +{ + m_process = 0L; + m_isXml = false; +} + + +K3bVideoCdInfo::~K3bVideoCdInfo() +{ + delete m_process; +} + +void K3bVideoCdInfo::cancelAll() +{ + if ( m_process->isRunning() ) { + m_process->disconnect( this ); + m_process->kill(); + } +} + +void K3bVideoCdInfo::info( const QString& device ) +{ + if ( !k3bcore ->externalBinManager() ->foundBin( "vcdxrip" ) ) { + kdDebug() << "(K3bVideoCdInfo::info) could not find vcdxrip executable" << endl; + emit infoFinished( false ); + return ; + } + + delete m_process; + m_process = new K3bProcess(); + + *m_process << k3bcore ->externalBinManager() ->binPath( "vcdxrip" ); + + *m_process << "-q" << "--norip" << "-i" << device << "-o" << "-"; + + connect( m_process, SIGNAL( receivedStderr( KProcess*, char*, int ) ), + this, SLOT( slotParseOutput( KProcess*, char*, int ) ) ); + connect( m_process, SIGNAL( receivedStdout( KProcess*, char*, int ) ), + this, SLOT( slotParseOutput( KProcess*, char*, int ) ) ); + connect( m_process, SIGNAL( processExited( KProcess* ) ), + this, SLOT( slotInfoFinished() ) ); + + if ( !m_process->start( KProcess::NotifyOnExit, KProcess::AllOutput ) ) { + kdDebug() << "(K3bVideoCdInfo::info) could not start vcdxrip" << endl; + cancelAll(); + emit infoFinished( false ); + } +} + +void K3bVideoCdInfo::slotParseOutput( KProcess*, char* output, int len ) +{ + QString buffer = QString::fromLocal8Bit( output, len ); + + // split to lines + QStringList lines = QStringList::split( "\n", buffer ); + QStringList::Iterator end( lines.end()); + for ( QStringList::Iterator str = lines.begin(); str != end; ++str ) { + + if ( ( *str ).contains( "<?xml" ) ) + m_isXml = true; + + if ( m_isXml ) + m_xmlData += *str; + else + kdDebug() << "(K3bVideoCdInfo::slotParseOutput) " << *str << endl; + + if ( ( *str ).contains( "</videocd>" ) ) + m_isXml = false; + } +} + +void K3bVideoCdInfo::slotInfoFinished() +{ + if ( m_process->normalExit() ) { + // TODO: check the process' exitStatus() + switch ( m_process->exitStatus() ) { + case 0: + break; + default: + cancelAll(); + emit infoFinished( false ); + return ; + } + } else { + cancelAll(); + emit infoFinished( false ); + return ; + } + + if ( m_xmlData.isEmpty() ) { + emit infoFinished( false ); + return ; + } + + parseXmlData(); + emit infoFinished( true ); +} + +void K3bVideoCdInfo::parseXmlData() +{ + QDomDocument xml_doc; + QDomElement xml_root; + + m_Result.xmlData = m_xmlData; + + xml_doc.setContent( m_xmlData ); + xml_root = xml_doc.documentElement(); + + m_Result.type = xml_root.attribute( "class" ); + m_Result.version = xml_root.attribute( "version" ); + + for ( QDomNode node = xml_root.firstChild(); !node.isNull(); node = node.nextSibling() ) { + QDomElement el = node.toElement(); + QString tagName = el.tagName().lower(); + + if ( tagName == "pvd" ) { + for ( QDomNode snode = node.firstChild(); !snode.isNull(); snode = snode.nextSibling() ) { + QDomElement sel = snode.toElement(); + QString pvdElement = sel.tagName().lower(); + QString pvdElementText = sel.text(); + if ( pvdElement == "volume-id" ) + m_Result.volumeId = pvdElementText; + } + + } else if ( tagName == "sequence-items" ) { + for ( QDomNode snode = node.firstChild(); !snode.isNull(); snode = snode.nextSibling() ) { + QDomElement sel = snode.toElement(); + QString seqElement = sel.tagName().lower(); + m_Result.addEntry( K3bVideoCdInfoResultEntry( + sel.attribute( "src" ), + sel.attribute( "id" ) ), + K3bVideoCdInfoResult::SEQUENCE + ); + } + } else if ( tagName == "segment-items" ) { + for ( QDomNode snode = node.firstChild(); !snode.isNull(); snode = snode.nextSibling() ) { + QDomElement sel = snode.toElement(); + QString seqElement = sel.tagName().lower(); + m_Result.addEntry( K3bVideoCdInfoResultEntry( + sel.attribute( "src" ), + sel.attribute( "id" ) ), + K3bVideoCdInfoResult::SEGMENT + ); + } + } else { + kdDebug() << QString( "(K3bVideoCdInfo::parseXmlData) tagName '%1' not used" ).arg( tagName ) << endl; + } + } +} + +const K3bVideoCdInfoResult& K3bVideoCdInfo::result() const +{ + return m_Result; +} + +const K3bVideoCdInfoResultEntry& K3bVideoCdInfoResult::entry( unsigned int number, int type ) const +{ + switch ( type ) { + case K3bVideoCdInfoResult::FILE: + if ( number >= m_fileEntry.count() ) + return m_emptyEntry; + return m_fileEntry[ number ]; + case K3bVideoCdInfoResult::SEGMENT: + if ( number >= m_segmentEntry.count() ) + return m_emptyEntry; + return m_segmentEntry[ number ]; + case K3bVideoCdInfoResult::SEQUENCE: + if ( number >= m_sequenceEntry.count() ) + return m_emptyEntry; + return m_sequenceEntry[ number ]; + default: + kdDebug() << "(K3bVideoCdInfoResult::entry) not supported entrytype." << endl; + } + + return m_emptyEntry; + +} + + +void K3bVideoCdInfoResult::addEntry( const K3bVideoCdInfoResultEntry& entry, int type ) +{ + switch ( type ) { + case K3bVideoCdInfoResult::FILE: + m_fileEntry.append( entry ); + break; + case K3bVideoCdInfoResult::SEGMENT: + m_segmentEntry.append( entry ); + break; + case K3bVideoCdInfoResult::SEQUENCE: + m_sequenceEntry.append( entry ); + break; + default: + kdDebug() << "(K3bVideoCdInfoResult::addEntry) not supported entrytype." << endl; + } +} + +int K3bVideoCdInfoResult::foundEntries( int type ) const +{ + switch ( type ) { + case K3bVideoCdInfoResult::FILE: + return m_fileEntry.count(); + case K3bVideoCdInfoResult::SEGMENT: + return m_segmentEntry.count(); + case K3bVideoCdInfoResult::SEQUENCE: + return m_sequenceEntry.count(); + default: + kdDebug() << "(K3bVideoCdInfoResult::addEntry) not supported entrytype." << endl; + } + return 0; +} + +#include "k3bvideocdinfo.moc" + diff --git a/src/rip/k3bvideocdinfo.h b/src/rip/k3bvideocdinfo.h new file mode 100644 index 0000000..0b295e6 --- /dev/null +++ b/src/rip/k3bvideocdinfo.h @@ -0,0 +1,107 @@ +/* +* +* $Id: k3bvideocdinfo.h 619556 2007-01-03 17:38:12Z trueg $ +* Copyright (C) 2003 Christian Kvasny <chris@k3b.org> +* +* This file is part of the K3b project. +* Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> +* +* 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 2 of the License, or +* (at your option) any later version. +* See the file "COPYING" for the exact licensing terms. +*/ + + +#ifndef K3BVIDEOCDINFO_H +#define K3BVIDEOCDINFO_H + +#include <qstring.h> +#include <qstringlist.h> +#include <qobject.h> + +#include <k3btoc.h> +#include <k3bcore.h> + +class KProcess; + +class K3bVideoCdInfoResultEntry +{ + public: + K3bVideoCdInfoResultEntry() : name( 0 ), id( 0 ) + {} + + K3bVideoCdInfoResultEntry( const QString& name, const QString& id ) + : name( name ), id( id ) + {} + + QString name; + QString id; + + long size; +}; + +class K3bVideoCdInfoResult +{ + public: + K3bVideoCdInfoResult() + {} + + enum type {NONE = 0, FILE, SEGMENT, SEQUENCE}; + + void addEntry( const K3bVideoCdInfoResultEntry& = K3bVideoCdInfoResultEntry(), int type = K3bVideoCdInfoResult::SEQUENCE ); + const K3bVideoCdInfoResultEntry& entry( unsigned int number = 0 , int type = K3bVideoCdInfoResult::SEQUENCE ) const; + int foundEntries( int type = K3bVideoCdInfoResult::SEQUENCE ) const; + + QString volumeId; + QString type; + QString version; + + QString xmlData; + + private: + QValueList<K3bVideoCdInfoResultEntry> m_fileEntry; + QValueList<K3bVideoCdInfoResultEntry> m_segmentEntry; + QValueList<K3bVideoCdInfoResultEntry> m_sequenceEntry; + + K3bVideoCdInfoResultEntry m_emptyEntry; +}; + +class K3bVideoCdInfo : public QObject +{ + Q_OBJECT + + public: + K3bVideoCdInfo( QObject* parent = 0, const char* name = 0 ); + ~K3bVideoCdInfo(); + + /** + * Do NOT call this before queryResult has + * been emitted + */ + const K3bVideoCdInfoResult& result() const; + + void info( const QString& ); + + signals: + void infoFinished( bool success ); + + private slots: + void slotInfoFinished(); + void slotParseOutput( KProcess*, char* output, int len ); + + private: + void cancelAll(); + + K3bVideoCdInfoResult m_Result; + void parseXmlData(); + + KProcess* m_process; + + QString m_xmlData; + bool m_isXml; + +}; + +#endif diff --git a/src/rip/k3bvideocdrip.cpp b/src/rip/k3bvideocdrip.cpp new file mode 100644 index 0000000..a7467c9 --- /dev/null +++ b/src/rip/k3bvideocdrip.cpp @@ -0,0 +1,355 @@ +/* +* +* $Id: k3bvideocdrip.cpp 619556 2007-01-03 17:38:12Z trueg $ +* Copyright (C) 2003 Christian Kvasny <chris@k3b.org> +* +* This file is part of the K3b project. +* Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> +* +* 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 2 of the License, or +* (at your option) any later version. +* See the file "COPYING" for the exact licensing terms. +*/ + +#include <kconfig.h> +#include <kdebug.h> +#include <kio/global.h> +#include <klocale.h> +#include <kstandarddirs.h> +#include <ktempfile.h> +#include <kurl.h> + +#include <qdatetime.h> +#include <qdom.h> +#include <qfile.h> +#include <qstring.h> +#include <qregexp.h> +#include <qtimer.h> +#include <qurl.h> + +// K3b Includes +#include "k3bvideocdrip.h" +#include <k3bcore.h> +#include <k3bexternalbinmanager.h> +#include <k3bglobals.h> +#include <k3bprocess.h> + +K3bVideoCdRip::K3bVideoCdRip( K3bJobHandler* hdl, K3bVideoCdRippingOptions* options, QObject* parent, const char* name ) + : K3bJob( hdl, parent, name ), + m_ripsourceType( 0 ), + m_subPosition ( 0 ), + m_videooptions( options ), + m_canceled( false ), + m_process( 0 ) +{} + + +K3bVideoCdRip::~K3bVideoCdRip() +{ + if ( m_process ) + delete m_process; + +} + + +void K3bVideoCdRip::cancel() +{ + cancelAll(); + + emit infoMessage( i18n( "Job canceled by user." ), K3bJob::ERROR ); + emit canceled(); + jobFinished( false ); +} + + +void K3bVideoCdRip::cancelAll() +{ + m_canceled = true; + + if ( m_process->isRunning() ) { + m_process->disconnect( this ); + m_process->kill(); + } +} + + +void K3bVideoCdRip::start() +{ + kdDebug() << "(K3bVideoCdRip) starting job" << endl; + + jobStarted(); + m_canceled = false; + + vcdxRip(); +} + +void K3bVideoCdRip::vcdxRip() +{ + emit newTask( i18n( "Check files" ) ); + + m_stage = stageUnknown; + delete m_process; + m_process = new K3bProcess(); + + const K3bExternalBin* bin = k3bcore ->externalBinManager() ->binObject( "vcdxrip" ); + + if ( !bin ) { + kdDebug() << "(K3bVideoCdRip) could not find vcdxrip executable" << endl; + emit infoMessage( i18n( "Could not find %1 executable." ).arg( "vcdxrip" ), K3bJob::ERROR ); + emit infoMessage( i18n( "To rip VideoCD's you must install VcdImager Version %1." ).arg( ">= 0.7.12" ), K3bJob::INFO ); + emit infoMessage( i18n( "You can find this on your distribution disks or download it from http://www.vcdimager.org" ), K3bJob::INFO ); + cancelAll(); + jobFinished( false ); + return ; + } + + if( bin->version < K3bVersion("0.7.12") ) { + kdDebug() << "(K3bVideoCdRip) vcdxrip executable too old!" << endl; + emit infoMessage( i18n( "%1 executable too old! Need version %2 or greater" ).arg( "Vcdxrip" ).arg( "0.7.12" ), K3bJob::ERROR ); + emit infoMessage( i18n( "You can find this on your distribution disks or download it from http://www.vcdimager.org" ), K3bJob::INFO ); + cancelAll(); + jobFinished( false ); + return ; + } + + if ( !bin->copyright.isEmpty() ) + emit infoMessage( i18n( "Using %1 %2 - Copyright (C) %3" ).arg( bin->name() ).arg( bin->version ).arg( bin->copyright ), INFO ); + + + *m_process << k3bcore ->externalBinManager() ->binPath( "vcdxrip" ); + + // additional user parameters from config + const QStringList& params = k3bcore->externalBinManager() ->program( "vcdxrip" ) ->userParameters(); + for ( QStringList::const_iterator it = params.begin(); it != params.end(); ++it ) + *m_process << *it; + + *m_process << "--gui" << "--progress"; + + if ( !m_videooptions ->getVideoCdRipFiles() ) + *m_process << "--nofiles"; + + if ( !m_videooptions ->getVideoCdRipSegments() ) + *m_process << "--nosegments"; + + if ( !m_videooptions ->getVideoCdRipSequences() ) + *m_process << "--nosequences"; + + if ( m_videooptions ->getVideoCdIgnoreExt() ) + *m_process << "--no-ext-psd"; + + if ( m_videooptions ->getVideoCdSector2336() ) + *m_process << "--sector-2336"; + + *m_process << "-i" << QString( "%1" ).arg( QFile::encodeName( m_videooptions ->getVideoCdSource() ) ); + + if ( m_videooptions ->getVideoCdExtractXml() ) + *m_process << "-o" << QString( "%1" ).arg( QFile::encodeName( m_videooptions ->getVideoCdDescription() + ".xml" ) ); + else + *m_process << "-o" << "/dev/null"; + + + connect( m_process, SIGNAL( receivedStderr( KProcess*, char*, int ) ), + this, SLOT( slotParseVcdXRipOutput( KProcess*, char*, int ) ) ); + connect( m_process, SIGNAL( receivedStdout( KProcess*, char*, int ) ), + this, SLOT( slotParseVcdXRipOutput( KProcess*, char*, int ) ) ); + connect( m_process, SIGNAL( processExited( KProcess* ) ), + this, SLOT( slotVcdXRipFinished() ) ); + + m_process->setWorkingDirectory( QUrl( m_videooptions ->getVideoCdDestination() ).dirPath() ); + + // vcdxrip commandline parameters + kdDebug() << "***** vcdxrip parameters:" << endl; + ; + const QValueList<QCString>& args = m_process->args(); + QString s; + for ( QValueList<QCString>::const_iterator it = args.begin(); it != args.end(); ++it ) { + s += *it + " "; + } + kdDebug() << s << flush << endl; + emit debuggingOutput( "vcdxrip command:", s ); + + emit newTask( i18n( "Extracting" ) ); + emit infoMessage( i18n( "Start extracting." ), K3bJob::INFO ); + emit infoMessage( i18n( "Extract files from %1 to %2." ).arg( m_videooptions ->getVideoCdSource() ).arg( m_videooptions ->getVideoCdDestination() ), K3bJob::INFO ); + + if ( !m_process->start( KProcess::NotifyOnExit, KProcess::AllOutput ) ) { + kdDebug() << "(K3bVideoCdRip) could not start vcdxrip" << endl; + emit infoMessage( i18n( "Could not start %1." ).arg( "vcdxrip" ), K3bJob::ERROR ); + cancelAll(); + jobFinished( false ); + } +} + +void K3bVideoCdRip::slotParseVcdXRipOutput( KProcess*, char* output, int len ) +{ + QString buffer = QString::fromLocal8Bit( output, len ); + + // split to lines + QStringList lines = QStringList::split( "\n", buffer ); + + QDomDocument xml_doc; + QDomElement xml_root; + + // do every line + QStringList::Iterator end( lines.end()); + for ( QStringList::Iterator str = lines.begin(); str != end; ++str ) { + *str = ( *str ).stripWhiteSpace(); + + emit debuggingOutput( "vcdxrip", *str ); + + xml_doc.setContent( QString( "<?xml version='1.0'?><vcdxrip>" ) + *str + "</vcdxrip>" ); + + xml_root = xml_doc.documentElement(); + + for ( QDomNode node = xml_root.firstChild(); !node.isNull(); node = node.nextSibling() ) { + QDomElement el = node.toElement(); + if ( el.isNull() ) + continue; + + const QString tagName = el.tagName().lower(); + + if ( tagName == "progress" ) { + const QString oper = el.attribute( "operation" ).lower(); + const unsigned long long overallPos = el.attribute( "position" ).toLong(); + const unsigned long long pos = overallPos - m_subPosition; + const unsigned long long size = el.attribute( "size" ).toLong() - m_subPosition; + + if ( oper == "extract" ) { + emit subPercent( ( int ) ( 100.0 * ( double ) pos / ( double ) size ) ); + emit processedSubSize( ( pos * 2352 ) / 1024 / 1024 , ( size * 2352 ) / 1024 / 1024 ); + + m_bytesFinished = pos; + + kdDebug() << "(slotParseVcdXRipOutput) overall: " << ((long)overallPos * 2352) + << ", videocdsize: " << m_videooptions->getVideoCdSize() << endl; + double relOverallWritten = ( ( double ) overallPos * 2352 ) / ( double ) m_videooptions ->getVideoCdSize() ; + int newpercent = ( int ) ( 100 * relOverallWritten ); + if ( newpercent > m_oldpercent ) { + emit percent( newpercent ); + m_oldpercent = newpercent; + } + + } else { + return ; + } + + } else if ( tagName == "log" ) { + QDomText tel = el.firstChild().toText(); + const QString level = el.attribute( "level" ).lower(); + if ( tel.isText() ) { + const QString text = tel.data(); + if ( level == "information" ) { + kdDebug() << QString( "(K3bVideoCdRip) vcdxrip information, %1" ).arg( text ) << endl; + parseInformation( text ); + } else { + if ( level != "error" ) { + kdDebug() << QString( "(K3bVideoCdRip) vcdxrip warning, %1" ).arg( text ) << endl; + emit debuggingOutput( "vcdxrip", text ); + parseInformation( text ); + } else { + kdDebug() << QString( "(K3bVideoCdRip) vcdxrip error, %1" ).arg( text ) << endl; + emit infoMessage( text, K3bJob::ERROR ); + } + } + } + } + } + } +} + + +void K3bVideoCdRip::slotVcdXRipFinished() +{ + if ( m_process->normalExit() ) { + // TODO: check the process' exitStatus() + switch ( m_process->exitStatus() ) { + case 0: + emit infoMessage( i18n( "Files successfully extracted." ), K3bJob::SUCCESS ); + break; + default: + emit infoMessage( i18n( "%1 returned an unknown error (code %2)." ).arg( "vcdxrip" ).arg( m_process->exitStatus() ), K3bJob::ERROR ); + emit infoMessage( i18n( "Please send me an email with the last output..." ), K3bJob::ERROR ); + cancelAll(); + jobFinished( false ); + return ; + } + } else { + emit infoMessage( i18n( "%1 did not exit cleanly." ).arg( "Vcdxrip" ), K3bJob::ERROR ); + cancelAll(); + jobFinished( false ); + return ; + } + + jobFinished( true ); +} + +void K3bVideoCdRip::parseInformation( QString text ) +{ + // parse warning + if ( text.contains( "encountered non-form2 sector" ) ) { + // I think this is an error not a warning. Finish ripping with invalid mpegs. + emit infoMessage( i18n( "%1 encountered non-form2 sector" ).arg("Vcdxrip"), K3bJob::ERROR ); + emit infoMessage( i18n( "leaving loop" ), K3bJob::ERROR ); + cancelAll(); + jobFinished( false ); + return; + } + + // parse extra info + else if ( text.contains( "detected extended VCD2.0 PBC files" ) ) + emit infoMessage( i18n( "detected extended VCD2.0 PBC files" ), K3bJob::INFO ); + + // parse startposition and extracting sequence info + // extracting avseq05.mpg... (start lsn 32603 (+28514)) + else if ( text.startsWith( "extracting" ) ) { + if ( text.contains( "(start lsn" ) ) { + int index = text.find( "(start lsn" ); + int end = text.find( " (+" ); + if ( end > 0) { + m_subPosition = text.mid( index + 11, end - index - 11 ).stripWhiteSpace().toLong(); + } + else { + // found segment here we can get only the start lsn :) + // extracting item0001.mpg... (start lsn 225, 1 segments) + int end = text.find( ",", index ); + int overallPos = text.mid( index + 11, end - index - 11 ).stripWhiteSpace().toLong(); + double relOverallWritten = ( ( double ) overallPos * 2352 ) / ( double ) m_videooptions ->getVideoCdSize() ; + int newpercent = ( int ) ( 100 * relOverallWritten ); + if ( newpercent > m_oldpercent ) { + emit percent( newpercent ); + m_oldpercent = newpercent; + } + } + + + index = 11; + end = text.find( "(start lsn" ); + emit newSubTask( i18n( "Extracting %1" ).arg( text.mid( index, end - index ).stripWhiteSpace() ) ); + } + // parse extracting files info + // extracting CDI/CDI_IMAG.RTF to _cdi_cdi_imag.rtf (lsn 258, size 1315168, raw 1) + else if ( text.contains( "(lsn" ) && text.contains( "size" ) ) { + int index = 11; + int end = text.find( "to" ); + QString extractFileName = text.mid( index, end - index ).stripWhiteSpace(); + index = text.find( " to " ); + end = text.find( " (lsn" ); + QString toFileName = text.mid( index + 4, end - index - 4 ).stripWhiteSpace(); + emit newSubTask( i18n( "Extracting %1 to %2" ).arg( extractFileName ).arg( toFileName ) ); + } + } +} + +QString K3bVideoCdRip::jobDescription() const +{ + return i18n( "Extracting %1" ).arg( m_videooptions ->getVideoCdDescription() ); +} + +QString K3bVideoCdRip::jobDetails() const +{ + return QString( "(%1)" ).arg ( KIO::convertSize( m_videooptions ->getVideoCdSize() ) ); +} + +#include "k3bvideocdrip.moc" diff --git a/src/rip/k3bvideocdrip.h b/src/rip/k3bvideocdrip.h new file mode 100644 index 0000000..fe0d6f9 --- /dev/null +++ b/src/rip/k3bvideocdrip.h @@ -0,0 +1,74 @@ +/* +* +* $Id: k3bvideocdrip.h 619556 2007-01-03 17:38:12Z trueg $ +* Copyright (C) 2003 Christian Kvasny <chris@k3b.org> +* +* This file is part of the K3b project. +* Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> +* +* 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 2 of the License, or +* (at your option) any later version. +* See the file "COPYING" for the exact licensing terms. +*/ + +#ifndef K3BVIDEOCDRIP_H +#define K3BVIDEOCDRIP_H + +#include <k3bjob.h> +#include <k3bdiskinfo.h> +#include "k3bvideocdrippingoptions.h" + +class QString; +class KProcess; +class QDataStream; + +class K3bVideoCdRip : public K3bJob +{ + Q_OBJECT + + public: + K3bVideoCdRip( K3bJobHandler*, K3bVideoCdRippingOptions* options, QObject* parent = 0, const char* name = 0 ); + ~K3bVideoCdRip(); + + enum { CDROM, BIN_IMAGE, NRG_IMAGE }; + + QString jobDescription() const; + QString jobDetails() const; + + public slots: + void start(); + void cancel(); + + private slots: + void cancelAll(); + + protected slots: + void slotVcdXRipFinished(); + void slotParseVcdXRipOutput( KProcess*, char* output, int len ); + + private: + void vcdxRip(); + void parseInformation( QString ); + + enum { stageUnknown, stageScan, stageFinished, _stage_max }; + + int m_stage; + int m_bytesFinished; + int m_ripsourceType; + int m_oldpercent; + + long m_subPosition; + + QString m_collectedOutput; + + K3bVideoCdRippingOptions * m_videooptions; + + bool m_canceled; + + KProcess* m_process; + +}; + +#endif diff --git a/src/rip/k3bvideocdrippingdialog.cpp b/src/rip/k3bvideocdrippingdialog.cpp new file mode 100644 index 0000000..490f531 --- /dev/null +++ b/src/rip/k3bvideocdrippingdialog.cpp @@ -0,0 +1,260 @@ +/* +* +* $Id: k3bvideocdrippingdialog.cpp 640370 2007-03-07 19:44:32Z trueg $ +* Copyright (C) 2003 Christian Kvasny <chris@k3b.org> +* +* This file is part of the K3b project. +* Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> +* +* 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 2 of the License, or +* (at your option) any later version. +* See the file "COPYING" for the exact licensing terms. +*/ + + +// kde include +#include <klocale.h> +#include <kapplication.h> +#include <kconfig.h> +#include <kurlrequester.h> +#include <kdebug.h> +#include <kmessagebox.h> +#include <kstandarddirs.h> + +// qt includes +#include <qgroupbox.h> +#include <qcheckbox.h> +#include <qlabel.h> +#include <qtimer.h> +#include <qlayout.h> +#include <qtooltip.h> +#include <qwhatsthis.h> +#include <qdir.h> +#include <qfileinfo.h> +#include <qstringlist.h> +#include <qhbox.h> + +// k3b includes +#include "k3bvideocdrippingdialog.h" +#include "k3bvideocdrip.h" + +#include <k3bjobprogressdialog.h> +#include <k3bcore.h> +#include <k3bglobals.h> +#include <k3bstdguiitems.h> + +K3bVideoCdRippingDialog::K3bVideoCdRippingDialog( K3bVideoCdRippingOptions* options, QWidget* parent, const char* name ) + : K3bInteractionDialog( parent, name, + i18n( "Video CD Ripping" ), + QString::null, + START_BUTTON|CANCEL_BUTTON, + START_BUTTON, + "Video CD Ripping" ), // config group + m_videooptions( options ) +{ + setupGui(); + setupContextHelp(); +} + + +K3bVideoCdRippingDialog::~K3bVideoCdRippingDialog() +{ +} + + +void K3bVideoCdRippingDialog::setupGui() +{ + QWidget * frame = mainWidget(); + QGridLayout* MainLayout = new QGridLayout( frame ); + MainLayout->setSpacing( KDialog::spacingHint() ); + MainLayout->setMargin( 0 ); + + // ---------------------------------------------------- Directory group --- + QGroupBox* groupDirectory = new QGroupBox( 0, Qt::Vertical, i18n( "Destination Directory" ), frame ); + groupDirectory->layout() ->setSpacing( KDialog::spacingHint() ); + groupDirectory->layout() ->setMargin( KDialog::marginHint() ); + + QGridLayout* groupDirectoryLayout = new QGridLayout( groupDirectory->layout() ); + groupDirectoryLayout->setAlignment( Qt::AlignTop ); + + QLabel* rippathLabel = new QLabel( i18n( "Rip files to:" ), groupDirectory ); + m_editDirectory = new KURLRequester( groupDirectory, "m_editDirectory" ); + m_editDirectory->setURL( QDir::homeDirPath() ); + m_editDirectory->setMode( KFile::Directory | KFile::ExistingOnly | KFile::LocalOnly ); + + rippathLabel->setBuddy( m_editDirectory ); + + QHBox* freeSpaceBox = new QHBox( groupDirectory ); + freeSpaceBox->setSpacing( KDialog::spacingHint() ); + ( void ) new QLabel( i18n( "Free space in directory:" ), freeSpaceBox, "FreeSpaceLabel" ); + m_labelFreeSpace = new QLabel( " ", freeSpaceBox, "m_labelFreeSpace" ); + m_labelFreeSpace->setAlignment( int( QLabel::AlignVCenter | QLabel::AlignRight ) ); + + QHBox* necessarySizeBox = new QHBox( groupDirectory ); + necessarySizeBox->setSpacing( KDialog::spacingHint() ); + ( void ) new QLabel( i18n( "Necessary storage size:" ), necessarySizeBox, "StorSize" ); + m_labelNecessarySize = new QLabel( " ", necessarySizeBox, "m_labelNecessarySize" ); + m_labelNecessarySize->setAlignment( int( QLabel::AlignVCenter | QLabel::AlignRight ) ); + + + groupDirectoryLayout->addWidget( rippathLabel, 0, 0 ); + groupDirectoryLayout->addWidget( m_editDirectory, 0, 1 ); + groupDirectoryLayout->addWidget( freeSpaceBox, 1, 1 ); + groupDirectoryLayout->addWidget( necessarySizeBox, 2, 1 ); + + // ---------------------------------------------------- Options group --- + QGroupBox* groupOptions = new QGroupBox( 4, Qt::Vertical, i18n( "Settings" ), frame ); + + m_ignoreExt = new QCheckBox( i18n( "Ignore /EXT/PSD_X.VCD" ), groupOptions ); + + m_sector2336 = new QCheckBox( i18n( "Use 2336 byte sector mode for image file" ), groupOptions ); + // Only available for image file ripping + m_sector2336->setEnabled( false ); + m_sector2336->setChecked( false ); + + m_extractXML = new QCheckBox( i18n( "Extract XML structure" ), groupOptions ); + + + MainLayout->addWidget( groupDirectory, 0, 0 ); + MainLayout->addWidget( groupOptions, 1, 0 ); + MainLayout->setRowStretch( 0, 1 ); + + setStartButtonText( i18n( "Start Ripping" ), i18n( "Starts extracting the selected VideoCd tracks" ) ); + // ---------------------------------------------------------------------------------- + + connect( m_editDirectory, SIGNAL(textChanged(const QString&)), this, SLOT(slotUpdateFreeSpace()) ); + + m_labelNecessarySize ->setText( KIO::convertSize( m_videooptions ->getVideoCdSize() ) ); +} + + +void K3bVideoCdRippingDialog::setupContextHelp() +{ + QToolTip::add( m_labelFreeSpace, i18n("Free space on destination directory: %1").arg( m_editDirectory ->url() ) ); + + QToolTip::add( m_labelNecessarySize, i18n("Necessary space for extracted files") ); + + QToolTip::add( m_ignoreExt, i18n("Ignore extended PSD") ); + QWhatsThis::add( m_ignoreExt, i18n("<p>Ignore extended PSD (located in the ISO-9660 filesystem under `/EXT/PSD_X.VCD') and use the <em>standard</em> PSD.</p>") ); + + QToolTip::add( m_sector2336, i18n("Assume a 2336-byte sector mode") ); + QWhatsThis::add( m_sector2336, i18n("<p>This option only makes sense if you are reading from a BIN CD disk image. This indicates to `vcdxrip' to assume a 2336-byte sector mode for image file.</p>" + "<b>Note: This option is slated to disappear.</b>") ); + + QToolTip::add( m_extractXML, i18n("Create XML description file.") ); + QWhatsThis::add( m_extractXML, i18n("<p>This option creates an XML description file with all video CD information.</p>" + "<p>This file will always contain all of the information.</p>" + "<p>Example: If you only extract sequences, the description file will also hold the information for files and segments.</p>" + "<p>The filename is the same as the video CD name, with a .xml extension. The default is VIDEOCD.xml.</p>") ); +} + +void K3bVideoCdRippingDialog::slotStartClicked() +{ + + QStringList filesExists; + QDir d; + d.setPath( m_editDirectory ->url() ); + if( !d.exists() ) { + if( KMessageBox::warningYesNo( this, i18n("Image folder '%1' does not exist. Do you want K3b to create it?").arg( m_editDirectory->url() ) ) + == KMessageBox::Yes ) { + if( !KStandardDirs::makeDir( m_editDirectory->url() ) ) { + KMessageBox::error( this, i18n("Failed to create folder '%1'.").arg( m_editDirectory->url() ) ); + return; + } + } + } + const QFileInfoList* list = d.entryInfoList(); + QFileInfoListIterator it( *list ); + QFileInfo* fi; + while ( ( fi = it.current() ) != 0 ) { + if ( fi ->fileName() != "." && fi ->fileName() != ".." ) + filesExists.append( QString( "%1 (%2)" ).arg( QFile::encodeName( fi ->fileName() ) ).arg( KIO::convertSize( fi ->size() ) ) ); + ++it; + } + + if( !filesExists.isEmpty() ) + if( KMessageBox::questionYesNoList( this, + i18n("Continue although the folder is not empty?"), + filesExists, + i18n("Files Exist"),KStdGuiItem::cont(),KStdGuiItem::cancel() ) == KMessageBox::No ) + return; + + m_videooptions ->setVideoCdIgnoreExt( m_ignoreExt ->isChecked() ); + m_videooptions ->setVideoCdSector2336( m_sector2336 ->isChecked() ); + m_videooptions ->setVideoCdExtractXml( m_extractXML ->isChecked() ); + m_videooptions ->setVideoCdDestination( m_editDirectory ->url() ); + + K3bJobProgressDialog ripDialog( kapp->mainWidget(), "Ripping" ); + K3bVideoCdRip * rip = new K3bVideoCdRip( &ripDialog, m_videooptions ); + + hide(); + ripDialog.startJob( rip ); + + delete rip; + + close(); +} + +void K3bVideoCdRippingDialog::slotFreeSpace(const QString&, + unsigned long, + unsigned long, + unsigned long kbAvail) +{ + m_labelFreeSpace->setText( KIO::convertSizeFromKB(kbAvail) ); + + m_freeSpace = kbAvail; + + if( m_freeSpace < m_videooptions ->getVideoCdSize() /1024 ) + m_labelNecessarySize->setPaletteForegroundColor( red ); + else + m_labelNecessarySize->setPaletteForegroundColor( m_labelFreeSpace->paletteForegroundColor() ); + + QTimer::singleShot( 1000, this, SLOT(slotUpdateFreeSpace()) ); +} + + +void K3bVideoCdRippingDialog::slotUpdateFreeSpace() +{ + QString path = m_editDirectory->url(); + + if( !QFile::exists( path ) ) + path.truncate( path.findRev('/') ); + + unsigned long size, avail; + if( K3b::kbFreeOnFs( path, size, avail ) ) + slotFreeSpace( path, size, 0, avail ); + else + m_labelFreeSpace->setText("-"); +} + +void K3bVideoCdRippingDialog::loadK3bDefaults() +{ + m_editDirectory->setURL( QDir::homeDirPath() ); + m_ignoreExt ->setChecked( false ); + m_sector2336 ->setChecked( false ); + m_extractXML ->setChecked( false ); + + slotUpdateFreeSpace(); +} + +void K3bVideoCdRippingDialog::loadUserDefaults( KConfigBase* c ) +{ + m_editDirectory ->setURL( c->readPathEntry( "last ripping directory", QDir::homeDirPath() ) ); + m_ignoreExt ->setChecked( c->readBoolEntry( "ignore ext", false ) ); + m_sector2336 ->setChecked( c->readBoolEntry( "sector 2336", false ) ); + m_extractXML ->setChecked( c->readBoolEntry( "extract xml", false ) ); + + slotUpdateFreeSpace(); +} + +void K3bVideoCdRippingDialog::saveUserDefaults( KConfigBase* c ) +{ + c->writePathEntry( "last ripping directory", m_editDirectory->url() ); + c->writeEntry( "ignore ext", m_ignoreExt ->isChecked( ) ); + c->writeEntry( "sector 2336", m_sector2336 ->isChecked( ) ); + c->writeEntry( "extract xml", m_extractXML ->isChecked( ) ); +} + +#include "k3bvideocdrippingdialog.moc" diff --git a/src/rip/k3bvideocdrippingdialog.h b/src/rip/k3bvideocdrippingdialog.h new file mode 100644 index 0000000..98d16f6 --- /dev/null +++ b/src/rip/k3bvideocdrippingdialog.h @@ -0,0 +1,73 @@ +/* + * + * $Id: k3bvideocdrippingdialog.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Christian Kvasny <chris@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_VIDEOCD_RIPPING_DIALOG_H_ +#define _K3B_VIDEOCD_RIPPING_DIALOG_H_ + +#include <qstringlist.h> + +#include <k3binteractiondialog.h> +#include <k3bdiskinfo.h> +#include "k3bvideocdrippingoptions.h" + +class KListView; +class QCheckBox; +class QLabel; +class QSpinBox; +class QComboBox; +class QToolButton; +class KURLRequester; +class K3bTempDirSelectionWidget; + +class K3bVideoCdRippingDialog : public K3bInteractionDialog +{ + Q_OBJECT + + public: + K3bVideoCdRippingDialog( K3bVideoCdRippingOptions* options, QWidget* parent = 0, const char* name = 0 ); + ~K3bVideoCdRippingDialog(); + + private: + void setupGui(); + void setupContextHelp(); + + void loadK3bDefaults(); + void loadUserDefaults( KConfigBase* ); + void saveUserDefaults( KConfigBase* ); + + K3bTempDirSelectionWidget* m_tempDirSelectionWidget; + + KURLRequester* m_editDirectory; + + QLabel* m_labelFreeSpace; + QLabel* m_labelNecessarySize; + QCheckBox* m_ignoreExt; + QCheckBox* m_sector2336; + QCheckBox* m_extractXML; + + K3bVideoCdRippingOptions* m_videooptions; + + unsigned long m_freeSpace; + + private slots: + void slotStartClicked(); + + void slotUpdateFreeSpace(); + void slotFreeSpace(const QString&, unsigned long, unsigned long, unsigned long); + +}; + +#endif diff --git a/src/rip/k3bvideocdrippingoptions.h b/src/rip/k3bvideocdrippingoptions.h new file mode 100644 index 0000000..bd8aea9 --- /dev/null +++ b/src/rip/k3bvideocdrippingoptions.h @@ -0,0 +1,74 @@ +/* + * + * $Id: k3bvideocdrippingoptions.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Christian Kvasny <chris@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_VIDEOCD_OPTIONS_H_ +#define _K3B_VIDEOCD_OPTIONS_H_ + +#include <qstring.h> + +class K3bVideoCdRippingOptions +{ + public: + K3bVideoCdRippingOptions() + : m_videocdsize( 0 ), + m_videocdsource( "/dev/cdrom" ), + m_videocddestination( "/tmp" ), + m_videocddescription( i18n( "Video CD" ) ), + m_videocdripfiles( false ), + m_videocdripsegments( false ), + m_videocdripsequences( false ), + m_ignoreExt( false ), + m_sector2336( false ), + m_extractXML( false ) + {} + + void setVideoCdSize( unsigned long size ) { m_videocdsize = size;} + void setVideoCdSource( const QString& source ) { m_videocdsource = source;} + void setVideoCdDestination( const QString& destination ) { m_videocddestination = destination;} + void setVideoCdDescription( const QString& description ) { m_videocddescription = description;} + void setVideoCdRipFiles( bool ripfiles ) { m_videocdripfiles = ripfiles;} + void setVideoCdRipSegments( bool ripsegments ) { m_videocdripsegments = ripsegments;} + void setVideoCdRipSequences( bool ripsequences ) { m_videocdripsequences = ripsequences;} + void setVideoCdIgnoreExt( bool ignoreext ) { m_ignoreExt = ignoreext;} + void setVideoCdSector2336( bool sector2336 ) { m_sector2336 = sector2336;} + void setVideoCdExtractXml( bool extractxml ) { m_extractXML = extractxml;} + + unsigned long getVideoCdSize( ) { return m_videocdsize;} + QString getVideoCdSource( ) { return m_videocdsource;} + QString getVideoCdDestination( ) { return m_videocddestination;} + QString getVideoCdDescription( ) { return m_videocddescription;} + bool getVideoCdRipFiles( ) { return m_videocdripfiles;} + bool getVideoCdRipSegments( ) { return m_videocdripsegments;} + bool getVideoCdRipSequences( ) { return m_videocdripsequences;} + bool getVideoCdIgnoreExt( ) { return m_ignoreExt;} + bool getVideoCdSector2336( ) { return m_sector2336;} + bool getVideoCdExtractXml( ) { return m_extractXML;} + + private: + unsigned long m_videocdsize; + + QString m_videocdsource; + QString m_videocddestination; + QString m_videocddescription; + + bool m_videocdripfiles; + bool m_videocdripsegments; + bool m_videocdripsequences; + bool m_ignoreExt; + bool m_sector2336; + bool m_extractXML; +}; + +#endif diff --git a/src/rip/k3bvideocdview.cpp b/src/rip/k3bvideocdview.cpp new file mode 100644 index 0000000..c0f5ae2 --- /dev/null +++ b/src/rip/k3bvideocdview.cpp @@ -0,0 +1,509 @@ +/* +* +* $Id: k3bvideocdview.cpp 619556 2007-01-03 17:38:12Z trueg $ +* Copyright (C) 2003 Christian Kvasny <chris@k3b.org> +* +* This file is part of the K3b project. +* Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> +* +* 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 2 of the License, or +* (at your option) any later version. +* See the file "COPYING" for the exact licensing terms. +*/ + +// kde includes +#include <kaction.h> +#include <kcutlabel.h> +#include <kdebug.h> +#include <kdialogbase.h> +#include <kiconloader.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kstandarddirs.h> +#include <kstdaction.h> + +// qt includes +#include <qfont.h> +#include <qframe.h> +#include <qheader.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qcursor.h> +#include <qapplication.h> + +// k3b includes +#include "k3bvideocdview.h" +#include "k3bvideocdrippingdialog.h" + +#include <k3bdevice.h> +#include <k3bmsf.h> +#include <k3btoc.h> +#include <k3bcore.h> +#include <k3blistview.h> +#include <k3bstdguiitems.h> +#include <k3btoolbox.h> + + +class K3bVideoCdView::VideoTrackViewItem : public QListViewItem +{ + public: + VideoTrackViewItem( QListViewItem* parent, QListViewItem* after ) + : QListViewItem( parent, after ) + { + setSelectable( false ); + } + + VideoTrackViewItem( QListView* parent, QListViewItem* after ) + : QListViewItem( parent, after ) + { + setSelectable( false ); + } + + VideoTrackViewItem( QListViewItem* parent, + const QString& name, + const QString& id, + int _trackNumber, + const K3b::Msf& length ) + : QListViewItem( parent ) + { + setText( 0, QString( "%1. %2" ).arg( _trackNumber ).arg( id ) ); + setText( 1, name ); + if ( length > 0 ) { + setText( 2, length.toString() ); + setText( 3, KIO::convertSize( length.mode2Form2Bytes() ) ); + } + + trackNumber = _trackNumber; + setSelectable( false ); + } + + int trackNumber; + + void updateData( const K3bVideoCdInfoResultEntry& resultEntry ) + { + setText( 0, QString( "%1. %2" ).arg( trackNumber ).arg( resultEntry.id ) ); + setText( 1, resultEntry.name ); + } + +}; + +class K3bVideoCdView::VideoTrackViewCheckItem : public QCheckListItem +{ + public: + VideoTrackViewCheckItem( QListViewItem* parent, + const QString& desc ) + : QCheckListItem( parent, + QString::null, + QCheckListItem::CheckBox ) + { + setText( 0, desc ); + + setOn( true ); + } + + VideoTrackViewCheckItem( QListView* parent, + const QString& desc ) + : QCheckListItem( parent, + QString::null, + QCheckListItem::CheckBox ) + { + setText( 0, desc ); + + setOn( true ); + } + + VideoTrackViewCheckItem( VideoTrackViewCheckItem* parent, + const QString& desc ) + : QCheckListItem( parent, + QString::null, + QCheckListItem::CheckBox ) + { + setText( 0, desc ); + + setOn( true ); + } + + void updateData( const K3b::Msf& length, bool form2 = false ) + { + setText( 2, length.toString() ); + if ( form2 ) + setText( 3, KIO::convertSize( length.mode2Form2Bytes() ) ); + else + setText( 3, KIO::convertSize( length.mode2Form1Bytes() ) ); + } + +}; + +K3bVideoCdView::K3bVideoCdView( QWidget* parent, const char *name ) + : K3bMediaContentsView( true, + K3bMedium::CONTENT_VIDEO_CD, + K3bDevice::MEDIA_CD_ALL, + K3bDevice::STATE_INCOMPLETE|K3bDevice::STATE_COMPLETE, + parent, name ) +{ + QGridLayout * mainGrid = new QGridLayout( mainWidget() ); + + // toolbox + // ---------------------------------------------------------------------------------- + QHBoxLayout* toolBoxLayout = new QHBoxLayout( 0, 0, 0, "toolBoxLayout" ); + m_toolBox = new K3bToolBox( mainWidget() ); + toolBoxLayout->addWidget( m_toolBox ); + QSpacerItem* spacer = new QSpacerItem( 10, 10, QSizePolicy::Expanding, QSizePolicy::Minimum ); + toolBoxLayout->addItem( spacer ); + m_labelLength = new QLabel( mainWidget() ); + m_labelLength->setAlignment( int( QLabel::AlignVCenter | QLabel::AlignRight ) ); + toolBoxLayout->addWidget( m_labelLength ); + + // the track view + // ---------------------------------------------------------------------------------- + m_trackView = new K3bListView( mainWidget() ); + m_trackView->setFullWidth( true ); + m_trackView->setAllColumnsShowFocus( true ); + m_trackView->setSelectionMode( QListView::Single ); + m_trackView->setDragEnabled( true ); + m_trackView->addColumn( i18n( "Item Name" ) ); + m_trackView->addColumn( i18n( "Extracted Name" ) ); + m_trackView->addColumn( i18n( "Length" ) ); + m_trackView->addColumn( i18n( "Size" ) ); + + m_trackView->header() ->setClickEnabled( false ); + + m_trackView->setItemsRenameable( false ); + m_trackView->setRootIsDecorated( true ); + + connect( m_trackView, SIGNAL( contextMenu( KListView*, QListViewItem*, const QPoint& ) ), + this, SLOT( slotContextMenu( KListView*, QListViewItem*, const QPoint& ) ) ); + connect( m_trackView, SIGNAL( selectionChanged( QListViewItem* ) ), + this, SLOT( slotTrackSelectionChanged( QListViewItem* ) ) ); + connect( m_trackView, SIGNAL( clicked( QListViewItem* ) ), + this, SLOT( slotStateChanged( QListViewItem* ) ) ); + connect( m_trackView, SIGNAL( spacePressed( QListViewItem* ) ), + this, SLOT( slotStateChanged( QListViewItem* ) ) ); + + + mainGrid->addLayout( toolBoxLayout, 0, 0 ); + mainGrid->addWidget( m_trackView, 1, 0 ); + + initActions(); + slotTrackSelectionChanged( 0 ); + + m_videocdinfo = 0L; + m_videooptions = new K3bVideoCdRippingOptions(); + + m_contentList.clear(); +} + + +K3bVideoCdView::~K3bVideoCdView() +{ + delete m_videocdinfo; + delete m_videooptions; +} + + +void K3bVideoCdView::reloadMedium() +{ + m_toc = medium().toc(); + + m_trackView->clear(); + + m_trackView->setEnabled( false ); + m_toolBox->setEnabled( false ); + QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); + + m_contentList.append( new VideoTrackViewCheckItem( m_trackView, i18n("Video CD MPEG tracks") ) ); + m_contentList.append( new VideoTrackViewCheckItem( m_trackView, i18n("Video CD DATA track" ) ) ); + + ( ( VideoTrackViewCheckItem* ) m_contentList[ 0 ] ) ->setOpen( true ); + + // create a listviewItem for every video track + int index = 0; + m_videocddatasize = 0; + m_videocdmpegsize = 0; + + K3b::Msf sequenceSize; + + for ( K3bDevice::Toc::const_iterator it = m_toc.begin(); + it != m_toc.end(); ++it ) { + + if ( index > 0 ) { + K3b::Msf length( ( *it ).length() ); + sequenceSize += length; + m_videocdmpegsize += length.mode2Form2Bytes(); + ( void ) new VideoTrackViewItem( ( VideoTrackViewCheckItem* ) m_contentList[ 0 ], i18n( "Sequence-%1" ).arg( index ), "", index, length ); + } else { + K3b::Msf length( ( *it ).length() ); + m_videocddatasize += length.mode2Form1Bytes(); + ( ( VideoTrackViewCheckItem* ) m_contentList[ 1 ] ) ->updateData( length ); + ( void ) new VideoTrackViewCheckItem( ( VideoTrackViewCheckItem* ) m_contentList[ 1 ], i18n( "Files" ) ); + ( void ) new VideoTrackViewCheckItem( ( VideoTrackViewCheckItem* ) m_contentList[ 1 ], i18n( "Segments" ) ); + } + + index++; + } + + ( ( VideoTrackViewCheckItem* ) m_contentList[ 0 ] ) ->updateData( sequenceSize, true ); + + m_videooptions ->setVideoCdSource( device()->devicename() ); + + m_videocdinfo = new K3bVideoCdInfo( this ); + m_videocdinfo->info( device()->devicename() ); + + connect( m_videocdinfo, SIGNAL( infoFinished( bool ) ), + this, SLOT( slotVideoCdInfoFinished( bool ) ) ); + +} + +void K3bVideoCdView::slotVideoCdInfoFinished( bool success ) +{ + if ( success ) { + m_videocdinfoResult = m_videocdinfo->result(); + updateDisplay(); + } + + m_trackView->setEnabled( true ); + m_toolBox->setEnabled( true ); + QApplication::restoreOverrideCursor(); + +} + +void K3bVideoCdView::updateDisplay() +{ + // update the listview + + VideoTrackViewItem * item = ( VideoTrackViewItem* ) m_contentList[ 0 ] ->firstChild(); + int index = 0; + while ( item ) { + item->updateData( m_videocdinfoResult.entry( index, K3bVideoCdInfoResult::SEQUENCE ) ); + item = ( VideoTrackViewItem* ) item->nextSibling(); + index++; + } + + VideoTrackViewCheckItem* check_item = ( VideoTrackViewCheckItem* ) m_contentList[ 1 ] ->firstChild(); + while ( check_item ) { + if ( check_item->key( 0, false ).compare( i18n( "Files" ) ) == 0 ) { + if ( domTree.setContent( m_videocdinfoResult.xmlData ) ) { + + QDomElement root = domTree.documentElement(); + QDomNode node; + node = root.firstChild(); + while ( !node.isNull() ) { + if ( node.isElement() && node.nodeName() == "filesystem" ) { + QDomElement body = node.toElement(); + buildTree( check_item, body ); + break; + } + node = node.nextSibling(); + } + } + } else { + for ( index = 0; index < m_videocdinfoResult.foundEntries( K3bVideoCdInfoResult::SEGMENT ); index++ ) { + ( void ) new VideoTrackViewItem( check_item, m_videocdinfoResult.entry( index, K3bVideoCdInfoResult::SEGMENT ).name, m_videocdinfoResult.entry( index, K3bVideoCdInfoResult::SEGMENT ).id , index + 1, 0 ); + } + } + check_item = ( VideoTrackViewCheckItem* ) check_item->nextSibling(); + } + + if ( !m_videocdinfoResult.volumeId.isEmpty() ) { + QString description = m_videocdinfoResult.volumeId + " (" + m_videocdinfoResult.type + " " + m_videocdinfoResult.version + ")" ; + setTitle( description ); + m_videooptions ->setVideoCdDescription( description ); + } + else + setTitle( i18n( "Video CD" ) ); + + m_labelLength->setText( i18n( "1 track (%1)", "%n tracks (%1)", m_toc.count() ).arg( K3b::Msf( m_toc.length() ).toString() ) ); +} + + +void K3bVideoCdView::initActions() +{ + m_actionCollection = new KActionCollection( this ); + + KAction* actionSelectAll = KStdAction::selectAll( this, SLOT( slotSelectAll() ), + m_actionCollection, "select_all" ); + KAction* actionDeselectAll = KStdAction::deselect( this, SLOT( slotDeselectAll() ), + m_actionCollection, "deselect_all" ); + actionDeselectAll->setText( i18n( "Dese&lect All" ) ); + KAction* actionSelect = new KAction( i18n( "Select Track" ), 0, 0, this, + SLOT( slotSelect() ), actionCollection(), + "select_track" ); + KAction* actionDeselect = new KAction( i18n( "Deselect Track" ), 0, 0, this, + SLOT( slotDeselect() ), actionCollection(), + "deselect_track" ); + + KAction* actionStartRip = new KAction( i18n( "Start Ripping" ), "run", 0, this, + SLOT( startRip() ), actionCollection(), "start_rip" ); + + // TODO: set the actions tooltips and whatsthis infos + + // setup the popup menu + m_popupMenu = new KActionMenu( actionCollection(), "popup_menu" ); + KAction* separator = new KActionSeparator( actionCollection(), "separator" ); + m_popupMenu->insert( actionSelect ); + m_popupMenu->insert( actionDeselect ); + m_popupMenu->insert( actionSelectAll ); + m_popupMenu->insert( actionDeselectAll ); + m_popupMenu->insert( separator ); + m_popupMenu->insert( actionStartRip ); + + // setup the toolbox + m_toolBox->addButton( actionStartRip, true ); +} + + +void K3bVideoCdView::slotContextMenu( KListView*, QListViewItem*, const QPoint& p ) +{ + m_popupMenu->popup( p ); +} + + +void K3bVideoCdView::slotTrackSelectionChanged( QListViewItem* item ) +{ + actionCollection() ->action( "select_track" ) ->setEnabled( item != 0 ); + actionCollection() ->action( "deselect_track" ) ->setEnabled( item != 0 ); +} + +void K3bVideoCdView::slotStateChanged( QListViewItem* item ) +{ + /* > QT 3.1 + if ( !item == 0 && item ->isSelectable() ) { + if ( ( ( VideoTrackViewCheckItem* ) item) ->state() == QCheckListItem::On) + slotSelect(); + else if ( ( ( VideoTrackViewCheckItem* ) item) ->state() == QCheckListItem::Off) + slotDeselect(); + } + */ + if ( !item == 0 && item ->isSelectable() ) { + if ( ( ( VideoTrackViewCheckItem* ) item) ->isOn() ) + slotSelect(); + else + slotDeselect(); + } +} + +void K3bVideoCdView::startRip() +{ + + int selectedItems = 0; + for ( QListViewItemIterator it( m_trackView ); it.current(); ++it ) { + if ( it.current() ->isSelectable() ) { + if ( ( ( ( VideoTrackViewCheckItem* ) it.current()) ->key( 0, false ).compare( i18n("Video CD MPEG tracks" ) ) == 0 ) && ( ( VideoTrackViewCheckItem* ) it.current() ) ->isOn() ) { + m_videooptions ->setVideoCdRipSequences( true ); + selectedItems++; + } + else if ( ( ( ( VideoTrackViewCheckItem* ) it.current()) ->key( 0, false ).compare( i18n("Files" ) ) == 0 ) && ( ( VideoTrackViewCheckItem* ) it.current() ) ->isOn() ) { + m_videooptions ->setVideoCdRipFiles( true ); + selectedItems++; + } + else if ( ( ( ( VideoTrackViewCheckItem* ) it.current()) ->key( 0, false ).compare( i18n("Segments" ) ) == 0 ) && ( ( VideoTrackViewCheckItem* ) it.current() ) ->isOn() ) { + m_videooptions ->setVideoCdRipSegments( true ); + selectedItems++; + } + } + } + + if( selectedItems == 0 ) { + KMessageBox::error( this, i18n("Please select the tracks to rip."), i18n("No Tracks Selected") ); + } + else { + unsigned long videocdsize = 0; + // TODO: split SegmentSize and FileSize. Have no infos now + if ( m_videooptions ->getVideoCdRipSegments() || m_videooptions ->getVideoCdRipFiles()) + videocdsize += m_videocddatasize; + if ( m_videooptions ->getVideoCdRipSequences() ) + videocdsize += m_videocdmpegsize; + + kdDebug() << QString("(K3bVideoCdView::startRip()) m_videooptions ->setVideoCdSize( %1)").arg( videocdsize ) << endl; + m_videooptions ->setVideoCdSize( videocdsize ); + K3bVideoCdRippingDialog rip( m_videooptions, this ); + rip.exec(); + } +} + +void K3bVideoCdView::slotSelectAll() +{ + for ( QListViewItemIterator it( m_trackView ); it.current(); ++it ) + if ( it.current() ->isSelectable() ) + ( ( VideoTrackViewCheckItem* ) it.current() ) ->setOn( true ); +} + +void K3bVideoCdView::slotDeselectAll() +{ + for ( QListViewItemIterator it( m_trackView ); it.current(); ++it ) + if ( it.current() ->isSelectable() ) + ( ( VideoTrackViewCheckItem* ) it.current() ) ->setOn( false ); +} + +void K3bVideoCdView::slotSelect() +{ + if ( QListViewItem * sel = m_trackView->selectedItem() ) { + ( ( VideoTrackViewCheckItem* ) sel) ->setOn( true ); + QListViewItem * item = sel ->firstChild(); + while ( item ) { + if ( item ->isSelectable() ) + ( ( VideoTrackViewCheckItem* ) item) ->setOn( true ); + + item = item->nextSibling(); + } + } +} + +void K3bVideoCdView::slotDeselect() +{ + if ( QListViewItem * sel = m_trackView->selectedItem() ) { + ( ( VideoTrackViewCheckItem* ) sel) ->setOn( false ); + QListViewItem * item = sel ->firstChild(); + while ( item ) { + if ( item ->isSelectable() ) + ( ( VideoTrackViewCheckItem* ) item) ->setOn( false ); + + item = item->nextSibling(); + } + } +} + +void K3bVideoCdView::enableInteraction( bool b ) +{ + actionCollection()->action( "start_rip" )->setEnabled( b ); +} + +void K3bVideoCdView::buildTree( QListViewItem *parentItem, const QDomElement &parentElement, const QString& pname ) +{ + VideoTrackViewItem * thisItem = 0; + QDomNode node = parentElement.firstChild(); + + while ( !node.isNull() ) { + if ( node.isElement() && node.nodeName() == "folder" || node.nodeName() == "file" ) { + if ( parentItem == 0 ) + thisItem = new VideoTrackViewItem( m_trackView, thisItem ); + else + thisItem = new VideoTrackViewItem( parentItem, thisItem ); + + QString txt = node.firstChild().toElement().text(); + thisItem->setText( 0, txt); + if ( node.nodeName() == "folder" ) { + buildTree( thisItem, node.toElement(), pname + "_" + txt.lower() ); + } + else { + thisItem->setText( 1, pname + "_" + txt.lower() ); + buildTree( thisItem, node.toElement(), pname ); + } + } else if ( node.isElement() && node.nodeName() == "segment-item" || node.nodeName() == "sequence-item" ) { + if ( parentItem == 0 ) + thisItem = new VideoTrackViewItem( m_trackView, thisItem ); + else + thisItem = new VideoTrackViewItem( parentItem, thisItem ); + + thisItem->setText( 0, node.toElement().attribute( "src" ) ); + + buildTree( thisItem, node.toElement() ); + } + + node = node.nextSibling(); + } +} + +#include "k3bvideocdview.moc" diff --git a/src/rip/k3bvideocdview.h b/src/rip/k3bvideocdview.h new file mode 100644 index 0000000..cb3e7a6 --- /dev/null +++ b/src/rip/k3bvideocdview.h @@ -0,0 +1,105 @@ +/* +* +* $Id: k3bvideocdview.h 619556 2007-01-03 17:38:12Z trueg $ +* Copyright (C) 2003 Christian Kvasny <chris@k3b.org> +* +* This file is part of the K3b project. +* Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> +* +* 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 2 of the License, or +* (at your option) any later version. +* See the file "COPYING" for the exact licensing terms. +*/ + + +#ifndef _K3B_VIDEOCDVIEW_H_ +#define _K3B_VIDEOCDVIEW_H_ + +#include <qdom.h> + +#include <k3bmediacontentsview.h> +#include <k3bmedium.h> + +#include "k3bvideocdinfo.h" + +class KActionCollection; +class KActionMenu; +class KListView; + +class QLabel; +class QListViewItem; + +class K3bListView; +class K3bToolBox; +class K3bVideoCdRippingOptions; + +namespace K3bDevice +{ + class DiskInfoDetector; + class Toc; + class Device; +} + + +class K3bVideoCdView : public K3bMediaContentsView +{ + Q_OBJECT + + public: + K3bVideoCdView( QWidget* parent = 0, const char * name = 0 ); + ~K3bVideoCdView(); + + KActionCollection* actionCollection() const + { + return m_actionCollection; + } + + private slots: + void slotContextMenu( KListView*, QListViewItem*, const QPoint& ); + void slotTrackSelectionChanged( QListViewItem* ); + void slotStateChanged( QListViewItem* ); + void slotVideoCdInfoFinished( bool ); + + void startRip(); + void slotSelectAll(); + void slotDeselectAll(); + void slotSelect(); + void slotDeselect(); + + private: + + class VideoTrackViewCheckItem; + class VideoTrackViewItem; + + void reloadMedium(); + + void initActions(); + void updateDisplay(); + void enableInteraction( bool ); + void buildTree( QListViewItem *parentItem, const QDomElement &parentElement, const QString& pname = QString::null ); + + K3bDevice::Toc m_toc; + + KActionCollection* m_actionCollection; + KActionMenu* m_popupMenu; + + K3bVideoCdInfoResult m_videocdinfoResult; + K3bVideoCdInfo* m_videocdinfo; + K3bVideoCdRippingOptions* m_videooptions; + + K3bListView* m_trackView; + K3bToolBox* m_toolBox; + QLabel* m_labelLength; + + QDomDocument domTree; + + QValueList<VideoTrackViewCheckItem *> m_contentList; + + unsigned long m_videocddatasize; + unsigned long m_videocdmpegsize; + +}; + +#endif diff --git a/src/rip/videodvd/Makefile.am b/src/rip/videodvd/Makefile.am new file mode 100644 index 0000000..bac9b0a --- /dev/null +++ b/src/rip/videodvd/Makefile.am @@ -0,0 +1,16 @@ +AM_CPPFLAGS = -I$(srcdir)/../../../libk3b/core \ + -I$(srcdir)/../../../libk3bdevice \ + -I$(srcdir)/../../../libk3b/tools \ + -I$(srcdir)/../../../libk3b/videodvd/ \ + -I$(srcdir)/../../../libk3b/jobs/ \ + -I$(srcdir)/../.. \ + $(all_includes) + +METASOURCES = AUTO + +noinst_LTLIBRARIES = libvideodvdrip.la + +libvideodvdrip_la_SOURCES = base_k3bvideodvdrippingwidget.ui k3bvideodvdrippingview.cpp \ + k3bvideodvdrippingtitlelistview.cpp \ + k3bvideodvdrippingjob.cpp k3bvideodvdrippingwidget.cpp \ + k3bvideodvdrippingdialog.cpp k3bvideodvdrippingpreview.cpp diff --git a/src/rip/videodvd/base_k3bvideodvdrippingwidget.ui b/src/rip/videodvd/base_k3bvideodvdrippingwidget.ui new file mode 100644 index 0000000..72b03b4 --- /dev/null +++ b/src/rip/videodvd/base_k3bvideodvdrippingwidget.ui @@ -0,0 +1,721 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>base_K3bVideoDVDRippingWidget</class> +<author>Seastian Trueg</author> +<widget class="QWidget"> + <property name="name"> + <cstring>Form1</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>644</width> + <height>387</height> + </rect> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel4</cstring> + </property> + <property name="text"> + <string>Please select the audio streams you want to include in every ripped title</string> + </property> + </widget> + <widget class="KListView"> + <property name="name"> + <cstring>m_titleView</cstring> + </property> + <property name="allColumnsShowFocus"> + <bool>true</bool> + </property> + <property name="fullWidth"> + <bool>true</bool> + </property> + </widget> + <widget class="QTabWidget"> + <property name="name"> + <cstring>tabWidget2</cstring> + </property> + <widget class="QWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string>Setti&ngs</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QGroupBox" row="0" column="1"> + <property name="name"> + <cstring>groupBox6</cstring> + </property> + <property name="title"> + <string>Video Quality</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout9</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel2_2</cstring> + </property> + <property name="text"> + <string>Video Size:</string> + </property> + </widget> + <widget class="QComboBox"> + <property name="name"> + <cstring>m_comboVideoSize</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>1</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_buttonCustomPictureSize</cstring> + </property> + <property name="text"> + <string>&Custom...</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout9</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel2_3</cstring> + </property> + <property name="text"> + <string>Video Bitrate:</string> + </property> + </widget> + <widget class="QSpinBox"> + <property name="name"> + <cstring>m_spinVideoBitrate</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>1</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="suffix"> + <string> kbps</string> + </property> + <property name="maxValue"> + <number>10000</number> + </property> + <property name="value"> + <number>1800</number> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + <widget class="QGroupBox" row="1" column="0"> + <property name="name"> + <cstring>groupBox1_2</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>1</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>Target Folder</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel1_2</cstring> + </property> + <property name="text"> + <string>Free space in directory:</string> + </property> + </widget> + <widget class="KURLRequester" row="0" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>m_editBaseDir</cstring> + </property> + </widget> + <widget class="QLabel" row="1" column="1"> + <property name="name"> + <cstring>m_labelFreeSpace</cstring> + </property> + <property name="text"> + <string>-</string> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>textLabel1_2_2</cstring> + </property> + <property name="text"> + <string>Space needed:</string> + </property> + </widget> + <widget class="QLabel" row="2" column="1"> + <property name="name"> + <cstring>m_labelNeededSpace</cstring> + </property> + <property name="text"> + <string>-</string> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + </grid> + </widget> + <widget class="QGroupBox" row="1" column="1"> + <property name="name"> + <cstring>groupBox4</cstring> + </property> + <property name="title"> + <string>Audio Quality</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QWidgetStack"> + <property name="name"> + <cstring>m_stackAudioQuality</cstring> + </property> + <widget class="QWidget"> + <property name="name"> + <cstring>m_stackPageAudioQualityMp3</cstring> + </property> + <attribute name="id"> + <number>0</number> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_checkAudioVBR</cstring> + </property> + <property name="text"> + <string>Variable &Bitrate</string> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout4</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>m_labelAudioBitrate</cstring> + </property> + <property name="text"> + <string>Audio Bitrate:</string> + </property> + </widget> + <widget class="QComboBox"> + <property name="name"> + <cstring>m_comboAudioBitrate</cstring> + </property> + <property name="duplicatesEnabled"> + <bool>false</bool> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>m_stackPageAudioQualityAC3Pt</cstring> + </property> + <attribute name="id"> + <number>1</number> + </attribute> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="KActiveLabel"> + <property name="name"> + <cstring>m_labelNoAudioSettings</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>7</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string><p>No Audio Quality settings available for <em>AC3 pass-through</em>. The audio stream from the Video DVD is used without any changes.</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>m_stackPageAudioQualityAC3</cstring> + </property> + <attribute name="id"> + <number>2</number> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout8</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1_3</cstring> + </property> + <property name="text"> + <string>Audio Bitrate:</string> + </property> + </widget> + <widget class="QSpinBox"> + <property name="name"> + <cstring>m_spinAudioBitrate</cstring> + </property> + <property name="suffix"> + <string> kbps</string> + </property> + <property name="maxValue"> + <number>640</number> + </property> + <property name="minValue"> + <number>32</number> + </property> + <property name="lineStep"> + <number>2</number> + </property> + <property name="value"> + <number>128</number> + </property> + </widget> + </hbox> + </widget> + <spacer> + <property name="name"> + <cstring>spacer3</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>0</height> + </size> + </property> + </spacer> + </vbox> + </widget> + </widget> + </vbox> + </widget> + <widget class="QGroupBox" row="0" column="0"> + <property name="name"> + <cstring>groupBox1</cstring> + </property> + <property name="title"> + <string>Filetype</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout10</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Video Codec:</string> + </property> + </widget> + <widget class="K3bIntMapComboBox"> + <property name="name"> + <cstring>m_comboVideoCodec</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>Select the Video codec used to encode the DVD titles</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout9</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Audio Codec:</string> + </property> + </widget> + <widget class="K3bIntMapComboBox"> + <property name="name"> + <cstring>m_comboAudioCodec</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>Select the Audio codec used to encode the DVD titles</string> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + </grid> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>TabPage</cstring> + </property> + <attribute name="title"> + <string>File Namin&g</string> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout14</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1_4</cstring> + </property> + <property name="text"> + <string>Ripped files pattern:</string> + </property> + </widget> + <widget class="QComboBox"> + <property name="name"> + <cstring>m_comboFilenamePattern</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>1</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="acceptDrops"> + <bool>true</bool> + </property> + <property name="editable"> + <bool>true</bool> + </property> + <property name="duplicatesEnabled"> + <bool>false</bool> + </property> + </widget> + </hbox> + </widget> + <widget class="KURLLabel"> + <property name="name"> + <cstring>m_specialStringsLabel</cstring> + </property> + <property name="text"> + <string>See special strings</string> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout8</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_checkBlankReplace</cstring> + </property> + <property name="text"> + <string>Replace all &blanks with:</string> + </property> + </widget> + <widget class="KLineEdit"> + <property name="name"> + <cstring>m_editBlankReplace</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>1</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>_</string> + </property> + </widget> + </hbox> + </widget> + <spacer> + <property name="name"> + <cstring>spacer5</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>5</width> + <height>1</height> + </size> + </property> + </spacer> + </vbox> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string>&Advanced</string> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_checkTwoPassEncoding</cstring> + </property> + <property name="text"> + <string>&2-pass encoding</string> + </property> + <property name="accel"> + <string>Alt+2</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + <property name="toolTip" stdset="0"> + <string>Enable 2-pass encoding</string> + </property> + <property name="whatsThis" stdset="0"> + <string><p>If this option is checked K3b encodes the video titles in two passes. The first pass is used to gather information about the video in order to improve the distribution of bits in the second pass. The resulting video will have a higher quality using a variable bitrate. +<p>If this option is not checked K3b will create video files with a constant bitrate and a lower quality. +<p>2-pass encoding results in a doubled encoding time.</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_checkAutoClipping</cstring> + </property> + <property name="text"> + <string>Automatic &Video Clipping</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + <property name="toolTip" stdset="0"> + <string>Automatically detect the black borders of the video</string> + </property> + <property name="whatsThis" stdset="0"> + <string><p>Most Video DVDs are encoded in a letterboxed format. <em>Letterboxed</em> refers to black bars used at the top and bottom (and sometimes at the sides) of the video to force it into one of the aspect ratios supported by the Video DVD standard. +<p>If this option is checked K3b will automatically detect and remove these black bars from the resulting video. +<p>Although this method is very reliable there may be problems if the source material is exceptionally short or dark.</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_checkAudioResampling</cstring> + </property> + <property name="text"> + <string>Resample Audio to &44.1 KHz</string> + </property> + <property name="accel"> + <string>Alt+4</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + <property name="toolTip" stdset="0"> + <string>Change the sample rate of the audio stream to 44.1 KHz</string> + </property> + <property name="whatsThis" stdset="0"> + <string><p>Video DVD audio streams normally are encoded with a sampling rate of 48000 Hz. Audio CDs on the other hand are encoded with a sampling rate of 44100 Hz. +<p>If this option is checked K3b will change the sampling rate of the audio stream to 44100 Hz.</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_checkLowPriority</cstring> + </property> + <property name="text"> + <string>Low s&cheduling priority for the video transcoding process</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>1</height> + </size> + </property> + </spacer> + </vbox> + </widget> + </widget> + </vbox> +</widget> +<customwidgets> + <customwidget> + <class>K3bIntMapComboBox</class> + <header location="global">k3bintmapcombobox.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>0</container> + <sizepolicy> + <hordata>5</hordata> + <verdata>5</verdata> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + <pixmap>image0</pixmap> + </customwidget> +</customwidgets> +<images> + <image name="image0"> + <data format="PNG" length="1125">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000042c49444154388db5954f6c14551cc73fefcd7476b65bdaae4bb78bb5502a14d404e4801c88182d1c4c2c693da847400f9c24c68b878684238660e2b1e01f12c19493012ef2478c814412d354a46017a8a564bb6da5bbedccee767776e63d0ffb073751d483bfe49799974c3eeffb7ebf37df9fd05a530b2184040cc0042420aaf9a4d0d554800f045a6b256ae0e1e1e1d6bebebe838ee31c48a7d39b5cd7fd075e251cc7617272f2ded8d8d819cff33e0316819259537aead4a9839d5dd6d1784f91f55b0a94830242088404d304292bef68a89f520802a598fecddaa04f1a876f5c250c7c0a64cdeac686e33807e23d45e6b297c8b877f1831542614550b6599835c83c2a81b6786a75134faf2f1169f12997350881d9021d0903e06de0745d3160a6d3e94dbd5b0a64dcbb94b5831d0e3375ab892b1772dcf9790528543f8dd0d367b36768153b5e31503a0f1aecb004580b44ffac58baae8b1714f0833c7638cc8dab303a320f4822ab4c7a37c69196203de3319d5ce1c4d13c733331dedc67a129a154fd128401ab0616d55a130ac3d42d93d1913940d13fd0c9ee0183685c60da01c5421bd72f7a8c8efccef9afd374267ad93d642365be0636a0d28ec7600941d9e6f23917f0e97f23ce5bef35d19ec863da0ed9059b2be70bec196c66dfa10ec0e49b338f7017258651bf95021035c595429bb0903248fe52a2b5b595dd7b4d945cc2340cdca536be389ee3f67886c5798f773fe8e0dac508c989659277a2180da4ca4ff07821058b8b251445d63d6b13ed1098a6417e39cac85197dbe31962ab9bd9f1f22a226d45366f6d0620fdb08c900d281af6110284b20085b414861d905d88f2e52739ee8cbb8022143259d3dd84691730aa2d52da441a8de0c6958068870022a41e9629ad3473fd3b8fdbe319dadb9b4924da994d2d716c7896fbe35152f78b48245d6b2da4507faf582be8eaf159b721cc837b05ae7debb1f79d08cb8b515edad942a22bc4b1c33eb3d34b1c797f06af90a72d16e2f96d9a74aa11dca8586b222d01af0fb60070f6c402d72f15d97f28c6f6d7027a5f5ce6c3233dc4e2ede496b278be4fff608cee8d3e1add806aeca51094cbb06397c1ecc328e746537c7e3ccdb5cb1136bf60635882d4d41c6ec6836ab37efa214f72208ed9f4d7cdd38ee310280542e38b1c43fb6de26b3672e1ec3cc99bcb246f66a938a3241ab3e91f7c861fbf77710b1e5e49915bae974203ba0e9e9c9cbc373d6d6d305a040a89c2a77f50b27d5782bbbf7acccf28349235dd16cf6dd374f7295e1de8a45c02d37499182b01cc0201a085d61a2144d8b2ac8fb6ed340e77240c4261890e04c250185262546d534a032154b59e0ad394e41c98182bf268ce6721ed9f064e0253356f6da2e24c1f030f783c15fe6da680af8021602bd051532ca9b8521488559f61aa86c29343578fbf0264a94c906c7d3409214c20043457a116ff6de6795578012889ff6b98fe016ea0ce1c6a2573410000000049454e44ae426082</data> + </image> +</images> +<connections> + <connection> + <sender>m_checkBlankReplace</sender> + <signal>toggled(bool)</signal> + <receiver>m_editBlankReplace</receiver> + <slot>setEnabled(bool)</slot> + </connection> +</connections> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>klistview.h</includehint> + <includehint>kurlrequester.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kactivelabel.h</includehint> + <includehint>k3bintmapcombobox.h</includehint> + <includehint>k3bintmapcombobox.h</includehint> + <includehint>kurllabel.h</includehint> + <includehint>klineedit.h</includehint> +</includehints> +</UI> diff --git a/src/rip/videodvd/k3bvideodvdrippingdialog.cpp b/src/rip/videodvd/k3bvideodvdrippingdialog.cpp new file mode 100644 index 0000000..ddb5ff2 --- /dev/null +++ b/src/rip/videodvd/k3bvideodvdrippingdialog.cpp @@ -0,0 +1,634 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bvideodvdrippingdialog.h" +#include "k3bvideodvdrippingwidget.h" +#include <k3bvideodvdtitletranscodingjob.h> +#include <k3bjobprogressdialog.h> +#include <k3bapplication.h> +#include <k3bmedium.h> +#include <k3bmediacache.h> +#include <k3bglobals.h> +#include <k3bfilesysteminfo.h> + +#include <klocale.h> +#include <klistview.h> +#include <klocale.h> +#include <kglobal.h> +#include <kurlrequester.h> +#include <kcombobox.h> +#include <klineedit.h> +#include <kio/global.h> +#include <kconfig.h> +#include <kmessagebox.h> + +#include <qlayout.h> +#include <qcheckbox.h> +#include <qspinbox.h> +#include <qstyle.h> +#include <qfontmetrics.h> + + +static QString videoCodecId( K3bVideoDVDTitleTranscodingJob::VideoCodec codec ) +{ + switch( codec ) { + case K3bVideoDVDTitleTranscodingJob::VIDEO_CODEC_FFMPEG_MPEG4: + return "ffmpeg_mpeg4"; + case K3bVideoDVDTitleTranscodingJob::VIDEO_CODEC_XVID: + return "xvid"; + default: + return "none"; + } +} + + +static QString audioCodecId( K3bVideoDVDTitleTranscodingJob::AudioCodec codec ) +{ + switch( codec ) { + case K3bVideoDVDTitleTranscodingJob::AUDIO_CODEC_MP3: + return "mp3"; + case K3bVideoDVDTitleTranscodingJob::AUDIO_CODEC_AC3_STEREO: + return "ac3_stereo"; + case K3bVideoDVDTitleTranscodingJob::AUDIO_CODEC_AC3_PASSTHROUGH: + return "ac3_passthrough"; + default: + return "none"; + } +} + + +static K3bVideoDVDTitleTranscodingJob::VideoCodec videoCodecFromId( const QString& codec ) +{ + if( codec == "xvid" ) + return K3bVideoDVDTitleTranscodingJob::VIDEO_CODEC_XVID; + else // if( codec == "ffmpeg_mpeg4" ) + return K3bVideoDVDTitleTranscodingJob::VIDEO_CODEC_FFMPEG_MPEG4; +} + + +static K3bVideoDVDTitleTranscodingJob::AudioCodec audioCodecFromId( const QString& codec ) +{ + if( codec == "ac3_stereo" ) + return K3bVideoDVDTitleTranscodingJob::AUDIO_CODEC_AC3_STEREO; + else if( codec == "ac3_passthrough" ) + return K3bVideoDVDTitleTranscodingJob::AUDIO_CODEC_AC3_PASSTHROUGH; + else // if( codec == "mp3" ) + return K3bVideoDVDTitleTranscodingJob::AUDIO_CODEC_MP3; +} + + +// resize according to aspect ratio +static QSize resizeTitle( const K3bVideoDVD::VideoStream& title, const QSize& size ) +{ + int w = size.width(); + int h = size.height(); + int rw = title.realPictureWidth(); + int rh = title.realPictureHeight(); + + if( w == 0 && h == 0 ) { + w = rw; + h = rh; + } + else if( w == 0 ) { + w = h * rw / rh; + } + else if( h == 0 ) { + h = w * rh / rw; + } + + return QSize(w,h); +} + + + +class K3bVideoDVDRippingDialog::AudioStreamViewItem : public QCheckListItem +{ +public: + AudioStreamViewItem( K3bVideoDVDRippingDialog* dlg, + QCheckListItem* parent, QListViewItem* after, const QString& text, + int audioStream ) + : QCheckListItem( parent, after, text, RadioButton ), + m_audioStream( audioStream ), + m_dlg( dlg ) { + } + +private: + void stateChange( bool ) { + if( state() == On ) { + m_dlg->m_titleRipInfos[static_cast<QCheckListItem*>(parent())].audioStream = m_audioStream; + m_dlg->slotUpdateFilenames(); + } + } + + int m_audioStream; + K3bVideoDVDRippingDialog* m_dlg; +}; + + +class K3bVideoDVDRippingDialog::Private +{ +public: + K3bFileSystemInfo fsInfo; +}; + + +K3bVideoDVDRippingDialog::K3bVideoDVDRippingDialog( const K3bVideoDVD::VideoDVD& dvd, + const QValueList<int>& titles, + QWidget* parent, const char* name ) + : K3bInteractionDialog( parent, name, + i18n("Video DVD Ripping"), + QString::null, + START_BUTTON|CANCEL_BUTTON, + START_BUTTON, + "VideoDVD Ripping" ), // config group + m_dvd( dvd ) +{ + d = new Private; + + QWidget* frame = mainWidget(); + QHBoxLayout* frameLayout = new QHBoxLayout( frame ); + frameLayout->setMargin( 0 ); + frameLayout->setAutoAdd( true ); + m_w = new K3bVideoDVDRippingWidget( frame ); + + connect( m_w, SIGNAL(changed()), + this, SLOT(slotUpdateFilesizes()) ); + connect( m_w, SIGNAL(changed()), + this, SLOT(slotUpdateFilenames()) ); + connect( m_w, SIGNAL(changed()), + this, SLOT(slotUpdateVideoSizes()) ); + + setTitle( i18n("Video DVD Ripping"), + i18n("1 title from %1", "%n titles from %1", titles.count()) + .arg( k3bappcore->mediaCache()->medium(m_dvd.device()).beautifiedVolumeId() ) ); + + // populate list map + populateTitleView( titles ); +} + + +K3bVideoDVDRippingDialog::~K3bVideoDVDRippingDialog() +{ + delete d; +} + + +void K3bVideoDVDRippingDialog::populateTitleView( const QValueList<int>& titles ) +{ + m_w->m_titleView->clear(); + m_titleRipInfos.clear(); + + QCheckListItem* titleItem = 0; + for( QValueList<int>::const_iterator it = titles.begin(); it != titles.end(); ++it ) { + titleItem = new QCheckListItem( m_w->m_titleView, + titleItem, + i18n("Title %1 (%2)") + .arg(*it) + .arg(m_dvd[*it-1].playbackTime().toString()), + QCheckListItem::RadioButtonController ); + titleItem->setText( 1, QString("%1x%2") + .arg(m_dvd[*it-1].videoStream().realPictureWidth()) + .arg(m_dvd[*it-1].videoStream().realPictureHeight()) ); + titleItem->setText( 3, QString("%1 Title %2.avi").arg(m_dvd.volumeIdentifier()).arg(*it) ); + + // now for the rip info + K3bVideoDVDRippingJob::TitleRipInfo ri( *it ); + + // + // Determine default language selection: + // first try the configured locale, if that fails, fall back to the first audio stream + // + ri.audioStream = 0; + for( unsigned int i = 0; i < m_dvd[*it-1].numAudioStreams(); ++i ) { + if( m_dvd[*it-1].audioStream(i).langCode() == KGlobal::locale()->language() && + m_dvd[*it-1].audioStream(i).format() != K3bVideoDVD::AUDIO_FORMAT_DTS ) { + ri.audioStream = i; + break; + } + } + + QListViewItem* asI = 0; + for( unsigned int i = 0; i < m_dvd[*it-1].numAudioStreams(); ++i ) { + QString text = i18n("%1 %2Ch (%3%4)") + .arg( K3bVideoDVD::audioFormatString( m_dvd[*it-1].audioStream(i).format() ) ) + .arg( m_dvd[*it-1].audioStream(i).channels() ) + .arg( m_dvd[*it-1].audioStream(i).langCode().isEmpty() + ? i18n("unknown language") + : KGlobal::locale()->twoAlphaToLanguageName( m_dvd[*it-1].audioStream(i).langCode() ) ) + .arg( m_dvd[*it-1].audioStream(i).codeExtension() != K3bVideoDVD::AUDIO_CODE_EXT_UNSPECIFIED + ? QString(" ") + K3bVideoDVD::audioCodeExtensionString( m_dvd[*it-1].audioStream(i).codeExtension() ) + : QString::null ); + + if( m_dvd[*it-1].audioStream(i).format() == K3bVideoDVD::AUDIO_FORMAT_DTS ) { + // width of the radio button from QCheckListItem::paintCell + int buttonSize = style().pixelMetric( QStyle::PM_CheckListButtonSize, m_w->m_titleView ) + 4; + int spaceWidth = fontMetrics().width( ' ' ); + int numSpaces = buttonSize/spaceWidth; + asI = new QListViewItem( titleItem, asI, QString().fill( ' ', numSpaces ) + text + " (" + i18n("not supported") + ")" ); + } + else { + asI = new AudioStreamViewItem( this, titleItem, asI, text, i ); + + if( ri.audioStream == (int)i ) + ((AudioStreamViewItem*)asI)->setState( QCheckListItem::On ); + } + } + + titleItem->setOpen( true ); + + m_titleRipInfos[titleItem] = ri; + } +} + + +void K3bVideoDVDRippingDialog::slotUpdateFilenames() +{ + QString baseDir = K3b::prepareDir( m_w->m_editBaseDir->url() ); + d->fsInfo.setPath( baseDir ); + + for( QMap<QCheckListItem*, K3bVideoDVDRippingJob::TitleRipInfo>::iterator it = m_titleRipInfos.begin(); + it != m_titleRipInfos.end(); ++it ) { + QString f = d->fsInfo.fixupPath( createFilename( it.data(), m_w->m_comboFilenamePattern->currentText() ) ); + if( m_w->m_checkBlankReplace->isChecked() ) + f.replace( QRegExp( "\\s" ), m_w->m_editBlankReplace->text() ); + it.data().filename = baseDir + f; + it.key()->setText( 3, f ); + } +} + + +void K3bVideoDVDRippingDialog::slotUpdateFilesizes() +{ + double bitrate = (double)m_w->m_spinVideoBitrate->value(); + KIO::filesize_t overallSize = 0ULL; + + // update file sizes + for( QMap<QCheckListItem*, K3bVideoDVDRippingJob::TitleRipInfo>::iterator it = m_titleRipInfos.begin(); + it != m_titleRipInfos.end(); ++it ) { + + double sec = m_dvd[it.data().title-1].playbackTime().totalSeconds(); + + // estimate the filesize + KIO::filesize_t size = (KIO::filesize_t)( sec * bitrate * 1000.0 / 8.0 ); + + // add audio stream size + // FIXME: consider AC3 passthrough + size += (KIO::filesize_t)( sec * m_w->selectedAudioBitrate() / 8.0 * 1024.0 ); + + it.key()->setText( 2, KIO::convertSize( size ) ); + + overallSize += size; + } + + m_w->setNeededSize( overallSize ); +} + + +void K3bVideoDVDRippingDialog::slotUpdateVideoSizes() +{ + QSize size = m_w->selectedPictureSize(); + for( QMap<QCheckListItem*, K3bVideoDVDRippingJob::TitleRipInfo>::iterator it = m_titleRipInfos.begin(); + it != m_titleRipInfos.end(); ++it ) { + QSize s( resizeTitle( m_dvd[it.data().title-1].videoStream(), size ) ); + it.key()->setText( 1, QString("%1x%2").arg(s.width()).arg(s.height()) ); + } +} + + +void K3bVideoDVDRippingDialog::setBaseDir( const QString& path ) +{ + m_w->m_editBaseDir->setURL( path ); +} + + +QString K3bVideoDVDRippingDialog::createFilename( const K3bVideoDVDRippingJob::TitleRipInfo& info, const QString& pattern ) const +{ + QString f; + + const K3bVideoDVD::Title& title = m_dvd[info.title-1]; + + for( unsigned int i = 0; i < pattern.length(); ++i ) { + // + // every pattern starts with a % sign + // + if( pattern[i] == '%' ) { + ++i; // skip the % + QChar c = pattern[i]; + + // + // first check if we have a long keyword instead of a one-char + // + if( pattern[i] == '{' ) { + int j = pattern.find( '}', i ); + if( j < 0 ) // no closing bracket -> no valid pattern + c = '*'; + else { + QString keyword = pattern.mid( i+1, j-i-1 ); + if( keyword == "titlenumber" || + keyword == "title_number" || + keyword == "title" ) { + c = PATTERN_TITLE_NUMBER; + } + else if( keyword == "volumeid" || + keyword == "volume_id" || + keyword == "volid" || + keyword == "vol_id" ) { + c = PATTERN_VOLUME_ID; + } + else if( keyword == "beautifiedvolumeid" || + keyword == "beautified_volumeid" || + keyword == "beautified_volume_id" || + keyword == "beautifiedvolid" || + keyword == "beautified_volid" || + keyword == "beautified_vol_id" || + keyword == "nicevolid" || + keyword == "nice_volid" || + keyword == "nice_vol_id" ) { + c = PATTERN_BEAUTIFIED_VOLUME_ID; + } + else if( keyword == "languagecode" || + keyword == "language_code" || + keyword == "langcode" || + keyword == "lang_code" ) { + c = PATTERN_LANGUAGE_CODE; + + } + else if( keyword == "lang" || + keyword == "language" || + keyword == "langname" || + keyword == "languagename" || + keyword == "lang_name" || + keyword == "language_name" ) { + c = PATTERN_LANGUAGE_NAME; + } + else if( keyword == "audioformat" || + keyword == "audio_format" || + keyword == "audio" ) { + c = PATTERN_AUDIO_FORMAT; + } + else if( keyword == "channels" || + keyword == "audiochannels" || + keyword == "audio_channels" || + keyword == "ch" ) { + c = PATTERN_AUDIO_CHANNELS; + } + else if( keyword == "videosize" || + keyword == "video_size" || + keyword == "vsize" ) { + c = PATTERN_VIDEO_SIZE; + } + else if( keyword == "originalvideosize" || + keyword == "original_video_size" || + keyword == "origvideosize" || + keyword == "orig_video_size" || + keyword == "origvsize" ) { + c = PATTERN_ORIG_VIDEO_SIZE; + } + else if( keyword == "aspect_ratio" || + keyword == "aspectratio" || + keyword == "ratio" ) { + c = PATTERN_ASPECT_RATIO; + } + else if( keyword == "current_date" || + keyword == "currentdate" || + keyword == "date" ) { + c = PATTERN_CURRENT_DATE; + } + else { + // unusable pattern + c = '*'; + } + + // + // skip the keyword and the closing bracket + // + if( c != '*' ) { + i += keyword.length() + 1; + } + } + } + + switch( c ) { + case PATTERN_TITLE_NUMBER: + f.append( QString::number(info.title).rightJustify( 2, '0' ) ); + break; + case PATTERN_VOLUME_ID: + f.append( m_dvd.volumeIdentifier() ); + break; + case PATTERN_BEAUTIFIED_VOLUME_ID: + f.append( k3bappcore->mediaCache()->medium( m_dvd.device() ).beautifiedVolumeId() ); + break; + case PATTERN_LANGUAGE_CODE: + if( title.numAudioStreams() > 0 ) + f.append( title.audioStream( info.audioStream ).langCode() ); + break; + case PATTERN_LANGUAGE_NAME: + if( title.numAudioStreams() > 0 ) + f.append( KGlobal::locale()->twoAlphaToLanguageName( title.audioStream( info.audioStream ).langCode() ) ); + break; + case PATTERN_AUDIO_FORMAT: + // FIXME: what about MPEG audio streams? + if( title.numAudioStreams() > 0 ) { + if( m_w->selectedAudioCodec() == K3bVideoDVDTitleTranscodingJob::AUDIO_CODEC_MP3 ) + f.append( K3bVideoDVDTitleTranscodingJob::audioCodecString( m_w->selectedAudioCodec() ) ); + else + f.append( K3bVideoDVD::audioFormatString( title.audioStream( info.audioStream ).format() ) ); + } + break; + case PATTERN_AUDIO_CHANNELS: + if( title.numAudioStreams() > 0 ) + f.append( i18n("%nCh", "%nCh", + m_w->selectedAudioCodec() == K3bVideoDVDTitleTranscodingJob::AUDIO_CODEC_AC3_PASSTHROUGH + ? title.audioStream( info.audioStream ).channels() + : 2 ) ); + break; + case PATTERN_ORIG_VIDEO_SIZE: + f.append( QString("%1x%2") + .arg(title.videoStream().pictureWidth()) + .arg(title.videoStream().pictureHeight()) ); + break; + case PATTERN_VIDEO_SIZE: { + QSize s( resizeTitle( m_dvd[info.title-1].videoStream(), m_w->selectedPictureSize() ) ); + f.append( QString("%1x%2").arg(s.width()).arg(s.height()) ); + break; + } + case PATTERN_ASPECT_RATIO: + if( title.videoStream().displayAspectRatio() == K3bVideoDVD::VIDEO_ASPECT_RATIO_4_3 ) + f.append( "4:3" ); + else + f.append( "16:9" ); + break; + case PATTERN_CURRENT_DATE: + f.append( KGlobal::locale()->formatDate( QDate::currentDate() ) ); + break; + default: + f.append( pattern[i-1] ); + f.append( pattern[i] ); + } + } + + // + // normal character -> just append to filename + // + else { + f.append( pattern[i] ); + } + } + + // + // and the extension (for now only avi) + // + f.append( ".avi" ); + + return f; +} + + +void K3bVideoDVDRippingDialog::loadK3bDefaults() +{ + m_w->m_spinVideoBitrate->setValue( 1800 ); + m_w->m_checkTwoPassEncoding->setChecked( true ); + m_w->m_checkAudioResampling->setChecked( false ); + m_w->m_checkAutoClipping->setChecked( false ); + m_w->m_checkLowPriority->setChecked( true ); + m_w->m_checkAudioVBR->setChecked( true ); + m_w->setSelectedAudioBitrate( 128 ); + m_w->setSelectedVideoCodec( K3bVideoDVDTitleTranscodingJob::VIDEO_CODEC_FFMPEG_MPEG4 ); + m_w->setSelectedAudioCodec( K3bVideoDVDTitleTranscodingJob::AUDIO_CODEC_MP3 ); + m_w->m_checkBlankReplace->setChecked( false ); + m_w->m_editBlankReplace->setText( "_" ); + m_w->m_comboFilenamePattern->setEditText( m_w->m_comboFilenamePattern->text(0) ); + m_w->m_editBaseDir->setURL( K3b::defaultTempPath() ); +} + + +void K3bVideoDVDRippingDialog::loadUserDefaults( KConfigBase* c ) +{ + m_w->m_spinVideoBitrate->setValue( c->readNumEntry( "video bitrate", 1200 ) ); + m_w->m_checkTwoPassEncoding->setChecked( c->readBoolEntry( "two pass encoding", true ) ); + m_w->m_checkAudioResampling->setChecked( c->readBoolEntry( "audio resampling", false ) ); + m_w->m_checkAutoClipping->setChecked( c->readBoolEntry( "auto clipping", false ) ); + m_w->m_checkLowPriority->setChecked( c->readBoolEntry( "low priority", true ) ); + m_w->m_checkAudioVBR->setChecked( c->readBoolEntry( "vbr audio", true ) ); + m_w->setSelectedAudioBitrate( c->readNumEntry( "audio bitrate", 128 ) ); + m_w->setSelectedVideoCodec( videoCodecFromId( c->readEntry( "video codec", videoCodecId( K3bVideoDVDTitleTranscodingJob::VIDEO_CODEC_FFMPEG_MPEG4 ) ) ) ); + m_w->setSelectedAudioCodec( audioCodecFromId( c->readEntry( "audio codec", audioCodecId( K3bVideoDVDTitleTranscodingJob::AUDIO_CODEC_MP3 ) ) ) ); + m_w->m_checkBlankReplace->setChecked( c->readBoolEntry( "replace blanks", false ) ); + m_w->m_editBlankReplace->setText( c->readEntry( "blank replace string", "_" ) ); + m_w->m_comboFilenamePattern->setEditText( c->readEntry( "filename pattern", m_w->m_comboFilenamePattern->text(0) ) ); + m_w->m_editBaseDir->setURL( c->readPathEntry( "base dir", K3b::defaultTempPath() ) ); +} + + +void K3bVideoDVDRippingDialog::saveUserDefaults( KConfigBase* c ) +{ + c->writeEntry( "video bitrate", m_w->m_spinVideoBitrate->value() ); + c->writeEntry( "two pass encoding", m_w->m_checkTwoPassEncoding->isChecked() ); + c->writeEntry( "audio resampling", m_w->m_checkAudioResampling->isChecked() ); + c->writeEntry( "auto clipping", m_w->m_checkAutoClipping->isChecked() ); + c->writeEntry( "low priority", m_w->m_checkLowPriority->isChecked() ); + c->writeEntry( "vbr audio", m_w->m_checkAudioVBR->isChecked() ); + c->writeEntry( "audio bitrate", m_w->selectedAudioBitrate() ); + c->writeEntry( "video codec", videoCodecId( m_w->selectedVideoCodec() ) ); + c->writeEntry( "audio codec", audioCodecId( m_w->selectedAudioCodec() ) ); + c->writeEntry( "replace blanks", m_w->m_checkBlankReplace->isChecked() ); + c->writeEntry( "blank replace string", m_w->m_editBlankReplace->text() ); + c->writeEntry( "filename pattern", m_w->m_comboFilenamePattern->currentText() ); + c->writePathEntry( "base dir", m_w->m_editBaseDir->url() ); +} + + +void K3bVideoDVDRippingDialog::slotStartClicked() +{ + // + // check if the selected audio codec is usable for all selected audio streams + // We can only use the AC3 pass-through mode for AC3 streams + // + if( m_w->selectedAudioCodec() == K3bVideoDVDTitleTranscodingJob::AUDIO_CODEC_AC3_PASSTHROUGH ) { + for( QMap<QCheckListItem*, K3bVideoDVDRippingJob::TitleRipInfo>::iterator it = m_titleRipInfos.begin(); + it != m_titleRipInfos.end(); ++it ) { + if( m_dvd[it.data().title-1].numAudioStreams() > 0 && + m_dvd[it.data().title-1].audioStream(it.data().audioStream).format() != K3bVideoDVD::AUDIO_FORMAT_AC3 ) { + KMessageBox::sorry( this, i18n("<p>When using the <em>AC3 pass-through</em> audio codec all selected audio " + "streams need to be in AC3 format. Please select another audio codec or " + "choose AC3 audio streams for all ripped titles."), + i18n("AC3 Pass-through") ); + return; + } + } + } + + // check if we need to overwrite some files... + QStringList filesToOverwrite; + for( QMap<QCheckListItem*, K3bVideoDVDRippingJob::TitleRipInfo>::iterator it = m_titleRipInfos.begin(); + it != m_titleRipInfos.end(); ++it ) { + if( QFile::exists( it.data().filename ) ) + filesToOverwrite.append( it.data().filename ); + } + + if( !filesToOverwrite.isEmpty() ) + if( KMessageBox::questionYesNoList( this, + i18n("Do you want to overwrite these files?"), + filesToOverwrite, + i18n("Files Exist"), i18n("Overwrite"), KStdGuiItem::cancel() ) == KMessageBox::No ) + return; + + + QSize videoSize = m_w->selectedPictureSize(); + int i = 0; + QValueVector<K3bVideoDVDRippingJob::TitleRipInfo> titles( m_titleRipInfos.count() ); + for( QMapConstIterator<QCheckListItem*, K3bVideoDVDRippingJob::TitleRipInfo> it = m_titleRipInfos.begin(); + it != m_titleRipInfos.end(); ++it ) { + titles[i] = it.data(); + titles[i].videoBitrate = 0; // use the global bitrate set below + titles[i].width = videoSize.width(); + titles[i].height = videoSize.height(); + ++i; + } + + // sort the titles which come from a map and are thus not sorted properly + // simple bubble sort for these small arrays is sufficient + for( unsigned int i = 0; i < titles.count(); ++i ) { + for( unsigned int j = i+1; j < titles.count(); ++j ) { + if( titles[i].title > titles[j].title ) { + K3bVideoDVDRippingJob::TitleRipInfo tmp = titles[i]; + titles[i] = titles[j]; + titles[j] = tmp; + } + } + } + + // start the job + K3bJobProgressDialog dlg( parentWidget() ); + K3bVideoDVDRippingJob* job = new K3bVideoDVDRippingJob( &dlg, &dlg ); + job->setVideoDVD( m_dvd ); + job->setTitles( titles ); + + job->setVideoBitrate( m_w->m_spinVideoBitrate->value() ); + job->setTwoPassEncoding( m_w->m_checkTwoPassEncoding->isChecked() ); + job->setResampleAudioTo44100( m_w->m_checkAudioResampling->isChecked() ); + job->setAutoClipping( m_w->m_checkAutoClipping->isChecked() ); + job->setVideoCodec( m_w->selectedVideoCodec() ); + job->setAudioCodec( m_w->selectedAudioCodec() ); + job->setLowPriority( m_w->m_checkLowPriority->isChecked() ); + job->setAudioBitrate( m_w->selectedAudioBitrate() ); + job->setAudioVBR( m_w->m_checkAudioVBR->isChecked() ); + + hide(); + dlg.startJob( job ); + close(); +} + +#include "k3bvideodvdrippingdialog.moc" diff --git a/src/rip/videodvd/k3bvideodvdrippingdialog.h b/src/rip/videodvd/k3bvideodvdrippingdialog.h new file mode 100644 index 0000000..1acad53 --- /dev/null +++ b/src/rip/videodvd/k3bvideodvdrippingdialog.h @@ -0,0 +1,82 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_VIDEODVD_RIPPING_DIALOG_H_ +#define _K3B_VIDEODVD_RIPPING_DIALOG_H_ + +#include <k3binteractiondialog.h> +#include <k3bvideodvd.h> +#include "k3bvideodvdrippingjob.h" + +#include <qvaluelist.h> +#include <qmap.h> + + +class K3bVideoDVDRippingWidget; +class QCheckListItem; + +class K3bVideoDVDRippingDialog : public K3bInteractionDialog +{ + Q_OBJECT + + public: + K3bVideoDVDRippingDialog( const K3bVideoDVD::VideoDVD& dvd, + const QValueList<int>& titles, + QWidget *parent = 0, const char *name = 0 ); + ~K3bVideoDVDRippingDialog(); + + void setBaseDir( const QString& path ); + + enum FileNamingPattern { + PATTERN_TITLE_NUMBER = 't', + PATTERN_VOLUME_ID = 'i', + PATTERN_BEAUTIFIED_VOLUME_ID = 'b', + PATTERN_LANGUAGE_CODE = 'l', + PATTERN_LANGUAGE_NAME = 'n', + PATTERN_AUDIO_FORMAT = 'a', + PATTERN_AUDIO_CHANNELS = 'c', + PATTERN_ORIG_VIDEO_SIZE = 'v', + PATTERN_VIDEO_SIZE = 's', + PATTERN_ASPECT_RATIO = 'r', + PATTERN_CURRENT_DATE = 'd' + }; + + private slots: + void slotStartClicked(); + void slotUpdateFilenames(); + void slotUpdateFilesizes(); + void slotUpdateVideoSizes(); + + private: + void populateTitleView( const QValueList<int>& titles ); + + QString createFilename( const K3bVideoDVDRippingJob::TitleRipInfo& info, const QString& pattern ) const; + + void loadK3bDefaults(); + void loadUserDefaults( KConfigBase* ); + void saveUserDefaults( KConfigBase* ); + + K3bVideoDVDRippingWidget* m_w; + + K3bVideoDVD::VideoDVD m_dvd; + QMap<QCheckListItem*, K3bVideoDVDRippingJob::TitleRipInfo> m_titleRipInfos; + + class AudioStreamViewItem; + + class Private; + Private* d; +}; + +#endif diff --git a/src/rip/videodvd/k3bvideodvdrippingjob.cpp b/src/rip/videodvd/k3bvideodvdrippingjob.cpp new file mode 100644 index 0000000..c10c127 --- /dev/null +++ b/src/rip/videodvd/k3bvideodvdrippingjob.cpp @@ -0,0 +1,385 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bvideodvdrippingjob.h" + +#include <k3bvideodvdtitletranscodingjob.h> +#include <k3bvideodvdtitledetectclippingjob.h> + +#include <kdebug.h> +#include <klocale.h> + + +K3bVideoDVDRippingJob::TitleRipInfo::TitleRipInfo() + : title(1), + audioStream(0), + width(0), + height(0), + videoBitrate(0), + clipTop(0), + clipLeft(0), + clipBottom(0), + clipRight(0) +{ +} + + +K3bVideoDVDRippingJob::TitleRipInfo::TitleRipInfo( int _title, + int _audioStream, + const QString& fn, + int _width, + int _height, + int _videoBitrate, + int _clipTop, + int _clipLeft, + int _clipBottom, + int _clipRight ) + : title(_title), + audioStream(_audioStream), + filename(fn), + width(_width), + height(_height), + videoBitrate(_videoBitrate), + clipTop(_clipTop), + clipLeft(_clipLeft), + clipBottom(_clipBottom), + clipRight(_clipRight) +{ +} + + + +class K3bVideoDVDRippingJob::Private { +public: + Private() + : autoClipping( true ) { + } + + unsigned int currentTitleInfoIndex; + bool autoClipping; + + bool canceled; + + int videoBitrate; + + int failedTitles; + + QValueVector<double> titleProgressParts; + QValueVector<double> titleClippingProgressParts; +}; + + + +K3bVideoDVDRippingJob::K3bVideoDVDRippingJob( K3bJobHandler* hdl, QObject* parent ) + : K3bJob( hdl, parent ) +{ + d = new Private(); + + m_transcodingJob = new K3bVideoDVDTitleTranscodingJob( this, this ); + connectSubJob( m_transcodingJob, + SLOT(slotTranscodingJobFinished(bool)), + SIGNAL(newTask(const QString&)), + SIGNAL(newSubTask(const QString&)), + SLOT(slotTranscodingProgress(int)), + SIGNAL(subPercent(int)), + 0, + 0 ); + m_detectClippingJob = 0; +} + + +K3bVideoDVDRippingJob::~K3bVideoDVDRippingJob() +{ + delete d; +} + + +QString K3bVideoDVDRippingJob::jobDescription() const +{ + return i18n("Ripping Video DVD Titles"); +} + + +QString K3bVideoDVDRippingJob::jobDetails() const +{ + return i18n("Transcoding %n title to %1/%2", "Transcoding %n titles to %1/%2", m_titleRipInfos.count() ) + .arg( K3bVideoDVDTitleTranscodingJob::videoCodecString( m_transcodingJob->videoCodec() ) ) + .arg( K3bVideoDVDTitleTranscodingJob::audioCodecString( m_transcodingJob->audioCodec() ) ); +} + + +void K3bVideoDVDRippingJob::start() +{ + jobStarted(); + d->canceled = false; + d->failedTitles = 0; + + initProgressInfo(); + + if( d->autoClipping ) + startDetectClipping( 0 ); + else + startTranscoding( 0 ); +} + + +void K3bVideoDVDRippingJob::slotTranscodingJobFinished( bool success ) +{ + if( d->canceled ) { + emit canceled(); + jobFinished( false ); + } + else { + if( success ) + emit infoMessage( i18n("Successfully ripped title %1").arg(m_titleRipInfos[d->currentTitleInfoIndex].title), SUCCESS ); + else { + d->failedTitles++; + emit infoMessage( i18n("Failed to rip title %1").arg(m_titleRipInfos[d->currentTitleInfoIndex].title), ERROR ); + } + + ++d->currentTitleInfoIndex ; + if( d->currentTitleInfoIndex < m_titleRipInfos.count() ) { + if( d->autoClipping ) + startDetectClipping( d->currentTitleInfoIndex ); + else + startTranscoding( d->currentTitleInfoIndex ); + } + else { + jobFinished( d->failedTitles == 0 ); + } + } +} + + +void K3bVideoDVDRippingJob::slotDetectClippingJobFinished( bool success ) +{ + if( d->canceled ) { + emit canceled(); + jobFinished( false ); + } + else { + m_titleRipInfos[d->currentTitleInfoIndex].clipTop = 0; + m_titleRipInfos[d->currentTitleInfoIndex].clipLeft = 0; + m_titleRipInfos[d->currentTitleInfoIndex].clipBottom = 0; + m_titleRipInfos[d->currentTitleInfoIndex].clipRight = 0; + + if( success ) { + emit infoMessage( i18n("Determined clipping values for title %1").arg(m_titleRipInfos[d->currentTitleInfoIndex].title), SUCCESS ); + emit infoMessage( i18n("Top: %1, Bottom: %2") + .arg(m_detectClippingJob->clippingTop()).arg(m_detectClippingJob->clippingBottom()), INFO ); + emit infoMessage( i18n("Left: %1, Right: %2") + .arg(m_detectClippingJob->clippingLeft()).arg(m_detectClippingJob->clippingRight()), INFO ); + + // let's see if the clipping values make sense + if( m_detectClippingJob->clippingTop() + m_detectClippingJob->clippingBottom() + >= (int)m_dvd[d->currentTitleInfoIndex].videoStream().pictureHeight() || + m_detectClippingJob->clippingLeft() + m_detectClippingJob->clippingRight() + >= (int)m_dvd[d->currentTitleInfoIndex].videoStream().pictureWidth() ) { + emit infoMessage( i18n("Insane clipping values. No clipping will be done at all."), WARNING ); + } + else { + m_titleRipInfos[d->currentTitleInfoIndex].clipTop = m_detectClippingJob->clippingTop(); + m_titleRipInfos[d->currentTitleInfoIndex].clipLeft = m_detectClippingJob->clippingLeft(); + m_titleRipInfos[d->currentTitleInfoIndex].clipBottom = m_detectClippingJob->clippingBottom(); + m_titleRipInfos[d->currentTitleInfoIndex].clipRight = m_detectClippingJob->clippingRight(); + } + } + else + emit infoMessage( i18n("Failed to determine clipping values for title %1").arg(m_titleRipInfos[d->currentTitleInfoIndex].title), ERROR ); + + startTranscoding( d->currentTitleInfoIndex ); + } +} + + +void K3bVideoDVDRippingJob::startTranscoding( int ripInfoIndex ) +{ + d->currentTitleInfoIndex = ripInfoIndex; + + m_transcodingJob->setVideoDVD( m_dvd ); + m_transcodingJob->setTitle( m_titleRipInfos[ripInfoIndex].title ); + m_transcodingJob->setAudioStream( m_titleRipInfos[ripInfoIndex].audioStream ); + m_transcodingJob->setClipping( m_titleRipInfos[ripInfoIndex].clipTop, + m_titleRipInfos[ripInfoIndex].clipLeft, + m_titleRipInfos[ripInfoIndex].clipBottom, + m_titleRipInfos[ripInfoIndex].clipRight ); + m_transcodingJob->setSize( m_titleRipInfos[ripInfoIndex].width, m_titleRipInfos[ripInfoIndex].height ); + m_transcodingJob->setFilename( m_titleRipInfos[ripInfoIndex].filename ); + + if( m_titleRipInfos[ripInfoIndex].videoBitrate > 0 ) + m_transcodingJob->setVideoBitrate( m_titleRipInfos[ripInfoIndex].videoBitrate ); + else + m_transcodingJob->setVideoBitrate( d->videoBitrate ); + + m_transcodingJob->start(); +} + + +void K3bVideoDVDRippingJob::startDetectClipping( int ripInfoIndex ) +{ + d->currentTitleInfoIndex = ripInfoIndex; + + if( !m_detectClippingJob ) { + m_detectClippingJob = new K3bVideoDVDTitleDetectClippingJob( this, this ); + connectSubJob( m_detectClippingJob, + SLOT(slotDetectClippingJobFinished(bool)), + SIGNAL(newTask(const QString&)), + SIGNAL(newSubTask(const QString&)), + SLOT(slotDetectClippingProgress(int)), + SIGNAL(subPercent(int)), + 0, + 0 ); + } + + m_detectClippingJob->setVideoDVD( m_dvd ); + m_detectClippingJob->setTitle( m_titleRipInfos[ripInfoIndex].title ); + m_detectClippingJob->setLowPriority( m_transcodingJob->lowPriority() ); + + m_detectClippingJob->start(); +} + + +void K3bVideoDVDRippingJob::slotTranscodingProgress( int p ) +{ + // calculate the part already done + double doneParts = 0.0; + for( unsigned int i = 0; i < d->currentTitleInfoIndex; ++i ) { + doneParts += d->titleProgressParts[i]; + if( d->autoClipping ) + doneParts += d->titleClippingProgressParts[i]; + } + if( d->autoClipping ) + doneParts += d->titleClippingProgressParts[d->currentTitleInfoIndex]; + + // and the current thing + doneParts += (double)p/100.0*d->titleProgressParts[d->currentTitleInfoIndex]; + + emit percent( (int)( 100.0*doneParts ) ); +} + + +void K3bVideoDVDRippingJob::slotDetectClippingProgress( int p ) +{ + // calculate the part already done + double doneParts = 0.0; + for( unsigned int i = 0; i < d->currentTitleInfoIndex; ++i ) { + doneParts += d->titleProgressParts[i]; + doneParts += d->titleClippingProgressParts[i]; + } + + // and the current thing + doneParts += (double)p/100.0*d->titleClippingProgressParts[d->currentTitleInfoIndex]; + + emit percent( (int)( 100.0*doneParts ) ); +} + + +void K3bVideoDVDRippingJob::cancel() +{ + d->canceled = true; + if( m_transcodingJob->active() ) + m_transcodingJob->cancel(); + else if( m_detectClippingJob && m_detectClippingJob->active() ) + m_detectClippingJob->cancel(); +} + + +void K3bVideoDVDRippingJob::setVideoCodec( K3bVideoDVDTitleTranscodingJob::VideoCodec codec ) +{ + m_transcodingJob->setVideoCodec( codec ); +} + + +void K3bVideoDVDRippingJob::setVideoBitrate( int bitrate ) +{ + d->videoBitrate = bitrate; +} + + +void K3bVideoDVDRippingJob::setTwoPassEncoding( bool b ) +{ + m_transcodingJob->setTwoPassEncoding( b ); +} + + +void K3bVideoDVDRippingJob::setAudioCodec( K3bVideoDVDTitleTranscodingJob::AudioCodec codec ) +{ + m_transcodingJob->setAudioCodec( codec ); +} + + +void K3bVideoDVDRippingJob::setAudioBitrate( int bitrate ) +{ + m_transcodingJob->setAudioBitrate( bitrate ); +} + + +void K3bVideoDVDRippingJob::setAudioVBR( bool vbr ) +{ + m_transcodingJob->setAudioVBR( vbr ); +} + + +void K3bVideoDVDRippingJob::setResampleAudioTo44100( bool b ) +{ + m_transcodingJob->setResampleAudioTo44100( b ); +} + + +void K3bVideoDVDRippingJob::setLowPriority( bool b ) +{ + m_transcodingJob->setLowPriority( b ); +} + + +void K3bVideoDVDRippingJob::setAutoClipping( bool b ) +{ + d->autoClipping = b; +} + + +void K3bVideoDVDRippingJob::initProgressInfo() +{ + d->titleProgressParts.resize( m_titleRipInfos.count() ); + d->titleClippingProgressParts.resize( m_titleRipInfos.count() ); + + unsigned long long totalFrames = 0ULL; + for( unsigned int i = 0; i < m_titleRipInfos.count(); ++i ) { + if( m_transcodingJob->twoPassEncoding() ) + totalFrames += m_dvd[m_titleRipInfos[i].title-1].playbackTime().totalFrames() * 2; + else + totalFrames += m_dvd[m_titleRipInfos[i].title-1].playbackTime().totalFrames(); + + // using my knowledge of the internals of the clipping detection job: it decodes 200 frames + // of every chapter + if( d->autoClipping ) + totalFrames += m_dvd[m_titleRipInfos[i].title-1].numChapters() * 200; + } + + for( unsigned int i = 0; i < m_titleRipInfos.count(); ++i ) { + unsigned long long titleFrames = m_dvd[m_titleRipInfos[i].title-1].playbackTime().totalFrames(); + if( m_transcodingJob->twoPassEncoding() ) + titleFrames *= 2; + + // using my knowledge of the internals of the clipping detection job: it decodes 200 frames + // of every chapter + unsigned long long titleClippingFrames = m_dvd[m_titleRipInfos[i].title-1].numChapters() * 200; + + d->titleProgressParts[i] = (double)titleFrames/(double)totalFrames; + d->titleClippingProgressParts[i] = (double)titleClippingFrames/(double)totalFrames; + } +} + +#include "k3bvideodvdrippingjob.moc" diff --git a/src/rip/videodvd/k3bvideodvdrippingjob.h b/src/rip/videodvd/k3bvideodvdrippingjob.h new file mode 100644 index 0000000..7c9f4d2 --- /dev/null +++ b/src/rip/videodvd/k3bvideodvdrippingjob.h @@ -0,0 +1,106 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_VIDEODVD_RIPPING_JOB_H_ +#define _K3B_VIDEODVD_RIPPING_JOB_H_ + +#include <k3bjob.h> +#include <k3bvideodvd.h> +#include <k3bvideodvdtitletranscodingjob.h> + +#include <qvaluevector.h> + + +class K3bVideoDVDTitleDetectClippingJob; + + +/** + * For details on the options see K3bVideoDVDTitleTranscodingJob + */ +class K3bVideoDVDRippingJob : public K3bJob +{ + Q_OBJECT + + public: + K3bVideoDVDRippingJob( K3bJobHandler* hdl, QObject* parent ); + ~K3bVideoDVDRippingJob(); + + class TitleRipInfo { + public: + TitleRipInfo(); + TitleRipInfo( int title, + int audioStream = 0, + const QString& fn = QString::null, + int width = 0, // 0 -> no resize + int height = 0, // 0 -> no resize + int videoBitrate = 0, // 0 -> use default from job settings + int clipTop = 0, + int clipLeft = 0, + int clipBottom = 0, + int clipRight = 0 ); + int title; + int audioStream; + QString filename; + int width; + int height; + int videoBitrate; + int clipTop; + int clipLeft; + int clipBottom; + int clipRight; + }; + + QString jobDescription() const; + QString jobDetails() const; + + public slots: + void start(); + void cancel(); + + void setVideoDVD( const K3bVideoDVD::VideoDVD& dvd ) { m_dvd = dvd; } + void setTitles( const QValueVector<TitleRipInfo>& titles ) { m_titleRipInfos = titles; } + + void setVideoCodec( K3bVideoDVDTitleTranscodingJob::VideoCodec codec ); + void setVideoBitrate( int bitrate ); + void setTwoPassEncoding( bool b ); + void setAudioCodec( K3bVideoDVDTitleTranscodingJob::AudioCodec codec ); + void setAudioBitrate( int bitrate ); + void setAudioVBR( bool vbr ); + void setResampleAudioTo44100( bool b ); + void setLowPriority( bool b ); + void setAutoClipping( bool b ); + + private slots: + void slotTranscodingJobFinished( bool ); + void slotDetectClippingJobFinished( bool ); + void slotTranscodingProgress( int ); + void slotDetectClippingProgress( int ); + + private: + void startTranscoding( int ripInfoIndex ); + void startDetectClipping( int ripInfoIndex ); + void initProgressInfo(); + + K3bVideoDVD::VideoDVD m_dvd; + QValueVector<TitleRipInfo> m_titleRipInfos; + + K3bVideoDVDTitleTranscodingJob* m_transcodingJob; + K3bVideoDVDTitleDetectClippingJob* m_detectClippingJob; + + class Private; + Private* d; +}; + +#endif diff --git a/src/rip/videodvd/k3bvideodvdrippingpreview.cpp b/src/rip/videodvd/k3bvideodvdrippingpreview.cpp new file mode 100644 index 0000000..3ba7582 --- /dev/null +++ b/src/rip/videodvd/k3bvideodvdrippingpreview.cpp @@ -0,0 +1,135 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bvideodvdrippingpreview.h" + +#include <k3bcore.h> +#include <k3bexternalbinmanager.h> +#include <k3bdevice.h> + +#include <kprocess.h> +#include <ktempdir.h> +#include <kdebug.h> + +#include <qdir.h> + + + +K3bVideoDVDRippingPreview::K3bVideoDVDRippingPreview( QObject* parent ) + : QObject( parent ), + m_tempDir( 0 ), + m_process( 0 ) +{ +} + + +K3bVideoDVDRippingPreview::~K3bVideoDVDRippingPreview() +{ + delete m_process; + delete m_tempDir; +} + + +void K3bVideoDVDRippingPreview::generatePreview( const K3bVideoDVD::VideoDVD& dvd, int title, int chapter ) +{ + // cleanup first + delete m_process; + delete m_tempDir; + m_process = 0; + m_tempDir = 0; + m_canceled = false; + + const K3bExternalBin* bin = k3bcore->externalBinManager()->binObject("transcode"); + if( !bin ) { + emit previewDone( false ); + return; + } + + // auto-select a chapter + // choose the center chapter, but not the first or last if possible + if( chapter == 0 ) + chapter = QMIN( QMAX( dvd[title-1].numChapters()/2, 2 ), QMAX( dvd[title-1].numChapters() - 1, 1 ) ); + + // select a frame number + unsigned int frame = 30; + if( dvd[title-1][chapter-1].playbackTime().totalFrames() < frame ) + frame = dvd[title-1][chapter-1].playbackTime().totalFrames() / 2; + + m_dvd = dvd; + m_title = title; + m_chapter = chapter; + + m_tempDir = new KTempDir(); + m_tempDir->setAutoDelete( true ); + + m_process = new KProcess(); + *m_process << bin->path; + *m_process << "-i" << dvd.device()->blockDeviceName(); + *m_process << "-T" << QString("%1,%2").arg(title).arg(chapter); + *m_process << "-x" << "dvd,null"; + *m_process << "--dvd_access_delay" << "0"; + *m_process << "-y" << "ppm,null"; + *m_process << "-c" << QString("%1-%2").arg( frame ).arg( frame+1 ); + *m_process << "-Z" << "x200"; + *m_process << "-o" << m_tempDir->name(); + + connect( m_process, SIGNAL(processExited(KProcess*)), + this, SLOT(slotTranscodeFinished(KProcess*)) ); + if( !m_process->start( KProcess::NotifyOnExit, KProcess::AllOutput ) ) { // we use AllOutput to not pollute stdout + // something went wrong when starting the program + // it "should" be the executable + kdDebug() << "(K3bVideoDVDRippingPreview) Could not start transcode." << endl; + delete m_process; + delete m_tempDir; + m_process = 0; + m_tempDir = 0; + emit previewDone( false ); + } +} + + +void K3bVideoDVDRippingPreview::cancel() +{ + if( m_process && m_process->isRunning() ) { + m_canceled = true; + m_process->kill(); + } +} + + +void K3bVideoDVDRippingPreview::slotTranscodeFinished( KProcess* ) +{ + // read the image + QString filename = m_tempDir->name() + "000000.ppm";// + tempQDir->entryList( QDir::Files ).first(); + kdDebug() << "(K3bVideoDVDRippingPreview) reading from file " << filename << endl; + m_preview = QImage( filename ); + bool success = !m_preview.isNull() && !m_canceled; + + // remove temp files + delete m_tempDir; + m_tempDir = 0; + + // clean up + delete m_process; + m_process = 0; + + // retry the first chapter in case another failed + if( !success && m_chapter > 1 ) + generatePreview( m_dvd, m_title, 1 ); + else + emit previewDone( success ); +} + +#include "k3bvideodvdrippingpreview.moc" diff --git a/src/rip/videodvd/k3bvideodvdrippingpreview.h b/src/rip/videodvd/k3bvideodvdrippingpreview.h new file mode 100644 index 0000000..f5beb69 --- /dev/null +++ b/src/rip/videodvd/k3bvideodvdrippingpreview.h @@ -0,0 +1,66 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_VIDEODVD_RIPPING_PREVIEW_H_ +#define _K3B_VIDEODVD_RIPPING_PREVIEW_H_ + +#include <qobject.h> +#include <qimage.h> + +#include <k3bvideodvd.h> + + +class KTempDir; +class KProcess; + +class K3bVideoDVDRippingPreview : public QObject +{ + Q_OBJECT + + public: + K3bVideoDVDRippingPreview( QObject* parent = 0 ); + ~K3bVideoDVDRippingPreview(); + + const QImage& preview() const { return m_preview; } + + public slots: + /** + * \param dvd The Video DVD object + * \param title The Video DVD title to generate the preview for + * \param chapter The Chapter number to use for the preview. + * If 0 the middle of the title is used. + */ + void generatePreview( const K3bVideoDVD::VideoDVD& dvd, int title, int chapter = 0 ); + + void cancel(); + + signals: + void previewDone( bool ); + + private slots: + void slotTranscodeFinished( KProcess* ); + + private: + QImage m_preview; + KTempDir* m_tempDir; + KProcess* m_process; + int m_title; + int m_chapter; + K3bVideoDVD::VideoDVD m_dvd; + + bool m_canceled; +}; + +#endif diff --git a/src/rip/videodvd/k3bvideodvdrippingtitlelistview.cpp b/src/rip/videodvd/k3bvideodvdrippingtitlelistview.cpp new file mode 100644 index 0000000..85379dc --- /dev/null +++ b/src/rip/videodvd/k3bvideodvdrippingtitlelistview.cpp @@ -0,0 +1,410 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bvideodvdrippingtitlelistview.h" +#include "k3bvideodvdrippingpreview.h" + +#include <k3btooltip.h> +#include <k3bapplication.h> +#include <k3bmediacache.h> + +#include <k3bvideodvd.h> +#include <k3bvideodvdaudiostream.h> +#include <k3bvideodvdvideostream.h> +#include <k3bvideodvdsubpicturestream.h> + +#include <qsimplerichtext.h> +#include <qfontmetrics.h> +#include <qpainter.h> +#include <qheader.h> +#include <qtooltip.h> + +#include <klocale.h> +#include <kglobal.h> +#include <kiconloader.h> +#include <kapplication.h> + + +static QString audioStreamString( const K3bVideoDVD::Title& title, unsigned int maxLines = 9999, bool includeExtInfo = true ) +{ + QString s = "<p>"; + for( unsigned int i = 0; i < QMIN( title.numAudioStreams(), maxLines ); ++i ) { + if( i > 0 ) + s += "<br>"; + s += QString::number(i+1) + ": " + + i18n("%1 %2Ch (%3<em>%4</em>)") + .arg( K3bVideoDVD::audioFormatString( title.audioStream(i).format() ) ) + .arg( title.audioStream(i).channels() ) + .arg( title.audioStream(i).langCode().isEmpty() + ? i18n("unknown language") + : KGlobal::locale()->twoAlphaToLanguageName( title.audioStream(i).langCode() ) ) + .arg( includeExtInfo && title.audioStream(i).codeExtension() != K3bVideoDVD::AUDIO_CODE_EXT_UNSPECIFIED + ? QString(" ") + K3bVideoDVD::audioCodeExtensionString( title.audioStream(i).codeExtension() ) + : QString::null ); + } + if( title.numAudioStreams() > maxLines ) + s += "..."; + + return s; +} + + +static QString subpictureStreamString( const K3bVideoDVD::Title& title, unsigned int maxLines = 9999, bool includeExtInfo = true ) +{ + QString s = "<p>"; + for( unsigned int i = 0; i < QMIN( title.numSubPictureStreams(), maxLines ); ++i ) { + if( i > 0 ) + s += "<br>"; + s += QString::number(i+1) + ": " + + QString("%1 (%2<em>%3</em>)") + .arg( title.subPictureStream(i).codeMode() == K3bVideoDVD::SUBPIC_CODE_MODE_RLE + ? i18n("RLE") + : i18n("Extended") ) + .arg( title.subPictureStream(i).langCode().isEmpty() + ? i18n("unknown language") + : KGlobal::locale()->twoAlphaToLanguageName( title.subPictureStream(i).langCode() ) ) + .arg( includeExtInfo && title.subPictureStream(i).codeExtension() != K3bVideoDVD::SUBPIC_CODE_EXT_UNSPECIFIED + ? QString(" ") + K3bVideoDVD::subPictureCodeExtensionString( title.subPictureStream(i).codeExtension() ) + : QString::null ); + } + if( title.numSubPictureStreams() > maxLines ) + s += "..."; + + return s; +} + + + +class K3bVideoDVDRippingTitleListView::TitleViewItem : public K3bCheckListViewItem +{ +public: + TitleViewItem( K3bVideoDVDRippingTitleListView* parent, QListViewItem* after, const K3bVideoDVD::Title& title ) + : K3bCheckListViewItem( parent, after ), + m_title( title ) { + + setMarginVertical( 4 ); + setMarginHorizontal( 1, 2 ); + setMarginHorizontal( 2, 2 ); + setMarginHorizontal( 3, 2 ); + setMarginHorizontal( 4, 2 ); + setMarginHorizontal( 5, 2 ); + setChecked(true); + + m_previewSet = false; + } + + const K3bVideoDVD::Title& videoDVDTitle() const { return m_title; } + + void setup() { + widthChanged(); + + // set a valid height + int maxH = 0; + for( int c = 1; c <= 4; ++c ) { + QSimpleRichText rt( text(c), listView()->font() ); + rt.setWidth( 600 ); // way to big to avoid line breaks + maxH = QMAX( maxH, rt.height() ); + } + + setHeight( maxH + 2*marginVertical() ); + } + + int width( const QFontMetrics& fm, const QListView* lv, int c ) const { + if( c == 0 ) + return K3bCheckListViewItem::width( fm, lv, c ); + else { + QSimpleRichText rt( text(c), lv->font() ); + rt.setWidth( 600 ); // way to big to avoid line breaks + return rt.widthUsed() + 2*marginHorizontal( c ); + } + } + + void setPreview( const QImage& preview ) { + m_preview = preview; + m_scaledPreview = QPixmap(); + + m_previewSet = true; + + repaint(); + } + + const QImage& preview() const { + return m_preview; + } + +protected: + void paintK3bCell( QPainter* p, const QColorGroup& cg, int col, int w, int align ) { + p->save(); + + if( col == 0 ) { + // the check mark + K3bCheckListViewItem::paintK3bCell( p, cg, col, w, align ); + } + else if( col == 2 ) { + if( isSelected() ) { + p->fillRect( 0, 0, w, height(), + cg.brush( QColorGroup::Highlight ) ); + p->setPen( cg.highlightedText() ); + } + else { + p->fillRect( 0, 0, w, height(), cg.base() ); + p->setPen( cg.text() ); + } + + // draw the preview + int h = height(); + h -= 2*marginVertical(); + h -= 1; // the separator + if( !m_preview.isNull() ) { + if( m_scaledPreview.height() != h ) { + // recreate scaled preview + int preH = m_preview.height()*w/m_preview.width(); + int preW = m_preview.width()*h/m_preview.height(); + if( preH > h ) + preH = m_preview.height()*preW/m_preview.width(); + if( preW > w ) + preW = m_preview.width()*preH/m_preview.height(); + m_scaledPreview.convertFromImage( m_preview.smoothScale( preW, preH ), 0 ); + } + + // center the preview in the column + int yPos = ( height() - m_scaledPreview.height() ) / 2; + int xPos = ( w - m_scaledPreview.width() ) / 2; + + p->drawPixmap( xPos, yPos, m_scaledPreview ); + } + else if( m_previewSet ) { + int preW = 0; + if( m_title.videoStream().displayAspectRatio() == K3bVideoDVD::VIDEO_ASPECT_RATIO_4_3 ) + preW = h*4/3; + else + preW = h*16/9; + + p->drawRect( ( w - preW ) / 2, ( height() - h ) / 2, preW, h ); + QPixmap noIcon = KApplication::kApplication()->iconLoader()->loadIcon( "no", KIcon::NoGroup, KIcon::SizeSmall, KIcon::DefaultState, 0, true ); + p->drawPixmap( ( w - noIcon.width() ) / 2, ( height() - noIcon.height() ) / 2, noIcon ); + } + else { + p->drawText( 0, 0, w, height(), Qt::AlignCenter, "..." ); + } + } + else { + QString s = text( col ); + if( s.isEmpty() ) + K3bCheckListViewItem::paintK3bCell( p, cg, col, w, align ); + else { + QColorGroup cg1( cg ); + if( isSelected() ) { + p->fillRect( 0, 0, w, height(), + cg.brush( QColorGroup::Highlight ) ); + cg1.setColor( QColorGroup::Text, cg.highlightedText() ); + } + else { + p->fillRect( 0, 0, w, height(), cg.base() ); + } + + // paint using QSimpleRichText + QSimpleRichText rt( text(col), listView()->font() ); + rt.setWidth( 600 ); // way to big to avoid line breaks + // normally we would have to clip the height to height()-2*marginVertical(). But if we do that + // some characters are cut (such as p or q). It seems as if QSimpleRichText does not properly + // calculate it's height... + rt.draw( p, 0, marginVertical(), QRect( 0, 0, w, height() ), cg1 ); + } + } + + // draw the separator + if( listView()->firstChild() != this ) { + p->translate( -1*marginHorizontal(col), 0 ); + // FIXME: modify the value from palette().disabled().foreground() to be lighter (or darker, depending on the background color ) + p->setPen( Qt::lightGray ); + p->drawLine( 0, 0, w+2*marginHorizontal(col), 0 ); + } + + p->restore(); + } + +private: + QString text( int col ) const { + switch( col ) { + case 1: + // Title X + length + return i18n("<p><b>Title %1 (%2)</b><br>" + "%3") + .arg( m_title.titleNumber(), 2 ) + .arg( m_title.playbackTime().toString( false ) ) + .arg( i18n("%n chapter", "%n chapters", m_title.numPTTs() ) ); + + case 3: + // video stream info + return QString("<p>%1 %2x%3<br>%4%5") + .arg( m_title.videoStream().mpegVersion() == 0 ? i18n("MPEG1") : i18n("MPEG2") ) + .arg( m_title.videoStream().pictureWidth() ) + .arg( m_title.videoStream().pictureHeight() ) + .arg( m_title.videoStream().displayAspectRatio() == K3bVideoDVD::VIDEO_ASPECT_RATIO_4_3 ? "4:3" : "16:9" ) + .arg( m_title.videoStream().letterboxed() ? QString(" - <em>") + i18n("letterboxed") + QString("</em>"): + m_title.videoStream().permittedDf() == K3bVideoDVD::VIDEO_PERMITTED_DF_LETTERBOXED + ? QString(" - <em>") + i18n("anamorph") + QString("</em>") : QString::null ); + + case 4: + // audio streams info + if( m_title.numAudioStreams() > 0 ) + return audioStreamString( m_title, 2, false ); + else + return "<p><small><em>" + i18n("No audio streams") + "</em>"; + + case 5: + // subpicture streams info + if( m_title.numSubPictureStreams() > 0 ) + return subpictureStreamString( m_title, 2, false ); + else + return "<p><small><em>" + i18n("No Subpicture streams") + "</em>"; + + default: + return K3bCheckListViewItem::text( col ); + } + } + + K3bVideoDVD::Title m_title; + + bool m_previewSet; + QImage m_preview; + QPixmap m_scaledPreview; +}; + + +class K3bVideoDVDRippingTitleListView::TitleToolTip : public K3bToolTip +{ +public: + TitleToolTip( K3bVideoDVDRippingTitleListView* view ) + : K3bToolTip( view->viewport() ), + m_view( view ) { + } + + void maybeTip( const QPoint& pos ) { + TitleViewItem* item = static_cast<TitleViewItem*>( m_view->itemAt( pos ) ); + QPoint contentsPos = m_view->viewportToContents( pos ); + if( !item ) + return; + int col = m_view->header()->sectionAt( contentsPos.x() ); + + QRect r = m_view->itemRect( item ); + int headerPos = m_view->header()->sectionPos( col ); + r.setLeft( headerPos ); + r.setRight( headerPos + m_view->header()->sectionSize( col ) ); + + switch( col ) { + case 2: + if( !item->preview().isNull() ) { + QPixmap previewPix; + if( previewPix.convertFromImage( item->preview() ) ) + tip( r, previewPix, 0 ); + } + break; + case 4: + if( item->videoDVDTitle().numAudioStreams() > 0 ) + tip( r, "<p><b>" + i18n("Audio Streams") + "</b><p>" + audioStreamString( item->videoDVDTitle() ), 0 ); + break; + case 5: + if( item->videoDVDTitle().numSubPictureStreams() > 0 ) + tip( r, "<p><b>" + i18n("Subpicture Streams") + "</b><p>" + subpictureStreamString( item->videoDVDTitle() ), 0 ); + break; + } + } + +private: + K3bVideoDVDRippingTitleListView* m_view; +}; + + + +K3bVideoDVDRippingTitleListView::K3bVideoDVDRippingTitleListView( QWidget* parent ) + : K3bListView( parent ) +{ + setFullWidth(true); + setSorting(-1); + setAllColumnsShowFocus( true ); + setSelectionModeExt( Single ); + + addColumn( "" ); + addColumn( i18n("Title") ); + addColumn( i18n("Preview") ); + addColumn( i18n("Video") ); + addColumn( i18n("Audio") ); + addColumn( i18n("Subpicture") ); + + header()->setClickEnabled( false ); + setColumnWidthMode( 0, QListView::Manual ); + setColumnWidth( 0, 20 ); + header()->setResizeEnabled( false, 0 ); + + m_toolTip = new TitleToolTip( this ); + + m_previewGen = new K3bVideoDVDRippingPreview( this ); + connect( m_previewGen, SIGNAL(previewDone(bool)), + this, SLOT(slotPreviewDone(bool)) ); +} + + +K3bVideoDVDRippingTitleListView::~K3bVideoDVDRippingTitleListView() +{ + delete m_toolTip; +} + + +void K3bVideoDVDRippingTitleListView::setVideoDVD( const K3bVideoDVD::VideoDVD& dvd ) +{ + clear(); + + m_dvd = dvd; + m_medium = k3bappcore->mediaCache()->medium( m_dvd.device() ); + m_itemMap.resize( dvd.numTitles() ); + + for( unsigned int i = 0; i < dvd.numTitles(); ++i ) + m_itemMap[i] = new TitleViewItem( this, lastItem(), dvd.title(i) ); + + m_currentPreviewTitle = 1; + m_previewGen->generatePreview( m_dvd, 1 ); +} + + +void K3bVideoDVDRippingTitleListView::slotPreviewDone( bool success ) +{ + if( success ) + m_itemMap[m_currentPreviewTitle-1]->setPreview( m_previewGen->preview() ); + else + m_itemMap[m_currentPreviewTitle-1]->setPreview( QImage() ); + + // cancel if we got hidden or if the medium changed. + if( isVisible() && m_medium == k3bappcore->mediaCache()->medium( m_dvd.device() ) ) { + ++m_currentPreviewTitle; + if( m_currentPreviewTitle <= m_dvd.numTitles() ) + m_previewGen->generatePreview( m_dvd, m_currentPreviewTitle ); + } +} + + +void K3bVideoDVDRippingTitleListView::hideEvent( QHideEvent* e ) +{ + // + // For now we do it the easy way: just stop the preview generation + // once this view is hidden + // + m_previewGen->cancel(); + + K3bListView::hideEvent( e ); +} + +#include "k3bvideodvdrippingtitlelistview.moc" diff --git a/src/rip/videodvd/k3bvideodvdrippingtitlelistview.h b/src/rip/videodvd/k3bvideodvdrippingtitlelistview.h new file mode 100644 index 0000000..7c21815 --- /dev/null +++ b/src/rip/videodvd/k3bvideodvdrippingtitlelistview.h @@ -0,0 +1,58 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_VIDEODVD_RIPPING_TITLE_LISTVIEW_H_ +#define _K3B_VIDEODVD_RIPPING_TITLE_LISTVIEW_H_ + +#include <k3blistview.h> +#include <k3bvideodvd.h> +#include <k3bmedium.h> + +#include <qvaluevector.h> + + +class K3bVideoDVDRippingPreview; +class QHideEvent; + +class K3bVideoDVDRippingTitleListView : public K3bListView +{ + Q_OBJECT + + public: + K3bVideoDVDRippingTitleListView( QWidget* parent ); + ~K3bVideoDVDRippingTitleListView(); + + void setVideoDVD( const K3bVideoDVD::VideoDVD& dvd ); + + private slots: + void slotPreviewDone( bool ); + + private: + void hideEvent( QHideEvent* ); + + class TitleViewItem; + class TitleToolTip; + + TitleToolTip* m_toolTip; + + QValueVector<TitleViewItem*> m_itemMap; + K3bVideoDVDRippingPreview* m_previewGen; + unsigned int m_currentPreviewTitle; + + K3bVideoDVD::VideoDVD m_dvd; + K3bMedium m_medium; +}; + +#endif diff --git a/src/rip/videodvd/k3bvideodvdrippingview.cpp b/src/rip/videodvd/k3bvideodvdrippingview.cpp new file mode 100644 index 0000000..f6c8c8d --- /dev/null +++ b/src/rip/videodvd/k3bvideodvdrippingview.cpp @@ -0,0 +1,256 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bvideodvdrippingview.h" +#include "k3bvideodvdrippingtitlelistview.h" +#include "k3bvideodvdrippingdialog.h" + +#include <k3bvideodvd.h> +#include <k3bvideodvdtitletranscodingjob.h> +#include <k3btoolbox.h> +#include <k3bthememanager.h> +#include <k3bglobals.h> +#include <k3blibdvdcss.h> +#include <k3bcore.h> +#include <k3bexternalbinmanager.h> + +#include <qcursor.h> +#include <qlayout.h> +#include <qlabel.h> + +#include <kapplication.h> +#include <kmessagebox.h> +#include <klocale.h> +#include <kaction.h> +#include <kconfig.h> + + +K3bVideoDVDRippingView::K3bVideoDVDRippingView( QWidget* parent, const char * name ) + : K3bMediaContentsView( true, + K3bMedium::CONTENT_VIDEO_DVD, + K3bDevice::MEDIA_DVD_ALL, + K3bDevice::STATE_INCOMPLETE|K3bDevice::STATE_COMPLETE, + parent, name ) +{ + QGridLayout* mainGrid = new QGridLayout( mainWidget() ); + + // toolbox + // ---------------------------------------------------------------------------------- + QHBoxLayout* toolBoxLayout = new QHBoxLayout( 0, 0, 0, "toolBoxLayout" ); + m_toolBox = new K3bToolBox( mainWidget() ); + toolBoxLayout->addWidget( m_toolBox ); + QSpacerItem* spacer = new QSpacerItem( 10, 10, QSizePolicy::Expanding, QSizePolicy::Minimum ); + toolBoxLayout->addItem( spacer ); + m_labelLength = new QLabel( mainWidget() ); + m_labelLength->setAlignment( int( QLabel::AlignVCenter | QLabel::AlignRight ) ); + toolBoxLayout->addWidget( m_labelLength ); + + + // the title view + // ---------------------------------------------------------------------------------- + m_titleView = new K3bVideoDVDRippingTitleListView( mainWidget() ); + + connect( m_titleView, SIGNAL(contextMenu(KListView*, QListViewItem*, const QPoint&)), + this, SLOT(slotContextMenu(KListView*, QListViewItem*, const QPoint&)) ); + + // general layout + // ---------------------------------------------------------------------------------- + mainGrid->addLayout( toolBoxLayout, 0, 0 ); + mainGrid->addWidget( m_titleView, 1, 0 ); + + + initActions(); + + m_toolBox->addButton( actionCollection()->action("start_rip"), true ); + + setLeftPixmap( K3bTheme::MEDIA_LEFT ); + setRightPixmap( K3bTheme::MEDIA_VIDEO ); +} + + +K3bVideoDVDRippingView::~K3bVideoDVDRippingView() +{ +} + + +void K3bVideoDVDRippingView::reloadMedium() +{ + // + // For VideoDVD reading it is important that the DVD is not mounted + // + if( K3b::isMounted( device() ) && !K3b::unmount( device() ) ) { + KMessageBox::error( this, + i18n("K3b was unable to unmount device '%1' containing medium '%2'. " + "Video DVD ripping will not work if the device is mounted. " + "Please unmount manually."), + i18n("Unmounting failed") ); + } + + // + // K3bVideoDVD::open does not necessarily fail on encrypted DVDs if dvdcss is not + // available. Thus, we test the availability of libdvdcss here + // + if( device()->copyrightProtectionSystemType() == 1 ) { + K3bLibDvdCss* css = K3bLibDvdCss::create(); + if( !css ) { + KMessageBox::error( this, i18n("<p>Unable to read Video DVD contents: Found encrypted Video DVD." + "<p>Install <i>libdvdcss</i> to get Video DVD decryption support.") ); + return; + } + else + delete css; + } + + QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); + + if( m_dvd.open( device() ) ) { + setTitle( medium().beautifiedVolumeId() + " (" + i18n("Video DVD") + ")" ); + m_labelLength->setText( i18n("%n title", "%n titles", m_dvd.numTitles() ) ); + m_titleView->setVideoDVD( m_dvd ); + QApplication::restoreOverrideCursor(); + + bool transcodeUsable = true; + + if( !k3bcore ->externalBinManager() ->foundBin( "transcode" ) ) { + KMessageBox::sorry( this, + i18n("K3b uses transcode to rip Video DVDs. " + "Please make sure it is installed.") ); + transcodeUsable = false; + } + else { + int vc = 0, ac = 0; + for( int i = 0; i < K3bVideoDVDTitleTranscodingJob::VIDEO_CODEC_NUM_ENTRIES; ++i ) + if( K3bVideoDVDTitleTranscodingJob::transcodeBinaryHasSupportFor( (K3bVideoDVDTitleTranscodingJob::VideoCodec)i ) ) + ++vc; + for( int i = 0; i < K3bVideoDVDTitleTranscodingJob::AUDIO_CODEC_NUM_ENTRIES; ++i ) + if( K3bVideoDVDTitleTranscodingJob::transcodeBinaryHasSupportFor( (K3bVideoDVDTitleTranscodingJob::AudioCodec)i ) ) + ++ac; + if( !ac || !vc ) { + KMessageBox::sorry( this, + i18n("<p>K3b uses transcode to rip Video DVDs. " + "Your installation of transcode (<em>%1</em>) lacks support for any of the " + "codecs supported by K3b." + "<p>Please make sure it is installed properly.") ); + transcodeUsable = false; + } + } + + actionCollection()->action("start_rip")->setEnabled( transcodeUsable ); + } + else { + QApplication::restoreOverrideCursor(); + + KMessageBox::error( this, i18n("Unable to read Video DVD contents.") ); + } +} + + +void K3bVideoDVDRippingView::slotStartRipping() +{ + QValueList<int> titles; + int i = 1; + for( QListViewItemIterator it( m_titleView ); *it; ++it, ++i ) + if( static_cast<K3bCheckListViewItem*>( *it )->isChecked() ) + titles.append( i ); + + if( titles.isEmpty() ) { + KMessageBox::error( this, i18n("Please select the titles to rip."), + i18n("No Titles Selected") ); + } + else { + K3bVideoDVDRippingDialog dlg( m_dvd, titles, this ); + dlg.exec(); + } +} + + +void K3bVideoDVDRippingView::slotContextMenu( KListView*, QListViewItem*, const QPoint& p ) +{ + m_popupMenu->popup(p); +} + + +void K3bVideoDVDRippingView::slotCheckAll() +{ + for( QListViewItemIterator it( m_titleView ); it.current(); ++it ) + dynamic_cast<K3bCheckListViewItem*>(it.current())->setChecked(true); +} + + +void K3bVideoDVDRippingView::slotUncheckAll() +{ + for( QListViewItemIterator it( m_titleView ); it.current(); ++it ) + dynamic_cast<K3bCheckListViewItem*>(it.current())->setChecked(false); +} + + +void K3bVideoDVDRippingView::slotCheck() +{ + QPtrList<QListViewItem> items( m_titleView->selectedItems() ); + for( QPtrListIterator<QListViewItem> it( items ); + it.current(); ++it ) + dynamic_cast<K3bCheckListViewItem*>(it.current())->setChecked(true); +} + + +void K3bVideoDVDRippingView::slotUncheck() +{ + QPtrList<QListViewItem> items( m_titleView->selectedItems() ); + for( QPtrListIterator<QListViewItem> it( items ); + it.current(); ++it ) + dynamic_cast<K3bCheckListViewItem*>(it.current())->setChecked(false); +} + + +void K3bVideoDVDRippingView::initActions() +{ + m_actionCollection = new KActionCollection( this ); + + KAction* actionSelectAll = new KAction( i18n("Check All"), 0, 0, this, + SLOT(slotCheckAll()), actionCollection(), + "check_all" ); + KAction* actionDeselectAll = new KAction( i18n("Uncheck All"), 0, 0, this, + SLOT(slotUncheckAll()), actionCollection(), + "uncheck_all" ); + KAction* actionSelect = new KAction( i18n("Check Track"), 0, 0, this, + SLOT(slotCheck()), actionCollection(), + "select_track" ); + KAction* actionDeselect = new KAction( i18n("Uncheck Track"), 0, 0, this, + SLOT(slotUncheck()), actionCollection(), + "deselect_track" ); + KAction* actionStartRip = new KAction( i18n("Start Ripping"), "gear", 0, this, + SLOT(slotStartRipping()), m_actionCollection, "start_rip" ); + + actionStartRip->setToolTip( i18n("Open the Video DVD ripping dialog") ); + + // setup the popup menu + m_popupMenu = new KActionMenu( actionCollection(), "popup_menu" ); + KAction* separator = new KActionSeparator( actionCollection(), "separator" ); + m_popupMenu->insert( actionSelect ); + m_popupMenu->insert( actionDeselect ); + m_popupMenu->insert( actionSelectAll ); + m_popupMenu->insert( actionDeselectAll ); + m_popupMenu->insert( separator ); + m_popupMenu->insert( actionStartRip ); +} + + +void K3bVideoDVDRippingView::enableInteraction( bool enable ) +{ + actionCollection()->action( "start_rip" )->setEnabled( enable ); +} + + +#include "k3bvideodvdrippingview.moc" diff --git a/src/rip/videodvd/k3bvideodvdrippingview.h b/src/rip/videodvd/k3bvideodvdrippingview.h new file mode 100644 index 0000000..679ea09 --- /dev/null +++ b/src/rip/videodvd/k3bvideodvdrippingview.h @@ -0,0 +1,66 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_VIDEODVD_RIPPING_VIEW_H_ +#define _K3B_VIDEODVD_RIPPING_VIEW_H_ + +#include <k3bmediacontentsview.h> +#include <k3bmedium.h> +#include <k3bvideodvd.h> + +class K3bVideoDVDRippingTitleListView; +class K3bToolBox; +class QLabel; +class KActionCollection; +class KActionMenu; +class KListView; +class QListViewItem; + +class K3bVideoDVDRippingView : public K3bMediaContentsView +{ + Q_OBJECT + + public: + K3bVideoDVDRippingView( QWidget* parent = 0, const char * name = 0 ); + ~K3bVideoDVDRippingView(); + + KActionCollection* actionCollection() const { return m_actionCollection; } + + private slots: + void slotStartRipping(); + + void slotContextMenu( KListView*, QListViewItem*, const QPoint& ); + + void slotCheckAll(); + void slotUncheckAll(); + void slotCheck(); + void slotUncheck(); + + private: + void reloadMedium(); + void enableInteraction( bool enable ); + void initActions(); + + KActionCollection* m_actionCollection; + KActionMenu* m_popupMenu; + + K3bToolBox* m_toolBox; + QLabel* m_labelLength; + K3bVideoDVDRippingTitleListView* m_titleView; + + K3bVideoDVD::VideoDVD m_dvd; +}; + +#endif diff --git a/src/rip/videodvd/k3bvideodvdrippingwidget.cpp b/src/rip/videodvd/k3bvideodvdrippingwidget.cpp new file mode 100644 index 0000000..721d191 --- /dev/null +++ b/src/rip/videodvd/k3bvideodvdrippingwidget.cpp @@ -0,0 +1,375 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bvideodvdrippingwidget.h" + +#include <k3bvideodvdtitletranscodingjob.h> +#include <k3bglobals.h> +#include <k3brichtextlabel.h> +#include <k3bintmapcombobox.h> + +#include <klistview.h> +#include <klocale.h> +#include <kurlrequester.h> +#include <kio/global.h> +#include <kurllabel.h> +#include <kdialogbase.h> +#include <klineedit.h> + +#include <qcombobox.h> +#include <qspinbox.h> +#include <qlabel.h> +#include <qtimer.h> +#include <qwhatsthis.h> +#include <qwidgetstack.h> +#include <qpushbutton.h> +#include <qcheckbox.h> +#include <qlayout.h> + + +static const int s_mp3Bitrates[] = { + 32, + 40, + 48, + 56, + 64, + 80, + 96, + 112, + 128, + 160, + 192, + 224, + 256, + 320, + 0 // just used for the loops below +}; + + +static const int PICTURE_SIZE_ORIGINAL = 0; +static const int PICTURE_SIZE_640 = 1; +static const int PICTURE_SIZE_320 = 2; +static const int PICTURE_SIZE_CUSTOM = 3; +static const int PICTURE_SIZE_MAX = 4; + +static const char* s_pictureSizeNames[] = { + I18N_NOOP("Keep original dimensions"), + I18N_NOOP("640x? (automatic height)"), + I18N_NOOP("320x? (automatic height)"), + I18N_NOOP("Custom") +}; + + +K3bVideoDVDRippingWidget::K3bVideoDVDRippingWidget( QWidget* parent ) + : base_K3bVideoDVDRippingWidget( parent ) +{ + m_editBaseDir->setMode( KFile::Directory | KFile::ExistingOnly | KFile::LocalOnly ); + + m_titleView->addColumn( i18n("Title") ); + m_titleView->addColumn( i18n("Video Size") ); + m_titleView->addColumn( i18n("File Size") ); + m_titleView->addColumn( i18n("Filename") ); + m_titleView->setSorting( -1 ); + + // + // Example filename pattern + // + m_comboFilenamePattern->insertItem( QString( "%b - %1 %t (%n %a %c)" ).arg(i18n("Title") ) ); + m_comboFilenamePattern->insertItem( QString( "%{volumeid} (%{title})" ) ); + + + // + // Add the Audio bitrates + // + for( int i = 0; s_mp3Bitrates[i]; ++i ) + m_comboAudioBitrate->insertItem( i18n("%1 kbps" ).arg(s_mp3Bitrates[i]) ); + + + for( int i = 0; i < K3bVideoDVDTitleTranscodingJob::VIDEO_CODEC_NUM_ENTRIES; ++i ) { + K3bVideoDVDTitleTranscodingJob::VideoCodec codec( (K3bVideoDVDTitleTranscodingJob::VideoCodec)i ); + if( K3bVideoDVDTitleTranscodingJob::transcodeBinaryHasSupportFor( codec ) ) + m_comboVideoCodec->insertItem( i, + K3bVideoDVDTitleTranscodingJob::videoCodecString( codec ), + K3bVideoDVDTitleTranscodingJob::videoCodecDescription( codec ) ); + } + for( int i = 0; i < K3bVideoDVDTitleTranscodingJob::AUDIO_CODEC_NUM_ENTRIES; ++i ) { + K3bVideoDVDTitleTranscodingJob::AudioCodec codec( (K3bVideoDVDTitleTranscodingJob::AudioCodec)i ); + if( K3bVideoDVDTitleTranscodingJob::transcodeBinaryHasSupportFor( codec ) ) + m_comboAudioCodec->insertItem( i, + K3bVideoDVDTitleTranscodingJob::audioCodecString( codec ), + K3bVideoDVDTitleTranscodingJob::audioCodecDescription( codec ) ); + } + + for( int i = 0; i < PICTURE_SIZE_MAX; ++i ) { + m_comboVideoSize->insertItem( i18n( s_pictureSizeNames[i] ) ); + } + + slotAudioCodecChanged( m_comboAudioCodec->selectedValue() ); + + connect( m_comboAudioBitrate, SIGNAL(textChanged(const QString&)), + this, SIGNAL(changed()) ); + connect( m_spinVideoBitrate, SIGNAL(valueChanged(int)), + this, SIGNAL(changed()) ); + connect( m_checkBlankReplace, SIGNAL(toggled(bool)), + this, SIGNAL(changed()) ); + connect( m_editBlankReplace, SIGNAL(textChanged(const QString&)), + this, SIGNAL(changed()) ); + connect( m_comboFilenamePattern, SIGNAL(textChanged(const QString&)), + this, SIGNAL(changed()) ); + connect( m_editBaseDir, SIGNAL(textChanged(const QString&)), + this, SIGNAL(changed()) ); + + connect( m_comboAudioCodec, SIGNAL(valueChanged(int)), + this, SLOT(slotAudioCodecChanged(int)) ); + connect( m_specialStringsLabel, SIGNAL(leftClickedURL()), + this, SLOT(slotSeeSpecialStrings()) ); + connect( m_buttonCustomPictureSize, SIGNAL(clicked()), + this, SLOT(slotCustomPictureSize()) ); + connect( m_comboVideoSize, SIGNAL(activated(int)), + this, SLOT(slotVideoSizeChanged(int)) ); + + // refresh every 2 seconds + m_freeSpaceUpdateTimer = new QTimer( this ); + connect( m_freeSpaceUpdateTimer, SIGNAL(timeout()), + this, SLOT(slotUpdateFreeTempSpace()) ); + m_freeSpaceUpdateTimer->start(2000); + slotUpdateFreeTempSpace(); +} + + +K3bVideoDVDRippingWidget::~K3bVideoDVDRippingWidget() +{ +} + + +K3bVideoDVDTitleTranscodingJob::VideoCodec K3bVideoDVDRippingWidget::selectedVideoCodec() const +{ + return (K3bVideoDVDTitleTranscodingJob::VideoCodec)m_comboVideoCodec->selectedValue(); +} + + +QSize K3bVideoDVDRippingWidget::selectedPictureSize() const +{ + switch( m_comboVideoSize->currentItem() ) { + case PICTURE_SIZE_ORIGINAL: + return QSize(0,0); + case PICTURE_SIZE_640: + return QSize(640,0); + case PICTURE_SIZE_320: + return QSize(320,0); + default: + return m_customVideoSize; + } +} + + +void K3bVideoDVDRippingWidget::setSelectedPictureSize( const QSize& size ) +{ + m_customVideoSize = size; + if( size == QSize(0,0) ) + m_comboVideoSize->setCurrentItem( PICTURE_SIZE_ORIGINAL ); + else if( size == QSize(640,0) ) + m_comboVideoSize->setCurrentItem( PICTURE_SIZE_640 ); + else if( size == QSize(320,0) ) + m_comboVideoSize->setCurrentItem( PICTURE_SIZE_320 ); + else { + m_comboVideoSize->changeItem( i18n(s_pictureSizeNames[PICTURE_SIZE_CUSTOM]) + + QString(" (%1x%2)") + .arg(size.width() == 0 ? i18n("auto") : QString::number(size.width())) + .arg(size.height() == 0 ? i18n("auto") : QString::number(size.height())), + PICTURE_SIZE_CUSTOM ); + m_comboVideoSize->setCurrentItem( PICTURE_SIZE_CUSTOM ); + } +} + + +void K3bVideoDVDRippingWidget::setSelectedVideoCodec( K3bVideoDVDTitleTranscodingJob::VideoCodec codec ) +{ + m_comboVideoCodec->setSelectedValue( (int)codec ); +} + + +K3bVideoDVDTitleTranscodingJob::AudioCodec K3bVideoDVDRippingWidget::selectedAudioCodec() const +{ + return (K3bVideoDVDTitleTranscodingJob::AudioCodec)m_comboAudioCodec->selectedValue(); +} + + +void K3bVideoDVDRippingWidget::setSelectedAudioCodec( K3bVideoDVDTitleTranscodingJob::AudioCodec codec ) +{ + m_comboAudioCodec->setSelectedValue( (int)codec ); + slotAudioCodecChanged( (int)codec ); +} + + +int K3bVideoDVDRippingWidget::selectedAudioBitrate() const +{ + if( selectedAudioCodec() == K3bVideoDVDTitleTranscodingJob::AUDIO_CODEC_MP3 ) + return s_mp3Bitrates[m_comboAudioBitrate->currentItem()]; + else + return m_spinAudioBitrate->value(); +} + + +void K3bVideoDVDRippingWidget::setSelectedAudioBitrate( int bitrate ) +{ + m_spinAudioBitrate->setValue( bitrate ); + + // select the bitrate closest to "bitrate" + int bi = 0; + int diff = 1000; + for( int i = 0; s_mp3Bitrates[i]; ++i ) { + int newDiff = s_mp3Bitrates[i] - bitrate; + if( newDiff < 0 ) + newDiff = -1 * newDiff; + if( newDiff < diff ) { + diff = newDiff; + bi = i; + } + } + + m_comboAudioBitrate->setCurrentItem( bi ); +} + + +void K3bVideoDVDRippingWidget::slotUpdateFreeTempSpace() +{ + QString path = m_editBaseDir->url(); + + if( !QFile::exists( path ) ) + path.truncate( path.findRev('/') ); + + unsigned long size, avail; + if( K3b::kbFreeOnFs( path, size, avail ) ) { + m_labelFreeSpace->setText( KIO::convertSizeFromKB(avail) ); + if( avail < m_neededSize/1024 ) + m_labelNeededSpace->setPaletteForegroundColor( Qt::red ); + else + m_labelNeededSpace->setPaletteForegroundColor( paletteForegroundColor() ); + } + else { + m_labelFreeSpace->setText("-"); + m_labelNeededSpace->setPaletteForegroundColor( paletteForegroundColor() ); + } +} + + +void K3bVideoDVDRippingWidget::setNeededSize( KIO::filesize_t size ) +{ + m_neededSize = size; + if( size > 0 ) + m_labelNeededSpace->setText( KIO::convertSize( size ) ); + else + m_labelNeededSpace->setText( i18n("unknown") ); + + slotUpdateFreeTempSpace(); +} + + +void K3bVideoDVDRippingWidget::slotSeeSpecialStrings() +{ + QWhatsThis::display( i18n( "<p><b>Pattern special strings:</b>" + "<p>The following strings will be replaced with their respective meaning in every " + "track name.<br>" + "<p><table border=\"0\">" + "<tr><td></td><td><em>Meaning</em></td><td><em>Alternatives</em></td></tr>" + "<tr><td>%t</td><td>title number</td><td>%{t} or %{title_number}</td></tr>" + "<tr><td>%i</td><td>volume id (mostly the name of the Video DVD)</td><td>%{i} or %{volume_id}</td></tr>" + "<tr><td>%b</td><td>beautified volume id</td><td>%{b} or %{beautified_volume_id}</td></tr>" + "<tr><td>%l</td><td>two chars language code</td><td>%{l} or %{lang_code}</td></tr>" + "<tr><td>%n</td><td>language name</td><td>%{n} or %{lang_name}</td></tr>" + "<tr><td>%a</td><td>audio format (on the Video DVD)</td><td>%{a} or %{audio_format}</td></tr>" + "<tr><td>%c</td><td>number of audio channels (on the Video DVD)</td><td>%{c} or %{channels}</td></tr>" + "<tr><td>%v</td><td>size of the original video</td><td>%{v} or %{orig_video_size}</td></tr>" + "<tr><td>%s</td><td>size of the resulting video (<em>Caution: auto-clipping values are not taken into account!</em>)</td><td>%{s} or %{video_size}</td></tr>" + "<tr><td>%r</td><td>aspect ratio of the original video</td><td>%{r} or %{aspect_ratio}</td></tr>" + "<tr><td>%d</td><td>current date</td><td>%{d} or %{date}</td></tr>" + "</table>" + "<p><em>Hint: K3b also accepts slight variations of the long special strings. " + "One can, for example, leave out the underscores.</em>") ); +} + + +void K3bVideoDVDRippingWidget::slotAudioCodecChanged( int codec ) +{ + switch( codec ) { + case K3bVideoDVDTitleTranscodingJob::AUDIO_CODEC_MP3: + m_stackAudioQuality->raiseWidget( m_stackPageAudioQualityMp3 ); + break; + case K3bVideoDVDTitleTranscodingJob::AUDIO_CODEC_AC3_STEREO: + m_stackAudioQuality->raiseWidget( m_stackPageAudioQualityAC3 ); + break; + case K3bVideoDVDTitleTranscodingJob::AUDIO_CODEC_AC3_PASSTHROUGH: + m_stackAudioQuality->raiseWidget( m_stackPageAudioQualityAC3Pt ); + break; + } + + emit changed(); +} + + +void K3bVideoDVDRippingWidget::slotVideoSizeChanged( int sizeIndex ) +{ + if( sizeIndex == PICTURE_SIZE_CUSTOM ) + slotCustomPictureSize(); + else + emit changed(); +} + + +void K3bVideoDVDRippingWidget::slotCustomPictureSize() +{ + KDialogBase dlg( KDialogBase::Plain, + i18n("Video Picture Size"), + KDialogBase::Ok|KDialogBase::Cancel, + KDialogBase::Ok, + this, + 0, + true, + true ); + K3bRichTextLabel* label = new K3bRichTextLabel( i18n("<p>Please choose the width and height of the resulting video. " + "If one value is set to <em>Auto</em> K3b will choose this value " + "depending on the aspect ratio of the video picture.<br>" + "Be aware that setting both the width and the height to fixed values " + "will result in no aspect ratio correction to be performed."), + dlg.plainPage() ); + QSpinBox* spinWidth = new QSpinBox( 0, 20000, 16, dlg.plainPage() ); + QSpinBox* spinHeight = new QSpinBox( 0, 20000, 16, dlg.plainPage() ); + spinWidth->setSpecialValueText( i18n("Auto") ); + spinHeight->setSpecialValueText( i18n("Auto") ); + QLabel* labelW = new QLabel( spinWidth, i18n("Width") + ':', dlg.plainPage() ); + QLabel* labelH = new QLabel( spinHeight, i18n("Height") + ':', dlg.plainPage() ); + labelW->setAlignment( Qt::AlignRight|Qt::AlignVCenter ); + labelH->setAlignment( Qt::AlignRight|Qt::AlignVCenter ); + + QGridLayout* grid = new QGridLayout( dlg.plainPage() ); + grid->setMargin( 0 ); + grid->setSpacing( KDialog::spacingHint() ); + grid->addMultiCellWidget( label, 0, 0, 0, 3 ); + grid->addWidget( labelW, 1, 0 ); + grid->addWidget( spinWidth, 1, 1 ); + grid->addWidget( labelH, 1, 2 ); + grid->addWidget( spinHeight, 1, 3 ); + + spinWidth->setValue( m_customVideoSize.width() ); + spinHeight->setValue( m_customVideoSize.height() ); + + if( dlg.exec() ) { + setSelectedPictureSize( QSize( spinWidth->value(), spinHeight->value() ) ); + emit changed(); + } +} + +#include "k3bvideodvdrippingwidget.moc" diff --git a/src/rip/videodvd/k3bvideodvdrippingwidget.h b/src/rip/videodvd/k3bvideodvdrippingwidget.h new file mode 100644 index 0000000..2d10da7 --- /dev/null +++ b/src/rip/videodvd/k3bvideodvdrippingwidget.h @@ -0,0 +1,67 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_VIDEODVD_RIPPING_WIDGET_H_ +#define _K3B_VIDEODVD_RIPPING_WIDGET_H_ + +#include "base_k3bvideodvdrippingwidget.h" + +#include <k3bvideodvdtitletranscodingjob.h> + +#include <qvaluevector.h> +#include <qmap.h> + +#include <kio/global.h> + +class QTimer; + +class K3bVideoDVDRippingWidget : public base_K3bVideoDVDRippingWidget +{ + Q_OBJECT + + public: + K3bVideoDVDRippingWidget( QWidget* parent ); + ~K3bVideoDVDRippingWidget(); + + K3bVideoDVDTitleTranscodingJob::VideoCodec selectedVideoCodec() const; + K3bVideoDVDTitleTranscodingJob::AudioCodec selectedAudioCodec() const; + int selectedAudioBitrate() const; + QSize selectedPictureSize() const; + + void setSelectedVideoCodec( K3bVideoDVDTitleTranscodingJob::VideoCodec codec ); + void setSelectedAudioCodec( K3bVideoDVDTitleTranscodingJob::AudioCodec codec ); + void setSelectedAudioBitrate( int bitrate ); + void setSelectedPictureSize( const QSize& ); + + void setNeededSize( KIO::filesize_t ); + + signals: + void changed(); + + private slots: + void slotUpdateFreeTempSpace(); + void slotSeeSpecialStrings(); + void slotAudioCodecChanged( int codec ); + void slotVideoSizeChanged( int sizeIndex ); + void slotCustomPictureSize(); + + private: + QTimer* m_freeSpaceUpdateTimer; + KIO::filesize_t m_neededSize; + + QSize m_customVideoSize; +}; + +#endif diff --git a/src/sounds/Makefile.am b/src/sounds/Makefile.am new file mode 100644 index 0000000..28cec7c --- /dev/null +++ b/src/sounds/Makefile.am @@ -0,0 +1,5 @@ + +soundsdir = $(kde_sounddir) +sounds_DATA = k3b_success1.wav k3b_error1.wav k3b_wait_media1.wav + +EXTRA_DIST = $(sounds_DATA) diff --git a/src/sounds/k3b_error1.wav b/src/sounds/k3b_error1.wav new file mode 100644 index 0000000..5b2e0b3 Binary files /dev/null and b/src/sounds/k3b_error1.wav differ diff --git a/src/sounds/k3b_success1.wav b/src/sounds/k3b_success1.wav new file mode 100644 index 0000000..7a42a2b Binary files /dev/null and b/src/sounds/k3b_success1.wav differ diff --git a/src/sounds/k3b_wait_media1.wav b/src/sounds/k3b_wait_media1.wav new file mode 100644 index 0000000..a629bae Binary files /dev/null and b/src/sounds/k3b_wait_media1.wav differ diff --git a/src/sourceheader b/src/sourceheader new file mode 100644 index 0000000..a83a4d5 --- /dev/null +++ b/src/sourceheader @@ -0,0 +1,15 @@ +/* + * + * $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $ + * Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2006 Sebastian Trueg <trueg@k3b.org> + * + * 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 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + diff --git a/src/tips b/src/tips new file mode 100644 index 0000000..3050e95 --- /dev/null +++ b/src/tips @@ -0,0 +1,47 @@ +<tip category="K3b"> +<html> +<p>...that you do not need to erase a CDRW before rewriting it manually +since K3b can do that automatically before writing.</p> +</html> +</tip> + +<tip category="K3b"> +<html> +<p>...that you do not need to bother with any settings if you do not know +what they mean. K3b is able to choose the settings best suited for you.</p> +</html> +</tip> + +<tip category="K3b"> +<html> +<p>...that K3b has two types of settings. On the one hand K3b has settings like most +KDE applications have accessable through the configuration dialog via the settings menu; +on the other hand every K3b action dialog has three buttons to load and save defaults +for that action. This way one may, for example, set the defaults for CD Copy: these defaults +will then be loaded every time the CD Copy dialog is opened. The button <em>K3b defaults</em> +will restore the <em>factory settings</em> in case you do not know if the settings you chose +are appropriate.</p> +</html> +</tip> + +<tip category="K3b"> +<html> +<p>...that you do not need to bother changing the settings marked as <em>advanced</em> if you +do not know what they mean. K3b's defaults are suitable for most daily use.</p> +</html> +</tip> + +<tip category="K3b"> +<html> +<p>Just left-click one of your devices in the device and file tree and see what happens. K3b opens a specific +window based on the media's contents. For an audio CD for example you will be given a list of the tracks with +the possibility to rip these tracks to any format supported by K3b (like mp3 or Ogg-Vorbis).</p> +</html> +</tip> + +<tip category="K3b"> +<html> +<p>...that K3b lets you choose media instead of devices for burning. So if you want to burn to a certain +medium simply insert it and wait for K3b to detect it. It will then appear as your burning medium.</p> +</html> +</tip> diff --git a/stamp-h.in b/stamp-h.in new file mode 100644 index 0000000..e69de29 diff --git a/subdirs b/subdirs new file mode 100644 index 0000000..85408f3 --- /dev/null +++ b/subdirs @@ -0,0 +1,8 @@ +doc +k3bsetup +kfile-plugins +kioslaves +libk3b +libk3bdevice +plugins +src