comparison src/mainwindow.cpp @ 422:2af4b5b0bf83

Merge from branch "ignore"
author Chris Cannam <chris.cannam@eecs.qmul.ac.uk>
date Wed, 22 Jun 2011 13:01:50 +0100
parents 653e9694a694
children 06e5c4f3dd7c
comparison
equal deleted inserted replaced
412:498c2ca0b367 422:2af4b5b0bf83
46 #include "settingsdialog.h" 46 #include "settingsdialog.h"
47 #include "moreinformationdialog.h" 47 #include "moreinformationdialog.h"
48 #include "annotatedialog.h" 48 #include "annotatedialog.h"
49 #include "version.h" 49 #include "version.h"
50 #include "workstatuswidget.h" 50 #include "workstatuswidget.h"
51 #include "hgignoredialog.h"
51 52
52 53
53 MainWindow::MainWindow(QString myDirPath) : 54 MainWindow::MainWindow(QString myDirPath) :
54 m_myDirPath(myDirPath), 55 m_myDirPath(myDirPath),
55 m_fsWatcherGeneralTimer(0), 56 m_fsWatcherGeneralTimer(0),
544 m_runner->requestAction(HgAction(ACT_TAG, m_workFolderPath, params)); 545 m_runner->requestAction(HgAction(ACT_TAG, m_workFolderPath, params));
545 } 546 }
546 } 547 }
547 } 548 }
548 549
549 void MainWindow::hgIgnore() 550 void MainWindow::initHgIgnore()
550 { 551 {
551 QString hgIgnorePath;
552 QStringList params;
553
554 hgIgnorePath = m_workFolderPath;
555 hgIgnorePath += "/.hgignore";
556
557 if (!QDir(m_workFolderPath).exists()) return; 552 if (!QDir(m_workFolderPath).exists()) return;
553 QString hgIgnorePath = m_workFolderPath + "/.hgignore";
554
558 QFile f(hgIgnorePath); 555 QFile f(hgIgnorePath);
559 if (!f.exists()) { 556 if (!f.exists()) {
560 f.open(QFile::WriteOnly); 557 f.open(QFile::WriteOnly);
561 QTextStream *ts = new QTextStream(&f); 558 QTextStream *ts = new QTextStream(&f);
562 *ts << "syntax: glob\n"; 559 *ts << "syntax: glob\n";
563 delete ts; 560 delete ts;
564 f.close(); 561 f.close();
565 } 562 }
566 563 }
564
565 void MainWindow::hgEditIgnore()
566 {
567 if (!QDir(m_workFolderPath).exists()) return;
568
569 initHgIgnore();
570
571 QString hgIgnorePath = m_workFolderPath + "/.hgignore";
572 QStringList params;
573
567 params << hgIgnorePath; 574 params << hgIgnorePath;
568 575
569 QString editor = getEditorBinaryName(); 576 QString editor = getEditorBinaryName();
570 577
571 if (editor == "") { 578 if (editor == "") {
572 DEBUG << "Failed to find a text editor" << endl; 579 QMessageBox::critical
573 //!!! visible error! 580 (this, tr("Edit .hgignore"),
581 tr("Failed to locate a system text editor program!"));
574 return; 582 return;
575 } 583 }
576 584
577 HgAction action(ACT_HG_IGNORE, m_workFolderPath, params); 585 HgAction action(ACT_HG_IGNORE, m_workFolderPath, params);
578 action.executable = editor; 586 action.executable = editor;
579 587
580 m_runner->requestAction(action); 588 m_runner->requestAction(action);
581 } 589 }
582 590
591 static QString regexEscape(QString filename)
592 {
593 return filename
594 .replace(".", "\\.")
595 .replace("[", "\\[")
596 .replace("]", "\\]")
597 .replace("(", "\\(")
598 .replace(")", "\\)")
599 .replace("?", "\\?");
600 }
601
583 void MainWindow::hgIgnoreFiles(QStringList files) 602 void MainWindow::hgIgnoreFiles(QStringList files)
584 { 603 {
585 //!!! not implemented yet 604 if (!QDir(m_workFolderPath).exists() || files.empty()) return;
586 DEBUG << "MainWindow::hgIgnoreFiles: Not implemented" << endl; 605
606 // we should:
607 //
608 // * show the user the list of file names selected
609 //
610 // * offer a choice (depending on the files selected?)
611 //
612 // - ignore only these files
613 //
614 // - ignore files with these names, in any subdirectories?
615 //
616 // - ignore all files with this extension (if they have a common
617 // extension)?
618 //
619 // - ignore all files with these extensions (if they have any
620 // extensions?)
621
622 DEBUG << "MainWindow::hgIgnoreFiles: File names are:" << endl;
623 foreach (QString file, files) DEBUG << file << endl;
624
625 QSet<QString> suffixes;
626 foreach (QString file, files) {
627 QString s = QFileInfo(file).suffix();
628 if (s != "") suffixes.insert(s);
629 }
630
631 QString directory;
632 bool dirCount = 0;
633 foreach (QString file, files) {
634 QString d = QFileInfo(file).path();
635 if (d != directory) {
636 ++dirCount;
637 directory = d;
638 }
639 }
640 if (dirCount != 1 || directory == ".") directory = "";
641
642 HgIgnoreDialog::IgnoreType itype =
643 HgIgnoreDialog::confirmIgnore
644 (this, files, QStringList::fromSet(suffixes), directory);
645
646 DEBUG << "hgIgnoreFiles: Ignore type is " << itype << endl;
647
648 if (itype == HgIgnoreDialog::IgnoreNothing) return;
649
650 // Now, .hgignore can be switched from regex to glob syntax
651 // part-way through -- and glob is much simpler for us, so we
652 // should do that if it's in regex mode at the end of the file.
653
654 initHgIgnore();
655
656 QString hgIgnorePath = m_workFolderPath + "/.hgignore";
657
658 // hgignore file should now exist (initHgIgnore should have
659 // created it if it didn't). Check for glob status first
660
661 QFile f(hgIgnorePath);
662 if (!f.exists()) {
663 std::cerr << "MainWindow::ignoreFiles: Internal error: .hgignore file not found (even though we were supposed to have created it)" << std::endl;
664 return;
665 }
666
667 f.open(QFile::ReadOnly);
668 bool glob = false;
669 while (!f.atEnd()) {
670 QByteArray ba = f.readLine();
671 QString s = QString::fromLocal8Bit(ba).trimmed();
672 if (s.startsWith("syntax:")) {
673 if (s.endsWith("glob")) {
674 glob = true;
675 } else {
676 glob = false;
677 }
678 }
679 }
680 f.close();
681
682 f.open(QFile::Append);
683 QTextStream out(&f);
684
685 if (!glob) {
686 out << "syntax: glob" << endl;
687 }
688
689 QString info = "<qt><h3>" + tr("Ignored files") + "</h3><p>";
690 info += tr("The following lines have been added to the .hgignore file for this working copy:");
691 info += "</p><code>";
692
693 QStringList args;
694 if (itype == HgIgnoreDialog::IgnoreAllFilesOfGivenSuffixes) {
695 args = QStringList::fromSet(suffixes);
696 } else if (itype == HgIgnoreDialog::IgnoreGivenFilesOnly) {
697 args = files;
698 } else if (itype == HgIgnoreDialog::IgnoreAllFilesOfGivenNames) {
699 QSet<QString> names;
700 foreach (QString f, files) {
701 names << QFileInfo(f).fileName();
702 }
703 args = QStringList::fromSet(names);
704 } else if (itype == HgIgnoreDialog::IgnoreWholeDirectory) {
705 args << directory;
706 }
707
708 bool first = true;
709
710 foreach (QString a, args) {
711 QString line;
712 if (itype == HgIgnoreDialog::IgnoreAllFilesOfGivenSuffixes) {
713 line = "*." + a;
714 } else if (itype == HgIgnoreDialog::IgnoreGivenFilesOnly) {
715 // Doesn't seem to be possible to do this with a glob,
716 // because the glob is always unanchored and there is no
717 // equivalent of ^ to anchor it
718 line = "re:^" + regexEscape(a);
719 } else if (itype == HgIgnoreDialog::IgnoreAllFilesOfGivenNames) {
720 line = a;
721 } else if (itype == HgIgnoreDialog::IgnoreWholeDirectory) {
722 line = "re:^" + regexEscape(a) + "/";
723 }
724 if (line != "") {
725 out << line << endl;
726 if (!first) info += "<br>";
727 first = false;
728 info += xmlEncode(line);
729 }
730 }
731
732 f.close();
733
734 info += "</code></qt>";
735
736 QMessageBox::information(this, tr("Ignored files"),
737 info);
738
739 hgRefresh();
587 } 740 }
588 741
589 void MainWindow::hgUnIgnoreFiles(QStringList files) 742 void MainWindow::hgUnIgnoreFiles(QStringList files)
590 { 743 {
591 //!!! not implemented yet 744 // Not implemented: edit the .hgignore instead
592 DEBUG << "MainWindow::hgUnIgnoreFiles: Not implemented" << endl; 745 hgEditIgnore();
593 } 746 }
594 747
595 QString MainWindow::getDiffBinaryName() 748 QString MainWindow::getDiffBinaryName()
596 { 749 {
597 QSettings settings; 750 QSettings settings;
2337 connect(m_hgCommitAct, SIGNAL(triggered()), this, SLOT(hgCommit())); 2490 connect(m_hgCommitAct, SIGNAL(triggered()), this, SLOT(hgCommit()));
2338 connect(m_hgFolderDiffAct, SIGNAL(triggered()), this, SLOT(hgFolderDiff())); 2491 connect(m_hgFolderDiffAct, SIGNAL(triggered()), this, SLOT(hgFolderDiff()));
2339 connect(m_hgUpdateAct, SIGNAL(triggered()), this, SLOT(hgUpdate())); 2492 connect(m_hgUpdateAct, SIGNAL(triggered()), this, SLOT(hgUpdate()));
2340 connect(m_hgRevertAct, SIGNAL(triggered()), this, SLOT(hgRevert())); 2493 connect(m_hgRevertAct, SIGNAL(triggered()), this, SLOT(hgRevert()));
2341 connect(m_hgMergeAct, SIGNAL(triggered()), this, SLOT(hgMerge())); 2494 connect(m_hgMergeAct, SIGNAL(triggered()), this, SLOT(hgMerge()));
2342 connect(m_hgIgnoreAct, SIGNAL(triggered()), this, SLOT(hgIgnore())); 2495 connect(m_hgEditIgnoreAct, SIGNAL(triggered()), this, SLOT(hgEditIgnore()));
2343 2496
2344 connect(m_settingsAct, SIGNAL(triggered()), this, SLOT(settings())); 2497 connect(m_settingsAct, SIGNAL(triggered()), this, SLOT(settings()));
2345 connect(m_openAct, SIGNAL(triggered()), this, SLOT(open())); 2498 connect(m_openAct, SIGNAL(triggered()), this, SLOT(open()));
2346 connect(m_changeRemoteRepoAct, SIGNAL(triggered()), this, SLOT(changeRemoteRepo())); 2499 connect(m_changeRemoteRepoAct, SIGNAL(triggered()), this, SLOT(changeRemoteRepo()));
2347 2500
2491 m_hgRemoveAct->setEnabled(m_localRepoActionsEnabled); 2644 m_hgRemoveAct->setEnabled(m_localRepoActionsEnabled);
2492 m_hgUpdateAct->setEnabled(m_localRepoActionsEnabled); 2645 m_hgUpdateAct->setEnabled(m_localRepoActionsEnabled);
2493 m_hgCommitAct->setEnabled(m_localRepoActionsEnabled); 2646 m_hgCommitAct->setEnabled(m_localRepoActionsEnabled);
2494 m_hgMergeAct->setEnabled(m_localRepoActionsEnabled); 2647 m_hgMergeAct->setEnabled(m_localRepoActionsEnabled);
2495 m_hgServeAct->setEnabled(m_localRepoActionsEnabled); 2648 m_hgServeAct->setEnabled(m_localRepoActionsEnabled);
2496 m_hgIgnoreAct->setEnabled(m_localRepoActionsEnabled); 2649 m_hgEditIgnoreAct->setEnabled(m_localRepoActionsEnabled);
2497 2650
2498 DEBUG << "m_localRepoActionsEnabled = " << m_localRepoActionsEnabled << endl; 2651 DEBUG << "m_localRepoActionsEnabled = " << m_localRepoActionsEnabled << endl;
2499 DEBUG << "canCommit = " << m_hgTabs->canCommit() << endl; 2652 DEBUG << "canCommit = " << m_hgTabs->canCommit() << endl;
2500 2653
2501 m_hgAddAct->setEnabled(m_localRepoActionsEnabled && m_hgTabs->canAdd()); 2654 m_hgAddAct->setEnabled(m_localRepoActionsEnabled && m_hgTabs->canAdd());
2708 m_hgMergeAct->setShortcut(tr("Ctrl+M")); 2861 m_hgMergeAct->setShortcut(tr("Ctrl+M"));
2709 m_hgMergeAct->setStatusTip(tr("Merge the two independent sets of changes in the local repository into the working folder")); 2862 m_hgMergeAct->setStatusTip(tr("Merge the two independent sets of changes in the local repository into the working folder"));
2710 2863
2711 //Advanced actions 2864 //Advanced actions
2712 2865
2713 m_hgIgnoreAct = new QAction(tr("Edit .hgignore File"), this); 2866 m_hgEditIgnoreAct = new QAction(tr("Edit .hgignore File"), this);
2714 m_hgIgnoreAct->setStatusTip(tr("Edit the .hgignore file, containing the names of files that should be ignored by Mercurial")); 2867 m_hgEditIgnoreAct->setStatusTip(tr("Edit the .hgignore file, containing the names of files that should be ignored by Mercurial"));
2715 2868
2716 m_hgServeAct = new QAction(tr("Serve via HTTP"), this); 2869 m_hgServeAct = new QAction(tr("Serve via HTTP"), this);
2717 m_hgServeAct->setStatusTip(tr("Serve local repository via http for workgroup access")); 2870 m_hgServeAct->setStatusTip(tr("Serve local repository via http for workgroup access"));
2718 2871
2719 //Help actions 2872 //Help actions
2758 remoteMenu->addAction(m_hgPushAct); 2911 remoteMenu->addAction(m_hgPushAct);
2759 remoteMenu->addSeparator(); 2912 remoteMenu->addSeparator();
2760 remoteMenu->addAction(m_changeRemoteRepoAct); 2913 remoteMenu->addAction(m_changeRemoteRepoAct);
2761 2914
2762 m_advancedMenu = menuBar()->addMenu(tr("&Advanced")); 2915 m_advancedMenu = menuBar()->addMenu(tr("&Advanced"));
2763 m_advancedMenu->addAction(m_hgIgnoreAct); 2916 m_advancedMenu->addAction(m_hgEditIgnoreAct);
2764 m_advancedMenu->addSeparator(); 2917 m_advancedMenu->addSeparator();
2765 m_advancedMenu->addAction(m_hgServeAct); 2918 m_advancedMenu->addAction(m_hgServeAct);
2766 2919
2767 m_helpMenu = menuBar()->addMenu(tr("&Help")); 2920 m_helpMenu = menuBar()->addMenu(tr("&Help"));
2768 m_helpMenu->addAction(m_aboutAct); 2921 m_helpMenu->addAction(m_aboutAct);