File indexing completed on 2025-01-05 05:23:30

0001 /*
0002     This file is part of the Okteta Kasten module, made within the KDE community.
0003 
0004     SPDX-FileCopyrightText: 2009 Friedrich W. H. Kossebau <kossebau@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0007 */
0008 
0009 #include "gotooffsetview.hpp"
0010 
0011 // tool
0012 #include "gotooffsettool.hpp"
0013 // libconfigentries
0014 #include <addresscomboboxcodingconfigentry.hpp>
0015 #include <directionconfigentry.hpp>
0016 // Okteta Kasten gui
0017 #include <Kasten/Okteta/AddressValidator>
0018 // KF
0019 #include <KGuiItem>
0020 #include <KConfigGroup>
0021 #include <KSharedConfig>
0022 #include <KLocalizedString>
0023 // Qt
0024 #include <QPushButton>
0025 #include <QCheckBox>
0026 #include <QLabel>
0027 #include <QHBoxLayout>
0028 #include <QVBoxLayout>
0029 
0030 
0031 template <>
0032 inline Kasten::GotoOffsetView::GotoDirection KConfigGroup::readEntry(const char *key, const Kasten::GotoOffsetView::GotoDirection &defaultValue) const
0033 {
0034     return static_cast<Kasten::GotoOffsetView::GotoDirection>(KConfigGroup::readEntry(key, static_cast<Kasten::Direction>(defaultValue)));
0035 }
0036 
0037 template <>
0038 inline void KConfigGroup::writeEntry(const char *key, const Kasten::GotoOffsetView::GotoDirection &value,
0039                                      KConfigBase::WriteConfigFlags flags)
0040 {
0041     writeEntry(key, static_cast<Kasten::Direction>(value), flags);
0042 }
0043 
0044 
0045 namespace Kasten {
0046 
0047 GotoOffsetView::GotoOffsetView(GotoOffsetTool* tool, QWidget* parent)
0048     : AbstractToolWidget(parent)
0049     , mTool(tool)
0050 {
0051     auto* baseLayout = new QHBoxLayout(this);
0052     baseLayout->setContentsMargins(0, 0, 0, 0);
0053 
0054     // offset
0055     auto* offsetLayout = new QHBoxLayout();
0056     offsetLayout->setContentsMargins(0, 0, 0, 0);
0057 
0058     auto* label = new QLabel(i18nc("@label:listbox", "O&ffset:"), this);
0059     mAddressEdit = new Okteta::AddressComboBox(this);
0060     connect(mAddressEdit, &Okteta::AddressComboBox::addressChanged,
0061             mTool, &GotoOffsetTool::setTargetOffset);
0062     connect(mAddressEdit, &Okteta::AddressComboBox::formatChanged,
0063             this, &GotoOffsetView::onFormatChanged);
0064     connect(mAddressEdit, &Okteta::AddressComboBox::addressTypeChanged,
0065             this, &GotoOffsetView::onAddressTypeChanged);
0066     label->setBuddy(mAddressEdit);
0067     const QString inputWhatsThis =
0068         i18nc("@info:whatsthis", "Enter an offset to go to, or select a previous offset from the list.");
0069     label->setWhatsThis(inputWhatsThis);
0070     mAddressEdit->setWhatsThis(inputWhatsThis);
0071 
0072     offsetLayout->addWidget(label);
0073     offsetLayout->addWidget(mAddressEdit, 1);
0074 
0075     baseLayout->addLayout(offsetLayout, 1);
0076     baseLayout->setAlignment(offsetLayout, Qt::AlignTop);
0077 
0078     setFocusProxy(mAddressEdit);   // TODO: see how KDialog does it, e.g. see if there is already a focuswidget as child
0079 
0080     // options
0081     auto* optionsLayout = new QVBoxLayout();
0082     optionsLayout->setContentsMargins(0, 0, 0, 0);
0083 
0084     mAtCursorCheckBox = new QCheckBox(i18nc("@option:check", "From c&ursor"), this);
0085     mAtCursorCheckBox->setWhatsThis(
0086         i18nc("@info:whatsthis", "Go relative from the current cursor location and not absolute."));
0087     connect(mAtCursorCheckBox, &QCheckBox::toggled,
0088             mTool, &GotoOffsetTool::setIsRelative);
0089     mExtendSelectionCheckBox = new QCheckBox(i18nc("@option:check", "&Extend selection"), this);
0090     mExtendSelectionCheckBox->setWhatsThis(
0091         i18nc("@info:whatsthis", "Extend the selection by the cursor move."));
0092     connect(mExtendSelectionCheckBox, &QCheckBox::toggled,
0093             mTool, &GotoOffsetTool::setIsSelectionToExtent);
0094     mBackwardsCheckBox = new QCheckBox(i18nc("@option:check", "&Backwards"), this);
0095     mBackwardsCheckBox->setWhatsThis(
0096         i18nc("@info:whatsthis", "Go backwards from the end or the current cursor location."));
0097     connect(mBackwardsCheckBox, &QCheckBox::toggled, mTool, &GotoOffsetTool::setIsBackwards);
0098 
0099     auto* upperOptionsLayout = new QHBoxLayout();
0100     upperOptionsLayout->setContentsMargins(0, 0, 0, 0);
0101     upperOptionsLayout->addWidget(mAtCursorCheckBox);
0102     upperOptionsLayout->addWidget(mBackwardsCheckBox);
0103 
0104     optionsLayout->addLayout(upperOptionsLayout);
0105     optionsLayout->addWidget(mExtendSelectionCheckBox);
0106 
0107     baseLayout->addLayout(optionsLayout);
0108 
0109     // Goto button
0110     const KGuiItem gotoGuiItem =
0111         KGuiItem(i18nc("@action:button", "&Go"),
0112                  QStringLiteral("go-jump"),
0113                  i18nc("@info:tooltip",
0114                        "Go to the Offset"),
0115                  xi18nc("@info:whatsthis",
0116                         "If you press the <interface>Go</interface> "
0117                         "button, the cursor will be moved in the document to or, "
0118                         "on your option, by the offset you entered above."));
0119     mGotoButton = new QPushButton(this);
0120     KGuiItem::assign(mGotoButton, gotoGuiItem);
0121     connect(mGotoButton, &QPushButton::clicked, this, &GotoOffsetView::onGotoButtonClicked);
0122     addButton(mGotoButton, AbstractToolWidget::Default);
0123     baseLayout->addWidget(mGotoButton);
0124     baseLayout->setAlignment(mGotoButton, Qt::AlignTop);
0125 
0126     setTabOrder(mAddressEdit, mAtCursorCheckBox);
0127     setTabOrder(mAtCursorCheckBox, mBackwardsCheckBox);
0128     setTabOrder(mBackwardsCheckBox, mExtendSelectionCheckBox);
0129     setTabOrder(mExtendSelectionCheckBox, mGotoButton);
0130 
0131     const KConfigGroup configGroup(KSharedConfig::openConfig(), ConfigGroupId);
0132 
0133     const bool fromCursor = configGroup.readEntry(FromCursorConfigKey, DefaultFromCursor);
0134     mAtCursorCheckBox->setChecked(fromCursor);
0135 
0136     const GotoDirection direction = configGroup.readEntry(DirectionConfigKey, DefaultDirection);
0137     mBackwardsCheckBox->setChecked(direction == GotoBackward);
0138 
0139     const bool extendSelection = configGroup.readEntry(ExtendSelectionConfigKey, DefaultExtendSelection);
0140     mExtendSelectionCheckBox->setChecked(extendSelection);
0141 
0142     const Okteta::AddressComboBox::Coding offsetCoding = configGroup.readEntry(OffsetCodingConfigKey, DefaultOffsetCoding);
0143     mAddressEdit->setFormat(offsetCoding);
0144 
0145     connect(mTool, &GotoOffsetTool::isApplyableChanged,
0146             this, &GotoOffsetView::onApplyableChanged);
0147 
0148     onApplyableChanged(mTool->isApplyable());
0149 }
0150 
0151 GotoOffsetView::~GotoOffsetView() = default;
0152 
0153 void GotoOffsetView::onApplyableChanged(bool isApplyable)
0154 {
0155     // TODO: set error tooltip, like offset out of range or no document
0156     // TODO: set color flag to offset input
0157     mGotoButton->setEnabled(isApplyable);
0158 }
0159 
0160 void GotoOffsetView::onGotoButtonClicked()
0161 {
0162     // TODO: collect recently used offset in tool instead?
0163     mAddressEdit->rememberCurrentAddress();
0164 
0165     KConfigGroup configGroup(KSharedConfig::openConfig(), ConfigGroupId);
0166     configGroup.writeEntry(OffsetCodingConfigKey, static_cast<Okteta::AddressComboBox::Coding>(mAddressEdit->format()));
0167     configGroup.writeEntry(DirectionConfigKey,
0168                            mBackwardsCheckBox->isChecked() ? GotoBackward : GotoForward);
0169     configGroup.writeEntry(ExtendSelectionConfigKey, mExtendSelectionCheckBox->isChecked());
0170     configGroup.writeEntry(FromCursorConfigKey, mAtCursorCheckBox->isChecked());
0171 
0172     mTool->gotoOffset();
0173 //     Q_EMIT toolUsed();
0174 }
0175 
0176 void GotoOffsetView::onAddressTypeChanged(int addressType)
0177 {
0178     const bool isNotExpression = (mAddressEdit->format() != Okteta::AddressComboBox::ExpressionCoding);
0179     if (isNotExpression
0180         || addressType == Okteta::AddressValidator::InvalidAddressType) {
0181         return;
0182     }
0183 
0184     bool fromCursor = false;
0185     bool backwards = false;
0186 
0187     if (addressType == Okteta::AddressValidator::AbsoluteAddress) {
0188         fromCursor = false;
0189         backwards = false; // TODO: there is no way yet for: absolute from end
0190     } else if (addressType == Okteta::AddressValidator::RelativeForwards) {
0191         fromCursor = true;
0192         backwards = false;
0193     } else if (addressType == Okteta::AddressValidator::RelativeBackwards) {
0194         fromCursor = true;
0195         backwards = true;
0196     }
0197 
0198     mAtCursorCheckBox->setChecked(fromCursor);
0199     mTool->setIsRelative(fromCursor);
0200     mBackwardsCheckBox->setChecked(backwards);
0201     mTool->setIsBackwards(backwards);
0202 }
0203 
0204 void GotoOffsetView::onFormatChanged(int formatIndex)
0205 {
0206     const bool isNotExpression = (formatIndex != Okteta::AddressComboBox::ExpressionCoding);
0207 
0208     mAtCursorCheckBox->setEnabled(isNotExpression);
0209     mBackwardsCheckBox->setEnabled(isNotExpression);
0210 }
0211 
0212 }
0213 
0214 #include "moc_gotooffsetview.cpp"