+BufferViewDock::BufferViewDock(BufferViewConfig* config, QWidget* parent)
+ : QDockWidget(parent)
+ , _childWidget(nullptr)
+ , _widget(new QWidget(parent))
+ , _filterEdit(new QLineEdit(parent))
+ , _active(false)
+ , _title(config->bufferViewName())
+{
+ setObjectName("BufferViewDock-" + QString::number(config->bufferViewId()));
+ toggleViewAction()->setData(config->bufferViewId());
+ setAllowedAreas(Qt::RightDockWidgetArea | Qt::LeftDockWidgetArea);
+ connect(config, &BufferViewConfig::bufferViewNameSet, this, &BufferViewDock::bufferViewRenamed);
+ connect(config, &BufferViewConfig::configChanged, this, &BufferViewDock::configChanged);
+ updateTitle();
+
+ _widget->setLayout(new QVBoxLayout);
+ _widget->layout()->setSpacing(0);
+ _widget->layout()->setContentsMargins(0, 0, 0, 0);
+
+ // We need to potentially hide it early, so it doesn't flicker
+ _filterEdit->setVisible(config->showSearch());
+ _filterEdit->setFocusPolicy(Qt::ClickFocus);
+ _filterEdit->installEventFilter(this);
+ _filterEdit->setPlaceholderText(tr("Search..."));
+ connect(_filterEdit, &QLineEdit::returnPressed, this, &BufferViewDock::onFilterReturnPressed);
+
+ _widget->layout()->addWidget(_filterEdit);
+ QDockWidget::setWidget(_widget);
+}
+
+void BufferViewDock::setLocked(bool locked)
+{
+ if (locked) {
+ setFeatures(nullptr);
+ }
+ else {
+ setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable);
+ }
+}
+
+void BufferViewDock::updateTitle()
+{
+ QString title = _title;
+ if (isActive())
+ title.prepend(QString::fromUtf8("• "));
+ setWindowTitle(title);
+}
+
+void BufferViewDock::configChanged()
+{
+ if (_filterEdit->isVisible() != config()->showSearch()) {
+ _filterEdit->setVisible(config()->showSearch());
+ _filterEdit->clear();
+ }
+}
+
+void BufferViewDock::onFilterReturnPressed()
+{
+ if (_oldFocusItem) {
+ _oldFocusItem->setFocus();
+ _oldFocusItem = nullptr;
+ }
+
+ if (!config()->showSearch()) {
+ _filterEdit->setVisible(false);
+ }
+
+ BufferView* view = bufferView();
+ if (!view) {
+ return;
+ }
+
+ if (!_filterEdit->text().isEmpty()) {
+ view->selectHighlighted();
+ _filterEdit->clear();
+ }
+ else {
+ view->clearHighlight();
+ }
+}
+
+void BufferViewDock::setActive(bool active)
+{
+ if (active != isActive()) {
+ _active = active;
+ updateTitle();
+ if (active) {
+ raise(); // for tabbed docks
+ }
+ }
+}
+
+bool BufferViewDock::eventFilter(QObject* object, QEvent* event)
+{
+ if (object != _filterEdit) {
+ return false;
+ }
+
+ if (event->type() == QEvent::FocusOut) {
+ if (!config()->showSearch() && _filterEdit->text().isEmpty()) {
+ _filterEdit->setVisible(false);
+ return true;
+ }
+ }
+ else if (event->type() == QEvent::KeyRelease) {
+ auto keyEvent = static_cast<QKeyEvent*>(event);
+
+ BufferView* view = bufferView();
+ if (!view) {
+ return false;
+ }
+
+ switch (keyEvent->key()) {
+ case Qt::Key_Escape: {
+ _filterEdit->clear();
+
+ if (!_oldFocusItem) {
+ return false;
+ }
+
+ _oldFocusItem->setFocus();
+ _oldFocusItem = nullptr;
+ return true;
+ }
+ case Qt::Key_Down:
+ view->changeHighlight(BufferView::Backward);
+ return true;
+ case Qt::Key_Up:
+ view->changeHighlight(BufferView::Forward);
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+ }
+
+ return false;
+}
+
+void BufferViewDock::bufferViewRenamed(const QString& newName)