/***************************************************************************
 *   Copyright (C) 2004-2006 by Pere Constans
 *   constans@molspaces.com
 *   cb2Bib version 0.6.1
 *   See LICENSE file that comes with this distribution
 ***************************************************************************/
#include "cb2bib.h"
#include "cb2bib_par.h"
#include "bibsyntaxhighlighter.h"
#include "c2bbibparser.h"
#include "c2bclipboard.h"
#include "c2bclipedit.h"
#include "c2beditor.h"
#include "c2bnetwork.h"
#include "c2bnetworkquery.h"
#include "c2bpostprocess.h"
#include "c2bsettings.h"
#include "c2btextbrowser.h"
#include "c2butils.h"
#include "cb2bibconf.h"
#include "cbsyntaxhighlighter.h"
#include "pdfimport.h"
#include "saveregexp.h"

#include <qaction.h>
#include <qapplication.h>
#include <qcursor.h>
#include <qmessagebox.h>
#include <qpopupmenu.h>
#include <qpushbutton.h>
#include <qstatusbar.h>
#include <qtooltip.h>
#include <qwidgetlist.h>
#include <qdragobject.h>


/*! \page overview Overview
 
The cb2Bib is a tool for rapidly extracting unformatted, or unstandardized
biblographic references from email alerts, journal Web pages, and PDF files.
 
<b>Current version: cb2Bib GET_VERSION</b>.
(See \ref changelog for a detailed list of changes and acknowledgments, and \ref
relnotes for additional notes and information.)
 
<b>Important:</b> \ref relnotes060.
 
<p>&nbsp;</p>
 
\section contents Contents:
- \ref descrip
- \ref usage
- \ref detail
- \ref deposform
- \ref requirements
- \ref credits
 
<p>&nbsp;</p>
 
\htmlonly
      <p align="center"><img src="cb2bib/p_cb2bib_main.gif" alt="cb2Bib Main window"
      width="762" height="589" hspace="10" vspace="10" border="0" /></p>
\endhtmlonly
 
<p>&nbsp;</p>
\section descrip Description
 
 
The cb2Bib reads the clipboard text contents and process it against a set of
predefined patterns. If this automatic detection is successful, cb2Bib formats
the clipboard data according to the structured BibTeX reference standard. 
 
Otherwise, if no predefined format pattern is found or if detection proves to be
difficult, manual data extraction is greatly simplified by cb2Bib. In most
cases, such manual data extraction will provide with a new, personalized pattern
to be included within the predefined pattern set for future automatic
extractions.
 
Once the bibliographic reference is correctly extracted, it is added to a
specified BibTeX database file. Optionally, article PDF files, if available, are
renamed to its citeID and moved to a desired directory as a personal article
library (See \ref c2bconf_files section).
 
 
<p>&nbsp;</p>
\section usage Using cb2Bib
 
 
\subsection procedure Procedure
 
- <b>Select the reference to import from the email or web browser</b> \n On Unix
machines, cb2Bib automatically detects mouse selections and clipboard changes.
On Windows machines, copy or Ctrl-C is necessary to activate cb2Bib automatic
processing.
 
- <b>cb2Bib automatic processing</b> \n Once text is selected cb2Bib initiates
the automatic reference extraction. It uses the predefined patterns from file
<tt>regexp.txt</tt> to attempt automatic extraction. See \ref c2bconf_files
section for setting the user predefined pattern matching expression file. After
a successful detection bibliographic fields appear on the cb2Bib item line
edits. Manual editing is possible at this stage.
 
- <b>cb2Bib manual processing</b> \n If no predefined format pattern is found or
if detection proves to be difficult, a manual data extraction must be performed.
Select individual reference items from the cb2Bib clipboard area. A popup menu
will appear after selection is made. Choose the corresponding bibliographic
field. See \ref entrytype. Selection is postprocessed and added to the cb2Bib
item line edit. cb2Bib field tags will show on the cb2Bib clipboard area. Once
the manual processing is done, cb2Bib clipboard area will contain the matching
pattern. The pattern can be further edited and stored to the <tt>regexp.txt</tt>
file using the <b>RegExp Editor</b>, Alt+E. See the \ref bibproc and \ref
regexpedit sections.
 
- <b>Adding article files</b> \n PDF or PS article files can be added to the
BibTeX reference by dragging the file icon and dropping it into cb2Bib.
Optionally, article PDF files, are renamed to its citeID and moved to a desired
directory as a personal article library (See \ref c2bconf_files section). If a
file with the citeID name already exists, a single, lowcase letter suffix is
added to citeID to avoid overwriting existing files. Usual reference manager
software will permit to retrieve and visualize these files.
 
- <b>Multiple retrieving from PDF files</b> \n Multiple PDF or convertible to
text files can be sequentially processed by dragging a set of files into
cb2Bib's PDFImport window. By starting the processing button, files are
sequentially converted to text and send to cb2Bib clipboard panel for reference
extraction. If the automatic recognition fails, the process pauses and allows
for cb2Bib manual extraction. Alternatively, if automatic recognition succeeds
references are optionally saved and next file is processed. See \ref
c2bconf_pdfimport section for setting your to text converter tool and setting
function mode as supervised or automatic.
 
- <b>Journal-Volume-Page Queries</b> \n Takes input Journal, Volume, and first
page from the corresponding edit lines and attempts to complete the reference.
See \ref c2bconf_network section, the distribution file <tt>netqinf.txt</tt>,
and \ref relnotes035 for customization and details.
 
- <b>BibTeX Editor</b> \n cb2Bib includes a practical text editor suitable for
corrections and additions. cb2Bib capabilities are readily available within the
editor. E.g., the reference is first sent to cb2Bib by selecting it, and later
retrieved from cb2Bib to the editor using 'right click' + 'Paste Current
BibTeX'. Interconversions Unicode <-> LaTeX, long <-> abbreviated journal name,
and adding/renaming PDF files are easily available. BibTeX Editor is also
accessible through a shell command line. See \ref commandline and  \ref
c2beditor.
 
 
\subsection c2bbuttons Buttons Functionality
 
- \b About \n About cb2Bib, bookmarks, and online help
 
- \b Configure \n Configure cb2Bib. See \ref c2bconf section.
 
- \b PDFImport \n Launches cb2Bib's PDFImport window. Files dragged into
PDFImport window are sequentially translated to text and sent to cb2Bib
clipboard panel. The cb2Bib automatic and manual capabilities are then easily
available to extract and supervise reference extractions. See \ref
c2bconf_pdfimport section to configure the external to text converter and its
command line arguments. See also \ref relnotes027.
 
- \b Exit \n Exits the cb2Bib
 
- <b>Dis/Connect Clipboard</b> \n Toggles automatic cb2Bib and desktop clipboard
connection. While the automatic cb2Bib-clipboard connection permits reducing
keystrokes, the disconnected mode is needed in cases where multiple mouse
selections or copies are required to complete a reference extraction. See also
\ref relnotes041 and \ref relnotes021 if you experience problems with this feature.
 
- <b>Make Network Query</b> \n Starts Network Query. Takes input Journal,
Volume, and first page from the corresponding edit lines and attempts to
complete the reference. See \ref c2bconf_network network section to customize
querying. See the distribution file <tt>netqinf.txt</tt> and also \ref
relnotes035 for the details.
 
- <b>View BibTeX</b> \n View captured BibTeX item. Eventual manual changes
should be done on the item line edit.
 
- <b>Add Bib</b> \n Adds bibliographic item to user defined database file.
 
- <b>BibTeX Editor</b> \n Edits the current BibTeX output file. Right click
within the BibTeX Editor window for its particular functionality. See also \ref
c2beditor.
 
 
\subsection keyboard Additional, Keyboard Functionality
 
- <b>Alt B</b> \n Edits the current Bookmarks and Network Query Info file
<tt>netqinf.txt</tt>.
 
- <b>Alt C</b> \n Preparses cb2Bib's clipboard through a user specified external
script or tool.  Preparsing is necessary to catch formatted references that can
not be easily extracted using recognition patterns, or that are written in
ambiguous formats. Many available scripts or specific user-written tools can be
incorporated to cb2Bib through this external preparsing capability. In addition,
simple, one-line scripts can be used within PDFImport to provide, for instance,
the journal name when missing from the PDF first page. The cb2Bib distribution
contains the sample scripts <tt>isi2bib</tt> and <tt>ris2bib</tt> that convert
ISI and RIS formatted strings to BibTeX. See \ref c2bconf_input for details.
 
- <b>Alt D</b> \n Deletes BibTeX output file. This permits using cb2Bib output
files as temporary media to transfer references to a preferred reference manager
and preferred format. <b>Caution</b>: This feature is not intended for the users
that actually store their references in one or several BibTeX files. Remember to
import references prior to delete cb2Bib output file.
 
- <b>Alt E</b> \n Edits and optionally Saves the current regular expression
pattern. See the \ref bibproc and \ref regexpedit sections.
 
- <b>Alt F</b> \n Edits the current regular expression file. It permits an easy
access and modification of stored extraction patterns. New patterns are
conveniently added to to the regular expression file by using the <b>RegExp
Editor</b> button functionality.
 
- <b>Alt P</b> \n Postprocess BibTeX output file. It launches a user specified
script or program to postprocess the current BibTeX file. The cb2Bib
distribution contains two sample scripts. One, <tt>bib2pdf</tt> is a shell
script for running <tt>latex</tt> and <tt>bibtex</tt>; this permits to check the
BibTeX file for possible errors, and to easily produce a suitable output for
printing. The other one, <tt>bib2end.bat</tt> is a batch script for running
<tt>bib2xml</tt> and <tt>xml2end</tt>, which converts references into Endnote
format. See \ref c2bconf_output for details.
 
- <b>Alt R</b> \n Restarts the cb2Bib automatic engine. Takes input data not
from the system clipboard but from the cb2Bib clipboard panel. This permits
editting the input stream from poorly translated PDF captions, correcting for
author superscripts, or helps in debugging regular expressions.
 
- <b>Esc</b> \n Quits cb2Bib popup menu. The cb2Bib menu pops up each time a
selection in made in the clipboard panel. This saves keystrokes in a normal
biblographic extraction. Press <b>Esc</b> or <b>Right Click</b> mouse button if
you need to gain access to the editor cut/copy/paste functionality instead.
 
 
<p>&nbsp;</p>
\section detail The cb2Bib detailed procedure
This section describes the details of the internal cb2Bib recognition scheme.
 
    -# \ref bibproc
    -# \ref authorproc
    -# \ref journalproc
 
<p>&nbsp;</p>
\section deposform Regular Expression Submition Form
cb2Bib usefullness increases when having a set of reliable regular expressions.
It can therefore be interesting to share one's favorite regexps among cb2Bib
users. If you have a working -which does not mean perfect- regexp that could
benefit other users, please take a moment and fill out the \ref submission.
These regexp will be later included into the cb2Bib distribution, as received,
without any additional editing. Interested users could then copy/paste needed
cb2Bib regexps into their own regexp file. In this way, no much of anybody's
time and effort should be needed.
 
<p>&nbsp;</p>
\section requirements cb2Bib Requirements
 
\subsection requirements_comp Compilation
To compile cb2Bib, the following libraries must be present and accessible:
 
   - Qt 3.2.0 -or higher, but lesser than 4.0.0- from
\htmlonly
<a href="http://www.trolltech.com/products/qt/index.html" 
target="_blank">Trolltech</a>.
\endhtmlonly
 On a Linux platform with Qt preinstalled, make sure that the <tt>devel</tt>
packages and Qt tools are also present. cb2Bib will be ported to Qt 4 whenever
this version becomes part of KDE.
 
   - X11 header files if compiling on Unix platforms. Concretely, headers
<tt>X11/Xlib.h</tt> and <tt>X11/Xatom.h</tt> are needed, unless cb2Bib is
configured as <tt>./configure --disable_cbpoll</tt>. On a native MacOSX
and Windows <tt>cbpoll</tt> is already disabled by default. 
 
   - The header files <tt>fcntl.h</tt> and <tt>unistd.h</tt> from
<tt>glibc-devel</tt> package are also required. Otherwise compilation will fail
with <tt>referencelist.cpp:227: `::close' undeclared</tt>.
 
\subsection requirements_run Deployment
Although not needed for running cb2Bib, the following tools extend cb2Bib
applicability:
 
   - <tt>pdftotext</tt>, found packaged as <tt>xpdf</tt>, and downloadable from
\htmlonly
<a href="http://www.foolabs.com/xpdf/download.html" 
target="_blank">http://www.foolabs.com/xpdf</a>.
\endhtmlonly
 
    - The <tt>bib2xml</tt> and <tt>xml2end</tt> 
\htmlonly
<a href="http://www.scripps.edu/~cdputnam/software/bibutils/bibutils.html" 
target="_blank">BibUtils</a>, 
\endhtmlonly
to test the postprocess script <tt>bib2end.bat</tt> on Windows platforms.
 
    - ... and LaTeX and friends, to check for BibTeX file correctness and to get
a nice printing through the shell script <tt>bib2pdf</tt>.
 
 
<p>&nbsp;</p>
\section credits Credits and License
 
All icons are taken from the <em>Crystal SVG</em> and <em>Noia</em> icon sets,
to be found at the 
\htmlonly
<a href="http://www.kde.org" 
target="_blank">KDE Desktop Environment.</a>
\endhtmlonly
 
 
 
The cb2Bib GET_VERSION program is licensed under the terms of the
\htmlonly
<a href="http://www.gnu.org/licenses/gpl.html" 
target="_blank">GNU General Public License.</a>
\endhtmlonly
 
 
<p>&nbsp;</p>
 
The <b>cb2Bib</b>, Pere Constans, Copyright &copy; 2004-2006. All rights reserved.\n
First realeased, version 0.1.0 on 2004-06-29. \n
GET_UPDATEDON \n \n
See \ref changelog for a detailed list of changes and acknowledgments.
 
<p>&nbsp;</p>
 
*/

/*! \page relnotes Release Notes
 
\section relnotes060 Release Note cb2Bib 0.6.0
 
The cb2Bib uses the internal tags <tt><<NewLine_n>></tt> and <tt><<Tab_n>></tt>
to ease the creation of regular expressions for reference extraction. New line
and tabular codes from the input stream are substituted by these numbered tags.
Numbering new lines and tabulars gives an extra safety when writing down a
regular expression. E. g., suppose field title is 'anything' between
'<tt><<NewLine1>></tt> and <tt><<NewLine2>></tt>'. We can then easily write
'anything' as '.+' without the risk of overextending the caption to several '\\n'
codes. On the other hand, one still can use <tt><<NewLine\\d>></tt> if not
interested in a specific numbering. All these internal tags are later removed,
once cb2Bib postprocesses the entry fields.
 
The cb2Bib identified so far new lines by checking for '\\n' codes. I was
unaware that this was a platform dependent, as well as a not completely accurate
way of detecting new lines. McKay Euan reported that <tt><<NewLine_n>></tt> tags
were not appearing as expected in the MacOSX version. I later learn that MacOSX
uses '\\r' codes, and that Windows uses '\\r\\n', instead of '\\n' for new line
encoding.
 
This realease addresses this issue. It is supposed now that the cb2Bib regular
expressions will be more transferable among the different platforms. Extraction
from plain text sources is expected to be completely platform independent.
Extraction from web pages will still remain browser dependent. In fact, each
browser adds its peculiar interpretation of a given HTML source. For example, in
Wiley webpages we see the sectioning header 'Abstract' in its source and in
several browsers, but we see, and get, 'ABSTRACT' if using Konqueror.
 
What we pay for this more uniform approach is, however, a <b>break in
compatibility</b> with previous versions of cb2Bib. Unix/Linux users should not
expect many differences, though. Only one from the nine regular expressions in
the examples needed to be modified, and the two contributed regular expressions
work perfectly without any change. Windows users will not see a duplication of
<tt><<NewLine_n>></tt> tags. To update previous expressions it should be enough
just shifting the <tt><<NewLine_n>></tt> numbering. And, of course, any working
regular expression that does not uses <tt><<NewLine_n>></tt> tags will still be
working in this new version.
 
Finally, just to mention that I do not have a MacOSX to test any of the cb2Bib
realeases in this particular platform. I am therefore assuming that these
changes will fix the problem at hand. If otherwise, please, let me know. Also,
let me know if release 0.6.0 'break' your own expressions. I consider this
realease a sort of experimental or beta version, and the previous version 0.5.3,
will still be available during this testing period.
 
 
<p>&nbsp;</p>
*/

