Coverage Report

Created: 2026-02-14 09:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/vcl/unx/generic/print/prtsetup.cxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 *
9
 * This file incorporates work covered by the following license notice:
10
 *
11
 *   Licensed to the Apache Software Foundation (ASF) under one or more
12
 *   contributor license agreements. See the NOTICE file distributed
13
 *   with this work for additional information regarding copyright
14
 *   ownership. The ASF licenses this file to you under the Apache
15
 *   License, Version 2.0 (the "License"); you may not use this file
16
 *   except in compliance with the License. You may obtain a copy of
17
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18
 */
19
20
#include "prtsetup.hxx"
21
#include <svdata.hxx>
22
#include <strings.hrc>
23
24
#include <officecfg/Office/Common.hxx>
25
#include <vcl/weld/Dialog.hxx>
26
27
using namespace psp;
28
29
void RTSDialog::insertAllPPDValues(weld::ComboBox& rBox, const PPDParser* pParser, const PPDKey* pKey )
30
0
{
31
0
    if( ! pKey || ! pParser )
32
0
        return;
33
34
0
    const PPDValue* pValue = nullptr;
35
0
    OUString aOptionText;
36
37
0
    for (int i = 0; i < pKey->countValues(); ++i)
38
0
    {
39
0
        pValue = pKey->getValue( i );
40
0
        if (pValue->m_bCustomOption)
41
0
            continue;
42
0
        aOptionText = pParser->translateOption( pKey->getKey(), pValue->m_aOption) ;
43
44
0
        OUString sId(weld::toId(pValue));
45
0
        int nCurrentPos = rBox.find_id(sId);
46
0
        if( m_aJobData.m_aContext.checkConstraints( pKey, pValue ) )
47
0
        {
48
0
            if (nCurrentPos == -1)
49
0
                rBox.append(sId, aOptionText);
50
0
        }
51
0
        else
52
0
        {
53
0
            if (nCurrentPos != -1)
54
0
                rBox.remove(nCurrentPos);
55
0
        }
56
0
    }
57
0
    pValue = m_aJobData.m_aContext.getValue( pKey );
58
0
    if (pValue && !pValue->m_bCustomOption)
59
0
    {
60
0
        OUString sId(weld::toId(pValue));
61
0
        int nPos = rBox.find_id(sId);
62
0
        if (nPos != -1)
63
0
            rBox.set_active(nPos);
64
0
    }
65
0
}
66
67
/*
68
 * RTSDialog
69
 */
70
71
RTSDialog::RTSDialog(const PrinterInfo& rJobData, weld::Window* pParent)
72
0
    : GenericDialogController(pParent, u"vcl/ui/printerpropertiesdialog.ui"_ustr, u"PrinterPropertiesDialog"_ustr)
73
0
    , m_aJobData(rJobData)
74
0
    , m_bDataModified(false)
75
0
    , m_xTabControl(m_xBuilder->weld_notebook(u"tabcontrol"_ustr))
76
0
    , m_xOKButton(m_xBuilder->weld_button(u"ok"_ustr))
77
0
    , m_xCancelButton(m_xBuilder->weld_button(u"cancel"_ustr))
78
0
    , m_xPaperPage(new RTSPaperPage(m_xTabControl->get_page(u"paper"_ustr), this))
79
0
    , m_xDevicePage(new RTSDevicePage(m_xTabControl->get_page(u"device"_ustr), this))
80
0
{
81
0
    OUString aTitle(m_xDialog->get_title());
82
0
    m_xDialog->set_title(aTitle.replaceAll("%s", m_aJobData.m_aPrinterName));
83
84
0
    m_xTabControl->connect_enter_page( LINK( this, RTSDialog, ActivatePage ) );
85
0
    m_xOKButton->connect_clicked( LINK( this, RTSDialog, ClickButton ) );
86
0
    m_xCancelButton->connect_clicked( LINK( this, RTSDialog, ClickButton ) );
87
0
    ActivatePage(m_xTabControl->get_current_page_ident());
88
0
}
89
90
RTSDialog::~RTSDialog()
91
0
{
92
0
}
93
94
IMPL_LINK(RTSDialog, ActivatePage, const OUString&, rPage, void)
95
0
{
96
0
    if (rPage == "paper")
97
0
        m_xPaperPage->update();
98
0
}
99
100
IMPL_LINK( RTSDialog, ClickButton, weld::Button&, rButton, void )
101
0
{
102
0
    if (&rButton == m_xOKButton.get())
103
0
    {
104
        // refresh the changed values
105
0
        if (m_xPaperPage)
106
0
        {
107
            // orientation
108
0
            m_aJobData.m_eOrientation = m_xPaperPage->getOrientation() == 0 ?
109
0
                orientation::Portrait : orientation::Landscape;
110
            // assume use of paper size from printer setup if the user
111
            // got here via File > Printer Settings ...
112
0
            if ( m_aJobData.meSetupMode == PrinterSetupMode::DocumentGlobal )
113
0
               m_aJobData.m_bPapersizeFromSetup = true;
114
0
        }
115
0
        if( m_xDevicePage )
116
0
        {
117
0
            m_aJobData.m_nColorDepth    = m_xDevicePage->getDepth();
118
0
            m_aJobData.m_nColorDevice   = m_xDevicePage->getColorDevice();
119
0
        }
120
0
        m_xDialog->response(RET_OK);
121
0
    }
122
0
    else if (&rButton == m_xCancelButton.get())
123
0
        m_xDialog->response(RET_CANCEL);
124
0
}
125
126
/*
127
 * RTSPaperPage
128
 */
