File indexing completed on 2024-05-12 16:36:08

0001 /* This file is part of the KDE project
0002    Copyright 1999-2006 The KSpread Team <calligra-devel@kde.org>
0003 
0004    This library is free software; you can redistribute it and/or
0005    modify it under the terms of the GNU Library General Public
0006    License as published by the Free Software Foundation; either
0007    version 2 of the License, or (at your option) any later version.
0008 
0009    This library is distributed in the hope that it will be useful,
0010    but WITHOUT ANY WARRANTY; without even the implied warranty of
0011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012    Library General Public License for more details.
0013 
0014    You should have received a copy of the GNU Library General Public License
0015    along with this library; see the file COPYING.LIB.  If not, write to
0016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017    Boston, MA 02110-1301, USA.
0018 */
0019 
0020 #include "LocationComboBox.h"
0021 
0022 // Sheets
0023 #include "CellStorage.h"
0024 #include "Map.h"
0025 #include "NamedAreaManager.h"
0026 #include "Selection.h"
0027 #include "Sheet.h"
0028 #include "SheetsDebug.h"
0029 
0030 #include "commands/NamedAreaCommand.h"
0031 
0032 // Qt
0033 #include <QKeyEvent>
0034 #include <QLineEdit>
0035 
0036 using namespace Calligra::Sheets;
0037 
0038 LocationComboBox::LocationComboBox(QWidget *_parent)
0039         : KComboBox(true, _parent)
0040         , m_selection(0)
0041 {
0042     setCompletionObject(&completionList, true);
0043     setCompletionMode(KCompletion::CompletionAuto);
0044 
0045     connect(this, SIGNAL(activated(QString)),
0046             this, SLOT(slotActivateItem()));
0047 }
0048 
0049 void LocationComboBox::setSelection(Selection *selection)
0050 {
0051     if (m_selection == selection) return;
0052 
0053     completionList.clear();
0054     clear();
0055     if (m_selection) {
0056         if (m_selection->activeSheet()) {
0057             Map *const oldMap = m_selection->activeSheet()->map();
0058             disconnect(oldMap->namedAreaManager(), SIGNAL(namedAreaAdded(QString)), this, SLOT(slotAddAreaName(QString)));
0059             disconnect(oldMap->namedAreaManager(), SIGNAL(namedAreaRemoved(QString)), this, SLOT(slotRemoveAreaName(QString)));
0060         }
0061         disconnect(m_selection, SIGNAL(activeSheetChanged(Sheet*)), this, SLOT(slotActiveSheetChanged(Sheet*)));
0062         disconnect(m_selection, SIGNAL(changed(Region)), this, SLOT(slotSelectionChanged()));
0063     }
0064 
0065     m_selection = selection;
0066 
0067     if (m_selection) {
0068         insertItem(0, QString());
0069         updateAddress();
0070         Sheet* sheet = m_selection->activeSheet();
0071         if (sheet) {
0072             slotActiveSheetChanged(sheet);
0073         } else {
0074             connect(m_selection, SIGNAL(activeSheetChanged(Sheet*)), this, SLOT(slotActiveSheetChanged(Sheet*)));
0075         }
0076         connect(m_selection, SIGNAL(changed(Region)), this, SLOT(slotSelectionChanged()));
0077     }
0078 }
0079 
0080 void LocationComboBox::slotActiveSheetChanged(Sheet *sheet)
0081 {
0082     if (!sheet) return;
0083     disconnect(this, SLOT(slotActiveSheetChanged(Sheet*)));
0084 
0085     Map *const map = sheet->map();
0086     const QList<QString> areaNames = map->namedAreaManager()->areaNames();
0087     for (int i = 0; i < areaNames.count(); ++i)
0088         slotAddAreaName(areaNames[i]);
0089 
0090     connect(map->namedAreaManager(), SIGNAL(namedAreaAdded(QString)), this, SLOT(slotAddAreaName(QString)));
0091     connect(map->namedAreaManager(), SIGNAL(namedAreaRemoved(QString)), this, SLOT(slotRemoveAreaName(QString)));
0092 }
0093 
0094 void LocationComboBox::updateAddress()
0095 {
0096     if (!m_selection) return;
0097 
0098     QString address;
0099     Selection *const selection = m_selection;
0100     Sheet *const sheet = m_selection->activeSheet();
0101     if (sheet) {
0102         const QList< QPair<QRectF, QString> > names = sheet->cellStorage()->namedAreas(*selection);
0103         {
0104             QRect range;
0105             if (selection->isSingular()) range = QRect(selection->marker(), QSize(1, 1));
0106             else range = selection->lastRange();
0107             for (int i = 0; i < names.size(); i++) {
0108                 if (names[i].first.toRect() == range) {
0109                     address = names[i].second;
0110                 }
0111             }
0112         }
0113     }
0114     if (sheet && sheet->getLcMode()) {
0115         if (selection->isSingular()) {
0116             address = 'L' + QString::number(selection->marker().y()) +
0117             'C' + QString::number(selection->marker().x());
0118         } else {
0119             const QRect lastRange = selection->lastRange();
0120             address = QString::number(lastRange.height()) + "Lx";
0121             address += QString::number(lastRange.width()) + 'C';
0122         }
0123     } else {
0124         address = selection->name();
0125     }
0126     setItemText(0, address);
0127     setCurrentItem(0);
0128     lineEdit()->setText(address);
0129 }
0130 
0131 void LocationComboBox::slotAddAreaName(const QString &_name)
0132 {
0133     insertItem(count(), _name);
0134     addCompletionItem(_name);
0135 }
0136 
0137 void LocationComboBox::slotRemoveAreaName(const QString &_name)
0138 {
0139     for (int i = 0; i < count(); i++) {
0140         if (itemText(i) == _name) {
0141             removeItem(i);
0142             break;
0143         }
0144     }
0145     removeCompletionItem(_name);
0146 }
0147 
0148 void LocationComboBox::addCompletionItem(const QString &_item)
0149 {
0150     if (completionList.items().contains(_item) == 0) {
0151         completionList.addItem(_item);
0152         debugSheetsUI << _item;
0153     }
0154 }
0155 
0156 void LocationComboBox::removeCompletionItem(const QString &_item)
0157 {
0158     completionList.removeItem(_item);
0159 }
0160 
0161 void LocationComboBox::slotActivateItem()
0162 {
0163     if (!m_selection) return;
0164 
0165     if (activateItem()) {
0166         m_selection->scrollToCursor();
0167     }
0168 }
0169 
0170 bool LocationComboBox::activateItem()
0171 {
0172     if (!m_selection) return false;
0173 
0174     Selection *const selection = m_selection;
0175 
0176     // Set the focus back on the canvas.
0177     parentWidget()->setFocus();
0178 
0179     const QString text = lineEdit()->text();
0180     // check whether an already existing named area was entered
0181     Region region = selection->activeSheet()->map()->namedAreaManager()->namedArea(text);
0182     if (region.isValid()) {
0183         // TODO Stefan: Merge the sheet change into Selection.
0184         if (region.firstSheet() != selection->activeSheet()) {
0185             selection->emitVisibleSheetRequested(region.firstSheet());
0186         }
0187         selection->initialize(region);
0188         return true;
0189     }
0190 
0191     // check whether a valid cell region was entered
0192     region = Region(text, selection->activeSheet()->map(), selection->activeSheet());
0193     if (region.isValid()) {
0194         // TODO Stefan: Merge the sheet change into Selection.
0195         if (region.firstSheet() != selection->activeSheet()) {
0196             selection->emitVisibleSheetRequested(region.firstSheet());
0197         }
0198         selection->initialize(region);
0199         return true;
0200     }
0201 
0202     // A name for an area entered?
0203     // FIXME Stefan: allow all characters
0204     bool validName = true;
0205     for (int i = 0; i < text.length(); ++i) {
0206         if (!text[i].isLetter()) {
0207             validName = false;
0208             break;
0209         }
0210     }
0211     if (validName) {
0212         NamedAreaCommand* command = new NamedAreaCommand();
0213         command->setSheet(selection->activeSheet());
0214         command->setAreaName(text);
0215         command->add(Region(selection->lastRange(), selection->activeSheet()));
0216         if (command->execute())
0217             return true;
0218         else
0219             delete command;
0220     }
0221     return false;
0222 }
0223 
0224 
0225 void LocationComboBox::keyPressEvent(QKeyEvent * _ev)
0226 {
0227     if (!m_selection) return;
0228 
0229     Selection *const selection = m_selection;
0230 
0231     // Do not handle special keys and accelerators. This is
0232     // done by KComboBox.
0233     if (_ev->modifiers() & (Qt::AltModifier | Qt::ControlModifier)) {
0234         KComboBox::keyPressEvent(_ev);
0235         // Never allow that keys are passed on to the parent.
0236         _ev->accept(); // QKeyEvent
0237 
0238         return;
0239     }
0240 
0241     // Handle some special keys here. Eve
0242     switch (_ev->key()) {
0243     case Qt::Key_Return:
0244     case Qt::Key_Enter: {
0245         if (activateItem()) {
0246             selection->scrollToCursor();
0247             return;
0248         }
0249         _ev->accept(); // QKeyEvent
0250     }
0251     break;
0252     // Escape pressed, restore original value
0253     case Qt::Key_Escape:
0254         updateAddress();
0255         parentWidget()->setFocus();
0256         _ev->accept(); // QKeyEvent
0257         break;
0258     default:
0259         KComboBox::keyPressEvent(_ev);
0260         // Never allow that keys are passed on to the parent.
0261         _ev->accept(); // QKeyEvent
0262     }
0263 }
0264 
0265 void LocationComboBox::slotSelectionChanged()
0266 {
0267     if (!m_selection->referenceSelectionMode()) {
0268         updateAddress();
0269     }
0270 }