/*! \page relnotes Release Notes
 
\section relnotes050 Release Note cb2Bib 0.5.0
 
Two issues had appeared regarding cb2Bib installation and deployment on MacOSX
platforms.
 
First, if you encounter a 'nothing to install'-error during installation on  
MacOSX 10.4.x using the cb2bib binary installer available at 
\htmlonly
<a href="http://naranja.umh.es/~atg"
target="_blank">http://naranja.umh.es/~atg</a>,
\endhtmlonly
please delete the cb2bib-receipts from <tt>/Library/Receipts</tt> and then rerun the
installer. See also M. Bongard's clarifying note 
'MACOSX 10.4.X "NOTHING TO INSTALL"-ERROR' for details.
 
Second, and also extensible to other cb2Bib platform versions, if PDFImport
issues the error message 'Failed to call <i>some_format_to_text</i>' tool, make
sure such a tool is installed and available. Go to Configure->PDFImport, click
at the 'Select External Convert Tool' button, and navigate to set its full path.
Since version 0.5.0 the default full path for the MacOSX is already set, and
pointing to <tt>/usr/local/bin/pdftotext</tt>.
 
 
<p>&nbsp;</p>
*/

/*! \page relnotes Release Notes
 
\section relnotes041 Release Note cb2Bib 0.4.1
 
Qt/KDE applications emit notifications whenever they change the clipboard
contents. The cb2Bib uses these notifications to automatically start its
'clipboard to BibTeX' processing. Other applications, however, does not notify
about them. Since version 0.2.1, see \ref relnotes021, cb2Bib started checking
the clipboard periodically. This checking was later disabled as a default,
needing a few lines of code to be uncomented to activate it. Without such a
checking, the cb2Bib appears unresponsive when selecting/copying from e.g.,
acroread or Mozilla. This release includes the class <tt>clipboardpoll</tt>
written by L. Lunak for the KDE's Klipper. Checking is performed in a very
optimized way. This checking is enabled by default. If you experience problems
with this feature, or if the required X11 headers aren't available, consider
disabling it by typing <tt>./configure --disable_cbpoll</tt> prior to
compilation. This will disable checking completely. If the naive, old checking
is preferred, uncomment the four usual lines, <tt>./configure
--disable_cbpoll</tt>, and compile.
 
<p>&nbsp;</p>
*/

/*! \page relnotes Release Notes
 
\section relnotes035 Release Note cb2Bib 0.3.5
 
Releases 0.3.3 and 0.3.4 brought querying functionality to cb2Bib. In essence,
cb2Bib was rearranged to accommodate copying and opening of network files.
Queries were then implemented as user customizable HTML posts to journal
databases. In addition, these arrangements permitted defining convenience,
dynamic bookmarks that were placed at the cb2Bib's 'About' panel.
 
cb2Bib contains three viewing panels: 'About', 'Clipboard' and 'View BibTeX',
being the 'Clipboard' panel the main working area. To keep cb2Bib simple, only
two buttons, 'About' and 'View BibTeX', are set to navigate through the panels.
The 'About' and 'View BibTeX' buttons are toggle buttons for momentarily
displaying their corresponding panels. Guidance was so far provided by
enabling/disabling the buttons.
 
After the bookmark introduction, the 'About' panel has greatly increased its
usefullness. Button functionality has been slightly redesigned now to avoid as
many keystrokes and mouse clicks as possible. The buttons remain switchable, but
they no longer disable the other buttons. User is guided by icon changes
instead. Hopefully these changes will not be confusing or counterintuitive.
 
Bookmarks and querying functionality are customizable through the
<tt>netqinf.txt</tt> file, which is editable by pressing the <tt>Alt+B</tt>
keys. Supported queries are of the form 'Journal-Volume-First Page'. cb2Bib
parses <tt>netqinf.txt</tt> each time a query is performed. It looks for
<tt>journal=<i>Full_Name|[code]</i></tt> to obtain the required information for
a specific journal. Empty, '<tt>journal=</tt>' entries have a meaning of 'any
journal'. New in this realease, cb2Bib will test all possible queries for a
given journal instead of giving up at the first <tt><i>No article found</i></tt>
message. The query process stops at the first successfull hit or, otherwise,
once <tt>netqinf.txt</tt> is parsed completely (in an equivalent way as the
automatic pattern recognition works). This permits querying multiple -and
incomplete- journal databases.
 
Users should order the <tt>netqinf.txt</tt> file in a way it is more convenient.
E.g., put PubMed in front of JACS if desired an automatic extraction. Or JACS in
front of PubMed and extract from the journal web page, if author accented
characters are wanted.
 
So far, this querying functionality is still tagged as <em>experimental</em>.
Either the querying itself or its syntax seem quite successful. However,
downloading of PDF files, on windows OS + T1 network, <b>was found to freeze</b>
once progress reaches the 30-50%. Any feedback on this issue will be greatly
appreciated. Also, information on <tt>kfmclient</tt> equivalent tools for non
KDE desktops would be worth to be included in the cb2Bib documentation.
 
<p>&nbsp;</p>
*/

/*! \page relnotes Release Notes
 
\section relnotes030 Release Note cb2Bib 0.3.0
 
cb2Bib considers the whole set of authors as an author-string pattern. This
string is later postprocessed, without requirements on the actual number of
authors it may contain, or on how the names are written. Once considered
author-string patterns, the extraction of bibliographic references by means of
regular expressions becomes relatively simple.
 
 
There are situations, however, where several author-strings are required. The
following box shows one of these cases. Authors are grouped according to their
affiliations. Selecting from 'F. N. First' to 'F. N. Fifth' would include 'First
Affiliation' within the author string. Cleaning up whatever wording 'First
Affiliation' may contain is a rather ill-posed problem. Instead, cb2Bib includes
an <tt>Add Authors</tt> option. The way of operation is then to select 'F. N.
First, F. N. Second, F. N. Third' and chose <tt>Authors</tt> and right after,
select 'F. N. Fourth and F. N. Fifth' and chose <tt>Add Authors</tt>.
 
\htmlonly
<? require("cb2bib/p_cb2bib_example_multiple_author_sets.html"); ?>
\endhtmlonly
 
At this point in the manual extraction, the user was faced with a red
<tt><<moreauthors>></tt> tag in the cb2Bib clipboard panel. The
<tt><<moreauthors>></tt> tag was intended to warn the user about the fact that
cb2Bib would not be able to consider the resulting extraction pattern as a
valid, general regular expression. Usual regular expressions are built up from
an a priori known level of nesting. In these cases, however, the level of
nesting is variable. It depends on the number of different affiliations
occurring in a particular reference.
 
So far the <tt><<moreauthors>></tt> tag has become a true FAQ about cb2Bib and a
source of many confusions. There is no real need, however, for such an user
warning. The <tt><<moreauthors>></tt> has therefore been removed and cb2Bib has
taken an step further, to its 0.3.0 version.
 
The cb2Bib 0.3.0 manual extraction works as usual. By clicking <tt>Authors</tt>
the Authors edit line is reseted and selection contents moved there.
Alternatively, if <tt>Add Authors</tt> is clicked, selection contents is added
to the author field. On this version, however, both operations are tagged as
<tt><<author>></tt> (singular form, as it is the BibTeX keyword for Authors).
The generated extraction pattern can now contain any number of
<tt><<author>></tt> fields. 
 
In automatic mode, cb2Bib now adds all <tt>author</tt> captions to Authors. In
this way, cb2Bib can treat interlaced author-affiliation cases. Obviously, users
needing such extractions will have to write particular regular expressions for
cases with one set of authors, for two sets, and so on. Eventhough it is not
rare a work having a hundred of authors, it would be quite umprobable that they
were working on so many different institutions. Therefore, few regular
expressions should actually be required in practice. Although not elegant, this
breaks what was a cb2Bib limitation and broadens its use when extracting from
PDF sources. Remember here to sort these regular expressions in decreasing
order, since at present, cb2Bib stops at the first hit. Also, consider <tt>Any
Pattern</tt> to get ride of the actual affiliation contents, as you might not
want to extract authors addresses.
 
<p>&nbsp;</p>
*/

