1 /*
2 For general Scribus (>=1.3.2) copyright and licensing information please refer
3 to the COPYING file provided with the program. Following this notice may exist
4 a copyright and/or license notice that predates the release of Scribus 1.3.2
5 for which a new license (GPL+exception) is in place.
6 */
7 /* This is the Scribus Short Words plugin main mechanism.
8 
9 This code is based on the Scribus-Vlna plug in rewritten for
10 international use.
11 
12 2004 Petr Vanek <petr@yarpen.cz>
13 with contributors.
14 
15 This program is free software - see LICENSE file in the distribution
16 or documentation
17 */
18 
19 #include <QProgressBar>
20 #include <QRegExp>
21 
22 #include "parse.h"
23 
24 #include "configuration.h"
25 #include "langmgr.h"
26 #include "pageitem.h"
27 #include "scpage.h"
28 #include "scribus.h"
29 #include "scribusdoc.h"
30 #include "scribusview.h"
31 #include "selection.h"
32 #include "shortwords.h"
33 #include "version.h"
34 
35 
SWParse()36 SWParse::SWParse()
37 {
38 	modify = 0;
39 }
40 
parseItem(PageItem * aFrame)41 void SWParse::parseItem(PageItem *aFrame)
42 {
43 	// the content of the frame - text itself
44 	QString content;
45 	int changes = 0;
46 	// list of the short words
47 	QStringList shorts;
48 	// text with special space
49 	QString unbreak;
50 	// the regexp
51 	QRegExp rx(" ");
52 	// cfg
53 	SWConfig *cfg = new SWConfig();
54 
55 	// just textframes processed
56 	if (!aFrame->isTextFrame())
57 		return;
58 
59 	// an ugly hack to get the language code from the item language property
60 	if (lang.isEmpty())
61 	{
62 		lang = aFrame->itemText.charStyle(0).language();
63 		if (lang.isEmpty())
64 			qDebug("SWParse::parseItem - variable lang is still empty. No changes are made.");
65 	}
66 
67 	// apply spaces after shorts
68 	shorts = cfg->getShortWords(lang);
69 	if (shorts.count()==0)
70 		return; // no changes
71 
72 	// get text from frame
73 	int i;
74 	for (i=0; i < aFrame->itemText.length() && ! aFrame->frameDisplays(i); ++i)
75 		;
76 	for (; i < aFrame->itemText.length() && aFrame->frameDisplays(i); ++i)
77 		content += aFrame->itemText.text(i,1);
78 	changes = content.count(SpecialChars::NBSPACE);
79 
80 	// for every config string, replace its spaces by nbsp's.
81 	for (QStringList::Iterator it = shorts.begin(); it != shorts.end(); ++it)
82 	{
83 		unbreak = (*it);
84 		// replace ' ' from cfg with '~' in the replacement string
85 		unbreak = unbreak.replace(SPACE, SpecialChars::NBSPACE);
86 		/*
87 		Regexp used to find the config string (*it) in content.
88 		Cheat sheet:
89 		- \b is a "word boundary"; it matches at a *position*
90 		not a *character*
91 		- \W is a "non-word character"; it matches every character
92 		that is neither a letter, nor a number, nor '_';
93 		for example, it matches all kind of whitespace
94 		(including carriage return) and punctuation
95 		Example occurrences when (*it) == "Mr ":
96 			- "Mr Bla etc." : there's one of the word boundaries
97 			of the word "Mr" before the pattern, and one of the
98 			word boundaries of the word "Bla" after.
99 		Example occurrences when (*it) == " !":
100 			- "ugly hack ! No." : there's a word boundary before,
101 			and a whitespace is matched by \W after.
102 			- "» !" : '«' is matched by \W before, newline is
103 			matched by \W after.
104 		*/
105 		rx.setPattern("(\\b|\\W)" + rx.escape(*it) + "(\\b|\\W)");
106 		/*
107 		QString::replace works on the whole string in one pass.
108 		On every occurrence of our regexp, \1 and \2 are replaced
109 		by what has been matched (captured characters) in,
110 		respectively, the first and second capturing parentheses.
111 		*/
112 		content.replace(rx, "\\1" + unbreak + "\\2");
113 	}
114 	// return text into frame
115 	for (i=0; i < aFrame->itemText.length() && ! aFrame->frameDisplays(i); ++i)
116 		;
117 	for (; i < aFrame->itemText.length() && aFrame->frameDisplays(i); ++i)
118 		aFrame->itemText.replaceChar(i, content.at(i));
119 	if (content.count(SpecialChars::NBSPACE) > changes)
120 		++modify;
121 
122 	delete(cfg);
123 } // end of method
124 
parseSelection(ScribusDoc * doc)125 void SWParse::parseSelection(ScribusDoc* doc)
126 {
127 	uint docSelectionCount = doc->m_Selection->count();
128 	if (docSelectionCount == 0)
129 		return;
130 	doc->scMW()->mainWindowProgressBar->setMaximum(docSelectionCount);
131 	for (uint i=0; i < docSelectionCount; ++i)
132 	{
133 		doc->scMW()->mainWindowProgressBar->setValue(i);
134 		parseItem(doc->m_Selection->itemAt(i));
135 	} // for items
136 	doc->scMW()->mainWindowProgressBar->setValue(docSelectionCount);
137 }
138 
139 
parsePage(ScribusDoc * doc)140 void SWParse::parsePage(ScribusDoc* doc)
141 {
142 	parsePage(doc, doc->currentPageNumber());
143 }
144 
parsePage(ScribusDoc * doc,int page)145 void SWParse::parsePage(ScribusDoc* doc, int page)
146 {
147 	uint count = 0;
148 	uint docItemsCount=doc->Items->count();
149 	if (docItemsCount == 0)
150 		return;
151 
152 	for (uint i = 0; i < docItemsCount; ++i)
153 	{
154 		PageItem* pi = doc->Items->at(i);
155 		if (pi->OwnPage == page)
156 			++count;
157 	}
158 	doc->scMW()->mainWindowProgressBar->setMaximum(count);
159 	doc->view()->GotoPage(page);
160 	uint j = 0;
161 	for (uint i = 0; i < docItemsCount; ++i)
162 	{
163 		PageItem* pi = doc->Items->at(i);
164 		if (pi->OwnPage == page)
165 		{
166 			doc->scMW()->mainWindowProgressBar->setValue(++j);
167 			parseItem(pi);
168 		}
169 	}
170 	doc->scMW()->mainWindowProgressBar->setValue(count);
171 }
172 
parseAll(ScribusDoc * doc)173 void SWParse::parseAll(ScribusDoc* doc)
174 {
175 	for (int i=0; i < doc->Pages->count(); ++i)
176 		parsePage(doc, i);
177 }
178