/*************************************************************************** * Copyright (C) 2006 by Vladimir Kuznetsov * * vovanec@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * ***************************************************************************/ #include #include #include #include #include "termwidgetholder.h" #include "tabwidget.h" #include "config.h" #include "properties.h" #define TAB_INDEX_PROPERTY "tab_index" TabWidget::TabWidget(QWidget* parent) : QTabWidget(parent), tabNumerator(0) { setFocusPolicy(Qt::NoFocus); /* On Mac OS X this will look similar to * the tabs in Safari or Leopard's Terminal.app . * I love this! */ setDocumentMode(true); tabBar()->setUsesScrollButtons(true); setTabsClosable(true); setMovable(true); setUsesScrollButtons(true); tabBar()->installEventFilter(this); connect(this, SIGNAL(tabCloseRequested(int)), this, SLOT(removeTab(int))); connect(tabBar(), SIGNAL(tabMoved(int,int)), this, SLOT(updateTabIndices())); connect(this, SIGNAL(tabRenameRequested(int)), this, SLOT(renameSession(int))); } TermWidgetHolder * TabWidget::terminalHolder() { return reinterpret_cast(widget(currentIndex())); } void TabWidget::setWorkDirectory(const QString& dir) { this->work_dir = dir; } int TabWidget::addNewTab(const QString & shell_program) { tabNumerator++; QString label = QString(tr("Shell No. %1")).arg(tabNumerator); TermWidgetHolder *ch = terminalHolder(); QString cwd(work_dir); if (Properties::Instance()->useCWD && ch) { cwd = ch->currentTerminal()->impl()->workingDirectory(); if (cwd.isEmpty()) cwd = work_dir; } TermWidgetHolder *console = new TermWidgetHolder(cwd, shell_program, this); connect(console, SIGNAL(finished()), SLOT(removeFinished())); connect(console, SIGNAL(lastTerminalClosed()), this, SLOT(removeFinished())); int index = addTab(console, label); updateTabIndices(); setCurrentIndex(index); console->setInitialFocus(); showHideTabBar(); return index; } void TabWidget::switchNextSubterminal() { terminalHolder()->switchNextSubterminal(); } void TabWidget::switchPrevSubterminal() { terminalHolder()->switchPrevSubterminal(); } void TabWidget::splitHorizontally() { terminalHolder()->splitHorizontal(terminalHolder()->currentTerminal()); } void TabWidget::splitVertically() { terminalHolder()->splitVertical(terminalHolder()->currentTerminal()); } void TabWidget::splitCollapse() { terminalHolder()->splitCollapse(terminalHolder()->currentTerminal()); } void TabWidget::copySelection() { terminalHolder()->currentTerminal()->impl()->copyClipboard(); } void TabWidget::pasteClipboard() { terminalHolder()->currentTerminal()->impl()->pasteClipboard(); } void TabWidget::pasteSelection() { terminalHolder()->currentTerminal()->impl()->pasteSelection(); } void TabWidget::zoomIn() { terminalHolder()->currentTerminal()->impl()->zoomIn(); } void TabWidget::zoomOut() { terminalHolder()->currentTerminal()->impl()->zoomOut(); } void TabWidget::zoomReset() { terminalHolder()->currentTerminal()->impl()->zoomReset(); } void TabWidget::updateTabIndices() { for(int i = 0; i < count(); i++) widget(i)->setProperty(TAB_INDEX_PROPERTY, i); } void TabWidget::renameSession(int index) { bool ok = false; QString text = QInputDialog::getText(this, tr("Tab name"), tr("New tab name:"), QLineEdit::Normal, QString(), &ok); if(ok && !text.isEmpty()) { setTabText(index, text); } } void TabWidget::renameTabsAfterRemove() { // it breaks custom names - it replaces original/custom title with shell no # #if 0 for(int i = 0; i < count(); i++) { setTabText(i, QString(tr("Shell No. %1")).arg(i+1)); } #endif } void TabWidget::contextMenuEvent ( QContextMenuEvent * event ) { QMenu menu(this); QAction *close = menu.addAction(QIcon::fromTheme("document-close"), tr("Close session")); QAction *rename = menu.addAction(tr("Rename session")); rename->setShortcut(tr(RENAME_SESSION_SHORTCUT)); int tabIndex = tabBar()->tabAt(event->pos()); QAction *action = menu.exec(event->globalPos()); if (action == close) { emit tabCloseRequested(tabIndex); } else if (action == rename) { emit tabRenameRequested(tabIndex); } } bool TabWidget::eventFilter(QObject *obj, QEvent *event) { if (event->type() == QEvent::MouseButtonDblClick) { QMouseEvent *e = reinterpret_cast(event); // if user doubleclicks on tab button - rename it. If user // clicks on free space - open new tab int index = tabBar()->tabAt(e->pos()); if (index == -1) addNewTab(); else renameSession(index); return true; } return QTabWidget::eventFilter(obj, event); } void TabWidget::removeFinished() { QObject* term = sender(); QVariant prop = term->property(TAB_INDEX_PROPERTY); if(prop.isValid() && prop.canConvert(QVariant::Int)) { int index = prop.toInt(); removeTab(index); // if (count() == 0) // emit closeTabNotification(); } } void TabWidget::removeTab(int index) { setUpdatesEnabled(false); QWidget * w = widget(index); QTabWidget::removeTab(index); w->deleteLater(); updateTabIndices(); int current = currentIndex(); if (current >= 0 ) { qobject_cast(widget(current))->setInitialFocus(); } // do not decrease it as renaming is disabled in renameTabsAfterRemove // tabNumerator--; setUpdatesEnabled(true); if (count() == 0) emit closeTabNotification(); renameTabsAfterRemove(); showHideTabBar(); } void TabWidget::removeCurrentTab() { // question disabled due user requests. Yes I agree it was anoying. // if (QMessageBox::question(this, // tr("Close current session"), // tr("Are you sure you want to close current sesstion?"), // QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) // { if (count() > 1) { removeTab(currentIndex()); } else { emit closeTabNotification(); } } int TabWidget::switchToRight() { int next_pos = currentIndex() + 1; if (next_pos < count()) setCurrentIndex(next_pos); else setCurrentIndex(0); return currentIndex(); } int TabWidget::switchToLeft() { int previous_pos = currentIndex() - 1; if (previous_pos < 0) setCurrentIndex(count() - 1); else setCurrentIndex(previous_pos); return currentIndex(); } void TabWidget::move(Direction dir) { if(count() > 1) { int index = currentIndex(); QWidget* child = widget(index); QString label = tabText(index); QString toolTip = tabToolTip(index); QIcon icon = tabIcon(index); int newIndex = 0; if(dir == Left) if(index == 0) newIndex = count() -1; else newIndex = index - 1; else if(index == count() - 1) newIndex = 0; else newIndex = index + 1; setUpdatesEnabled(false); QTabWidget::removeTab(index); newIndex = insertTab(newIndex, child, label); setTabToolTip(newIndex, toolTip); setTabIcon(newIndex, icon); setUpdatesEnabled(true); setCurrentIndex(newIndex); child->setFocus(); updateTabIndices(); } } void TabWidget::moveLeft() { move(Left); } void TabWidget::moveRight() { move(Right); } void TabWidget::changeScrollPosition(QAction *triggered) { QActionGroup *scrollPosition = static_cast(sender()); if(!scrollPosition) qFatal("scrollPosition is NULL"); Properties::Instance()->scrollBarPos = scrollPosition->actions().indexOf(triggered); Properties::Instance()->saveSettings(); propertiesChanged(); } void TabWidget::changeTabPosition(QAction *triggered) { QActionGroup *tabPosition = static_cast(sender()); if(!tabPosition) qFatal("tabPosition is NULL"); Properties *prop = Properties::Instance(); /* order is dictated from mainwindow.cpp */ QTabWidget::TabPosition position = (QTabWidget::TabPosition)tabPosition->actions().indexOf(triggered); setTabPosition(position); prop->tabsPos = position; prop->saveSettings(); return; } void TabWidget::propertiesChanged() { for (int i = 0; i < count(); ++i) { TermWidgetHolder *console = static_cast(widget(i)); console->propertiesChanged(); } showHideTabBar(); } void TabWidget::clearActiveTerminal() { reinterpret_cast(widget(currentIndex()))->clearActiveTerminal(); } void TabWidget::saveSession() { int ix = currentIndex(); reinterpret_cast(widget(ix))->saveSession(tabText(ix)); } void TabWidget::loadSession() { reinterpret_cast(widget(currentIndex()))->loadSession(); } void TabWidget::preset2Horizontal() { int ix = TabWidget::addNewTab(); TermWidgetHolder* term = reinterpret_cast(widget(ix)); term->splitHorizontal(term->currentTerminal()); // switch to the 1st terminal term->switchNextSubterminal(); } void TabWidget::preset2Vertical() { int ix = TabWidget::addNewTab(); TermWidgetHolder* term = reinterpret_cast(widget(ix)); term->splitVertical(term->currentTerminal()); // switch to the 1st terminal term->switchNextSubterminal(); } void TabWidget::preset4Terminals() { int ix = TabWidget::addNewTab(); TermWidgetHolder* term = reinterpret_cast(widget(ix)); term->splitVertical(term->currentTerminal()); term->splitHorizontal(term->currentTerminal()); term->switchNextSubterminal(); term->switchNextSubterminal(); term->splitHorizontal(term->currentTerminal()); // switch to the 1st terminal term->switchNextSubterminal(); } void TabWidget::showHideTabBar() { if (Properties::Instance()->tabBarless) tabBar()->setVisible(false); else tabBar()->setVisible(!Properties::Instance()->hideTabBarWithOneTab || count() > 1); }