示例#1
0
void
ErrorTracker::onLineTimesChanged(SubtitleLine *line)
{
	updateLineErrors(line, line->errorFlags() & SubtitleLine::TimesErrors);

	SubtitleLine *prevLine = line->prevLine();
	if(prevLine)
		updateLineErrors(prevLine, prevLine->errorFlags() & SubtitleLine::OverlapsWithNext);
}
void
SwapLinesTextsAction::_emitRedoSignals()
{
	for(SubtitleIterator it(m_subtitle, m_ranges); it.current(); ++it) {
		SubtitleLine *line = it.current();
		emit line->primaryTextChanged(line->m_primaryText);
		emit line->secondaryTextChanged(line->m_secondaryText);
	}
}
示例#3
0
void
Subtitle::joinLines(const RangeList &ranges)
{
	beginCompositeAction(i18n("Join Lines"));

	RangeList obsoletedRanges;

	for(RangeList::ConstIterator rangesIt = ranges.begin(), end = ranges.end(); rangesIt != end; ++rangesIt) {
		int rangeStart = (*rangesIt).start();
		int rangeEnd = normalizeRangeIndex((*rangesIt).end());

		if(rangeStart >= rangeEnd)
			continue;

		SubtitleLine *firstLine = m_lines.at(rangeStart);
		SubtitleLine *lastLine = m_lines.at(rangeEnd);

		SString primaryText, secondaryText;

		for(SubtitleIterator it(*this, Range(rangeStart, rangeEnd - 1)); it.current(); ++it) {
			if(!it.current()->primaryText().isEmpty()) {
				primaryText.append(it.current()->primaryText());
				primaryText.append("\n");
			}

			if(!it.current()->secondaryText().isEmpty()) {
				secondaryText.append(it.current()->secondaryText());
				secondaryText.append("\n");
			}
		}

		primaryText.append(lastLine->primaryText());
		secondaryText.append(lastLine->secondaryText());

		firstLine->setTexts(primaryText, secondaryText);
		firstLine->setHideTime(lastLine->hideTime());

		obsoletedRanges << Range(rangeStart + 1, rangeEnd);
	}

	removeLines(obsoletedRanges, Both);

	endCompositeAction();
}
// *** SubtitleLineAction
SubtitleLineAction::SubtitleLineAction(SubtitleLine &line, UndoAction::DirtyMode dirtyMode, const QString &description)
	: UndoAction(dirtyMode, line.subtitle(), description),
	  m_line(line)
{}
示例#5
0
void
Replacer::advance()
{
	SubtitleCompositeActionExecutor executor(*m_subtitle, i18n("Replace"));

	KFind::Result res = KFind::NoMatch;

	bool selection = m_replace->options() & KFind::SelectedText;
	bool backwards = m_replace->options() & KFind::FindBackwards;

	QDialog *replaceNextDialog = this->replaceNextDialog(); // creates the dialog if it didn't existed before

	do {
		if(m_replace->needData()) {
			SubtitleLine *dataLine = m_iterator->current();

			if(dataLine) {
				if(!m_translationMode || m_targetRadioButtons[SubtitleLine::Primary]->isChecked()) {
					m_feedingPrimary = true;
					m_replace->setData(dataLine->primaryText().string());
				} else if(m_targetRadioButtons[SubtitleLine::Secondary]->isChecked()) {
					m_feedingPrimary = false;
					m_replace->setData(dataLine->secondaryText().string());
				} else {                // m_translationMode && m_targetRadioButtons[SubtitleLine::Both]->isChecked()
					m_feedingPrimary = !m_feedingPrimary;   // we alternate the source of data
					m_replace->setData((m_feedingPrimary ? dataLine->primaryText() : dataLine->secondaryText()).string());
				}
			}
		}

		res = m_replace->replace();

		if(res == KFind::NoMatch && (!m_translationMode || !m_targetRadioButtons[SubtitleLine::Both]->isChecked() || !m_feedingPrimary)) {
			if(backwards)
				--(*m_iterator);
			else
				++(*m_iterator);

			if(m_firstIndex == m_iterator->index() || (backwards ? (m_firstIndex == m_iterator->lastIndex() && m_iterator->index() == SubtitleIterator::BehindFirst) : (m_firstIndex == m_iterator->firstIndex() && m_iterator->index() == SubtitleIterator::AfterLast))) {
				if(replaceNextDialog)
					replaceNextDialog->hide();

				if(m_instancesFound && m_replace->numReplacements())
					KMessageBox::information(parentWidget(), i18np("1 replacement done.", "%1 replacements done.", m_replace->numReplacements()), i18n("Replace")
											 );
				else // special case
					KMessageBox::sorry(parentWidget(), i18n("No instances of '%1' found!", m_replace->pattern()), i18n("Replace")
									   );

				m_replace->resetCounts();
				break;
			}

			if(m_iterator->index() < 0) {
				if(backwards)
					m_iterator->toLast();
				else
					m_iterator->toFirst();

				int numReplacements = m_replace->numReplacements();

				m_replace->resetCounts();

				if(KMessageBox::warningContinueCancel(parentWidget(), i18np("1 replacement done.", "%1 replacements done.", numReplacements) + "\n\n" + (backwards ? (selection ? i18n("Beginning of selection reached.\nContinue from the end?") : i18n("Beginning of subtitle reached.\nContinue from the end?")) : (selection ? i18n("End of selection reached.\nContinue from the beginning?") : i18n("End of subtitle reached.\nContinue from the beginning?"))), i18n("Replace")
													  ) != KMessageBox::Continue)
				{
					if(replaceNextDialog)
						replaceNextDialog->hide();
					break;
				}
			}
		}
	} while(res != KFind::Match);
}
示例#6
0
void
Subtitle::setPrimaryData(const Subtitle &from, bool usePrimaryData)
{
	beginCompositeAction(i18n("Set Primary Data"));

	setFormatData(from.m_formatData);

	setFramesPerSecond(from.framesPerSecond());

	SubtitleIterator fromIt(from, Range::full());
	SubtitleIterator thisIt(*this, Range::full());

	// the errors that we are going to take from 'from':
	const int fromErrors = (usePrimaryData ? SubtitleLine::PrimaryOnlyErrors : SubtitleLine::SecondaryOnlyErrors) | SubtitleLine::SharedErrors;
	// the errors that we are going to keep:
	const int thisErrors = SubtitleLine::SecondaryOnlyErrors;

	for(SubtitleLine *fromLine = fromIt.current(), *thisLine = thisIt.current(); fromLine && thisLine; ++fromIt, ++thisIt, fromLine = fromIt.current(), thisLine = thisIt.current()) {
		thisLine->setPrimaryText(usePrimaryData ? fromLine->primaryText() : fromLine->secondaryText());
		thisLine->setTimes(fromLine->showTime(), fromLine->hideTime());
		thisLine->setErrorFlags((fromLine->errorFlags() & fromErrors) | (thisLine->errorFlags() & thisErrors));
		thisLine->setFormatData(fromLine->formatData());
	}

	if(fromIt.current()) {          // 'from' had more lines than '*this'
		QList<SubtitleLine *> lines;
		for(; fromIt.current(); ++fromIt) {
			SubtitleLine *thisLine = new SubtitleLine(*fromIt.current());
			if(!usePrimaryData)
				thisLine->setPrimaryText(thisLine->secondaryText());
			thisLine->setSecondaryText(SString());
			thisLine->setErrorFlags(SubtitleLine::SecondaryOnlyErrors, false);
			thisLine->setFormatData(fromIt.current()->formatData());
			lines.append(thisLine);
		}
		InsertLinesAction a(*this, lines);
		processAction(&a);
	} else if(thisIt.current()) {   // '*this'  had more lines than 'from'
		for(SubtitleLine *thisLine = thisIt.current(); thisLine; ++thisIt, thisLine = thisIt.current()) {
			thisLine->setPrimaryText(SString());
			thisLine->setErrorFlags(SubtitleLine::PrimaryOnlyErrors, false);
			thisLine->setFormatData(0);
		}
	}

	endCompositeAction();
}
示例#7
0
void
Subtitle::splitLines(const RangeList &ranges)
{
	beginCompositeAction(i18n("Split Lines"));

	for(SubtitleIterator it(*this, ranges, true); it.current(); --it) {
		SubtitleLine *line = it.current();
		if(line->primaryLines() > 1) {
			line->simplifyTextWhiteSpace(SubtitleLine::Primary);

			long autoDurationsSum = 0;
			QList<int> autoDurations;
			SStringList primaryLines = line->primaryText().split('\n');
			for(SStringList::ConstIterator ptIt = primaryLines.begin(), ptEnd = primaryLines.end(); ptIt != ptEnd; ++ptIt) {
				const Time &autoDuration = SubtitleLine::autoDuration((*ptIt).string(), 60, 50,
																	  50);
				autoDurations.append(autoDuration.toMillis());
				autoDurationsSum += autoDuration.toMillis();
			}

			double factor = line->durationTime().toMillis() / autoDurationsSum;

			SStringList secondaryLines = line->secondaryText().split('\n');
			while(secondaryLines.count() < primaryLines.count())
				secondaryLines.append(SString());
			while(secondaryLines.count() > primaryLines.count()) {
				SString lastLine = secondaryLines.last();
				secondaryLines.pop_back();
				secondaryLines.last() += '\n';
				secondaryLines.last() += lastLine;
			}

			int subLineIndex = it.index(), splitLineIndex = 0;
			for(SStringList::ConstIterator ptIt = primaryLines.begin(), ptEnd = secondaryLines.end(), stIt = secondaryLines.begin(), stEnd = secondaryLines.end(); ptIt != ptEnd && stIt != stEnd; ++ptIt, ++stIt, ++subLineIndex, ++splitLineIndex) {
				if(splitLineIndex) {
					SubtitleLine *newLine = new SubtitleLine();
					newLine->setShowTime(line->hideTime() + 1);
					insertLine(newLine, subLineIndex);
					line = newLine;
				}

				line->setTexts(*ptIt, *stIt);
				line->setDurationTime(Time((factor * autoDurations[splitLineIndex]) - 1.0));
			}
		}
	}

	endCompositeAction();
}
示例#8
0
void
Subtitle::removeLines(const RangeList &r, TextTarget target)
{
	if(m_lines.isEmpty())
		return;

	RangeList ranges = r;
	ranges.trimToIndex(m_lines.count() - 1);

	if(ranges.isEmpty())
		return;

	if(target == Both) {
		beginCompositeAction(i18n("Remove Lines"));

		RangeList::ConstIterator rangesIt = ranges.end(), begin = ranges.begin();
		do {
			rangesIt--;
			processAction(new RemoveLinesAction(*this, (*rangesIt).start(), (*rangesIt).end()));
		} while(rangesIt != begin);

		endCompositeAction();
	} else if(target == Secondary) {
		beginCompositeAction(i18n("Remove Lines"));

		RangeList rangesComplement = ranges.complement();
		rangesComplement.trimToRange(Range(ranges.firstIndex(), m_lines.count() - 1));

		// we have to move the secondary texts up (we do it in chunks)
		SubtitleIterator srcIt(*this, rangesComplement);
		SubtitleIterator dstIt(*this, Range::upper(ranges.firstIndex()));
		for(; srcIt.current() && dstIt.current(); ++srcIt, ++dstIt)
			dstIt.current()->setSecondaryText(srcIt.current()->secondaryText());

		// the remaining lines secondary text must be cleared
		for(; dstIt.current(); ++dstIt)
			dstIt.current()->setSecondaryText(SString());

		endCompositeAction();
	} else {                                        // if target == Primary
		beginCompositeAction(i18n("Remove Lines"), true, false);

		RangeList mutableRanges(ranges);
		mutableRanges.trimToIndex(m_lines.count() - 1);

		// first, we need to append as many empty lines as we're to remove
		// we insert them with a greater time than the one of the last (non deleted) line

		int linesCount = m_lines.count();

		Range lastRange = mutableRanges.last();
		int lastIndex = lastRange.end() == linesCount - 1 ? lastRange.start() - 1 : linesCount - 1;
		SubtitleLine *lastLine = lastIndex < linesCount ? m_lines.at(lastIndex) : 0;
		Time showTime(lastLine ? lastLine->hideTime() + 100 : 0);
		Time hideTime(showTime + 1000);

		QList<SubtitleLine *> lines;
		for(int index = 0, size = ranges.indexesCount(); index < size; ++index) {
			lines.append(new SubtitleLine(SString(), SString(), showTime, hideTime));
			showTime.shift(1100);
			hideTime.shift(1100);
		}

		processAction(new InsertLinesAction(*this, lines));

		// then, we move the secondary texts down (we need to iterate from bottom to top for that)
		RangeList rangesComplement = mutableRanges.complement();

		SubtitleIterator srcIt(*this, Range(ranges.firstIndex(), m_lines.count() - lines.count() - 1), true);
		SubtitleIterator dstIt(*this, rangesComplement, true);
		for(; srcIt.current() && dstIt.current(); --srcIt, --dstIt)
			dstIt.current()->setSecondaryText(srcIt.current()->secondaryText());

		// finally, we can remove the specified lines
		RangeList::ConstIterator rangesIt = ranges.end(), begin = ranges.begin();
		do {
			rangesIt--;
			processAction(new RemoveLinesAction(*this, (*rangesIt).start(), (*rangesIt).end()));
		} while(rangesIt != begin);

		endCompositeAction();
	}
}
示例#9
0
SubtitleLine *
Subtitle::insertNewLine(int index, bool timeAfter, TextTarget target)
{
	Q_ASSERT(index <= m_lines.count());

	if(index < 0)
		index = m_lines.count();

	SubtitleLine *newLine = new SubtitleLine();
	int newLineIndex = (target == Secondary) ? m_lines.count() : index;

	if(timeAfter) {
		if(newLineIndex) {              // there is a previous line
			SubtitleLine *prevLine = m_lines.value(newLineIndex - 1);
			newLine->setTimes(prevLine->hideTime() + 100, prevLine->hideTime() + 1000);
		} else if(newLineIndex < m_lines.count()) {     // there is a next line
			SubtitleLine *nextLine = m_lines.value(newLineIndex);
			newLine->setTimes(nextLine->showTime() - 1100, nextLine->showTime() - 100);
		} else
			newLine->setHideTime(1000);
	} else {                                        // ! timeAfter
		if(newLineIndex < m_lines.count()) {    // there is a next line
			SubtitleLine *nextLine = m_lines.at(newLineIndex);
			newLine->setTimes(nextLine->showTime() - 1100, nextLine->showTime() - 100);
		} else if(newLineIndex) {       // there is a previous line
			SubtitleLine *prevLine = m_lines.at(newLineIndex - 1);
			newLine->setTimes(prevLine->hideTime() + 100, prevLine->hideTime() + 1000);
		} else
			newLine->setHideTime(1000);
	}

	if(target == Both || index == m_lines.count()) {
		insertLine(newLine, newLineIndex);
	} else if(target == Primary) {
		beginCompositeAction(i18n("Insert Line"));

		insertLine(newLine, newLineIndex);

		SubtitleLine *line = newLine;
		SubtitleIterator it(*this, Range::full(), false);
		for(it.toIndex(newLineIndex + 1); it.current(); ++it) {
			line->setSecondaryText(it.current()->secondaryText());
			line = it.current();
		}
		line->setSecondaryText(SString());

		endCompositeAction();
	} else if(target == Secondary) {
		beginCompositeAction(i18n("Insert Line"));

		insertLine(newLine, newLineIndex);

		SubtitleIterator it(*this, Range::full(), true);
		SubtitleLine *line = it.current();
		for(--it; it.index() >= index; --it) {
			line->setSecondaryText(it.current()->secondaryText());
			line = it.current();
		}
		line->setSecondaryText(SString());

		newLine = line;

		endCompositeAction();
	}

	return newLine;
}
示例#10
0
void
Subtitle::setSecondaryData(const Subtitle &from, bool usePrimaryData)
{
	beginCompositeAction(i18n("Set Secondary Data"));

	SubtitleIterator fromIt(from, Range::full());
	SubtitleIterator thisIt(*this, Range::full());

	// the errors that we are going to take from 'from':
	const int fromErrors = usePrimaryData ? SubtitleLine::PrimaryOnlyErrors : SubtitleLine::SecondaryOnlyErrors;
	// the errors that we are going to keep:
	const int thisErrors = SubtitleLine::PrimaryOnlyErrors | SubtitleLine::SharedErrors;

	for(SubtitleLine *fromLine = fromIt.current(), *thisLine = thisIt.current(); fromLine && thisLine; ++fromIt, ++thisIt, fromLine = fromIt.current(), thisLine = thisIt.current()) {
		thisLine->setSecondaryText(usePrimaryData ? fromLine->primaryText() : fromLine->secondaryText());
		thisLine->setErrorFlags((thisLine->errorFlags() & thisErrors) | (fromLine->errorFlags() & fromErrors));
	}

	if(fromIt.current()) {          // from subtitle had more lines than *this
		QList<SubtitleLine *> lines;
		for(; fromIt.current(); ++fromIt) {
			SubtitleLine *thisLine = new SubtitleLine(*fromIt.current());
			if(usePrimaryData)
				thisLine->setSecondaryText(thisLine->primaryText());
			thisLine->setPrimaryText(SString());
			thisLine->setErrorFlags(SubtitleLine::PrimaryOnlyErrors, false);
			lines.append(thisLine);
		}
		processAction(new InsertLinesAction(*this, lines));
	} else if(thisIt.current()) {   // *this had more lines than from subtitle
		for(SubtitleLine *thisLine = thisIt.current(); thisLine; ++thisIt, thisLine = thisIt.current()) {
			thisLine->setSecondaryText(SString());
			thisLine->setErrorFlags(SubtitleLine::SecondaryOnlyErrors, false);
		}
	}

	endCompositeAction();
}
示例#11
0
void
Subtitle::splitLines(const RangeList &ranges)
{
	beginCompositeAction(i18n("Split Lines"));

	for(SubtitleIterator it(*this, ranges, true); it.current(); --it) {
		SubtitleLine *line = it.current();

		line->simplifyTextWhiteSpace(SubtitleLine::Primary);
		SString primaryText = line->primaryText();
		if(primaryText.isEmpty())
			continue;

		if(line->primaryLines() < 2) {
			if(primaryText.count(QChar::Space) == 0)
				continue;
			int len = primaryText.length();
			int i = len / 2;
			int j = i + len % 2;
			for(; ; i--, j++) {
				if(primaryText[i] == QChar::Space) {
					primaryText[i] = QChar::LineFeed;
					break;
				}
				Q_ASSERT(j <= len);
				if(primaryText[j] == QChar::Space) {
					primaryText[j] = QChar::LineFeed;
					break;
				}
				if(i == 0) {
					primaryText.append(QChar::LineFeed);
					break;
				}
			}
		}

		double autoDurationsSum = 0;
		QList<double> autoDurations;
		SStringList primaryLines = primaryText.split('\n');
		for(SStringList::ConstIterator ptIt = primaryLines.begin(), ptEnd = primaryLines.end(); ptIt != ptEnd; ++ptIt) {
			const Time &autoDuration = SubtitleLine::autoDuration(ptIt->string(), 60, 50, 50);
			autoDurations.append(autoDuration.toMillis());
			autoDurationsSum += autoDuration.toMillis();
		}

		double factor = (line->durationTime().toMillis() + 1.) / autoDurationsSum;

		SStringList secondaryLines = line->secondaryText().split('\n');
		while(secondaryLines.count() < primaryLines.count())
			secondaryLines.append(SString());
		while(secondaryLines.count() > primaryLines.count()) {
			SString lastLine = secondaryLines.last();
			secondaryLines.pop_back();
			secondaryLines.last() += '\n';
			secondaryLines.last() += lastLine;
		}

		int subLineIndex = it.index(), splitLineIndex = 0;
		for(SStringList::ConstIterator ptIt = primaryLines.begin(), ptEnd = secondaryLines.end(), stIt = secondaryLines.begin(), stEnd = secondaryLines.end(); ptIt != ptEnd && stIt != stEnd; ++ptIt, ++stIt, ++subLineIndex, ++splitLineIndex) {
			if(splitLineIndex) {
				SubtitleLine *newLine = new SubtitleLine();
				newLine->setShowTime(line->hideTime() + 1);
				insertLine(newLine, subLineIndex);
				line = newLine;
			}

			line->setTexts(*ptIt, *stIt);
			line->setDurationTime(Time((factor * autoDurations[splitLineIndex]) - 1.0));
		}
	}

	endCompositeAction();
}