Rev 22639 |
Rev 23049 |
Go to most recent revision |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
/*
Copyright (C) 2011 Elvis Stansvik <elvstone@gmail.com>
For general Scribus (>=1.3.2) copyright and licensing information please refer
to the COPYING file provided with the program. Following this notice may exist
a copyright and/or license notice that predates the release of Scribus 1.3.2
for which a new license (GPL+exception) is in place.
*/
#include <QTabWidget>
#include <QMessageBox>
#include "prefsmanager.h"
#include "smcellstyle.h"
#include "smcellstylewidget.h"
#include "ui/scmessagebox.h"
SMCellStyle::SMCellStyle() :
m_widget(nullptr),
m_page(nullptr),
m_doc(nullptr),
m_selectionIsDirty(false)
{
m_widget = new QTabWidget();
Q_CHECK_PTR(m_widget);
m_widget->setContentsMargins(5, 5, 5, 5);
m_page = new SMCellStyleWidget();
Q_CHECK_PTR(m_page);
m_widget->addTab(m_page, tr("Properties"));
}
SMCellStyle::~SMCellStyle()
{
delete m_page;
delete m_widget;
m_page = nullptr;
m_widget = nullptr;
}
QTabWidget* SMCellStyle::widget()
{
return m_widget;
}
QString SMCellStyle::typeNamePlural()
{
return tr("Cell Styles");
}
QString SMCellStyle::typeNameSingular()
{
return tr("Cell Style");
}
void SMCellStyle::setCurrentDoc(ScribusDoc *doc)
{
m_doc = doc;
if (m_page)
m_page->setDoc(doc);
if (!m_doc)
{
removeConnections();
m_selection.clear();
m_cachedStyles.clear();
}
}
QList<StyleName> SMCellStyle::styles(bool reloadFromDoc)
{
QList<StyleName> stylesList;
if (!m_doc)
return stylesList; // No document available.
if (reloadFromDoc)
updateStylesCache(); // Update cache.
// Return a list of names of cached styles.
for (int i = 0; i < m_cachedStyles.count(); ++i)
{
if (m_cachedStyles[i].hasName())
{
QString styleName(m_cachedStyles[i].displayName());
QString parentName(QString::null);
if (m_cachedStyles[i].hasParent())
{
const BaseStyle* parentStyle = m_cachedStyles[i].parentStyle();
if (parentStyle)
parentName = parentStyle->displayName();
}
stylesList << StyleName(styleName, parentName);
}
}
return stylesList;
}
void SMCellStyle::reload()
{
updateStylesCache();
}
void SMCellStyle::selected(const QStringList &styleNames)
{
m_selection.clear();
m_selectionIsDirty = false;
removeConnections();
QList<CellStyle> cellStyles;
m_cachedStyles.invalidate();
for (int i = 0; i < m_cachedStyles.count(); ++i)
cellStyles << m_cachedStyles[i];
for (const QString& styleName : styleNames)
{
int index = m_cachedStyles.find(styleName);
// FIXME: #7133: Use .isDefaultStyle() instead here rather than relying on tr text comparison
if (index < 0 && styleName == CommonStrings::trDefaultCellStyle)
index = m_cachedStyles.find(CommonStrings::DefaultCellStyle);
if (index > -1)
m_selection.append(&m_cachedStyles[index]);
}
m_page->show(m_selection, cellStyles, PrefsManager::instance()->appPrefs.docSetupPrefs.language, m_doc->unitIndex());
setupConnections();
}
QString SMCellStyle::fromSelection() const
{
// TODO: Implement this once we have cell items.
return QString::null;
}
void SMCellStyle::toSelection(const QString &styleName) const
{
// TODO: Implement this once we have cell items.
}
QString SMCellStyle::newStyle()
{
Q_ASSERT(m_doc);
QString name = getUniqueName(tr("New Style"));
CellStyle style;
style.setDefaultStyle(false);
style.setName(name);
m_cachedStyles.create(style);
return name;
}
QString SMCellStyle::newStyle(const QString &fromStyle)
{
// #7179, do our name switch yet again to handle this properly for default styles
// FIXME: use isDefaultStyle somehow
QString fromStyleName(fromStyle);
if (fromStyle == CommonStrings::trDefaultCellStyle)
fromStyleName = CommonStrings::DefaultCellStyle;
Q_ASSERT(m_cachedStyles.resolve(fromStyleName));
if (!m_cachedStyles.resolve(fromStyleName))
return QString::null;
// Copy the style with name constructed from the original name.
QString styleName(getUniqueName(tr("Clone of %1").arg(fromStyle)));
CellStyle cellStyle(m_cachedStyles.get(fromStyleName));
cellStyle.setDefaultStyle(false);
cellStyle.setName(styleName);
cellStyle.setShortcut(QString::null);
m_cachedStyles.create(cellStyle);
return styleName;
}
void SMCellStyle::apply()
{
if (!m_doc)
return; // No document available.
// Handle replacement of deleted styles.
QMap<QString, QString> replacement;
for (int i = 0; i < m_deleted.count(); ++i)
{
if (m_deleted[i].first == m_deleted[i].second)
continue; // Nothing to do.
replacement[m_deleted[i].first] = m_deleted[i].second;
}
m_doc->redefineCellStyles(m_cachedStyles, false);
m_doc->replaceCellStyles(replacement);
m_deleted.clear(); // Deletion done at this point.
// TODO: We should probably have something similar to this for tables/cells.
//m_doc->scMW()->requestUpdate(reqTextStylesUpdate);
m_doc->changed();
}
void SMCellStyle::editMode(bool isOn)
{
if (isOn)
updateStylesCache();
}
bool SMCellStyle::isDefaultStyle(const QString &styleName) const
{
int index = m_cachedStyles.find(styleName);
bool result = false;
if (index > -1)
result = m_cachedStyles[index].isDefaultStyle();
else
{
if (CommonStrings::trDefaultCellStyle == styleName)
{
index = m_cachedStyles.find(CommonStrings::DefaultCellStyle);
if (index > -1)
result = m_cachedStyles[index].isDefaultStyle();
}
}
return result;
}
void SMCellStyle::setDefaultStyle(bool isDefaultStyle)
{
Q_ASSERT(m_selection.count() == 1);
if (m_selection.count() != 1)
return;
m_selection[0]->setDefaultStyle(isDefaultStyle);
if (!m_selectionIsDirty)
{
m_selectionIsDirty = true;
emit selectionDirty();
}
}
QString SMCellStyle::shortcut(const QString &styleName) const
{
QString result(QString::null);
int index = m_cachedStyles.find(styleName);
if (index > -1)
result = m_cachedStyles[index].shortcut();
else
{
// FIXME: Use isDefaultStyle somehow.
if (CommonStrings::trDefaultCellStyle == styleName)
{
index = m_cachedStyles.find(CommonStrings::DefaultCellStyle);
if (index > -1)
result = m_cachedStyles[index].shortcut();
}
}
return result;
}
void SMCellStyle::setShortcut(const QString &shortcut)
{
Q_ASSERT(m_selection.count() == 1);
if (m_selection.count() != 1)
return;
m_selection[0]->setShortcut(shortcut);
if (!m_selectionIsDirty)
{
m_selectionIsDirty = true;
emit selectionDirty();
}
}
void SMCellStyle::deleteStyles(const QList<RemoveItem> &removeList)
{
for (const RemoveItem& removeItem : removeList)
{
for (int i = 0; i < m_selection.count(); ++i)
{
if (m_selection[i]->name() == removeItem.first)
{
m_selection.removeAt(i);
break;
}
}
int index = m_cachedStyles.find(removeItem.first);
if (index > -1)
m_cachedStyles.remove(index);
m_deleted << removeItem;
}
// Check other styles and replace inherited styles if necessary
for (int i = 0; i < m_cachedStyles.count(); ++i)
{
CellStyle& cellStyle = m_cachedStyles[i];
QString parentName = cellStyle.parent();
if (parentName.isEmpty())
continue;
QString replacementName = parentName;
for (int j = 0; j < removeList.count(); ++j)
{
if (removeList.at(j).first == parentName)
{
replacementName = removeList.at(j).second;
break;
}
}
if (replacementName == parentName)
continue;
if (replacementName == CommonStrings::trDefaultCellStyle)
replacementName = CommonStrings::DefaultCellStyle;
if (!cellStyle.canInherit(replacementName))
replacementName = QString();
if (!replacementName.isEmpty() && (m_cachedStyles.find(replacementName) < 0))
replacementName = QString();
cellStyle.setParent(replacementName);
}
}
void SMCellStyle::nameChanged(const QString &newName)
{
// Save the old name.
QString oldName(m_selection[0]->name());
// Make a copy of the old style but with new name.
CellStyle newStyle(*m_selection[0]);
newStyle.setName(newName);
m_cachedStyles.create(newStyle);
// Select the new style.
m_selection.clear();
m_selection.append(&m_cachedStyles[m_cachedStyles.find(newName)]);
// Remove old style from cache.
for (int j = 0; j < m_cachedStyles.count(); ++j)
{
int index = m_cachedStyles.find(oldName);
if (index > -1)
{
m_cachedStyles.remove(index);
break;
}
}
// Set parent references to old style to new style.
for (int j = 0; j < m_cachedStyles.count(); ++j)
{
if (m_cachedStyles[j].parent() == oldName)
m_cachedStyles[j].setParent(newName);
}
// Update the deleted list to reflect the name change.
QList<RemoveItem>::iterator it;
for (it = m_deleted.begin(); it != m_deleted.end(); ++it)
{
if ((*it).second == oldName)
{
oldName = (*it).first;
m_deleted.erase(it);
break;
}
}
m_deleted.append(RemoveItem(oldName, newName));
// Mark selection as dirty.
if (!m_selectionIsDirty)
{
m_selectionIsDirty = true;
emit selectionDirty();
}
}
QString SMCellStyle::getUniqueName(const QString &name)
{
int id = 0;
bool done = false;
QString s(name);
while (!done)
{
start:
++id;
for (int i = 0; i < m_cachedStyles.count(); ++i)
{
if (m_cachedStyles[i].name() == s)
{
s = tr("%1 (%2)", "This for unique name when creating "
"a new character style. %1 will be the name "
"of the style and %2 will be a number forming "
"a style name like: New Style (2)").arg(name).arg(id);
goto start;
}
}
done = true;
}
return s;
}
void SMCellStyle::languageChange()
{
if (m_widget && m_page)
{
m_widget->setTabText(m_widget->indexOf(m_page), tr("Properties"));
m_page->languageChange();
}
}
void SMCellStyle::unitChange()
{
// Unimplemented.
}
void SMCellStyle::updateStylesCache()
{
if (!m_doc)
return; // No document available.
m_selection.clear();
m_cachedStyles.clear();
m_deleted.clear();
m_cachedStyles.redefine(m_doc->cellStyles(), true);
}
void SMCellStyle::setupConnections()
{
if (!m_page)
return;
connect(m_page->fillColor, SIGNAL(activated(const QString&)), this, SLOT(slotFillColor()));
connect(m_page->fillShade, SIGNAL(clicked()), this, SLOT(slotFillShade()));
connect(m_page->parentCombo, SIGNAL(activated(const QString&)), this, SLOT(slotParentChanged(const QString&)));
}
void SMCellStyle::removeConnections()
{
if (!m_page)
return;
disconnect(m_page->fillColor, SIGNAL(activated(const QString&)), this, SLOT(slotFillColor()));
disconnect(m_page->fillShade, SIGNAL(clicked()), this, SLOT(slotFillShade()));
disconnect(m_page->parentCombo, SIGNAL(activated(const QString&)), this, SLOT(slotParentChanged(const QString&)));
}
void SMCellStyle::slotFillColor()
{
if (m_page->fillColor->useParentValue())
{
for (int i = 0; i < m_selection.count(); ++i)
m_selection[i]->resetFillColor();
}
else
{
QString col(m_page->fillColor->currentText());
for (int i = 0; i < m_selection.count(); ++i)
{
m_selection[i]->setFillColor(col);
}
}
if (!m_selectionIsDirty)
{
m_selectionIsDirty = true;
emit selectionDirty();
}
}
void SMCellStyle::slotFillShade()
{
if (m_page->fillShade->useParentValue())
{
for (int i = 0; i < m_selection.count(); ++i)
{
m_selection[i]->resetFillShade();
}
}
else
{
int fs = m_page->fillShade->getValue();
for (int i = 0; i < m_selection.count(); ++i)
{
m_selection[i]->setFillShade(fs);
}
}
if (!m_selectionIsDirty)
{
m_selectionIsDirty = true;
emit selectionDirty();
}
}
void SMCellStyle::slotParentChanged(const QString &parent)
{
Q_ASSERT(!parent.isNull());
bool loop = false, parentLoop = false;
const BaseStyle* parentStyle = (!parent.isEmpty()) ? m_cachedStyles.resolve(parent) : nullptr;
QStringList sel;
for (int i = 0; i < m_selection.count(); ++i)
{
loop = false;
// Check if setting parent won't create a loop
const BaseStyle* pStyle = parentStyle;
while (pStyle)
{
if (pStyle->hasParent() && (pStyle->parent() == m_selection[i]->name()))
{
loop = parentLoop = true;
break;
}
pStyle = pStyle->hasParent() ? pStyle->parentStyle() : nullptr;
}
if (!loop)
{
m_selection[i]->erase();
m_selection[i]->setParent(parent);
}
sel << m_selection[i]->name();
}
if (parentLoop)
ScMessageBox::warning(this->widget(), CommonStrings::trWarning, tr("Setting that style as parent would create an infinite loop."));
selected(sel);
if (!m_selectionIsDirty)
{
m_selectionIsDirty = true;
emit selectionDirty();
}
}