Coverage Report

Created: 2026-11-06 11:29

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