/*! \page relnotes Release Notes
 
\section relnotes027 Release Note cb2Bib 0.2.7
 
The cb2Bib 0.2.7 realease introduces multiple retrieving from PDF files. PDF
documents are becoming more and more widely used, not only to transfer and
printing articles, but also are substituting the personal paper files and
classifiers for the electronic equivalents. 
 
cb2Bib is intended to help updating personal databases of papers. It is a tool
focused on what is left behind in database retrieving. Cases such as email
alerts, or inter colleague references and PDF sharing are example situations.
Though in an electronic format, sources are not standardized or not globally
used as to permit using habitual import filters in reference managers. cb2Bib is
designed to consider a direct user intervention, either by creating its own
usefull filters or by a simple copy-paste assistance when handtyping.
 
Hopefully someday cb2Bib will be able to take that old directory, with perhaps a
few hundreds of papers, to automatically index the references and rename the
files by author, in a consistent manner. The required mechanism is already
there, in this version. But I guess that this new feature will manifest some
present limitations in cb2Bib. For instance, most printed and PDF papers
interlace author names and affiliations. cb2Bib doesn't has the means to
automatically discern an author name from a department or street name. So far
one needs to manually use the 'Add to Authors' feature to deal with these
situations. Also, the managing of regular expressions needs developing,
specially thinking in the spread variety of design patterns in publications.
 
In summary, this current version is already usefull in classifying and
extracting the reference of that couple of papers that someone send right before
submitting a work. A complete unsupervised extraction is still far away,
however.
 
<p>&nbsp;</p> 
*/

/*! \page relnotes Release Notes
 
\section relnotes021 Release Note cb2Bib 0.2.1
 
The cb2Bib mechanism 'select-and-catch' failed in some cases. Acrobat and
Mozilla selections were not always notified to the cb2Bib. Indeed, this 'window
manager - application' connection seems to be broken on a KDE 3.3.0 + Qt 3.3.3
system.
 
The cb2Bib 0.2.1 continues to listen to system clipboard change notifications,
whenever they are received and whenever cb2Bib is on connected mode.
Additionally, the cb2Bib 0.2.1 periodically checks for changes in the system
clipboard. Checks are performed every second, approximately. This permits cb2Bib
to work as usual, although one could experience 1-2 seconds delays in systems
where the automatic notification is broken.
 
If the 'select-and-catch' functionality appears 'sticky', possibly happening
while using non KDE applications from where text is selected, check the source
file <tt>c2bclipboard</tt><tt>.cpp</tt>, look for <tt>'Setting timer'</tt>, and
set variable <tt>interval</tt> to 1000. This is the interval of time in ms that
cb2Bib will use to check for clipboard changes.
 
<p>&nbsp;</p>
*/


cb2Bib::cb2Bib(QWidget* parent, const char* name, WFlags fl)
        : cb2bibbase(parent,name,fl)
{

    //  Initializing GUI
    setButtonIcons();
    htmlbrowser->setFrameShape( QTextEdit::StyledPanel );
    htmlbrowser->setFrameShadow( QTextEdit::Raised );
    htmlbrowser->hide();
    htmlbrowser->setReadOnly( TRUE );
    bibS = new bibSyntaxHighlighter( htmlbrowser );
    connect( htmlbrowser, SIGNAL( linkClicked(const QString&) ), this, SLOT( linkClicked(const QString &) ) );
    connect( htmlbrowser, SIGNAL( highlighted(const QString&) ), this, SLOT( setMessage(const QString &) ) );
    clipb->setFrameShape( QTextEdit::StyledPanel );
    clipb->setFrameShadow( QTextEdit::Raised );
    cbS = new cbSyntaxHighlighter( clipb );
    m_viewingbib = FALSE;
    m_viewingabout = FALSE;
    m_viewingabout_x = 0;
    m_viewingabout_y = 0;

    connect( viewAboutB, SIGNAL( clicked() ), this, SLOT( viewAbout() ) );
    connect( addBibB, SIGNAL( clicked() ), this, SLOT( prepareAddToFile() ) );
    connect( BibTeXEditorB, SIGNAL( clicked() ), this, SLOT( BibTeXEditor() ) );
    connect( clearFieldsAction, SIGNAL( activated() ), this, SLOT( c2bInit() ) );
    connect( composeRE, SIGNAL( activated() ), this, SLOT( RegExpEditor() ) );
    connect( configureB, SIGNAL( clicked() ), this, SLOT( settings() ) );
    connect( connectB, SIGNAL( clicked() ), this, SLOT( connectCB() ) );
    connect( deleteTmpBibTeX, SIGNAL( activated() ), this, SLOT( deleteTmpBib() ) );
    connect( editBookmark, SIGNAL( activated() ), this, SLOT( bookmarkEditor() ) );
    connect( editREFile, SIGNAL( activated() ), this, SLOT( REFileEditor() ) );
    connect( exitB, SIGNAL( clicked() ), qApp, SLOT( closeAllWindows() ) );
    connect( file_dirs, SIGNAL( clicked() ), this, SLOT( getBF() ) );
    connect( guessFieldsAction, SIGNAL( activated() ), this, SLOT( guessFields() ) );
    connect( makeNetworkQuery, SIGNAL( clicked() ), this, SLOT( makeNetQuery() ) );
    connect( PDFImportB, SIGNAL( clicked() ), this, SLOT( launchPDFImport() ) );
    connect( preprocessClipAction, SIGNAL( activated() ), this, SLOT( preParseClipboard() ) );
    connect( postprocessBibAction, SIGNAL( activated() ), this, SLOT( postProcessBibTeX() ) );
    connect( startEngineAction, SIGNAL( activated() ), this, SLOT( restartEngine() ) );
    connect( viewBibB, SIGNAL( clicked() ), this, SLOT( viewBib() ) );

    clipb->viewport()->setAcceptDrops(FALSE);
    setAcceptDrops(TRUE);

    // Seting Input Menu
    setManualMenu();

    // List cb2Bib Actions
    aList.append( &clearFieldsAction );
    aList.append( &guessFieldsAction );
    aList.append( &startEngineAction );
    aList.append( &preprocessClipAction );
    aList.append( &postprocessBibAction );
    aList.append( &editBookmark );
    aList.append( &editREFile );
    aList.append( &composeRE );
    clipb->setActions( &aList );
    htmlbrowser->setActions( &aList );

    //  Recovering previous settings
    s = new c2bSettings( this );
    resize( s->m_windowWidth, s->m_windowHeight );
    clipb->setFont( s->m_font );
    htmlbrowser->setFont( s->m_font );
    bibfile->setText( s->m_bibfile );

    // Creating Bibliographic Parser
    bp = new c2bBibParser( s, this );
    connect( bp, SIGNAL( bibModified() ), this, SLOT( bibModified() ) );
    m_modified = FALSE;
    addBibB->setEnabled( m_modified );
    connect( bp, SIGNAL( preParserDataAvailable(const QString&) ), this, SLOT( preParserEnded(const QString&) ) );
    connect( bp, SIGNAL( helpRequested(const QString&) ), this, SLOT( displayHelp(const QString&) ) );

    // Connecting cb2bib network
    net = new c2bNetwork( this );
    netQ = new c2bNetworkQuery( net, this );
    connect( this, SIGNAL(newSettingAvailable()), netQ, SLOT(readSettings()) );
    connect( netQ, SIGNAL(message(const QString&)), this, SLOT( setMessage(const QString&) ) );
    connect( netQ, SIGNAL(queryEnded(bool, const QString&, const QString&)),
             this, SLOT(netQueryEnded(bool, const QString&, const QString&) ));

    // Init PDFImport
    pdfImport = 0;

    // Connecting cb2bib clipboard and start
    m_connected = FALSE;
    cb = new c2bClipboard();
    connect( cb, SIGNAL( cbDataChanged( const QString& ) ), this, SLOT( dataChanged( const QString& ) ) );
    connectCB();
    raw_input_data = "";
    dataChanged( cb->text() );
    if ( s->m_autostart_bibedit )
    {
        initBibTeXEditor();
        showMinimized();
    }
}

cb2Bib::~cb2Bib()
{
    delete bibS;
    delete bp;
    delete cb;
    delete cbS;
    delete net;
    delete netQ;
    delete pmenu;
    delete pomenu;
    delete s;
}


/****************************************************************************
 
  GUI FUNCTIONALITY
 
*****************************************************************************/

void cb2Bib::connectCB()
{
    if( m_connected )
    {
        connectB->setPixmap( QPixmap::fromMimeSource( APP_ICON_DISCONNECTB ) );
        QToolTip::add
            ( connectB, tr("cb2Bib is disconnected from the clipboard, click to connect") );
        m_connected = FALSE;
        cb->setConnected( m_connected );
    }
    else
    {
        connectB->setPixmap( QPixmap::fromMimeSource( APP_ICON_CONNECTB ) );
        QToolTip::add
            ( connectB, tr("cb2Bib is connected to the clipboard, click to disconnect") );
        m_connected = TRUE;
        cb->setConnected( m_connected );
    }
}

