You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
qterminal-packaging/src/tabwidget.cpp

423 lines
11 KiB

/***************************************************************************
* 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 <http://www.gnu.org/licenses/>. *
***************************************************************************/
#include <QTabBar>
#include <QInputDialog>
#include <QMouseEvent>
#include <QMenu>
#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<TermWidgetHolder*>(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<QMouseEvent*>(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<TermWidgetHolder*>(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<QActionGroup *>(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<QActionGroup *>(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<TermWidgetHolder*>(widget(i));
console->propertiesChanged();
}
showHideTabBar();
}
void TabWidget::clearActiveTerminal()
{
reinterpret_cast<TermWidgetHolder*>(widget(currentIndex()))->clearActiveTerminal();
}
void TabWidget::saveSession()
{
int ix = currentIndex();
reinterpret_cast<TermWidgetHolder*>(widget(ix))->saveSession(tabText(ix));
}
void TabWidget::loadSession()
{
reinterpret_cast<TermWidgetHolder*>(widget(currentIndex()))->loadSession();
}
void TabWidget::preset2Horizontal()
{
int ix = TabWidget::addNewTab();
TermWidgetHolder* term = reinterpret_cast<TermWidgetHolder*>(widget(ix));
term->splitHorizontal(term->currentTerminal());
// switch to the 1st terminal
term->switchNextSubterminal();
}
void TabWidget::preset2Vertical()
{
int ix = TabWidget::addNewTab();
TermWidgetHolder* term = reinterpret_cast<TermWidgetHolder*>(widget(ix));
term->splitVertical(term->currentTerminal());
// switch to the 1st terminal
term->switchNextSubterminal();
}
void TabWidget::preset4Terminals()
{
int ix = TabWidget::addNewTab();
TermWidgetHolder* term = reinterpret_cast<TermWidgetHolder*>(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);
}