1 | /****************************************************************************
|
---|
2 | **
|
---|
3 | ** Copyright (C) 2010 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 | #ifndef Q_WS_PM
|
---|
54 |
|
---|
55 | typedef int (*CupsGetDests)(cups_dest_t **dests);
|
---|
56 | typedef void (*CupsFreeDests)(int num_dests, cups_dest_t *dests);
|
---|
57 | typedef const char* (*CupsGetPPD)(const char *printer);
|
---|
58 | typedef int (*CupsMarkOptions)(ppd_file_t *ppd, int num_options, cups_option_t *options);
|
---|
59 | typedef ppd_file_t* (*PPDOpenFile)(const char *filename);
|
---|
60 | typedef void (*PPDMarkDefaults)(ppd_file_t *ppd);
|
---|
61 | typedef int (*PPDMarkOption)(ppd_file_t *ppd, const char *keyword, const char *option);
|
---|
62 | typedef void (*PPDClose)(ppd_file_t *ppd);
|
---|
63 | typedef int (*PPDMarkOption)(ppd_file_t *ppd, const char *keyword, const char *option);
|
---|
64 | typedef void (*CupsFreeOptions)(int num_options, cups_option_t *options);
|
---|
65 | typedef void (*CupsSetDests)(int num_dests, cups_dest_t *dests);
|
---|
66 | typedef cups_lang_t* (*CupsLangGet)(const char *language);
|
---|
67 | typedef const char* (*CupsLangEncoding)(cups_lang_t *language);
|
---|
68 | typedef int (*CupsAddOption)(const char *name, const char *value, int num_options, cups_option_t **options);
|
---|
69 | typedef int (*CupsTempFd)(char *name, int len);
|
---|
70 | typedef int (*CupsPrintFile)(const char * name, const char * filename, const char * title, int num_options, cups_option_t * options);
|
---|
71 |
|
---|
72 | static bool cupsLoaded = false;
|
---|
73 | static int qt_cups_num_printers = 0;
|
---|
74 | static CupsGetDests _cupsGetDests = 0;
|
---|
75 | static CupsFreeDests _cupsFreeDests = 0;
|
---|
76 | static CupsGetPPD _cupsGetPPD = 0;
|
---|
77 | static PPDOpenFile _ppdOpenFile = 0;
|
---|
78 | static PPDMarkDefaults _ppdMarkDefaults = 0;
|
---|
79 | static PPDClose _ppdClose = 0;
|
---|
80 | static CupsMarkOptions _cupsMarkOptions = 0;
|
---|
81 | static PPDMarkOption _ppdMarkOption = 0;
|
---|
82 | static CupsFreeOptions _cupsFreeOptions = 0;
|
---|
83 | static CupsSetDests _cupsSetDests = 0;
|
---|
84 | static CupsLangGet _cupsLangGet = 0;
|
---|
85 | static CupsLangEncoding _cupsLangEncoding = 0;
|
---|
86 | static CupsAddOption _cupsAddOption = 0;
|
---|
87 | static CupsTempFd _cupsTempFd = 0;
|
---|
88 | static CupsPrintFile _cupsPrintFile = 0;
|
---|
89 |
|
---|
90 | #else // ifndef Q_WS_PM
|
---|
91 |
|
---|
92 | // On OS/2, we link to libcups statically
|
---|
93 |
|
---|
94 | static bool cupsLoaded = false;
|
---|
95 | static int qt_cups_num_printers = 0;
|
---|
96 |
|
---|
97 | #define _cupsGetDests cupsGetDests
|
---|
98 | #define _cupsFreeDests cupsFreeDests
|
---|
99 | #define _cupsGetPPD cupsGetPPD
|
---|
100 | #define _cupsLangGet cupsLangGet
|
---|
101 | #define _cupsLangEncoding cupsLangEncoding
|
---|
102 | #define _ppdOpenFile ppdOpenFile
|
---|
103 | #define _ppdMarkDefaults ppdMarkDefaults
|
---|
104 | #define _ppdClose ppdClose
|
---|
105 | #define _cupsMarkOptions cupsMarkOptions
|
---|
106 | #define _ppdMarkOption ppdMarkOption
|
---|
107 | #define _cupsFreeOptions cupsFreeOptions
|
---|
108 | #define _cupsSetDests cupsSetDests
|
---|
109 | #define _cupsAddOption cupsAddOption
|
---|
110 | #define _cupsTempFd cupsTempFd
|
---|
111 | #define _cupsPrintFile cupsPrintFile
|
---|
112 |
|
---|
113 | #endif // ifndef Q_WS_PM
|
---|
114 |
|
---|
115 | static void resolveCups()
|
---|
116 | {
|
---|
117 | #ifndef Q_WS_PM
|
---|
118 | QLibrary cupsLib(QLatin1String("cups"), 2);
|
---|
119 | if(cupsLib.load()) {
|
---|
120 | _cupsGetDests = (CupsGetDests) cupsLib.resolve("cupsGetDests");
|
---|
121 | _cupsFreeDests = (CupsFreeDests) cupsLib.resolve("cupsFreeDests");
|
---|
122 | _cupsGetPPD = (CupsGetPPD) cupsLib.resolve("cupsGetPPD");
|
---|
123 | _cupsLangGet = (CupsLangGet) cupsLib.resolve("cupsLangGet");
|
---|
124 | _cupsLangEncoding = (CupsLangEncoding) cupsLib.resolve("cupsLangEncoding");
|
---|
125 | _ppdOpenFile = (PPDOpenFile) cupsLib.resolve("ppdOpenFile");
|
---|
126 | _ppdMarkDefaults = (PPDMarkDefaults) cupsLib.resolve("ppdMarkDefaults");
|
---|
127 | _ppdClose = (PPDClose) cupsLib.resolve("ppdClose");
|
---|
128 | _cupsMarkOptions = (CupsMarkOptions) cupsLib.resolve("cupsMarkOptions");
|
---|
129 | _ppdMarkOption = (PPDMarkOption) cupsLib.resolve("ppdMarkOption");
|
---|
130 | _cupsFreeOptions = (CupsFreeOptions) cupsLib.resolve("cupsFreeOptions");
|
---|
131 | _cupsSetDests = (CupsSetDests) cupsLib.resolve("cupsSetDests");
|
---|
132 | _cupsAddOption = (CupsAddOption) cupsLib.resolve("cupsAddOption");
|
---|
133 | _cupsTempFd = (CupsTempFd) cupsLib.resolve("cupsTempFd");
|
---|
134 | _cupsPrintFile = (CupsPrintFile) cupsLib.resolve("cupsPrintFile");
|
---|
135 |
|
---|
136 | if (_cupsGetDests && _cupsFreeDests) {
|
---|
137 | #endif
|
---|
138 | cups_dest_t *printers;
|
---|
139 | int num_printers = _cupsGetDests(&printers);
|
---|
140 | if (num_printers)
|
---|
141 | _cupsFreeDests(num_printers, printers);
|
---|
142 | qt_cups_num_printers = num_printers;
|
---|
143 | #ifndef Q_WS_PM
|
---|
144 | }
|
---|
145 | }
|
---|
146 | #endif
|
---|
147 | cupsLoaded = true;
|
---|
148 | }
|
---|
149 |
|
---|
150 | // ================ CUPS Support class ========================
|
---|
151 |
|
---|
152 | QCUPSSupport::QCUPSSupport()
|
---|
153 | :
|
---|
154 | prnCount(0),
|
---|
155 | printers(0),
|
---|
156 | page_sizes(0),
|
---|
157 | currPrinterIndex(0),
|
---|
158 | currPPD(0)
|
---|
159 | {
|
---|
160 | if (!cupsLoaded)
|
---|
161 | resolveCups();
|
---|
162 |
|
---|
163 | // getting all available printers
|
---|
164 | if (!isAvailable())
|
---|
165 | return;
|
---|
166 |
|
---|
167 | prnCount = _cupsGetDests(&printers);
|
---|
168 |
|
---|
169 | for (int i = 0; i < prnCount; ++i) {
|
---|
170 | if (printers[i].is_default) {
|
---|
171 | currPrinterIndex = i;
|
---|
172 | setCurrentPrinter(i);
|
---|
173 | break;
|
---|
174 | }
|
---|
175 | }
|
---|
176 |
|
---|
177 | #ifndef QT_NO_TEXTCODEC
|
---|
178 | cups_lang_t *cupsLang = _cupsLangGet(0);
|
---|
179 | codec = QTextCodec::codecForName(_cupsLangEncoding(cupsLang));
|
---|
180 | if (!codec)
|
---|
181 | codec = QTextCodec::codecForLocale();
|
---|
182 | #endif
|
---|
183 | }
|
---|
184 |
|
---|
185 | QCUPSSupport::~QCUPSSupport()
|
---|
186 | {
|
---|
187 | if (currPPD)
|
---|
188 | _ppdClose(currPPD);
|
---|
189 | if (prnCount)
|
---|
190 | _cupsFreeDests(prnCount, printers);
|
---|
191 | }
|
---|
192 |
|
---|
193 | int QCUPSSupport::availablePrintersCount() const
|
---|
194 | {
|
---|
195 | return prnCount;
|
---|
196 | }
|
---|
197 |
|
---|
198 | const cups_dest_t* QCUPSSupport::availablePrinters() const
|
---|
199 | {
|
---|
200 | return printers;
|
---|
201 | }
|
---|
202 |
|
---|
203 | const ppd_file_t* QCUPSSupport::currentPPD() const
|
---|
204 | {
|
---|
205 | return currPPD;
|
---|
206 | }
|
---|
207 |
|
---|
208 | const ppd_file_t* QCUPSSupport::setCurrentPrinter(int index)
|
---|
209 | {
|
---|
210 | Q_ASSERT(index >= 0 && index <= prnCount);
|
---|
211 | if (index == prnCount)
|
---|
212 | return 0;
|
---|
213 |
|
---|
214 | currPrinterIndex = index;
|
---|
215 |
|
---|
216 | if (currPPD)
|
---|
217 | _ppdClose(currPPD);
|
---|
218 | currPPD = 0;
|
---|
219 | page_sizes = 0;
|
---|
220 |
|
---|
221 | const char *ppdFile = _cupsGetPPD(printers[index].name);
|
---|
222 |
|
---|
223 | if (!ppdFile)
|
---|
224 | return 0;
|
---|
225 |
|
---|
226 | currPPD = _ppdOpenFile(ppdFile);
|
---|
227 | unlink(ppdFile);
|
---|
228 |
|
---|
229 | // marking default options
|
---|
230 | _ppdMarkDefaults(currPPD);
|
---|
231 |
|
---|
232 | // marking options explicitly set
|
---|
233 | _cupsMarkOptions(currPPD, printers[currPrinterIndex].num_options, printers[currPrinterIndex].options);
|
---|
234 |
|
---|
235 | // getting pointer to page sizes
|
---|
236 | page_sizes = ppdOption("PageSize");
|
---|
237 |
|
---|
238 | return currPPD;
|
---|
239 | }
|
---|
240 |
|
---|
241 | int QCUPSSupport::currentPrinterIndex() const
|
---|
242 | {
|
---|
243 | return currPrinterIndex;
|
---|
244 | }
|
---|
245 |
|
---|
246 | bool QCUPSSupport::isAvailable()
|
---|
247 | {
|
---|
248 | if(!cupsLoaded)
|
---|
249 | resolveCups();
|
---|
250 |
|
---|
251 | return
|
---|
252 | #ifndef Q_WS_PM
|
---|
253 | _cupsGetDests &&
|
---|
254 | _cupsFreeDests &&
|
---|
255 | _cupsGetPPD &&
|
---|
256 | _ppdOpenFile &&
|
---|
257 | _ppdMarkDefaults &&
|
---|
258 | _ppdClose &&
|
---|
259 | _cupsMarkOptions &&
|
---|
260 | _ppdMarkOption &&
|
---|
261 | _cupsFreeOptions &&
|
---|
262 | _cupsSetDests &&
|
---|
263 | _cupsLangGet &&
|
---|
264 | _cupsLangEncoding &&
|
---|
265 | _cupsAddOption &&
|
---|
266 | #endif
|
---|
267 | (qt_cups_num_printers > 0);
|
---|
268 | }
|
---|
269 |
|
---|
270 | const ppd_option_t* QCUPSSupport::ppdOption(const char *key) const
|
---|
271 | {
|
---|
272 | if (currPPD) {
|
---|
273 | for (int gr = 0; gr < currPPD->num_groups; ++gr) {
|
---|
274 | for (int opt = 0; opt < currPPD->groups[gr].num_options; ++opt) {
|
---|
275 | if (qstrcmp(currPPD->groups[gr].options[opt].keyword, key) == 0)
|
---|
276 | return &currPPD->groups[gr].options[opt];
|
---|
277 | }
|
---|
278 | }
|
---|
279 | }
|
---|
280 | return 0;
|
---|
281 | }
|
---|
282 |
|
---|
283 | const cups_option_t* QCUPSSupport::printerOption(const QString &key) const
|
---|
284 | {
|
---|
285 | for (int i = 0; i < printers[currPrinterIndex].num_options; ++i) {
|
---|
286 | if (QLatin1String(printers[currPrinterIndex].options[i].name) == key)
|
---|
287 | return &printers[currPrinterIndex].options[i];
|
---|
288 | }
|
---|
289 | return 0;
|
---|
290 | }
|
---|
291 |
|
---|
292 | const ppd_option_t* QCUPSSupport::pageSizes() const
|
---|
293 | {
|
---|
294 | return page_sizes;
|
---|
295 | }
|
---|
296 |
|
---|
297 | int QCUPSSupport::markOption(const char* name, const char* value)
|
---|
298 | {
|
---|
299 | return _ppdMarkOption(currPPD, name, value);
|
---|
300 | }
|
---|
301 |
|
---|
302 | void QCUPSSupport::saveOptions(QList<const ppd_option_t*> options, QList<const char*> markedOptions)
|
---|
303 | {
|
---|
304 | int oldOptionCount = printers[currPrinterIndex].num_options;
|
---|
305 | cups_option_t* oldOptions = printers[currPrinterIndex].options;
|
---|
306 |
|
---|
307 | int newOptionCount = 0;
|
---|
308 | cups_option_t* newOptions = 0;
|
---|
309 |
|
---|
310 | // copying old options that are not on the new list
|
---|
311 | for (int i = 0; i < oldOptionCount; ++i) {
|
---|
312 | bool contains = false;
|
---|
313 | for (int j = 0; j < options.count(); ++j) {
|
---|
314 | if (qstrcmp(options.at(j)->keyword, oldOptions[i].name) == 0) {
|
---|
315 | contains = true;
|
---|
316 | break;
|
---|
317 | }
|
---|
318 | }
|
---|
319 |
|
---|
320 | if (!contains) {
|
---|
321 | newOptionCount = _cupsAddOption(oldOptions[i].name, oldOptions[i].value, newOptionCount, &newOptions);
|
---|
322 | }
|
---|
323 | }
|
---|
324 |
|
---|
325 | // we can release old option list
|
---|
326 | _cupsFreeOptions(oldOptionCount, oldOptions);
|
---|
327 |
|
---|
328 | // adding marked options
|
---|
329 | for (int i = 0; i < markedOptions.count(); ++i) {
|
---|
330 | const char* name = markedOptions.at(i);
|
---|
331 | ++i;
|
---|
332 | newOptionCount = _cupsAddOption(name, markedOptions.at(i), newOptionCount, &newOptions);
|
---|
333 | }
|
---|
334 |
|
---|
335 | // placing the new option list
|
---|
336 | printers[currPrinterIndex].num_options = newOptionCount;
|
---|
337 | printers[currPrinterIndex].options = newOptions;
|
---|
338 |
|
---|
339 | // saving new default values
|
---|
340 | _cupsSetDests(prnCount, printers);
|
---|
341 | }
|
---|
342 |
|
---|
343 | QRect QCUPSSupport::paperRect(const char *choice) const
|
---|
344 | {
|
---|
345 | if (!currPPD)
|
---|
346 | return QRect();
|
---|
347 | for (int i = 0; i < currPPD->num_sizes; ++i) {
|
---|
348 | if (qstrcmp(currPPD->sizes[i].name, choice) == 0)
|
---|
349 | return QRect(0, 0, qRound(currPPD->sizes[i].width), qRound(currPPD->sizes[i].length));
|
---|
350 | }
|
---|
351 | return QRect();
|
---|
352 | }
|
---|
353 |
|
---|
354 | QRect QCUPSSupport::pageRect(const char *choice) const
|
---|
355 | {
|
---|
356 | if (!currPPD)
|
---|
357 | return QRect();
|
---|
358 | for (int i = 0; i < currPPD->num_sizes; ++i) {
|
---|
359 | if (qstrcmp(currPPD->sizes[i].name, choice) == 0)
|
---|
360 | return QRect(qRound(currPPD->sizes[i].left),
|
---|
361 | qRound(currPPD->sizes[i].length - currPPD->sizes[i].top),
|
---|
362 | qRound(currPPD->sizes[i].right - currPPD->sizes[i].left),
|
---|
363 | qRound(currPPD->sizes[i].top - currPPD->sizes[i].bottom));
|
---|
364 | }
|
---|
365 | return QRect();
|
---|
366 | }
|
---|
367 |
|
---|
368 | QStringList QCUPSSupport::options() const
|
---|
369 | {
|
---|
370 | QStringList list;
|
---|
371 | collectMarkedOptions(list);
|
---|
372 | return list;
|
---|
373 | }
|
---|
374 |
|
---|
375 | bool QCUPSSupport::printerHasPPD(const char *printerName)
|
---|
376 | {
|
---|
377 | if (!isAvailable())
|
---|
378 | return false;
|
---|
379 | const char *ppdFile = _cupsGetPPD(printerName);
|
---|
380 | unlink(ppdFile);
|
---|
381 | return (ppdFile != 0);
|
---|
382 | }
|
---|
383 |
|
---|
384 | QString QCUPSSupport::unicodeString(const char *s)
|
---|
385 | {
|
---|
386 | #ifndef QT_NO_TEXTCODEC
|
---|
387 | return codec->toUnicode(s);
|
---|
388 | #else
|
---|
389 | return QLatin1String(s);
|
---|
390 | #endif
|
---|
391 | }
|
---|
392 |
|
---|
393 | void QCUPSSupport::collectMarkedOptions(QStringList& list, const ppd_group_t* group) const
|
---|
394 | {
|
---|
395 | if (group == 0) {
|
---|
396 | if (!currPPD)
|
---|
397 | return;
|
---|
398 | for (int i = 0; i < currPPD->num_groups; ++i) {
|
---|
399 | collectMarkedOptions(list, &currPPD->groups[i]);
|
---|
400 | collectMarkedOptionsHelper(list, &currPPD->groups[i]);
|
---|
401 | }
|
---|
402 | } else {
|
---|
403 | for (int i = 0; i < group->num_subgroups; ++i)
|
---|
404 | collectMarkedOptionsHelper(list, &group->subgroups[i]);
|
---|
405 | }
|
---|
406 | }
|
---|
407 |
|
---|
408 | void QCUPSSupport::collectMarkedOptionsHelper(QStringList& list, const ppd_group_t* group) const
|
---|
409 | {
|
---|
410 | for (int i = 0; i < group->num_options; ++i) {
|
---|
411 | for (int j = 0; j < group->options[i].num_choices; ++j) {
|
---|
412 | if (group->options[i].choices[j].marked == 1 && qstrcmp(group->options[i].choices[j].choice, group->options[i].defchoice) != 0)
|
---|
413 | list << QString::fromLocal8Bit(group->options[i].keyword) << QString::fromLocal8Bit(group->options[i].choices[j].choice);
|
---|
414 | }
|
---|
415 | }
|
---|
416 | }
|
---|
417 |
|
---|
418 | QPair<int, QString> QCUPSSupport::tempFd()
|
---|
419 | {
|
---|
420 | char filename[512];
|
---|
421 | int fd = _cupsTempFd(filename, 512);
|
---|
422 | return QPair<int, QString>(fd, QString::fromLocal8Bit(filename));
|
---|
423 | }
|
---|
424 |
|
---|
425 | // Prints the given file and returns a job id.
|
---|
426 | int QCUPSSupport::printFile(const char * printerName, const char * filename, const char * title,
|
---|
427 | int num_options, cups_option_t * options)
|
---|
428 | {
|
---|
429 | return _cupsPrintFile(printerName, filename, title, num_options, options);
|
---|
430 | }
|
---|
431 |
|
---|
432 | QT_END_NAMESPACE
|
---|
433 |
|
---|
434 | #endif // QT_NO_CUPS
|
---|