void cb2Bib::getBF()
{
    QString fn = bibfile->text();
    QString new_fn = QFileDialog::getSaveFileName( fn, "BibTeX (*.bib);;All (*)",
                     this, "save file dialog", "Select a new or existing filename" );
    if( ! new_fn.isEmpty() )
        bibfile->setText(new_fn);
}

void cb2Bib::launchPDFImport()
{
    if( !pdfImport )
    {
        pdfImport = new PDFImport( s, this, "PDFImport", Qt::WType_TopLevel | Qt::WDestructiveClose );
        connect( this, SIGNAL(addedBibtoFile(const QString&)), pdfImport, SLOT(processNext()) );
        connect( pdfImport, SIGNAL(textProcessed(const QString&)), this, SLOT(dataChanged(const QString&)) );
        connect( pdfImport, SIGNAL(fileProcessed(const QString&)), this, SLOT(fileDropped(const QString&)) );
        connect( pdfImport, SIGNAL(helpRequested(const QString&)), this, SLOT(displayHelp(const QString&)) );
        statusBar()->message( tr("PDF Import launched."), MESSAGE_TIME );
        pdfImport->show();
    }
    if ( pdfImport->isMinimized() )
        pdfImport->showNormal();
    pdfImport->raise();
    pdfImport->setActiveWindow();
}

void cb2Bib::closeEvent( QCloseEvent* ce )
{
    if( pdfImport )
        pdfImport->close();
    s->m_windowHeight = height();
    s->m_windowWidth = width();
    s->m_bibfile = bibfile->text();
    s->writeMainSettings();
    ce->accept();
}

void cb2Bib::dragEnterEvent( QDragEnterEvent *e )
{
    QString fn;
    e->accept( QTextDrag::decode(e, fn) );
}

void cb2Bib::dropEvent( QDropEvent *e )
{
    QString fn;
    if ( QTextDrag::decode(e, fn) )
        fileDropped( fn.stripWhiteSpace() ); // On Windows, there was a trailing blank in name
    else
    {
        e->ignore();
        return;
    }
}

void cb2Bib::fileDropped( const QString& fn )
{
    if( fn.isEmpty() )
        return;
    m_dropped_article_file = fn;
    m_dropped_article_file.replace( QRegExp( "\\n.*$" ), "" );
    setArticleFileName();
    if( s->m_movepdf )
    {
        statusBar()->message( tr("Scheduled inclusion of file %1.").arg(m_dropped_article_file), MESSAGE_TIME );
        QToolTip::add
            ( pdf, tr("From file '%1'.").arg(m_dropped_article_file) );
    }
}

void cb2Bib::viewAbout()
{
    if( m_viewingabout )
    {
        m_viewingabout = FALSE;
        m_viewingabout_x = htmlbrowser->contentsX();
        m_viewingabout_y = htmlbrowser->contentsY();
        m_viewingbib = !m_viewingbib;
        viewBib();
    }
    else
    {
        m_viewingabout = TRUE;
        switchViewButtons();
        QString AboutS =
            QString(
                "<br /><br /><p align=\"center\"><b>cb2Bib %1</b></p>"
                "<p align=\"center\">"
                "A tool for rapidly extracting unformatted biblographic references from email "
                "alerts, journal Web pages, and PDF files.<br />"
                "<p align=\"center\"><img src=\"cb2bib.png\"></p>"
                "<p align=\"center\">"
                "<a href=\"http://www.molspaces.com/cb2bib/index.html\">"
                "cb2Bib Help and User's Guide</a></p><br />"
                "<p align=\"center\">"
                "Additional Functionality:</p>"
                "<p align=\"center\"><table border=\"1\"align=\"center\">"
                "<thead><tr>"
                "<th>Keys</th><th>Description</th></tr>"
                "</thead><tbody><tr>"
                "<td>Alt B</td><td>Bookmarks File Editor</td></tr><tr>"
                "<td>Alt C</td><td>Preparses cb2Bib's clipboard</td></tr><tr>"
                "<td>Alt D</td><td>Deletes BibTeX output file</td></tr><tr>"
                "<td>Alt E</td><td>Edit and Save Regular Expressions</td></tr><tr>"
                "<td>Alt F</td><td>Regular Expression File Editor</td></tr><tr>"
                "<td>Alt P</td><td>Postprocess BibTeX</td></tr><tr>"
                "<td>Alt R</td><td>Restarts automatic recognition</td></tr><tr>"
                "<td>Esc</td><td>Quits cb2Bib popup menu</td></tr><tr>"
                "<td>Right Click</td><td>Editor popup menu"
                "</td></tr></tbody>"
                "</table></p><br /> %2 <br />"
                "<p align=\"center\">Copyright (C) 2004-2006 by Pere Constans<br />"
                "<a href=\"http://www.molspaces.com/cb2bib/index.html\">"
                "http://www.molspaces.com/cb2bib</a></p>&nbsp;"
                "<p align=\"center\"><i>The cb2Bib is licensed under the terms of the "
                "<a href=\"http://www.gnu.org/licenses/gpl.html\">"
                "GNU General Public License</a>"
                "</i><br /></p>&nbsp;")
            .arg(APP_VERSION).arg(netQ->bookMarks());
        bibS->blockSyntaxHighlighting( TRUE );
        htmlbrowser->setText( AboutS );
        htmlbrowser->setContentsPos( m_viewingabout_x, m_viewingabout_y );
        clipb->hide();
        htmlbrowser->show();
    }
}

void cb2Bib::viewBib()
{
    if( m_viewingabout )
    {
        m_viewingabout_x = htmlbrowser->contentsX();
        m_viewingabout_y = htmlbrowser->contentsY();
    }
    if( m_viewingbib )
    {
        m_viewingbib = FALSE;
        htmlbrowser->hide();
        clipb->show();
    }
    else
    {
        m_viewingbib = TRUE;
        bibS->blockSyntaxHighlighting( FALSE );
        htmlbrowser->setText( bp->makeBib() );
        htmlbrowser->setContentsPos( 0, 0 );
        clipb->hide();
        htmlbrowser->show();
    }
    m_viewingabout = FALSE;
    switchViewButtons();
}

void cb2Bib::switchViewButtons()
{
    // Correlate viewAboutB, connectB and viewBibB buttons
    if( m_viewingbib )
    {
        viewBibB->setPixmap( QPixmap::fromMimeSource( APP_ICON_VIEWC2BB ) );
        QToolTip::add
            ( viewBibB, tr("cb2Bib clipboard area - Ctrl+B") );
    }
    else
    {
        viewBibB->setPixmap( QPixmap::fromMimeSource( APP_ICON_VIEWBIBB ) );
        QToolTip::add
            ( viewBibB, tr("View BibTeX Reference - Ctrl+B") );
    }

    if( m_viewingabout )
    {
        viewAboutB->setPixmap( QPixmap::fromMimeSource( APP_ICON_ABOUTBBACK ) );
        if( m_viewingbib )
            QToolTip::add
                ( viewAboutB, tr("Back to View BibTeX Reference - Ctrl+A") );
        else
            QToolTip::add
                ( viewAboutB, tr("Back to cb2Bib clipboard area - Ctrl+A") );
    }
    else
    {
        viewAboutB->setPixmap( QPixmap::fromMimeSource( APP_ICON_ABOUTB ) );
        QToolTip::add
            ( viewAboutB, tr("viewAbout cb2bib and cb2bib Bookmarks - Ctrl+A") );
    }
}

