• Skip to content
  • Skip to link menu
KDE 4.1 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KDEUI

keditlistbox.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE libraries
00002    Copyright (C) 2000 David Faure <faure@kde.org>, Alexander Neundorf <neundorf@kde.org>
00003    2000, 2002 Carsten Pfeiffer <pfeiffer@kde.org>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018    Boston, MA 02110-1301, USA.
00019 */
00020 
00021 #include "keditlistbox.h"
00022 
00023 #include <QtCore/QStringList>
00024 #include <QtGui/QKeyEvent>
00025 #include <QtGui/QLabel>
00026 #include <QtGui/QLayout>
00027 #include <QtGui/QListView>
00028 
00029 #include <kcombobox.h>
00030 #include <kdebug.h>
00031 #include <kdialog.h>
00032 #include <klineedit.h>
00033 #include <klocale.h>
00034 #include <knotification.h>
00035 #include <kpushbutton.h>
00036 
00037 #include <assert.h>
00038 
00039 class KEditListBoxPrivate
00040 {
00041 public:
00042     KEditListBoxPrivate( KEditListBox* parent )
00043         : lineEdit(0),
00044           editingWidget(0),
00045           q(parent) {
00046     }
00047     QListView *listView;
00048     QPushButton *servUpButton, *servDownButton;
00049     QPushButton *servNewButton, *servRemoveButton;
00050     KLineEdit *lineEdit;
00051     QWidget* editingWidget;
00052     QGridLayout* mainLayout;
00053     QStringListModel *model;
00054 
00055     bool checkAtEntering;
00056     KEditListBox::Buttons buttons;
00057 
00058     void init( bool checkAtEntering = false, KEditListBox::Buttons buttons = KEditListBox::All,
00059                QWidget *representationWidget = 0 );
00060     void setEditor( KLineEdit* lineEdit, QWidget* representationWidget = 0 );
00061     void updateButtonState();
00062     QModelIndex selectedIndex();
00063 
00064 private:
00065     KEditListBox* q;
00066 };
00067 
00068 
00069 void KEditListBoxPrivate::init( bool checkAtEntering, KEditListBox::Buttons newButtons,
00070                                 QWidget *representationWidget )
00071 {
00072     checkAtEntering = checkAtEntering;
00073 
00074     servNewButton = servRemoveButton = servUpButton = servDownButton = 0L;
00075     q->setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding,
00076                                  QSizePolicy::MinimumExpanding));
00077 
00078     mainLayout = new QGridLayout(q);
00079     mainLayout->setMargin( KDialog::marginHint() );
00080     mainLayout->setSpacing( KDialog::spacingHint() );
00081     mainLayout->setRowStretch( 6, 1 );
00082 
00083     model = new QStringListModel();
00084     listView = new QListView(q);
00085 
00086     listView->setModel(model);
00087 
00088     mainLayout->addWidget(listView, 2, 0, 5, 1);
00089 
00090     setEditor( lineEdit, representationWidget );
00091 
00092     buttons = 0;
00093     q->setButtons( newButtons );
00094 
00095     q->connect(listView->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
00096                SLOT(slotSelectionChanged(const QItemSelection&, const QItemSelection&)));
00097 }
00098 
00099 
00100 void KEditListBoxPrivate::setEditor( KLineEdit* newLineEdit, QWidget* representationWidget )
00101 {
00102     if (editingWidget != lineEdit &&
00103         editingWidget != representationWidget) {
00104         delete editingWidget;
00105     }
00106     if (lineEdit != newLineEdit) {
00107         delete lineEdit;
00108     }
00109     lineEdit = newLineEdit ? newLineEdit : new KLineEdit(q);
00110     editingWidget = representationWidget ?
00111                     representationWidget : lineEdit;
00112 
00113     if ( representationWidget )
00114         representationWidget->setParent(q);
00115 
00116     mainLayout->addWidget(editingWidget,1,0,1,2);
00117 
00118     lineEdit->setTrapReturnKey(true);
00119     lineEdit->installEventFilter(q);
00120 
00121     q->connect(lineEdit,SIGNAL(textChanged(const QString&)),SLOT(typedSomething(const QString&)));
00122     q->connect(lineEdit,SIGNAL(returnPressed()),SLOT(addItem()));
00123 
00124     // maybe supplied lineedit has some text already
00125     q->typedSomething( lineEdit->text() );
00126 
00127 
00128     // fix tab ordering
00129     q->setTabOrder(editingWidget, listView);
00130     QWidget* w = listView;
00131     if (servNewButton) {
00132         q->setTabOrder(w,servNewButton);
00133         w = servNewButton;
00134     }
00135     if (servRemoveButton) {
00136         q->setTabOrder(w,servRemoveButton);
00137         w = servRemoveButton;
00138     }
00139     if (servUpButton) {
00140         q->setTabOrder(w,servUpButton);
00141         w = servUpButton;
00142     }
00143     if (servDownButton) {
00144         q->setTabOrder(w,servDownButton);
00145         w = servDownButton;
00146     }
00147 }
00148 
00149 
00150 void KEditListBoxPrivate::updateButtonState()
00151 {
00152     QModelIndex index = selectedIndex();
00153     if (servUpButton) {
00154         servUpButton->setEnabled(index.isValid());
00155     }
00156     if (servDownButton) {
00157         servDownButton->setEnabled(index.isValid());
00158     }
00159     if (servRemoveButton) {
00160         servRemoveButton->setEnabled(index.isValid());
00161     }
00162 }
00163 
00164 QModelIndex KEditListBoxPrivate::selectedIndex()
00165 {
00166     QItemSelectionModel *selection = listView->selectionModel();
00167     const QModelIndexList selectedIndexes = selection->selectedIndexes();
00168     if ( !selectedIndexes.isEmpty() && selectedIndexes[0].isValid() )
00169         return selectedIndexes[0];
00170     else
00171         return QModelIndex();
00172 }
00173 
00174 
00175 class KEditListBox::CustomEditorPrivate
00176 {
00177 public:
00178     CustomEditorPrivate(KEditListBox::CustomEditor *q):
00179         q(q),
00180         representationWidget(0),
00181         lineEdit(0) {}
00182 
00183     KEditListBox::CustomEditor *q;
00184     QWidget *representationWidget;
00185     KLineEdit *lineEdit;
00186 };
00187 
00188 KEditListBox::CustomEditor::CustomEditor()
00189     : d(new CustomEditorPrivate(this))
00190 {
00191 }
00192 
00193 KEditListBox::CustomEditor::CustomEditor( QWidget *repWidget, KLineEdit *edit )
00194     : d(new CustomEditorPrivate(this))
00195 {
00196     d->representationWidget = repWidget;
00197     d->lineEdit = edit;
00198 }
00199 
00200 KEditListBox::CustomEditor::CustomEditor( KComboBox *combo )
00201     : d(new CustomEditorPrivate(this))
00202 {
00203     d->representationWidget = combo;
00204     d->lineEdit = qobject_cast<KLineEdit*>( combo->lineEdit() );
00205     Q_ASSERT( d->lineEdit );
00206 }
00207 
00208 KEditListBox::CustomEditor::~CustomEditor()
00209 {
00210     delete d;
00211 }
00212 
00213 void KEditListBox::CustomEditor::setRepresentationWidget( QWidget *repWidget )
00214 {
00215     d->representationWidget = repWidget;
00216 }
00217 
00218 void KEditListBox::CustomEditor::setLineEdit( KLineEdit *edit )
00219 {
00220     d->lineEdit = edit;
00221 }
00222 
00223 QWidget *KEditListBox::CustomEditor::representationWidget() const
00224 {
00225     return d->representationWidget;
00226 }
00227 
00228 KLineEdit *KEditListBox::CustomEditor::lineEdit() const
00229 {
00230     return d->lineEdit;
00231 }
00232 
00233 KEditListBox::KEditListBox(QWidget *parent)
00234     : QGroupBox(parent), d(new KEditListBoxPrivate(this))
00235 {
00236     d->init();
00237 }
00238 
00239 KEditListBox::KEditListBox(const QString &title, QWidget *parent)
00240     :QGroupBox(title, parent), d(new KEditListBoxPrivate(this))
00241 {
00242     d->init();
00243 }
00244 
00245 KEditListBox::KEditListBox(QWidget *parent, const char *name,
00246                            bool checkAtEntering, Buttons buttons )
00247     :QGroupBox(parent ), d(new KEditListBoxPrivate(this))
00248 {
00249     setObjectName(name);
00250     d->init( checkAtEntering, buttons );
00251 }
00252 
00253 KEditListBox::KEditListBox(const QString& title, QWidget *parent,
00254                            const char *name, bool checkAtEntering, Buttons buttons)
00255     :QGroupBox(title, parent ), d(new KEditListBoxPrivate(this))
00256 {
00257     setObjectName(name);
00258     d->init( checkAtEntering, buttons );
00259 }
00260 
00261 KEditListBox::KEditListBox(const QString& title, const CustomEditor& custom,
00262                            QWidget *parent, const char *name,
00263                            bool checkAtEntering, Buttons buttons)
00264     :QGroupBox(title, parent), d(new KEditListBoxPrivate(this))
00265 {
00266     setObjectName(name);
00267     d->lineEdit = custom.lineEdit();
00268     d->init( checkAtEntering, buttons, custom.representationWidget() );
00269 }
00270 
00271 KEditListBox::~KEditListBox()
00272 {
00273     delete d;
00274 }
00275 
00276 void KEditListBox::setCustomEditor( const CustomEditor& editor )
00277 {
00278     d->setEditor( editor.lineEdit(), editor.representationWidget() );
00279 }
00280 
00281 QListView *KEditListBox::listView() const
00282 {
00283     return d->listView;
00284 }
00285 
00286 KLineEdit *KEditListBox::lineEdit() const
00287 {
00288     return d->lineEdit;
00289 }
00290 
00291 QPushButton *KEditListBox::addButton() const
00292 {
00293     return d->servNewButton;
00294 }
00295 
00296 QPushButton *KEditListBox::removeButton() const
00297 {
00298     return d->servRemoveButton;
00299 }
00300 
00301 QPushButton *KEditListBox::upButton() const
00302 {
00303     return d->servUpButton;
00304 }
00305 
00306 QPushButton *KEditListBox::downButton() const
00307 {
00308     return d->servDownButton;
00309 }
00310 
00311 int KEditListBox::count() const
00312 {
00313     return int(d->model->rowCount());
00314 }
00315 
00316 void KEditListBox::setButtons( Buttons buttons )
00317 {
00318     if ( d->buttons == buttons )
00319         return;
00320 
00321     QGridLayout* grid = static_cast<QGridLayout *>( layout() );
00322     if ( ( buttons & Add ) && !d->servNewButton ) {
00323         d->servNewButton = new KPushButton(KIcon("list-add"), i18n("&Add"), this);
00324         d->servNewButton->setEnabled(false);
00325         d->servNewButton->show();
00326         connect(d->servNewButton, SIGNAL(clicked()), SLOT(addItem()));
00327 
00328         grid->addWidget(d->servNewButton, 2, 1);
00329     } else if ( ( buttons & Add ) == 0 && d->servNewButton ) {
00330         delete d->servNewButton;
00331         d->servNewButton = 0;
00332     }
00333 
00334     if ( ( buttons & Remove ) && !d->servRemoveButton ) {
00335         d->servRemoveButton = new KPushButton(KIcon("list-remove"), i18n("&Remove"), this);
00336         d->servRemoveButton->setEnabled(false);
00337         d->servRemoveButton->show();
00338         connect(d->servRemoveButton, SIGNAL(clicked()), SLOT(removeItem()));
00339 
00340         grid->addWidget(d->servRemoveButton, 3, 1);
00341     } else if ( ( buttons & Remove ) == 0 && d->servRemoveButton ) {
00342         delete d->servRemoveButton;
00343         d->servRemoveButton = 0;
00344     }
00345 
00346     if ( ( buttons & UpDown ) && !d->servUpButton ) {
00347         d->servUpButton = new KPushButton(KIcon("arrow-up"), i18n("Move &Up"), this);
00348         d->servUpButton->setEnabled(false);
00349         d->servUpButton->show();
00350         connect(d->servUpButton, SIGNAL(clicked()), SLOT(moveItemUp()));
00351 
00352         d->servDownButton = new KPushButton(KIcon("arrow-down"), i18n("Move &Down"), this);
00353         d->servDownButton->setEnabled(false);
00354         d->servDownButton->show();
00355         connect(d->servDownButton, SIGNAL(clicked()), SLOT(moveItemDown()));
00356 
00357         grid->addWidget(d->servUpButton, 4, 1);
00358         grid->addWidget(d->servDownButton, 5, 1);
00359     } else if ( ( buttons & UpDown ) == 0 && d->servUpButton ) {
00360         delete d->servUpButton; d->servUpButton = 0;
00361         delete d->servDownButton; d->servDownButton = 0;
00362     }
00363 
00364     d->buttons = buttons;
00365 }
00366 
00367 void KEditListBox::setCheckAtEntering(bool check)
00368 {
00369     d->checkAtEntering = check;
00370 }
00371 
00372 bool KEditListBox::checkAtEntering()
00373 {
00374     return d->checkAtEntering;
00375 }
00376 
00377 void KEditListBox::typedSomething(const QString& text)
00378 {
00379     if(currentItem() >= 0) {
00380         if(currentText() != d->lineEdit->text())
00381         {
00382             // IMHO changeItem() shouldn't do anything with the value
00383             // of currentItem() ... like changing it or emitting signals ...
00384             // but TT disagree with me on this one (it's been that way since ages ... grrr)
00385             bool block = d->listView->signalsBlocked();
00386             d->listView->blockSignals( true );
00387             QModelIndex currentIndex = d->selectedIndex();
00388             if ( currentIndex.isValid() )
00389               d->model->setData(currentIndex,text);
00390             d->listView->blockSignals( block );
00391             emit changed();
00392         }
00393     }
00394 
00395     if ( !d->servNewButton )
00396         return;
00397 
00398     if (!d->checkAtEntering)
00399         d->servNewButton->setEnabled(!text.isEmpty());
00400     else
00401     {
00402         if (text.isEmpty())
00403         {
00404             d->servNewButton->setEnabled(false);
00405         }
00406         else
00407         {
00408             QStringList list = d->model->stringList();
00409             bool enable = !list.contains( text, Qt::CaseSensitive );
00410             d->servNewButton->setEnabled( enable );
00411         }
00412     }
00413 }
00414 
00415 void KEditListBox::moveItemUp()
00416 {
00417     if (!d->listView->isEnabled())
00418     {
00419         KNotification::beep();
00420         return;
00421     }
00422 
00423     QModelIndex index = d->selectedIndex();
00424     if ( index.isValid() ) {
00425       if (index.row() == 0) {
00426           KNotification::beep();
00427           return;
00428       }
00429 
00430       QModelIndex aboveIndex = d->model->index( index.row() - 1, index.column() );
00431 
00432       QString tmp = d->model->data( aboveIndex, Qt::DisplayRole ).toString();
00433       d->model->setData( aboveIndex, d->model->data( index, Qt::DisplayRole ) );
00434       d->model->setData( index, tmp );
00435 
00436       d->listView->selectionModel()->select(index, QItemSelectionModel::Deselect);
00437       d->listView->selectionModel()->select(aboveIndex, QItemSelectionModel::Select);
00438     }
00439 
00440     emit changed();
00441 }
00442 
00443 void KEditListBox::moveItemDown()
00444 {
00445     if (!d->listView->isEnabled())
00446     {
00447         KNotification::beep();
00448         return;
00449     }
00450 
00451     QModelIndex index = d->selectedIndex();
00452     if ( index.isValid() ) {
00453       if (index.row() == d->model->rowCount() - 1) {
00454           KNotification::beep();
00455           return;
00456       }
00457 
00458       QModelIndex belowIndex = d->model->index( index.row() + 1, index.column() );
00459 
00460       QString tmp = d->model->data( belowIndex, Qt::DisplayRole ).toString();
00461       d->model->setData( belowIndex, d->model->data( index, Qt::DisplayRole ) );
00462       d->model->setData( index, tmp );
00463 
00464       d->listView->selectionModel()->select(index, QItemSelectionModel::Deselect);
00465       d->listView->selectionModel()->select(belowIndex, QItemSelectionModel::Select);
00466     }
00467 
00468     emit changed();
00469 }
00470 
00471 void KEditListBox::addItem()
00472 {
00473     // when checkAtEntering is true, the add-button is disabled, but this
00474     // slot can still be called through Key_Return/Key_Enter. So we guard
00475     // against this.
00476     if ( !d->servNewButton || !d->servNewButton->isEnabled() )
00477         return;
00478 
00479     QModelIndex currentIndex = d->selectedIndex();
00480 
00481     const QString& currentTextLE=d->lineEdit->text();
00482     bool alreadyInList(false);
00483     //if we didn't check for dupes at the inserting we have to do it now
00484     if (!d->checkAtEntering)
00485     {
00486         // first check current item instead of dumb iterating the entire list
00487         if ( currentIndex.isValid() ) {
00488           if ( d->model->data( currentIndex, Qt::DisplayRole ).toString() == currentTextLE )
00489             alreadyInList = true;
00490         }
00491         else
00492         {
00493             alreadyInList = d->model->stringList().contains( currentTextLE, Qt::CaseSensitive );
00494         }
00495     }
00496     if ( d->servNewButton )
00497         d->servNewButton->setEnabled(false);
00498 
00499     bool block = d->lineEdit->signalsBlocked();
00500     d->lineEdit->blockSignals(true);
00501     d->lineEdit->clear();
00502     d->lineEdit->blockSignals(block);
00503 
00504     d->listView->selectionModel()->setCurrentIndex(currentIndex, QItemSelectionModel::Deselect);
00505 
00506     if (!alreadyInList)
00507     {
00508         block = d->listView->signalsBlocked();
00509 
00510         if ( currentIndex.isValid() ) {
00511           d->model->setData(currentIndex, currentTextLE );
00512         } else {
00513             QStringList lst;
00514             lst<<currentTextLE;
00515             lst<<d->model->stringList();
00516             d->model->setStringList(lst);
00517         }
00518         emit changed();
00519         emit added( currentTextLE );
00520     }
00521 
00522     d->updateButtonState();
00523 }
00524 
00525 int KEditListBox::currentItem() const
00526 {
00527     QModelIndex selectedIndex = d->selectedIndex();
00528     if ( selectedIndex.isValid() )
00529         return selectedIndex.row();
00530     else
00531         return -1;
00532 }
00533 
00534 void KEditListBox::removeItem()
00535 {
00536     QModelIndex currentIndex = d->selectedIndex();
00537     if ( !currentIndex.isValid() )
00538       return;
00539 
00540     if ( currentIndex.row() >= 0 )
00541     {
00542         QString removedText = d->model->data( currentIndex, Qt::DisplayRole ).toString();
00543 
00544         d->model->removeRows( currentIndex.row(), 1 );
00545 
00546         d->listView->selectionModel()->clear();
00547 
00548         emit changed();
00549 
00550         emit removed( removedText );
00551     }
00552 
00553     d->updateButtonState();
00554 }
00555 
00556 void KEditListBox::enableMoveButtons(const QModelIndex &newIndex, const QModelIndex&)
00557 {
00558     int index = newIndex.row();
00559 
00560     // Update the lineEdit when we select a different line.
00561     if(currentText() != d->lineEdit->text())
00562         d->lineEdit->setText(currentText());
00563 
00564     bool moveEnabled = d->servUpButton && d->servDownButton;
00565 
00566     if (moveEnabled )
00567     {
00568         if (d->model->rowCount() <= 1)
00569         {
00570             d->servUpButton->setEnabled(false);
00571             d->servDownButton->setEnabled(false);
00572         }
00573         else if (index == (d->model->rowCount() - 1))
00574         {
00575             d->servUpButton->setEnabled(true);
00576             d->servDownButton->setEnabled(false);
00577         }
00578         else if (index == 0)
00579         {
00580             d->servUpButton->setEnabled(false);
00581             d->servDownButton->setEnabled(true);
00582         }
00583         else
00584         {
00585             d->servUpButton->setEnabled(true);
00586             d->servDownButton->setEnabled(true);
00587         }
00588     }
00589 
00590     if ( d->servRemoveButton )
00591         d->servRemoveButton->setEnabled(true);
00592 }
00593 
00594 void KEditListBox::clear()
00595 {
00596     d->lineEdit->clear();
00597     d->model->setStringList( QStringList() );
00598     emit changed();
00599 }
00600 
00601 void KEditListBox::insertStringList(const QStringList& list, int index)
00602 {
00603     QStringList content = d->model->stringList();
00604     if ( index > content.count() )
00605       content += list;
00606     else
00607       for ( int i = 0, j = index; i < list.count(); ++i, ++j )
00608         content.insert( j, list[ i ] );
00609 
00610     d->model->setStringList( content );
00611 }
00612 
00613 void KEditListBox::insertItem(const QString& text, int index)
00614 {
00615   QStringList list = d->model->stringList();
00616 
00617   if ( index == -1 )
00618     list.append( text );
00619   else
00620     list.insert( index, text );
00621 
00622   d->model->setStringList(list);
00623 }
00624 
00625 QString KEditListBox::text(int index) const
00626 {
00627   const QStringList list = d->model->stringList();
00628 
00629   return list[ index ];
00630 }
00631 
00632 QString KEditListBox::currentText() const
00633 {
00634   QModelIndex index = d->selectedIndex();
00635   if ( !index.isValid() )
00636     return QString();
00637   else
00638     return text( index.row() );
00639 }
00640 
00641 QStringList KEditListBox::items() const
00642 {
00643     return d->model->stringList();
00644 }
00645 
00646 void KEditListBox::setItems(const QStringList& items)
00647 {
00648   d->model->setStringList(items);
00649 }
00650 
00651 KEditListBox::Buttons KEditListBox::buttons() const
00652 {
00653   return d->buttons;
00654 }
00655 
00656 void KEditListBox::slotSelectionChanged( const QItemSelection&, const QItemSelection& )
00657 {
00658     d->updateButtonState();
00659     QModelIndex index = d->selectedIndex();
00660     enableMoveButtons(index,  QModelIndex());
00661     if (index.isValid()) {
00662         d->lineEdit->setFocus( Qt::OtherFocusReason );
00663     }
00664 }
00665 
00666 bool KEditListBox::eventFilter( QObject* o, QEvent* e )
00667 {
00668     if (o == d->lineEdit && e->type() == QEvent::KeyPress ) {
00669         QKeyEvent* keyEvent = (QKeyEvent*)e;
00670         if (keyEvent->key() == Qt::Key_Down ||
00671             keyEvent->key() == Qt::Key_Up) {
00672             return ((QObject*)d->listView)->event(e);
00673         }
00674     }
00675 
00676     return false;
00677 }
00678 
00679 #include "keditlistbox.moc"

KDEUI

Skip menu "KDEUI"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • KIO
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal