1 | /****************************************************************************
|
---|
2 | **
|
---|
3 | ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
---|
4 | ** All rights reserved.
|
---|
5 | ** Contact: Nokia Corporation ([email protected])
|
---|
6 | **
|
---|
7 | ** This file is part of the QtGui module of the Qt Toolkit.
|
---|
8 | **
|
---|
9 | ** $QT_BEGIN_LICENSE:LGPL$
|
---|
10 | ** Commercial Usage
|
---|
11 | ** Licensees holding valid Qt Commercial licenses may use this file in
|
---|
12 | ** accordance with the Qt Commercial License Agreement provided with the
|
---|
13 | ** Software or, alternatively, in accordance with the terms contained in
|
---|
14 | ** a written agreement between you and Nokia.
|
---|
15 | **
|
---|
16 | ** GNU Lesser General Public License Usage
|
---|
17 | ** Alternatively, this file may be used under the terms of the GNU Lesser
|
---|
18 | ** General Public License version 2.1 as published by the Free Software
|
---|
19 | ** Foundation and appearing in the file LICENSE.LGPL included in the
|
---|
20 | ** packaging of this file. Please review the following information to
|
---|
21 | ** ensure the GNU Lesser General Public License version 2.1 requirements
|
---|
22 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
---|
23 | **
|
---|
24 | ** In addition, as a special exception, Nokia gives you certain additional
|
---|
25 | ** rights. These rights are described in the Nokia Qt LGPL Exception
|
---|
26 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
---|
27 | **
|
---|
28 | ** GNU General Public License Usage
|
---|
29 | ** Alternatively, this file may be used under the terms of the GNU
|
---|
30 | ** General Public License version 3.0 as published by the Free Software
|
---|
31 | ** Foundation and appearing in the file LICENSE.GPL included in the
|
---|
32 | ** packaging of this file. Please review the following information to
|
---|
33 | ** ensure the GNU General Public License version 3.0 requirements will be
|
---|
34 | ** met: http://www.gnu.org/copyleft/gpl.html.
|
---|
35 | **
|
---|
36 | ** If you have questions regarding the use of this file, please contact
|
---|
37 | ** Nokia at [email protected].
|
---|
38 | ** $QT_END_LICENSE$
|
---|
39 | **
|
---|
40 | ****************************************************************************/
|
---|
41 | #include <qdebug.h>
|
---|
42 | #include "qcups_p.h"
|
---|
43 |
|
---|
44 | #ifndef QT_NO_CUPS
|
---|
45 |
|
---|
46 | #ifndef QT_LINUXBASE // LSB merges everything into cups.h
|
---|
47 | # include <cups/language.h>
|
---|
48 | #endif
|
---|
49 | #include <qtextcodec.h>
|
---|
50 |
|
---|
51 | QT_BEGIN_NAMESPACE
|
---|
52 |
|
---|
53 | typedef int (*CupsGetDests)(cups_dest_t **dests);
|
---|
54 | typedef void (*CupsFreeDests)(int num_dests, cups_dest_t *dests);
|
---|
55 | typedef const char* (*CupsGetPPD)(const char *printer);
|
---|
56 | typedef int (*CupsMarkOptions)(ppd_file_t *ppd, int num_options, cups_option_t *options);
|
---|
57 | typedef ppd_file_t* (*PPDOpenFile)(const char *filename);
|
---|
58 | typedef void (*PPDMarkDefaults)(ppd_file_t *ppd);
|
---|
59 | typedef int (*PPDMarkOption)(ppd_file_t *ppd, const char *keyword, const char *option);
|
---|
60 | typedef void (*PPDClose)(ppd_file_t *ppd);
|
---|
61 | typedef int (*PPDMarkOption)(ppd_file_t *ppd, const char *keyword, const char *option);
|
---|
62 | typedef void (*CupsFreeOptions)(int num_options, cups_option_t *options);
|
---|
63 | typedef void (*CupsSetDests)(int num_dests, cups_dest_t *dests);
|
---|
64 | typedef cups_lang_t* (*CupsLangGet)(const char *language);
|
---|
65 | typedef const char* (*CupsLangEncoding)(cups_lang_t *language);
|
---|
66 | typedef int (*CupsAddOption)(const char *name, const char *value, int num_options, cups_option_t **options);
|
---|
67 | typedef int (*CupsTempFd)(char *name, int len);
|
---|
68 | typedef int (*CupsPrintFile)(const char * name, const char * filename, const char * title, int num_options, cups_option_t * options);
|
---|
69 |
|
---|
70 | static bool cupsLoaded = false;
|
---|
71 | static int qt_cups_num_printers = 0;
|
---|
72 | static CupsGetDests _cupsGetDests = 0;
|
---|
73 | static CupsFreeDests _cupsFreeDests = 0;
|
---|
74 | static CupsGetPPD _cupsGetPPD = 0;
|
---|
75 | static PPDOpenFile _ppdOpenFile = 0;
|
---|
76 | static PPDMarkDefaults _ppdMarkDefaults = 0;
|
---|
77 | static PPDClose _ppdClose = 0;
|
---|
78 | static CupsMarkOptions _cupsMarkOptions = 0;
|
---|
79 | static PPDMarkOption _ppdMarkOption = 0;
|
---|
80 | static CupsFreeOptions _cupsFreeOptions = 0;
|
---|
81 | static CupsSetDests _cupsSetDests = 0;
|
---|
82 | static CupsLangGet _cupsLangGet = 0;
|
---|
83 | static CupsLangEncoding _cupsLangEncoding = 0;
|
---|
84 | static CupsAddOption _cupsAddOption = 0;
|
---|
85 | static CupsTempFd _cupsTempFd = 0;
|
---|
86 | static CupsPrintFile _cupsPrintFile = 0;
|
---|
87 |
|
---|
88 | #ifdef Q_OS_OS2
|
---|
89 | #define CUPS_RESOLVE_cups(func) _cups##func = (Cups##func) cupsLib.resolve("_cups"#func)
|
---|
90 | #define CUPS_RESOLVE_ppd(func) _ppd##func = (PPD##func) cupsLib.resolve("_ppd"#func)
|
---|
91 | #else
|
---|
92 | #define CUPS_RESOLVE_cups(func) _cups##func = (Cups##func) cupsLib.resolve("cups"#func)
|
---|
93 | #define CUPS_RESOLVE_ppd(func) _ppd##func = (PPD##func) cupsLib.resolve("ppd"#func)
|
---|
94 | #endif
|
---|
95 |
|
---|
96 | static void resolveCups()
|
---|
97 | {
|
---|
98 | QLibrary cupsLib(QLatin1String("cups"), 2);
|
---|
99 | if(cupsLib.load()) {
|
---|
100 | CUPS_RESOLVE_cups(GetDests);
|
---|
101 | CUPS_RESOLVE_cups(FreeDests);
|
---|
102 | CUPS_RESOLVE_cups(GetPPD);
|
---|
103 | CUPS_RESOLVE_cups(LangGet);
|
---|
104 | CUPS_RESOLVE_cups(LangEncoding);
|
---|
105 | CUPS_RESOLVE_ppd(OpenFile);
|
---|
106 | CUPS_RESOLVE_ppd(MarkDefaults);
|
---|
107 | CUPS_RESOLVE_ppd(Close);
|
---|
108 | CUPS_RESOLVE_cups(MarkOptions);
|
---|
109 | CUPS_RESOLVE_ppd(MarkOption);
|
---|
110 | CUPS_RESOLVE_cups(FreeOptions);
|
---|
111 | CUPS_RESOLVE_cups(SetDests);
|
---|
112 | CUPS_RESOLVE_cups(AddOption);
|
---|
113 | CUPS_RESOLVE_cups(TempFd);
|
---|
114 | CUPS_RESOLVE_cups(PrintFile);
|
---|
115 |
|
---|
116 | if (_cupsGetDests && _cupsFreeDests) {
|
---|
117 | cups_dest_t *printers;
|
---|
118 | int num_printers = _cupsGetDests(&printers);
|
---|
119 | if (num_printers)
|
---|
120 | _cupsFreeDests(num_printers, printers);
|
---|
121 | qt_cups_num_printers = num_printers;
|
---|
122 | }
|
---|
123 | }
|
---|
124 | cupsLoaded = true;
|
---|
125 | }
|
---|
126 |
|
---|
127 | // ================ CUPS Support class ========================
|
---|
128 |
|
---|
129 | QCUPSSupport::QCUPSSupport()
|
---|
130 | :
|
---|
131 | prnCount(0),
|
---|
132 | printers(0),
|
---|
133 | page_sizes(0),
|
---|
134 | currPrinterIndex(0),
|
---|
135 | currPPD(0)
|
---|
136 | {
|
---|
137 | if (!cupsLoaded)
|
---|
138 | resolveCups();
|
---|
139 |
|
---|
140 | // getting all available printers
|
---|
141 | if (!isAvailable())
|
---|
142 | return;
|
---|
143 |
|
---|
144 | prnCount = _cupsGetDests(&printers);
|
---|
145 |
|
---|
146 | for (int i = 0; i < prnCount; ++i) {
|
---|
147 | if (printers[i].is_default) {
|
---|
148 | currPrinterIndex = i;
|
---|
149 | setCurrentPrinter(i);
|
---|
150 | break;
|
---|
151 | }
|
---|
152 | }
|
---|
153 |
|
---|
154 | #ifndef QT_NO_TEXTCODEC
|
---|
155 | cups_lang_t *cupsLang = _cupsLangGet(0);
|
---|
156 | codec = QTextCodec::codecForName(_cupsLangEncoding(cupsLang));
|
---|
157 | if (!codec)
|
---|
158 | codec = QTextCodec::codecForLocale();
|
---|
159 | #endif
|
---|
160 | }
|
---|
161 |
|
---|
162 | QCUPSSupport::~QCUPSSupport()
|
---|
163 | {
|
---|
164 | if (currPPD)
|
---|
165 | _ppdClose(currPPD);
|
---|
166 | if (prnCount)
|
---|
167 | _cupsFreeDests(prnCount, printers);
|
---|
168 | }
|
---|
169 |
|
---|
170 | int QCUPSSupport::availablePrintersCount() const
|
---|
171 | {
|
---|
172 | return prnCount;
|
---|
173 | }
|
---|
174 |
|
---|
175 | const cups_dest_t* QCUPSSupport::availablePrinters() const
|
---|
176 | {
|
---|
177 | return printers;
|
---|
178 | }
|
---|
179 |
|
---|
180 | const ppd_file_t* QCUPSSupport::currentPPD() const
|
---|
181 | {
|
---|
182 | return currPPD;
|
---|
183 | }
|
---|
184 |
|
---|
185 | const ppd_file_t* QCUPSSupport::setCurrentPrinter(int index)
|
---|
186 | {
|
---|
187 | Q_ASSERT(index >= 0 && index <= prnCount);
|
---|
188 | if (index == prnCount)
|
---|
189 | return 0;
|
---|
190 |
|
---|
191 | currPrinterIndex = index;
|
---|
192 |
|
---|
193 | if (currPPD)
|
---|
194 | _ppdClose(currPPD);
|
---|
195 | currPPD = 0;
|
---|
196 | page_sizes = 0;
|
---|
197 |
|
---|
198 | const char *ppdFile = _cupsGetPPD(printers[index].name);
|
---|
199 |
|
---|
200 | if (!ppdFile)
|
---|
201 | return 0;
|
---|
202 |
|
---|
203 | currPPD = _ppdOpenFile(ppdFile);
|
---|
204 | unlink(ppdFile);
|
---|
205 |
|
---|
206 | // marking default options
|
---|
207 | _ppdMarkDefaults(currPPD);
|
---|
208 |
|
---|
209 | // marking options explicitly set
|
---|
210 | _cupsMarkOptions(currPPD, printers[currPrinterIndex].num_options, printers[currPrinterIndex].options);
|
---|
211 |
|
---|
212 | // getting pointer to page sizes
|
---|
213 | page_sizes = ppdOption("PageSize");
|
---|
214 |
|
---|
215 | return currPPD;
|
---|
216 | }
|
---|
217 |
|
---|
218 | int QCUPSSupport::currentPrinterIndex() const
|
---|
219 | {
|
---|
220 | return currPrinterIndex;
|
---|
221 | }
|
---|
222 |
|
---|
223 | bool QCUPSSupport::isAvailable()
|
---|
224 | {
|
---|
225 | if(!cupsLoaded)
|
---|
226 | resolveCups();
|
---|
227 |
|
---|
228 | return
|
---|
229 | _cupsGetDests &&
|
---|
230 | _cupsFreeDests &&
|
---|
231 | _cupsGetPPD &&
|
---|
232 | _ppdOpenFile &&
|
---|
233 | _ppdMarkDefaults &&
|
---|
234 | _ppdClose &&
|
---|
235 | _cupsMarkOptions &&
|
---|
236 | _ppdMarkOption &&
|
---|
237 | _cupsFreeOptions &&
|
---|
238 | _cupsSetDests &&
|
---|
239 | _cupsLangGet &&
|
---|
240 | _cupsLangEncoding &&
|
---|
241 | _cupsAddOption &&
|
---|
242 | (qt_cups_num_printers > 0);
|
---|
243 | }
|
---|
244 |
|
---|
245 | const ppd_option_t* QCUPSSupport::ppdOption(const char *key) const
|
---|
246 | {
|
---|
247 | if (currPPD) {
|
---|
248 | for (int gr = 0; gr < currPPD->num_groups; ++gr) {
|
---|
249 | for (int opt = 0; opt < currPPD->groups[gr].num_options; ++opt) {
|
---|
250 | if (qstrcmp(currPPD->groups[gr].options[opt].keyword, key) == 0)
|
---|
251 | return &currPPD->groups[gr].options[opt];
|
---|
252 | }
|
---|
253 | }
|
---|
254 | }
|
---|
255 | return 0;
|
---|
256 | }
|
---|
257 |
|
---|
258 | const cups_option_t* QCUPSSupport::printerOption(const QString &key) const
|
---|
259 | {
|
---|
260 | for (int i = 0; i < printers[currPrinterIndex].num_options; ++i) {
|
---|
261 | if (QLatin1String(printers[currPrinterIndex].options[i].name) == key)
|
---|
262 | return &printers[currPrinterIndex].options[i];
|
---|
263 | }
|
---|
264 | return 0;
|
---|
265 | }
|
---|
266 |
|
---|
267 | const ppd_option_t* QCUPSSupport::pageSizes() const
|
---|
268 | {
|
---|
269 | return page_sizes;
|
---|
270 | }
|
---|
271 |
|
---|
272 | int QCUPSSupport::markOption(const char* name, const char* value)
|
---|
273 | {
|
---|
274 | return _ppdMarkOption(currPPD, name, value);
|
---|
275 | }
|
---|
276 |
|
---|
277 | void QCUPSSupport::saveOptions(QList<const ppd_option_t*> options, QList<const char*> markedOptions)
|
---|
278 | {
|
---|
279 | int oldOptionCount = printers[currPrinterIndex].num_options;
|
---|
280 | cups_option_t* oldOptions = printers[currPrinterIndex].options;
|
---|
281 |
|
---|
282 | int newOptionCount = 0;
|
---|
283 | cups_option_t* newOptions = 0;
|
---|
284 |
|
---|
285 | // copying old options that are not on the new list
|
---|
286 | for (int i = 0; i < oldOptionCount; ++i) {
|
---|
287 | bool contains = false;
|
---|
288 | for (int j = 0; j < options.count(); ++j) {
|
---|
289 | if (qstrcmp(options.at(j)->keyword, oldOptions[i].name) == 0) {
|
---|
290 | contains = true;
|
---|
291 | break;
|
---|
292 | }
|
---|
293 | }
|
---|
294 |
|
---|
295 | if (!contains) {
|
---|
296 | newOptionCount = _cupsAddOption(oldOptions[i].name, oldOptions[i].value, newOptionCount, &newOptions);
|
---|
297 | }
|
---|
298 | }
|
---|
299 |
|
---|
300 | // we can release old option list
|
---|
301 | _cupsFreeOptions(oldOptionCount, oldOptions);
|
---|
302 |
|
---|
303 | // adding marked options
|
---|
304 | for (int i = 0; i < markedOptions.count(); ++i) {
|
---|
305 | const char* name = markedOptions.at(i);
|
---|
306 | ++i;
|
---|
307 | newOptionCount = _cupsAddOption(name, markedOptions.at(i), newOptionCount, &newOptions);
|
---|
308 | }
|
---|
309 |
|
---|
310 | // placing the new option list
|
---|
311 | printers[currPrinterIndex].num_options = newOptionCount;
|
---|
312 | printers[currPrinterIndex].options = newOptions;
|
---|
313 |
|
---|
314 | // saving new default values
|
---|
315 | _cupsSetDests(prnCount, printers);
|
---|
316 | }
|
---|
317 |
|
---|
318 | QRect QCUPSSupport::paperRect(const char *choice) const
|
---|
319 | {
|
---|
320 | if (!currPPD)
|
---|
321 | return QRect();
|
---|
322 | for (int i = 0; i < currPPD->num_sizes; ++i) {
|
---|
323 | if (qstrcmp(currPPD->sizes[i].name, choice) == 0)
|
---|
324 | return QRect(0, 0, qRound(currPPD->sizes[i].width), qRound(currPPD->sizes[i].length));
|
---|
325 | }
|
---|
326 | return QRect();
|
---|
327 | }
|
---|
328 |
|
---|
329 | QRect QCUPSSupport::pageRect(const char *choice) const
|
---|
330 | {
|
---|
331 | if (!currPPD)
|
---|
332 | return QRect();
|
---|
333 | for (int i = 0; i < currPPD->num_sizes; ++i) {
|
---|
334 | if (qstrcmp(currPPD->sizes[i].name, choice) == 0)
|
---|
335 | return QRect(qRound(currPPD->sizes[i].left),
|
---|
336 | qRound(currPPD->sizes[i].length - currPPD->sizes[i].top),
|
---|
337 | qRound(currPPD->sizes[i].right - currPPD->sizes[i].left),
|
---|
338 | qRound(currPPD->sizes[i].top - currPPD->sizes[i].bottom));
|
---|
339 | }
|
---|
340 | return QRect();
|
---|
341 | }
|
---|
342 |
|
---|
343 | QStringList QCUPSSupport::options() const
|
---|
344 | {
|
---|
345 | QStringList list;
|
---|
346 | collectMarkedOptions(list);
|
---|
347 | return list;
|
---|
348 | }
|
---|
349 |
|
---|
350 | bool QCUPSSupport::printerHasPPD(const char *printerName)
|
---|
351 | {
|
---|
352 | if (!isAvailable())
|
---|
353 | return false;
|
---|
354 | const char *ppdFile = _cupsGetPPD(printerName);
|
---|
355 | if (ppdFile)
|
---|
356 | unlink(ppdFile);
|
---|
357 | return (ppdFile != 0);
|
---|
358 | }
|
---|
359 |
|
---|
360 | QString QCUPSSupport::unicodeString(const char *s)
|
---|
361 | {
|
---|
362 | #ifndef QT_NO_TEXTCODEC
|
---|
363 | return codec->toUnicode(s);
|
---|
364 | #else
|
---|
365 | return QLatin1String(s);
|
---|
366 | #endif
|
---|
367 | }
|
---|
368 |
|
---|
369 | void QCUPSSupport::collectMarkedOptions(QStringList& list, const ppd_group_t* group) const
|
---|
370 | {
|
---|
371 | if (group == 0) {
|
---|
372 | if (!currPPD)
|
---|
373 | return;
|
---|
374 | for (int i = 0; i < currPPD->num_groups; ++i) {
|
---|
375 | collectMarkedOptions(list, &currPPD->groups[i]);
|
---|
376 | collectMarkedOptionsHelper(list, &currPPD->groups[i]);
|
---|
377 | }
|
---|
378 | } else {
|
---|
379 | for (int i = 0; i < group->num_subgroups; ++i)
|
---|
380 | collectMarkedOptionsHelper(list, &group->subgroups[i]);
|
---|
381 | }
|
---|
382 | }
|
---|
383 |
|
---|
384 | void QCUPSSupport::collectMarkedOptionsHelper(QStringList& list, const ppd_group_t* group) const
|
---|
385 | {
|
---|
386 | for (int i = 0; i < group->num_options; ++i) {
|
---|
387 | for (int j = 0; j < group->options[i].num_choices; ++j) {
|
---|
388 | if (group->options[i].choices[j].marked == 1 && qstrcmp(group->options[i].choices[j].choice, group->options[i].defchoice) != 0)
|
---|
389 | list << QString::fromLocal8Bit(group->options[i].keyword) << QString::fromLocal8Bit(group->options[i].choices[j].choice);
|
---|
390 | }
|
---|
391 | }
|
---|
392 | }
|
---|
393 |
|
---|
394 | QPair<int, QString> QCUPSSupport::tempFd()
|
---|
395 | {
|
---|
396 | char filename[512];
|
---|
397 | int fd = _cupsTempFd(filename, 512);
|
---|
398 | return QPair<int, QString>(fd, QString::fromLocal8Bit(filename));
|
---|
399 | }
|
---|
400 |
|
---|
401 | // Prints the given file and returns a job id.
|
---|
402 | int QCUPSSupport::printFile(const char * printerName, const char * filename, const char * title,
|
---|
403 | int num_options, cups_option_t * options)
|
---|
404 | {
|
---|
405 | return _cupsPrintFile(printerName, filename, title, num_options, options);
|
---|
406 | }
|
---|
407 |
|
---|
408 | QT_END_NAMESPACE
|
---|
409 |
|
---|
410 | #endif // QT_NO_CUPS
|
---|