void cb2Bib::setButtonIcons()
{
    // Workaround to get some nicer deactivated button icons
    configureB->iconSet()->setPixmap( QPixmap::fromMimeSource( APP_ICON_CONFIGUREB ),
                                      QIconSet::Small );
    configureB->iconSet()->setPixmap( QPixmap::fromMimeSource( "d_" + APP_ICON_CONFIGUREB ),
                                      QIconSet::Small, QIconSet::Disabled );
    PDFImportB->iconSet()->setPixmap( QPixmap::fromMimeSource( APP_ICON_PDFIMPORTB ),
                                      QIconSet::Small );
    PDFImportB->iconSet()->setPixmap( QPixmap::fromMimeSource( "d_" + APP_ICON_PDFIMPORTB ),
                                      QIconSet::Small, QIconSet::Disabled );
    exitB->iconSet()->setPixmap( QPixmap::fromMimeSource( APP_ICON_EXITB ),
                                 QIconSet::Small );
    makeNetworkQuery->iconSet()->setPixmap( QPixmap::fromMimeSource( APP_ICON_NETQUERY ),
                                            QIconSet::Small );
    makeNetworkQuery->iconSet()->setPixmap( QPixmap::fromMimeSource( "d_" + APP_ICON_NETQUERY ),
                                            QIconSet::Small, QIconSet::Disabled );
    BibTeXEditorB->iconSet()->setPixmap( QPixmap::fromMimeSource( APP_ICON_BIBEDITORB ),
                                         QIconSet::Small );
    BibTeXEditorB->iconSet()->setPixmap( QPixmap::fromMimeSource( "d_" + APP_ICON_BIBEDITORB ),
                                         QIconSet::Small, QIconSet::Disabled );
    addBibB->iconSet()->setPixmap( QPixmap::fromMimeSource( APP_ICON_ADDBIBB ),
                                   QIconSet::Small );
    addBibB->iconSet()->setPixmap( QPixmap::fromMimeSource( "d_" + APP_ICON_ADDBIBB ),
                                   QIconSet::Small, QIconSet::Disabled );

    //  viewAboutB, connectB and viewBibB have no iconSet
    // (for better pixmap switching, this changes size on some styles)
    viewAboutB->setBaseSize( exitB->sizeHint() );
    viewAboutB->setFixedSize( exitB->sizeHint() );
    connectB->setBaseSize( exitB->sizeHint() );
    connectB->setFixedSize( exitB->sizeHint() );
    viewBibB->setBaseSize( exitB->sizeHint() );
    viewBibB->setFixedSize( exitB->sizeHint() );
}

void cb2Bib::setMessage( const QString& ms )
{
    statusBar()->message( encodeLink( ms ), MESSAGE_TIME );
}

void cb2Bib::settings()
{
    cb2BibConf* con = new cb2BibConf( this );
    connect( con, SIGNAL(helpRequested(const QString&)),this,
             SLOT(displayHelp(const QString&)));
    if ( con->exec() == QDialog::Accepted )
    {
        s->readSettings();
        cbS->reloadColors();
        clipb->setFont( s->m_font );
        bibS->reloadColors();
        htmlbrowser->setFont( s->m_font );
        emit newSettingAvailable();
    }
    else
        statusBar()->message( tr("Cancelled."), MESSAGE_TIME );
    delete con;
}


/****************************************************************************
 
  CB2BIB FUNCTIONALITY
 
*****************************************************************************/

void cb2Bib::preParseClipboard()
{
    QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) );
    bp->preParseItem( raw_input_data );
}

void cb2Bib::preParserEnded( const QString& text )
{
    if ( !text.isEmpty() )
    {
        c2bInit();
        bp->processItem( text );    // Field Initialization & Auto Detecttion
        processingEnded();
    }
    QApplication::restoreOverrideCursor();
}

void cb2Bib::restartEngine()
{
    QString text = clipb->text();
    if ( !text.isEmpty() )
    {
        c2bInit();
        bp->processItem( text );        // Field Initialization & Auto Detecttion
        processingEnded();
    }
}

void cb2Bib::guessFields()
{
    QString text = clipb->text();
    if ( !text.isEmpty() )
    {
        c2bInit();                      // Field Initialization
        bp->guessItem( text );
        processingEnded();
    }
}

void cb2Bib::dataChanged( const QString& text )
{
    if ( !clipb->hasSelectedText() )
    {
        if ( !text.isEmpty() )
        {
            raw_input_data = text.stripWhiteSpace();
            if ( s->m_preparser_automatic )
                bp->preParseItem( text );
            else
            {
                c2bInit();
                bp->processItem( text );    // Field Initialization & Auto Detecttion
                processingEnded();
            }
        }
    }
}

void cb2Bib::c2bInit()
{
    setCaption( tr( "(none) - cb2Bib" ) );
    bp->clearFields();
    m_dropped_article_file = "";
    QToolTip::remove
        ( pdf );
    disconnect( id, SIGNAL(textChanged(const QString&)), this, SLOT(setArticleFileName()) );
    m_modified = FALSE;
    addBibB->setEnabled( m_modified );
}

void cb2Bib::deleteTmpBib()
{
    QFile BibFile( bibfile->text() );
    switch( QMessageBox::information( this, "cb2Bib Info", tr("Delete temporary BibTeX file %1 ?\n" ).
                                      arg( bibfile->text() ), "&Delete", "Cancel", 0, 2 ) )
    {
    case 0:
        if ( BibFile.remove() )
            statusBar()->message( tr("File %1 deleted.").arg( bibfile->text() ), MESSAGE_TIME );
        else
            QMessageBox::warning( this, tr("cb2Bib Info"), tr("Unable to delete file %1.\n\nError: '%2'\n" ).
                                  arg( bibfile->text() ).arg(BibFile.errorString() ), tr( "Continue" ) );
        break;
    case 1: // Cancel
        break;
    }
}

void cb2Bib::RegExpEditor()
{
    //  Extracting Reference Type
    QString reft = typecombo->currentText();

    //  Extracting Field Order
    QString order = clipb->text();
    QRegExp rx( "<<("+bp->fieldl.join("|")+")>>" );
    QStringList list;
    int pos = 0;
    while ( pos >= 0 )
    {
        pos = rx.search( order, pos );
        if ( pos > -1 )
        {
            list += rx.cap( 1 );
            pos  += rx.matchedLength();
            c2bDebug(rx.cap(1));
        }
    }
    order = list.join( " " );
    c2bDebug(order);

    //  Parsing Regular Expression
    QString str = "^" + QRegExp::escape( clipb->text() ) +"$";

    str.replace( QRegExp( "<<abstract>>" ), "(.+)" );
    str.replace( QRegExp( "<<address>>" ), "(.+)" );
    str.replace( QRegExp( "<<annote>>" ), "(.+)" );
    str.replace( QRegExp( "<AnyPattern>" ), ".+" );
    str.replace( QRegExp( "<<author>>" ), "(.+)" );
    str.replace( QRegExp( "<<booktitle>>" ), "(.+)" );
    str.replace( QRegExp( "<<chapter>>" ), "(\\d+)" );
    str.replace( QRegExp( "<<doi>>" ), "(10.[\\d\\.]+/\\S+)" );
    str.replace( QRegExp( "<<edition>>" ), "(.+)" );
    str.replace( QRegExp( "<<editor>>" ), "(.+)" );
    str.replace( QRegExp( "<<eprint>>" ), "(.+)" );
    str.replace( QRegExp( "<<file>>" ), "(\\S+)" );
    str.replace( QRegExp( "<<institution>>" ), "(.+)" );
    str.replace( QRegExp( "<<isbn>>" ), "(.+)" );
    str.replace( QRegExp( "<<issn>>" ), "(.+)" );
    str.replace( QRegExp( "<<journal>>" ), "(.+)" );
    str.replace( QRegExp( "<<keywords>>" ), "(.+)" );
    str.replace( QRegExp( "<<month>>" ), "(.+)" );
    str.replace( QRegExp( "<<note>>" ), "(.+)" );
    str.replace( QRegExp( "<<number>>" ), "(\\d+)" );
    str.replace( QRegExp( "<<organization>>" ), "(.+)" );
    str.replace( QRegExp( "<<pages>>" ), "([\\d|\\-|\\s]+)" );
    str.replace( QRegExp( "<<publisher>>" ), "(.+)" );
    str.replace( QRegExp( "<<school>>" ), "(.+)" );
    str.replace( QRegExp( "<<series>>" ), "(.+)" );
    str.replace( QRegExp( "<<title>>" ), "(.+)" );
    str.replace( QRegExp( "<<url>>" ), "(\\S+)" );
    str.replace( QRegExp( "<<volume>>" ), "(\\d+)" );
    str.replace( QRegExp( "<<year>>" ), "(\\d\\d\\d\\d)" );
    c2bDebug(str);

    //  User Editting
    str = reft + "\n" + order + "\n" + str;
    SaveRegExp* Sdiag = new SaveRegExp( str, this );
    connect( Sdiag, SIGNAL(savePatternInfo(const QString&, const QString&)),
             this, SLOT(savePattern(const QString&, const QString&)) );
    connect( Sdiag, SIGNAL(helpRequested(const QString&)), this, SLOT(displayHelp(const QString&)) );
    if ( Sdiag->exec() != QDialog::Accepted )
        statusBar()->message( tr("Cancelled."), MESSAGE_TIME );
}