129
130
RTSPaperPage::RTSPaperPage(weld::Widget* pPage, RTSDialog* pDialog)
131
0
    : m_xBuilder(Application::CreateBuilder(pPage, u"vcl/ui/printerpaperpage.ui"_ustr))
132
0
    , m_pParent(pDialog)
133
0
    , m_xContainer(m_xBuilder->weld_widget(u"PrinterPaperPage"_ustr))
134
0
    , m_xCbFromSetup(m_xBuilder->weld_check_button(u"papersizefromsetup"_ustr))
135
0
    , m_xPaperText(m_xBuilder->weld_label(u"paperft"_ustr))
136
0
    , m_xPaperBox(m_xBuilder->weld_combo_box(u"paperlb"_ustr))
137
0
    , m_xOrientText(m_xBuilder->weld_label(u"orientft"_ustr))
138
0
    , m_xOrientBox(m_xBuilder->weld_combo_box(u"orientlb"_ustr))
139
0
    , m_xDuplexText(m_xBuilder->weld_label(u"duplexft"_ustr))
140
0
    , m_xDuplexBox(m_xBuilder->weld_combo_box(u"duplexlb"_ustr))
141
0
    , m_xSlotText(m_xBuilder->weld_label(u"slotft"_ustr))
142
0
    , m_xSlotBox(m_xBuilder->weld_combo_box(u"slotlb"_ustr))
