Index: src/document/katedocument.h =================================================================== --- src/document/katedocument.h +++ src/document/katedocument.h @@ -939,6 +939,7 @@ private: void updateDocName(); + void setDocumentName(const QString &name, int number = -1); public: /** @@ -1363,10 +1364,6 @@ */ bool m_readWriteStateBeforeLoading = false; - /** - * if the document is untitled - */ - bool m_isUntitled = true; /** * loading job, we want to cancel with cancel in the loading message */ Index: src/document/katedocument.cpp =================================================================== --- src/document/katedocument.cpp +++ src/document/katedocument.cpp @@ -198,18 +198,11 @@ : KTextEditor::Document (this, parent), m_bSingleViewMode(bSingleViewMode), m_bReadOnly(bReadOnly), - m_undoManager(new KateUndoManager(this)), - m_buffer(new KateBuffer(this)), m_indenter(new KateAutoIndent(this)), - - m_docName(QStringLiteral("need init")), - m_fileType(QStringLiteral("Normal")), - m_config(new KateDocumentConfig(this)) - { /** * no plugins from kparts here @@ -4231,44 +4224,130 @@ .replace(QLatin1Char('\n'), QLatin1Char(' ')); } +static QStringList reverseSplittedUrl(const QUrl &url) { + + QString fullUrl = removeNewLines(url.url()); + + if (fullUrl.isEmpty()) { + return QStringList(); + } + + QStringList splittedUrl = fullUrl.split(QLatin1Char('/'), QString::SkipEmptyParts); + + // Remove not useful parts... + splittedUrl.removeLast(); // The file name + // ...to avoid odd naming in rare cases we force numbering fallback + if (splittedUrl.at(0) == QLatin1String("file:")) { + splittedUrl.removeAt(0); + if (splittedUrl.at(0) == QLatin1String("home")) { + splittedUrl.removeAt(0); + } + } + + // Reverse our url; Thanks to https://stackoverflow.com/a/20652805 + for(int k = 0, s = splittedUrl.size(), max = (s / 2); k < max; k++) { + splittedUrl.swap(k, s - (1 + k)); + } + + return splittedUrl; +} + void KTextEditor::DocumentPrivate::updateDocName() { + QString fileName = removeNewLines(url().fileName()); + // if the name is set, and starts with FILENAME, it should not be changed! - if (! url().isEmpty() - && (m_docName == removeNewLines(url().fileName()) || - m_docName.startsWith(removeNewLines(url().fileName()) + QLatin1String(" (")))) { + if (! url().isEmpty() && m_docName.startsWith(fileName)) { return; } - int count = -1; + QString newName = m_docName; + + if (m_docName.isEmpty() && url().isEmpty()) { + newName = i18n("Untitled"); + } else if (m_docName == i18n("Untitled") && !url().isEmpty()) { + newName = fileName; + } + + // Collect all files with same name... + typedef QPair FooPair; + QList fooList; + // ...and save to each the url in a special rehashed form, starting with current document + fooList << FooPair(this, reverseSplittedUrl(url())); + int count = -1; // To catch multiple "Untitled" case only foreach (KTextEditor::DocumentPrivate *doc, KTextEditor::EditorPrivate::self()->kateDocuments()) { - if ((doc != this) && (doc->url().fileName() == url().fileName())) - if (doc->m_docNameNumber > count) { - count = doc->m_docNameNumber; - } + if ((doc != this) && (doc->url().fileName() == url().fileName())) { + count = qMax(count, doc->m_docNameNumber); + fooList << FooPair(doc, reverseSplittedUrl(doc->url())); + } } - m_docNameNumber = count + 1; + // Did we find at least two files with same name? + if (fooList.size() > 1 && !url().isEmpty()) { + count = -1; // Count not unique names as fallback + // Sort our list with shortest url on top (position 0) + std::sort(fooList.begin(), fooList.end(), [](FooPair a, FooPair b) { return a.second.size() < b.second.size(); }); + QSet uniqueNames; // Remember given names + // To make an unique name, prefix some folder name to the document name + for (QList::iterator i = fooList.begin(); i != fooList.end(); ++i) { + if (!(*i).second.size()) { + // Can happen in rare cases due to quirks in reverseSplittedUrl(..); use numbering scheme fallback + (*i).first->setDocumentName(fileName, count++); + continue; + } + + // First Try: Is the folder name, where file is located, enough to be unique? + QString docName = (*i).second.at(0) + QLatin1String("/") + fileName; + if (!uniqueNames.contains(docName)) { + uniqueNames.insert(docName); + (*i).first->setDocumentName(docName); - QString oldName = m_docName; - m_docName = removeNewLines(url().fileName()); + } else { + // Second Try: Find a folder name somewhere above to become an unique name + bool noSuccess = true; + for (int j = 1; j < (*i).second.size(); ++j) { + // docName = (*i).second.at(j) + QLatin1String("/…/") + fileName; // Bad shown, why? + // docName = (*i).second.at(j) + QLatin1String("/~/") + fileName; // How about that? + docName = (*i).second.at(j) + QLatin1String("/.../") + fileName; + if (!uniqueNames.contains(docName)) { + uniqueNames.insert(docName); + (*i).first->setDocumentName(docName); + noSuccess = false; + break; + } + } + // Third: We need to use the numbering scheme fallback + if (noSuccess) { + (*i).first->setDocumentName(fileName, count++); + } + } + } - m_isUntitled = m_docName.isEmpty(); - if (m_isUntitled) { - m_docName = i18n("Untitled"); + // Either no doubles or an "Untitled" document + } else { + setDocumentName(newName, count); } +} + +void KTextEditor::DocumentPrivate::setDocumentName(const QString &name, int number /*= -1*/) +{ + m_docNameNumber = number + 1; + + QString newName = name; if (m_docNameNumber > 0) { - m_docName = QString(m_docName + QLatin1String(" (%1)")).arg(m_docNameNumber + 1); + // Should rarely happens in normal cases, but always when we have more than one "Untitled" document + newName = QString(name + QLatin1String(" (%1)")).arg(m_docNameNumber + 1); } - /** - * avoid to emit this, if name doesn't change! - */ - if (oldName != m_docName) { - emit documentNameChanged(this); + if (newName == m_docName) { + return; } + + m_docName = newName; + + emit documentNameChanged(this); } void KTextEditor::DocumentPrivate::slotModifiedOnDisk(KTextEditor::View * /*v*/)