void cb2Bib::savePattern( const QString& rx, const QString& rxname )
{
    QFile file( s->m_regexpfl );
    bool fopen;
    if ( file.exists() )
        fopen = file.open( IO_WriteOnly | IO_Append );
    else
        fopen = file.open( IO_WriteOnly );

    if ( fopen )
    {
        QTextStream stream( &file );
        stream << ("# cb2Bib " + APP_VERSION + "  Pattern:") << endl
        << rxname << endl << rx << endl << endl;
        file.close();
        statusBar()->message( tr("Pattern '%1' added to %2.").arg(rxname).arg(s->m_regexpfl), MESSAGE_TIME );
    }
    else
        QMessageBox::warning( this, tr("cb2Bib Info"),
                              tr("Unable to open file %1 for writing.\nError: '%2'\n" ).
                              arg(s->m_regexpfl).arg(file.errorString() ), tr( "&Continue" ) );
    c2bDebug("signal:");
    c2bDebug(rx);
    c2bDebug(rxname);
}

void cb2Bib::setArticleFileName()
{
    disconnect( id, SIGNAL(textChanged(const QString&)), this, SLOT(setArticleFileName()) );
    if( m_dropped_article_file.isEmpty() )
        return;
    if( !s->m_movepdf )
    {
        pdf->setText( bp->PProc( "pdf", m_dropped_article_file ) );
        return;
    }
    QString fileName = id->text();
    if( fileName.isEmpty() )
        fileName = "no_cite_id";
    QChar md_sep = QDir::separator();
    QString pdfdir = s->m_pdfdir;
    QFileInfo fi( m_dropped_article_file );
    QString pdfExtension = "." + fi.extension().lower();

    // Possible article file extensions
    if ( pdfExtension != ".djvu" &&
            pdfExtension != ".dvi" &&
            pdfExtension != ".ps" &&
            pdfExtension != ".ps.gz" &&
            pdfExtension != ".tex" &&
            pdfExtension != ".txt" )
        pdfExtension = ".pdf";  // Default

    fileName = pdfdir + md_sep + fileName + pdfExtension;
    pdf->setText( bp->PProc( "pdf", fileName ) );
    connect( id, SIGNAL(textChanged(const QString&)), this, SLOT(setArticleFileName()) );
}

void cb2Bib::prepareAddToFile()
{
    addBibB->setEnabled( FALSE );
    if( m_dropped_article_file.isEmpty() || pdf->text().isEmpty() || !s->m_movepdf )
        addToFile( TRUE );
    else
        net->getFile( m_dropped_article_file, pdf->text(), s->m_pdf_copymove, this, SLOT(addToFile(bool)) );
}

void cb2Bib::addToFile( bool ready )
{
    if( !ready )
    {
        QMessageBox::information( this, tr("cb2Bib Info"), tr("Not ready to add reference.\n%2\n" ).
                                  arg( net->getErrorString() ), tr( "&Continue" ) );
        addBibB->setEnabled( m_modified );
        return;
    }
    QFile file( bibfile->text() );
    bool fopen;
    if ( file.exists() )
        fopen = file.open( IO_WriteOnly | IO_Append );
    else
        fopen = file.open( IO_WriteOnly );

    if ( fopen )
    {
        QTextStream stream( &file );
        stream << bp->makeBib();
        file.close();
        m_modified = FALSE;
        addBibB->setEnabled( m_modified );
        emit addedBibtoFile( bibfile->text() );
        statusBar()->message( tr("Bib Item %1 added to %2.").arg(id->text()).arg(bibfile->text()), MESSAGE_TIME );
    }
    else
        QMessageBox::information( this, tr("cb2Bib Info"), tr("Unable to open file %1 for writing.\nError: '%2'\n" ).
                                  arg( bibfile->text() ).arg(file.errorString() ), tr( "&Continue" ) );
}

void cb2Bib::postProcessBibTeX()
{
    c2bPostProcess* ppBib = new c2bPostProcess( bibfile->text(), this );
    statusBar()->message( tr("BibTeX Postprocessing launched."), MESSAGE_TIME );
    connect( ppBib, SIGNAL(helpRequested(const QString&)),this, SLOT(displayHelp(const QString&)));
    connect( ppBib, SIGNAL(openFileRequested(const QString&)),this, SLOT(displayHelp(const QString&)));
    if ( ppBib->exec() != QDialog::Accepted )
        statusBar()->message( tr("BibTeX Postprocessing exited."), MESSAGE_TIME );
}

void cb2Bib::REFileEditor()
{
    refe = new c2bEditor( "RegExp", this );
    connect( refe, SIGNAL( aboutToQuit() ), this, SLOT( REFileEditorEnds() ) );
    connect( refe, SIGNAL( restartEngine() ), this, SLOT( restartEngine() ) );
    connect( refe, SIGNAL(helpRequested(const QString&)), this, SLOT(displayHelp(const QString&)));
    connect( this, SIGNAL(newSettingAvailable()), refe, SLOT(newSetting()));
    editREFile->setEnabled( FALSE );
    refe->show();
    statusBar()->message( tr("RegExp File Editor launched."), MESSAGE_TIME );
}

void cb2Bib::REFileEditorEnds()
{
    editREFile->setEnabled( TRUE );
    statusBar()->message( tr("RegExp File Editor exited."), MESSAGE_TIME );
}

void cb2Bib::bookmarkEditor()
{
    booke = new c2bEditor( "NetQInfo", this );
    connect( booke, SIGNAL( aboutToQuit() ), this, SLOT( bookmarkEditorEnds() ) );
    connect( booke, SIGNAL( restartQuery() ), this, SLOT( makeNetQuery() ) );
    connect( booke, SIGNAL(helpRequested(const QString&)), this, SLOT(displayHelp(const QString&)));
    connect( this, SIGNAL(newSettingAvailable()), booke, SLOT(newSetting()));
    editBookmark->setEnabled( FALSE );
    booke->show();
    statusBar()->message( tr("Bookmark File Editor launched."), MESSAGE_TIME );
}

void cb2Bib::bookmarkEditorEnds()
{
    editBookmark->setEnabled( TRUE );
    statusBar()->message( tr("Bookmark File Editor exited."), MESSAGE_TIME );
}

void cb2Bib::initBibTeXEditor()
{
    if( s->m_bibfile_list.count() > 1 )
        s->m_autostart_bibedit = FALSE; // To avoid exiting when multiple BibTeXEditors
    for( uint i = 0; i < s->m_bibfile_list.count(); i++ )
    {
        bibe = new c2bEditor( s->m_bibfile_list[i], "BibTeX", bp, this );
        connect( bibe, SIGNAL(aboutToQuit()), this, SLOT(BibTeXEditorEnds()) );
        connect( bibe, SIGNAL(helpRequested(const QString&)), this, SLOT(displayHelp(const QString&)));
        connect( this, SIGNAL(newSettingAvailable()), bibe, SLOT(newSetting()));
        bibe->show();
    }
    statusBar()->message( tr("BibTeX File Editor launched."), MESSAGE_TIME );
}

void cb2Bib::BibTeXEditor()
{
    QWidgetList* list = QApplication::topLevelWidgets();
    QWidgetListIt it(*list);
    QWidget* w;
    QString toBeEdited = bibfile->text();
    bool isBeingEdited = FALSE;
    while (( w = it.current() ))
    {
        QString wCName = w->className();
        if( wCName == "c2bEditor" )
        {
            c2bEditor* ew = (c2bEditor*)w;
            if( toBeEdited == ew->editFileName() )
            {
                isBeingEdited = TRUE;
                if ( ew->isMinimized() )
                    ew->showNormal();
                ew->raise();
                ew->setActiveWindow();
            }
        }
        ++it;
    }
    delete list;
    if( !isBeingEdited )
    {
        bibe = new c2bEditor( toBeEdited, "BibTeX", bp, this );
        connect( bibe, SIGNAL( aboutToQuit() ), this, SLOT( BibTeXEditorEnds() ) );
        connect( bibe, SIGNAL(helpRequested(const QString&)), this, SLOT(displayHelp(const QString&)));
        connect( this, SIGNAL(newSettingAvailable()), bibe, SLOT(newSetting()));
        bibe->show();
        s->m_autostart_bibedit = FALSE; // To avoid exiting when multiple BibTeXEditors
        statusBar()->message( tr("BibTeX File Editor launched."), MESSAGE_TIME );
    }
}

void cb2Bib::BibTeXEditorEnds()
{
    statusBar()->message( tr("BibTeX File Editor exited."), MESSAGE_TIME );
    if ( isMinimized() )
        if ( s->m_autostart_bibedit )
            close();
        else
            showNormal();
}

void cb2Bib::bibModified()
{
    m_modified = TRUE;
    addBibB->setEnabled( m_modified );
}


/****************************************************************************
 
  MANUAL BIB CAPTION
 
*****************************************************************************/

void cb2Bib::clipbRC()
{
    if ( clipb->hasSelectedText() )
        pmenu->exec( QCursor::pos() );
}

void cb2Bib::readField( int i )
{
    QString field = bp->fieldlm[i];
    bp->RefFields[ field ]->setText( bp->PProc( field, clipb->selectedText()) );
    clipb->insert( "<<" + field + ">>" );
}

void cb2Bib::addAuthors()
{
    authors->setText( bp->PProc( "addauthors", clipb->selectedText()) );
    clipb->insert( "<<author>>" );
    statusBar()->message( QString("Info: Creating a pattern with multiple author sets."), MESSAGE_TIME );
}

void cb2Bib::addEditor()
{
    editor->setText( bp->PProc( "addeditor", clipb->selectedText()) );
    clipb->insert( "<<editor>>" );
    statusBar()->message( QString("Info: Creating a pattern with multiple editor sets."), MESSAGE_TIME );
}

void cb2Bib::anyPattern()
{
    clipb->insert( "<AnyPattern>" );
}

void cb2Bib::setManualMenu()
{
    pmenu = new QPopupMenu( clipb );
    Q_CHECK_PTR( pmenu );
    int idm = 0;
    pmenu->insertItem( "Title", this, SLOT( readField( int ) ), 0, idm++ );
    pmenu->insertItem( "Authors", this, SLOT( readField( int ) ), 0, idm++ );
    pmenu->insertItem( QPixmap::fromMimeSource( "add.png" ), "Add Authors", this,SLOT( addAuthors() ));
    pmenu->insertItem( "Journal", this,SLOT( readField( int ) ), 0, idm++ );
    pmenu->insertSeparator();
    pmenu->insertItem( "Pages", this,SLOT( readField( int ) ), 0, idm++ );
    pmenu->insertItem( "Volume", this,SLOT( readField( int ) ), 0, idm++ );
    pmenu->insertItem( "Number", this,SLOT( readField( int ) ), 0, idm++ );
    pmenu->insertItem( "Year", this,SLOT( readField( int ) ), 0, idm++ );
    pmenu->insertSeparator();
    pmenu->insertItem( "Abstract", this,SLOT( readField( int ) ), 0, idm++ );
    pmenu->insertItem( "Keywords", this,SLOT( readField( int ) ), 0, idm++ );
    pmenu->insertItem( "File", this,SLOT( readField( int ) ), 0, idm++ );
    pmenu->insertSeparator();
    pmenu->insertItem( "Any Pattern", this,SLOT( anyPattern() ));
    pmenu->insertSeparator();
    pomenu = new QPopupMenu( clipb );
    Q_CHECK_PTR( pomenu );
    pomenu->insertItem( "Address", this,SLOT( readField( int ) ), 0, idm++ );
    pomenu->insertItem( "Annote", this,SLOT( readField( int ) ), 0, idm++ );
    pomenu->insertItem( "Booktitle", this,SLOT( readField( int ) ), 0, idm++ );
    pomenu->insertItem( "Chapter", this,SLOT( readField( int ) ), 0, idm++ );
    pomenu->insertItem( "DOI", this,SLOT( readField( int ) ), 0, idm++ );
    pomenu->insertItem( "Edition", this,SLOT( readField( int ) ), 0, idm++ );
    pomenu->insertItem( "Editor", this,SLOT( readField( int ) ), 0, idm++ );
    pomenu->insertItem( QPixmap::fromMimeSource( "add.png" ), "Add Editor", this,SLOT( addEditor() ));
    pomenu->insertItem( "Eprint", this,SLOT( readField( int ) ), 0, idm++ );
    pomenu->insertItem( "Institution", this,SLOT( readField( int ) ), 0, idm++ );
    pomenu->insertItem( "ISBN", this,SLOT( readField( int ) ), 0, idm++ );
    pomenu->insertItem( "ISSN", this,SLOT( readField( int ) ), 0, idm++ );
    pomenu->insertItem( "Month", this,SLOT( readField( int ) ), 0, idm++ );
    pomenu->insertItem( "Note", this,SLOT( readField( int ) ), 0, idm++ );
    pomenu->insertItem( "Organization", this,SLOT( readField( int ) ), 0, idm++ );
    pomenu->insertItem( "Publisher", this,SLOT( readField( int ) ), 0, idm++ );
    pomenu->insertItem( "School", this,SLOT( readField( int ) ), 0, idm++ );
    pomenu->insertItem( "Series", this,SLOT( readField( int ) ), 0, idm++ );
    pomenu->insertItem( "URL", this,SLOT( readField( int ) ), 0, idm++ );
    pmenu->insertItem( "Other fields...", pomenu );

    connect( clipb, SIGNAL( selectionChanged() ), this, SLOT( clipbRC() ) );
}


/****************************************************************************
 
  NETWORK FUNCTIONALITY
 
*****************************************************************************/

void cb2Bib::makeNetQuery()
{
    if ( !makeNetworkQuery->isEnabled() )
    {
        statusBar()->message( tr("Currently processing previous query. Resubmit later."), MESSAGE_TIME );
        return;
    }
    QString Qjournal = bp->fullJournal( bp->RefFields[ "journal" ]->text() );
    QString Qvolume = bp->RefFields[ "volume" ]->text();
    QString Qfpage = bp->RefFields[ "pages" ]->text();
    Qfpage = firstPage( Qfpage );
    if ( Qjournal.isEmpty() || Qvolume.isEmpty() || Qfpage.isEmpty() )
    {
        statusBar()->message( tr("Journal, Volume and first Page are all required for Queries."), MESSAGE_TIME );
        return;
    }
    makeNetworkQuery->setEnabled( FALSE );
    QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) );
    netQ->submitQ( Qjournal, Qvolume, Qfpage );
}

void cb2Bib::netQueryEnded( bool stat, const QString& pdffile, const QString& reference )
{
    if ( !stat )
        statusBar()->message( tr("Query submition error. %1").arg(netQ->errorString()), MESSAGE_TIME );
    else if ( pdffile.isEmpty() && reference.isEmpty() )
        statusBar()->message( tr("Query submitted. %1").arg(netQ->errorString()), MESSAGE_TIME );
    else
    {
        QString previous_article_file = m_dropped_article_file;  // Keep dropped file in case this is m_auto_regc
        dataChanged( reference );
        if( bp->m_auto_regc && !pdffile.isEmpty() )
            fileDropped( pdffile );
        else if( bp->m_auto_regc )
            fileDropped( previous_article_file );
        statusBar()->message( bp->c2bAutoRecogStr, MESSAGE_TIME );
    }
    QApplication::restoreOverrideCursor();
    makeNetworkQuery->setEnabled( TRUE );
}

void cb2Bib::processingEnded()
{
    if ( bp->m_auto_regc && s->m_autonetquery && makeNetworkQuery->isEnabled() )
    {
        bp->c2bAutoRecogStr = tr("Starting network query, using '%1'").arg(bp->c2bAutoRecogStr);
        makeNetQuery();
    }
}

QString cb2Bib::encodeLink( const QString& ln )
{
    QString eln = ln;
    QRegExp rx = QRegExp( "<<.+>>" );
    if ( eln.contains( rx ) )
    {
        for ( QStringList::Iterator it = bp->fieldl.begin(); it != bp->fieldl.end(); ++it )
        {
            QString tag = QString("<<%1>>").arg(*it);
            if ( eln.contains( tag ) )
            {
                QString fld;
                if ( *it == "pages" )
                    fld = bp->RefFields[*it]->text().replace(QRegExp("-.+$"), "");
                else
                    fld = bp->RefFields[*it]->text();
                QUrl::encode( fld );
                eln.replace( tag, fld );
                if ( !eln.contains( rx ) )
                    return eln;
            }
        }
    }
    return eln;
}

void cb2Bib::linkClicked( const QString& ln )
{
    net->openFile( encodeLink( ln ) );
}

void cb2Bib::displayHelp( const QString& ln )
{
    net->openFile( ln );
}