143
0
{
144
    //PrinterPaperPage
145
0
    m_xPaperBox->connect_changed( LINK( this, RTSPaperPage, SelectHdl ) );
146
0
    m_xOrientBox->connect_changed( LINK( this, RTSPaperPage, SelectHdl ) );
147
0
    m_xDuplexBox->connect_changed( LINK( this, RTSPaperPage, SelectHdl ) );
148
0
    m_xSlotBox->connect_changed( LINK( this, RTSPaperPage, SelectHdl ) );
149
0
    m_xCbFromSetup->connect_toggled( LINK( this, RTSPaperPage, CheckBoxHdl ) );
150
151
0
    update();
152
0
}
153
154
RTSPaperPage::~RTSPaperPage()
155
0
{
156
0
}
157
158
void RTSPaperPage::update()
159
0
{
160
0
    const PPDKey* pKey      = nullptr;
161
162
    // orientation
163
0
    m_xOrientBox->set_active(m_pParent->m_aJobData.m_eOrientation == orientation::Portrait ? 0 : 1);
164
165
    // duplex
166
0
    if( m_pParent->m_aJobData.m_pParser &&
167
0
        (pKey = m_pParent->m_aJobData.m_pParser->getKey( u"Duplex"_ustr )) )
168
0
    {
169
0
        m_pParent->insertAllPPDValues( *m_xDuplexBox, m_pParent->m_aJobData.m_pParser, pKey );
170
0
    }
171
0
    else
172
0
    {
173
0
        m_xDuplexText->set_sensitive( false );
174
0
        m_xDuplexBox->set_sensitive( false );
175
0
    }
176
177
    // paper
178
0
    if( m_pParent->m_aJobData.m_pParser &&
179
0
        (pKey = m_pParent->m_aJobData.m_pParser->getKey( u"PageSize"_ustr )) )
180
0
    {
181
0
        m_pParent->insertAllPPDValues( *m_xPaperBox, m_pParent->m_aJobData.m_pParser, pKey );
182
0
    }
183
0
    else
184
0
    {
185
0
        m_xPaperText->set_sensitive( false );
186
0
        m_xPaperBox->set_sensitive( false );
187
0
    }
188
189
    // input slots
190
0
    if( m_pParent->m_aJobData.m_pParser &&
191
0
        (pKey = m_pParent->m_aJobData.m_pParser->getKey( u"InputSlot"_ustr )) )
192
0
    {
193
0
        m_pParent->insertAllPPDValues( *m_xSlotBox, m_pParent->m_aJobData.m_pParser, pKey );
194
0
    }
195
0
    else
196
0
    {
197
0
        m_xSlotText->set_sensitive( false );
198
0
        m_xSlotBox->set_sensitive( false );
199
0
    }
200
201
0
    if ( m_pParent->m_aJobData.meSetupMode != PrinterSetupMode::SingleJob )
202
0
        return;
203
204
0
    m_xCbFromSetup->show();
205
206
0
    if ( m_pParent->m_aJobData.m_bPapersizeFromSetup )
207
0
        m_xCbFromSetup->set_active(m_pParent->m_aJobData.m_bPapersizeFromSetup);
208
    // disable those, unless user wants to use papersize from printer prefs
209
    // as they have no influence on what's going to be printed anyway
210
0
    else
211
0
    {
212
0
        m_xPaperText->set_sensitive( false );
213
0
        m_xPaperBox->set_sensitive( false );
214
0
        m_xOrientText->set_sensitive( false );
215
0
        m_xOrientBox->set_sensitive( false );
216
0
    }
217
0
}
218
219
IMPL_LINK( RTSPaperPage, SelectHdl, weld::ComboBox&, rBox, void )
220
0
{
221
0
    const PPDKey* pKey = nullptr;
222
0
    if( &rBox == m_xPaperBox.get() )
223
0
    {
224
0
        if( m_pParent->m_aJobData.m_pParser )
225
0
            pKey = m_pParent->m_aJobData.m_pParser->getKey( u"PageSize"_ustr );
226
0
    }
227
0
    else if( &rBox == m_xDuplexBox.get() )
228
0
    {
229
0
        if( m_pParent->m_aJobData.m_pParser )
230
0
            pKey = m_pParent->m_aJobData.m_pParser->getKey( u"Duplex"_ustr );
231
0
    }
232
0
    else if( &rBox == m_xSlotBox.get() )
233
0
    {
234
0
        if( m_pParent->m_aJobData.m_pParser )
235
0
            pKey = m_pParent->m_aJobData.m_pParser->getKey( u"InputSlot"_ustr );
236
0
    }
237
0
    else if( &rBox == m_xOrientBox.get() )
238
0
    {
239
0
        m_pParent->m_aJobData.m_eOrientation = m_xOrientBox->get_active() == 0 ? orientation::Portrait : orientation::Landscape;
240
0
    }
241
0
    if( pKey )
242
0
    {
243
0
        PPDValue* pValue = weld::fromId<PPDValue*>(rBox.get_active_id());
244
0
        m_pParent->m_aJobData.m_aContext.setValue( pKey, pValue );
245
0
        update();
246
0
    }
247
248
0
    m_pParent->SetDataModified( true );
249
0
}
250
251
IMPL_LINK_NOARG(RTSPaperPage, CheckBoxHdl, weld::Toggleable&, void)
252
0
{
253
0
    bool bFromSetup = m_xCbFromSetup->get_active();
254
0
    m_pParent->m_aJobData.m_bPapersizeFromSetup = bFromSetup;
255
0
    m_xPaperText->set_sensitive(bFromSetup);
256
0
    m_xPaperBox->set_sensitive(bFromSetup);
257
0
    m_xOrientText->set_sensitive(bFromSetup);
258
0
    m_xOrientBox->set_sensitive(bFromSetup);
259
0
    m_pParent->SetDataModified(true);
260
0
}
261
262
/*
263
 * RTSDevicePage
264
 */
265
RTSDevicePage::RTSDevicePage(weld::Widget* pPage, RTSDialog* pParent)
266
0
    : m_xBuilder(Application::CreateBuilder(pPage, u"vcl/ui/printerdevicepage.ui"_ustr))
267
0
    , m_pCustomValue(nullptr)
268
0
    , m_pParent(pParent)
269
0
    , m_xContainer(m_xBuilder->weld_widget(u"PrinterDevicePage"_ustr))
270
0
    , m_xPPDKeyBox(m_xBuilder->weld_tree_view(u"options"_ustr))
271
0
    , m_xPPDValueBox(m_xBuilder->weld_tree_view(u"values"_ustr))
272
0
    , m_xCustomEdit(m_xBuilder->weld_entry(u"custom"_ustr))
