Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: remove the limit of term splitting #353

Merged
merged 9 commits into from
Sep 8, 2024
24 changes: 6 additions & 18 deletions src/main/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1131,15 +1131,9 @@ inline void MainWindow::slotShortcutHorizonzalSplit()
// 判读数量是否允许分屏
if (Service::instance()->isCountEnable()) {
TermWidgetPage *page = currentPage();
if (page) {
if (page->currentTerminal()) {
int layer = page->currentTerminal()->getTermLayer();
DSplitter *splitter = qobject_cast<DSplitter *>(page->currentTerminal()->parentWidget());
if (1 == layer || (2 == layer && splitter && Qt::Horizontal == splitter->orientation())) {
page->split(Qt::Horizontal);
return ;
}
}
if (page && page->currentTerminal()->canSplit(Qt::Vertical)) {
page->split(Qt::Horizontal);
return ;
}
}
qInfo() << "can't split vertical again";
Expand All @@ -1150,15 +1144,9 @@ inline void MainWindow::slotShortcutVerticalSplit()
// 判读数量是否允许分屏
if (Service::instance()->isCountEnable()) {
TermWidgetPage *page = currentPage();
if (page) {
if (page->currentTerminal()) {
int layer = page->currentTerminal()->getTermLayer();
DSplitter *splitter = qobject_cast<DSplitter *>(page->currentTerminal()->parentWidget());
if (1 == layer || (2 == layer && splitter && Qt::Vertical == splitter->orientation())) {
page->split(Qt::Vertical);
return ;
}
}
if (page && page->currentTerminal()->canSplit(Qt::Horizontal)) {
page->split(Qt::Vertical);
return ;
}
}
qInfo() << "can't split vertical again";
Expand Down
66 changes: 38 additions & 28 deletions src/views/termwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,11 +121,7 @@ TermWidget::TermWidget(const TermProperties &properties, QWidget *parent) : QTer
// 按键滚动
setPressingScroll(Settings::instance()->PressingScroll());

/******** Modify by ut000439 wangpeili 2020-07-27: fix bug 39371: 分屏线可以拉到边****/
// 以最小mainwindow分4屏为标准的最小大小
/******** Modify by ut001000 renfeixiang 2020-08-07:修改成根据全局变量m_MinWidth,m_MinHeight计算出term的最小高度和宽度***************/
setMinimumSize(MainWindow::m_MinWidth / 2, (MainWindow::m_MinHeight - WIN_TITLE_BAR_HEIGHT) / 2);
/********************* Modify by n014361 wangpeili End ************************/
setMinimumSize(MIN_WIDTH, MIN_HEIGHT);

QString currentEnvLanguage = Utils::getCurrentEnvLanguage();
// 判断是维吾尔语或者藏语时
Expand Down Expand Up @@ -481,15 +477,11 @@ void TermWidget::addMenuActions(const QPoint &pos)

m_menu->addSeparator();


DSplitter *splitter = qobject_cast<DSplitter *>(parentWidget());
int layer = getTermLayer();

if (1 == layer || (2 == layer && splitter && Qt::Horizontal == splitter->orientation()))
m_menu->addAction(tr("Horizontal split"), this, &TermWidget::onHorizontalSplit);

if (1 == layer || (2 == layer && splitter && Qt::Vertical == splitter->orientation()))
m_menu->addAction(tr("Vertical split"), this, &TermWidget::onVerticalSplit);
QAction *action = 0;
action = m_menu->addAction(tr("Horizontal split"), this, &TermWidget::onHorizontalSplit);
action->setEnabled(canSplit(Qt::Vertical));
action = m_menu->addAction(tr("Vertical split"), this, &TermWidget::onVerticalSplit);
action->setEnabled(canSplit(Qt::Horizontal));

/******** Modify by n014361 wangpeili 2020-02-21: 增加关闭窗口和关闭其它窗口菜单 ****************/
m_menu->addAction(QObject::tr("Close workspace"), this, &TermWidget::onCloseCurrWorkSpace);
Expand Down Expand Up @@ -555,14 +547,12 @@ void TermWidget::addMenuActions(const QPoint &pos)

inline void TermWidget::onHorizontalSplit()
{
getTermLayer();
// menu关闭与分屏同时进行时,会导致QT计算光标位置异常。
QTimer::singleShot(10, this, &TermWidget::splitHorizontal);
}

inline void TermWidget::onVerticalSplit()
{
getTermLayer();
// menu关闭与分屏同时进行时,会导致QT计算光标位置异常。
QTimer::singleShot(10, this, &TermWidget::splitVertical);
}
Expand Down Expand Up @@ -824,18 +814,6 @@ void TermWidget::setDeleteMode(const EraseMode &deleteMode)
QTermWidget::setDeleteMode(&ch, length);
}

int TermWidget::getTermLayer()
{
int layer = 1;
QWidget *currentW = this;
while (currentW->parentWidget() != parentPage()) {
layer++;
currentW = currentW->parentWidget();
}
qInfo() << "getTermLayer = " << layer;
return layer;
}

void TermWidget::setTabFormat(const QString &tabFormat)
{
// 非全局设置优先级更高
Expand Down Expand Up @@ -1033,6 +1011,38 @@ bool TermWidget::isInRemoteServer()
return false;
}

bool TermWidget::canSplit(Qt::Orientation ori) {
qDebug() << "CanSplit:" << ori;
QSplitter *splitter = qobject_cast<QSplitter *>(this->parentWidget());
int minimumSize = ori == Qt::Horizontal ? TermWidget::MIN_WIDTH : TermWidget::MIN_HEIGHT;
if (splitter) {
if (splitter->orientation() == ori) {
QList<int> sizes = splitter->sizes();
// new term has same size portion as the current one.
sizes.append(sizes.at(splitter->indexOf(this)));

double sum = 0;
for (int i = 0; i < sizes.count(); i++) {
sum += sizes.at(i);
}

for(int i = 0; i < sizes.count(); i++) {
int totalSize = ori == Qt::Horizontal ? splitter->width() : splitter->height();
int actualSize = (totalSize) * (sizes.at(i) / sum);
if (actualSize < minimumSize)
return false;
}
} else {
int splitterSize = ori == Qt::Horizontal ? splitter->width() : splitter->height();
if (splitterSize / 2.0 < minimumSize)
return false;
}
}

return true;
}


void TermWidget::setTermOpacity(qreal opacity)
{
//这里再次判断一遍,因为刚启动时,还是需要判断一次当前是否开启了窗口特效
Expand Down
14 changes: 7 additions & 7 deletions src/views/termwidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,9 @@
{
Q_OBJECT
public:
bool canSplit(Qt::Orientation ori);

TermWidget(const TermProperties &properties, QWidget *parent = nullptr);

Check warning on line 70 in src/views/termwidget.h

View workflow job for this annotation

GitHub Actions / cppcheck

Class 'TermWidget' has a constructor with 1 argument that is not explicit. Such constructors should in general be explicit for type safety reasons. Using the explicit keyword in the constructor means some mistakes when using the class can be avoided.

Check warning on line 70 in src/views/termwidget.h

View workflow job for this annotation

GitHub Actions / static-check / Call-CppCheck

Class 'TermWidget' has a constructor with 1 argument that is not explicit. Such constructors should in general be explicit for type safety reasons. Using the explicit keyword in the constructor means some mistakes when using the class can be avoided.
~TermWidget();
/**
* @brief 获取父页面
Expand All @@ -79,6 +81,7 @@
* @return
*/
bool isInRemoteServer();

public:
/**
* @brief 设置不透明度
Expand Down Expand Up @@ -189,13 +192,6 @@
*/
void setDeleteMode(const EraseMode &deleteMode);

/**
* @brief 获取当前terminal距离page的层次.用于限定分屏
* @author ut000439 王培利
* @return
*/
int getTermLayer();

/**
* @brief 设置标签标题格式(全局设置)
* @author ut000610 戴正文
Expand Down Expand Up @@ -465,6 +461,10 @@
QString m_remotePassword;
//是否准备远程
bool m_remotePasswordIsReady = false;

// 9:6
static const int MIN_WIDTH = 180;
static const int MIN_HEIGHT = 120;
};

#endif // TERMWIDGET_H
148 changes: 93 additions & 55 deletions src/views/termwidgetpage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,27 @@
#include <QVBoxLayout>
#include <QApplication>

// Find the previous term widget in the widget tree.
static TermWidget* WidgetTreeReverseFindTerm(QWidget *widget)
{
QList<TermWidget*> termList = widget->findChildren<TermWidget *>();
for (TermWidget *t : termList) {
if (t) {

Check warning on line 27 in src/views/termwidgetpage.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Consider using std::find_if algorithm instead of a raw loop.

Check warning on line 27 in src/views/termwidgetpage.cpp

View workflow job for this annotation

GitHub Actions / static-check / Call-CppCheck

Consider using std::find_if algorithm instead of a raw loop.
qInfo() << "TermWidget found in current widget:" << t;
return t;
}
}

QWidget *parent = widget->parentWidget();
if (parent) {
qInfo() << "Searching in parent widget:" << parent;
return WidgetTreeReverseFindTerm(parent);
}
qInfo() << "No TermWidget found in the widget tree.";
return nullptr;
}


TermWidgetPage::TermWidgetPage(const TermProperties &properties, QWidget *parent)
: QWidget(parent), m_findBar(new PageSearchBar(this))
{
Expand Down Expand Up @@ -85,21 +106,26 @@
m_MainWindow = mainWin;
}

// TODO(hualet): maybe implement a subclass of DSplitter and
// override the createHandle method, all setSplitStyle should
// be removed.
void TermWidgetPage::setSplitStyle(DSplitter *splitter)
{
splitter->setHandleWidth(1);
QSplitterHandle *handle = splitter->handle(1);

if (handle) {
//分割线颜色暂时设置为Highlight颜色,需要和UI确认下
//此处代码暂时保留 //DPalette pa = DPaletteHelper::instance()->palette(handle);
//bug#57044 中的分割线颜色,保留的代码对默认主题,和十个内置主题的颜色是正确获取,但是在自定义的颜色获取存在异常,采取如下方式获取
DPalette pa = DGuiApplicationHelper::instance()->applicationPalette();
QColor splitBrush = pa.color(DPalette::Highlight);
pa.setBrush(DPalette::Background, splitBrush);
handle->setPalette(pa);
handle->setBackgroundRole(QPalette::Background);
handle->setAutoFillBackground(true);

for (int i = 1; i < splitter->count(); ++i) {
QSplitterHandle *handle = splitter->handle(i);
if (handle) {
//分割线颜色暂时设置为Highlight颜色,需要和UI确认下
//此处代码暂时保留 //DPalette pa = DPaletteHelper::instance()->palette(handle);
//bug#57044 中的分割线颜色,保留的代码对默认主题,和十个内置主题的颜色是正确获取,但是在自定义的颜色获取存在异常,采取如下方式获取
DPalette pa = DGuiApplicationHelper::instance()->applicationPalette();
QColor splitBrush = pa.color(DPalette::Highlight);
pa.setBrush(DPalette::Background, splitBrush);
handle->setPalette(pa);
handle->setBackgroundRole(QPalette::Background);
handle->setAutoFillBackground(true);
}
}
}

Expand All @@ -119,22 +145,42 @@
{
parentMainWindow()->showPlugin(MainWindow::PLUGIN_TYPE_NONE);
TermWidget *term = m_currentTerm;
if (1 == getTerminalCount()) {
qInfo() << "first split";
QSplitter *firstSplit = createSubSplit(term, orientation);
m_layout->addWidget(firstSplit);
//return ;

QSplitter *splitter = qobject_cast<QSplitter *>(term->parent());
int index = splitter ? splitter->indexOf(term) : m_layout->indexOf(term);

// if there's already a splitter, and the orientation is correct,
// just add a new term to the splitter.
if (splitter && splitter->orientation() != orientation) {
TermProperties properties(term->workingDirectory());
TermWidget *newTerm = createTerm(properties);

// copy the size of the current term to the new term, so the new term will
// keep the same size portion as the current term after the splitter relayout.
// this behavior is copied form iTerm2.
QList<int> sizes = splitter->sizes();
sizes.insert(index+1, sizes.at(index));
splitter->insertWidget(index+1, newTerm); // insert after the current term
splitter->setSizes(sizes);

setSplitStyle(splitter);
setCurrentTerminal(newTerm);
} else {
qInfo() << "not first split";
QSplitter *upSplit = qobject_cast<QSplitter *>(term->parent());
int index = upSplit->indexOf(term);
QList<int> parentSizes = upSplit->sizes();

// 用新的Split分割布局替换原来的位置
QSplitter *subSplit = createSubSplit(term, orientation);
upSplit->insertWidget(index, subSplit);
upSplit->setSizes(parentSizes);
setSplitStyle(upSplit);
// if there's no splitter, or the orientation is not correct,
// create a new splitter, put the 2 terms into the splitter,
// and replace the old term with the splitter.
if (splitter) {
// see above splitter->insertWidget part to know why.
QList<int> sizes = splitter->sizes();
sizes.insert(index, sizes.at(index));
QSplitter *newSplitter = createSubSplit(term, orientation);
splitter->insertWidget(index, newSplitter);
splitter->setSizes(sizes);
setSplitStyle(splitter);
} else {
QSplitter *newSplitter = createSubSplit(term, orientation);
m_layout->insertWidget(index, newSplitter);
}
}

/******** Add by ut001000 renfeixiang 2020-08-07:新增分屏时改变大小,bug#41436***************/
Expand All @@ -154,6 +200,7 @@
TermProperties properties(term->workingDirectory());
term->setParent(nullptr);
TermWidget *newTerm = createTerm(properties);
newTerm->resize(term->size());

// 意义与名称是相反的
DSplitter *subSplit = new DSplitter(orientation == Qt::Horizontal ? Qt::Vertical : Qt::Horizontal,
Expand All @@ -162,7 +209,6 @@
subSplit->setFocusPolicy(Qt::NoFocus);
subSplit->insertWidget(0, term);
subSplit->insertWidget(1, newTerm);
subSplit->setSizes({ 1, 1 });
setSplitStyle(subSplit);
setCurrentTerminal(newTerm);
/******** Modify by ut000439 wangpeili 2020-07-27: fix bug 39371: 分屏线可以拉到边****/
Expand All @@ -180,40 +226,31 @@
showExitConfirmDialog(Utils::CloseType_Terminal, 1, parentMainWindow());
return;
}
QSplitter *upSplit = qobject_cast<QSplitter *>(term->parent());
term->setParent(nullptr);

// 另一个兄弟也可能是终端,也可能是split,
QWidget *brother = upSplit->widget(0);
TermWidget *nextTerm = upSplit->findChild<TermWidget *>();
// 如果上级是分屏
if ("QSplitter" == QString(upSplit->parent()->metaObject()->className())) {
QSplitter *upupSplit = qobject_cast<QSplitter *>(upSplit->parent());
//兄弟替换parent split
upupSplit->replaceWidget(upupSplit->indexOf(upSplit), brother);
}
// 上级不是分屏控件,就是布局在控制了
else {
qInfo() << "TermWidgetPage only one term exist!";
m_layout->addWidget(brother);
}

// 子控件的变化会引起焦点的变化,控制焦点要放在最后
if (nextTerm != nullptr) {
qInfo() << "nextTerm change" << m_currentTerm->getSessionId();
nextTerm->setFocus();
} else {
qInfo() << "can not found nextTerm in TermWidget";
}
QWidget *parentWidget = term->parentWidget();

// step1, delete the term
// 释放控件,并隐藏term、upSplit,避免出现闪现窗口bug#80809
term->setParent(nullptr);
term->hide();
term->deleteLater();
// 断开相关的连接:(UT_MainWindow_Test, slotShortcutCloseWorkspace)出现的崩溃问题
Settings::instance()->disconnect(term);
upSplit->hide();
upSplit->setParent(nullptr);
upSplit->deleteLater();

// step2, find the next term to get focus
TermWidget *nextTerm = WidgetTreeReverseFindTerm(parentWidget);
if (nextTerm) {
setCurrentTerminal(nextTerm);
}

// step3, futurer clean the parent splitter if it's empty
QSplitter *upSplit = qobject_cast<QSplitter *>(parentWidget);
if (upSplit && upSplit->count() == 0) {
upSplit->setParent(nullptr);
upSplit->deleteLater();
upSplit = nullptr;
}

qInfo() << "page terminal count =" << getTerminalCount();
/******** Add by ut001000 renfeixiang 2020-08-07:关闭分屏时改变大小,bug#41436***************/
parentMainWindow()->updateMinHeight();
Expand Down Expand Up @@ -709,6 +746,7 @@
TermWidget *oldTerm = m_currentTerm;
m_currentTerm = term;
if (oldTerm != m_currentTerm) {
m_currentTerm->setFocus();
// 当前界面切换
qInfo() << "m_currentTerm change" << m_currentTerm->getSessionId();
QString tabTitle = term->getTabTitle();
Expand Down
Loading