273
0
    , m_xSpaceBox(m_xBuilder->weld_combo_box(u"colorspace"_ustr))
274
0
    , m_xDepthBox(m_xBuilder->weld_combo_box(u"colordepth"_ustr))
275
0
    , m_aReselectCustomIdle("RTSDevicePage m_aReselectCustomIdle")
276
0
{
277
0
    m_aReselectCustomIdle.SetInvokeHandler(LINK(this, RTSDevicePage, ImplHandleReselectHdl));
278
279
0
    m_xPPDKeyBox->set_size_request(m_xPPDKeyBox->get_approximate_digit_width() * 32,
280
0
                                   m_xPPDKeyBox->get_height_rows(12));
281
282
0
    m_xCustomEdit->connect_changed(LINK(this, RTSDevicePage, ModifyHdl));
283
284
0
    m_xPPDKeyBox->connect_selection_changed(LINK(this, RTSDevicePage, SelectHdl));
285
0
    m_xPPDValueBox->connect_selection_changed(LINK(this, RTSDevicePage, SelectHdl));
286
287
0
    m_xSpaceBox->connect_changed(LINK(this, RTSDevicePage, ComboChangedHdl));
288
0
    m_xDepthBox->connect_changed(LINK(this, RTSDevicePage, ComboChangedHdl));
289
290
0
    switch( m_pParent->m_aJobData.m_nColorDevice )
291
0
    {
292
0
        case 0:
293
0
            m_xSpaceBox->set_active(0);
294
0
            break;
295
0
        case 1:
296
0
            m_xSpaceBox->set_active(1);
297
0
            break;
298
0
        case -1:
299
0
            m_xSpaceBox->set_active(2);
300
0
            break;
301
0
    }
302
303
0
    if (m_pParent->m_aJobData.m_nColorDepth == 8)
304
0
        m_xDepthBox->set_active(0);
305
0
    else if (m_pParent->m_aJobData.m_nColorDepth == 24)
306
0
        m_xDepthBox->set_active(1);
307
308
    // fill ppd boxes
309
0
    if( !m_pParent->m_aJobData.m_pParser )
310
0
        return;
311
312
0
    for( int i = 0; i < m_pParent->m_aJobData.m_pParser->getKeys(); i++ )
313
0
    {
314
0
        const PPDKey* pKey = m_pParent->m_aJobData.m_pParser->getKey( i );
315
316
        // skip options already shown somewhere else
317
        // also skip options from the "InstallableOptions" PPD group
318
        // Options in that group define hardware features that are not
319
        // job-specific and should better be handled in the system-wide
320
        // printer configuration. Keyword is defined in PPD specification
321
        // (version 4.3), section 5.4.
322
0
        if( pKey->isUIKey()                   &&
323
0
            pKey->getKey() != "PageSize"      &&
324
0
            pKey->getKey() != "InputSlot"     &&
325
0
            pKey->getKey() != "PageRegion"    &&
326
0
            pKey->getKey() != "Duplex"        &&
327
0
            pKey->getGroup() != "InstallableOptions")
328
0
        {
329
0
            OUString aEntry( m_pParent->m_aJobData.m_pParser->translateKey( pKey->getKey() ) );
330
0
            m_xPPDKeyBox->append(weld::toId(pKey), aEntry);
331
0
        }
332
0
    }
333
0
}
334
335
RTSDevicePage::~RTSDevicePage()
336
0
{
337
0
}
338
339
sal_uLong RTSDevicePage::getDepth() const
340
0
{
341
0
    sal_uInt16 nSelectPos = m_xDepthBox->get_active();
342
0
    if (nSelectPos == 0)
343
0
        return 8;
344
0
    else
345
0
        return 24;
346
0
}
347
348
sal_uLong RTSDevicePage::getColorDevice() const
349
0
{
350
0
    sal_uInt16 nSelectPos = m_xSpaceBox->get_active();
351
0
    switch (nSelectPos)
352
0
    {
353
0
        case 0:
354
0
            return 0;
355
0
        case 1:
356
0
            return 1;
357
0
        case 2:
358
0
            return static_cast<sal_uLong>(-1);
359
0
    }
360
0
    return 0;
361
0
}
362
363
IMPL_LINK(RTSDevicePage, ModifyHdl, weld::Entry&, rEdit, void)
364
0
{
365
0
    if (m_pCustomValue)
366
0
    {
367
        // tdf#123734 Custom PPD option values are a CUPS extension to PPDs and the user-set value
368
        // needs to be prefixed with "Custom." in order to be processed properly
369
0
        m_pCustomValue->m_aCustomOption = "Custom." + rEdit.get_text();
370
0
        m_pCustomValue->m_bCustomOptionSetViaApp = true;
371
0
    }
372
0
}
373
374
IMPL_LINK( RTSDevicePage, SelectHdl, weld::TreeView&, rBox, void )
375
0
{
376
0
    if (&rBox == m_xPPDKeyBox.get())
377
0
    {
378
0
        const PPDKey* pKey = weld::fromId<PPDKey*>(m_xPPDKeyBox->get_selected_id());
379
0
        FillValueBox( pKey );
380
0
    }
381
0
    else if (&rBox == m_xPPDValueBox.get())
382
0
    {
383
0
        const PPDKey* pKey = weld::fromId<PPDKey*>(m_xPPDKeyBox->get_selected_id());
384
0
        const PPDValue* pValue = weld::fromId<PPDValue*>(m_xPPDValueBox->get_selected_id());
385
0
        if (pKey && pValue)
386
0
        {
387
0
            m_pParent->m_aJobData.m_aContext.setValue( pKey, pValue );
388
0
            ValueBoxChanged(pKey);
389
0
        }
390
0
    }
391
0
    m_pParent->SetDataModified( true );
392
0
}
393
394
IMPL_LINK_NOARG( RTSDevicePage, ComboChangedHdl, weld::ComboBox&, void )
395
0
{
396
0
    m_pParent->SetDataModified( true );
397
0
}
398
399
void RTSDevicePage::FillValueBox( const PPDKey* pKey )
400
0
{
401
0
    m_xPPDValueBox->clear();
402
0
    m_xCustomEdit->hide();
403
404
0
    if( ! pKey )
405
0
        return;
406
407
0
    const PPDValue* pValue = nullptr;
408
0
    for( int i = 0; i < pKey->countValues(); i++ )
409
0
    {
410
0
        pValue = pKey->getValue( i );
411
0
        if( m_pParent->m_aJobData.m_aContext.checkConstraints( pKey, pValue ) &&
412
0
            m_pParent->m_aJobData.m_pParser )
413
0
        {
414
0
            OUString aEntry;
415
0
            if (pValue->m_bCustomOption)
416
0
                aEntry = VclResId(SV_PRINT_CUSTOM_TXT);
417
0
            else
418
0
                aEntry = m_pParent->m_aJobData.m_pParser->translateOption( pKey->getKey(), pValue->m_aOption);
419
0
            m_xPPDValueBox->append(weld::toId(pValue), aEntry);
420
0
        }
421
0
    }
422
0
    pValue = m_pParent->m_aJobData.m_aContext.getValue( pKey );
423
0
    m_xPPDValueBox->select_id(weld::toId(pValue));
424
425
0
    ValueBoxChanged(pKey);
426
0
}
427
428
IMPL_LINK_NOARG(RTSDevicePage, ImplHandleReselectHdl, Timer*, void)
429
0
{
430
    //in case selected entry is now not visible select it again to scroll it into view
431
0
    m_xPPDValueBox->select(m_xPPDValueBox->get_selected_index());
432
0
}
433
434
void RTSDevicePage::ValueBoxChanged( const PPDKey* pKey )
435
0
{
436
0
    const PPDValue* pValue = m_pParent->m_aJobData.m_aContext.getValue(pKey);
437
0
    if (pValue->m_bCustomOption)
438
0
    {
439
0
        m_pCustomValue = pValue;
440
0
        m_pParent->m_aJobData.m_aContext.setValue(pKey, pValue);
441
        // don't show the "Custom." prefix in the UI, s.a. comment in ModifyHdl
442
0
        m_xCustomEdit->set_text(m_pCustomValue->m_aCustomOption.replaceFirst("Custom.", ""));
443
0
        m_xCustomEdit->show();
444
0
        m_aReselectCustomIdle.Start();
445
0
    }
446
0
    else
447
0
        m_xCustomEdit->hide();
448
0
}
449
450
int SetupPrinterDriver(weld::Window* pParent, ::psp::PrinterInfo& rJobData)
451
0
{
452
0
    int nRet = 0;
453
0
    RTSDialog aDialog(rJobData, pParent);
454
455
    // return 0 if cancel was pressed or if the data
456
    // weren't modified, 1 otherwise
457
0
    if (aDialog.run() != RET_CANCEL)
458
0
    {
459
0
        rJobData = aDialog.getSetup();
460
0
        nRet = aDialog.GetDataModified() ? 1 : 0;
461
0
    }
462
463
0
    return nRet;
464
0
}
465
466
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */