<commit_before>/**
 * @file
 * String formatting code.
 * Much of this code was adapted from Python's string formatting
 * code, but the actual formatting of individual items is done
 * by constructing printf formats and using them. Ugly, but easy.
 * There may be some dodgy assumptions about lengths here.
 */

#include "angort.h"
#include <ctype.h>
#define max(a,b) ((a)>(b)?(a):(b))

namespace angort {

static void formatSignedInt(char *s,int i,int width,int precision, bool zeropad, bool negpad){
    char format[32];
    sprintf(format,"%%%s%dd",zeropad?"0":"",negpad?-width:width);
    sprintf(s,format,i);
}

static void formatUnsignedInt(char *s,unsigned int i,int width,int precision, bool zeropad, bool negpad){
    char format[32];
    sprintf(format,"%%%s%du",zeropad?"0":"",negpad?-width:width);
    sprintf(s,format,i);
}

static void formatSignedLong(char *s,long i,int width,int precision, bool zeropad, bool negpad){
    char format[32];
    sprintf(format,"%%%s%dld",zeropad?"0":"",negpad?-width:width);
    sprintf(s,format,i);
}

static void formatUnsignedLong(char *s,unsigned long i,int width,int precision, bool zeropad, bool negpad){
    char format[32];
    sprintf(format,"%%%s%dlu",zeropad?"0":"",negpad?-width:width);
    sprintf(s,format,i);
}

static void formatHexInt(char *s,unsigned int i,int width,int precision, bool zeropad, bool negpad){
    char format[32];
    sprintf(format,"%%%s%dx",zeropad?"0":"",negpad?-width:width);
    sprintf(s,format,i);
}
static void formatHexLong(char *s,unsigned long i,int width,int precision, bool zeropad, bool negpad){
    char format[32];
    sprintf(format,"%%%s%dlx",zeropad?"0":"",negpad?-width:width);
    sprintf(s,format,i);
}

static void formatFloat(char *s,double f,int width,int precision, bool zeropad, bool negpad){
    char format[32];
    if(precision!=-9999)
        sprintf(format,"%%%s%d.%df",zeropad?"0":"",negpad?-width:width,precision);
    else
        sprintf(format,"%%%s%df",zeropad?"0":"",negpad?-width:width);
    sprintf(s,format,f);
}

static void formatFloat2(char *s,double f,int width,int precision, bool zeropad, bool negpad){
    char format[32];
    if(precision!=-9999)
        sprintf(format,"%%%s%d.%dg",zeropad?"0":"",negpad?-width:width,precision);
    else
        sprintf(format,"%%%s%dg",zeropad?"0":"",negpad?-width:width);
    sprintf(s,format,f);
}

static void formatString(char *s,const char *in,int width,int precision, bool negpad){
    char format[32];
    snprintf(format,20,"%%%ds",negpad?-width:width);
    sprintf(s,format,in);
}

void format(Value *out,Value *formatVal,ArrayList<Value> *items){

    // sorry, it actually has to be a string.
    if(formatVal->t != Types::tString)
        throw RUNT(EX_TYPE,"format must be a string");

    const char *format = Types::tString->getData(formatVal);

    ArrayListIterator<Value> iter(items);
    iter.first();

    unsigned int width,precision;

    // pass 1, work out the buffer size
    int size=0;
    int strsz;
    for(const char *f = format;*f;f++){
        precision=0;
        width=0;
        if(*f=='%'){
            const char *p = f++;
            if(*f=='-')f++;
            while(isdigit(*f))
                width = (width*10) + (*f++ - '0');
            if(*f=='.'){
                f++;
                while(isdigit(*f))
                    precision = (precision*10) + (*f++ - '0');
            }
            while(*f && *f!='%' && !isalpha(*f))
                ;
            if((*f=='l' || *f=='z') && (f[1]=='d' || f[1]=='u' || f[1]=='x'))
                ++f; // skip length flag (dealt with in pass 2)
            switch(*f){
            case 'c':
                iter.next();
                // fall through
            case '%':
                size++;
                break;
            case 'd':case 'u':case 'x':
                // 50 should be plenty
                iter.next();
                size+=max(50,width);
                break;
            case 'f':
            case 'g':
                iter.next();
                size+=50; // got to draw the line somewhere.
                break;
            case 's':{
                const StringBuffer& b = iter.current()->toString();
                strsz = max(strlen(b.get()),width);
                size+=strsz;
                iter.next();
                break;
            }
            default://unknown code; just add the rest of the string in. Ugh.
                size+=strlen(p);
                goto expand;
                break;
            }
        } else
            size++;
    }
expand:
    // now allocate a temporary buffer
    char *base=(char *)malloc(size+2);
    memset(base,0,size+1);
    char *s = base;

    // pass 2 - do the formatting
    iter.first();
    for(const char *f = format;*f;f++){
        if(*f=='%'){
            bool isLong=false;
            bool zeropad=false;
            bool negpad=false;
            const char *p = f++;
            precision=-9999; // rogue value for "no precision"
            width=0;
            if(*f=='-'){
                negpad=true;
                f++;
            }
            if(*f=='0')
                zeropad=true;
            while(isdigit(*f))
                width = (width*10) + (*f++ - '0');
            if(*f=='.'){
                precision=0;
                f++;
                while(isdigit(*f))
                    precision = (precision*10) + (*f++ - '0');
            }
            while(*f && *f!='%' && !isalpha(*f))
                f++;
            // length flags
            if((*f=='l' || *f=='z') && (f[1]=='d' || f[1]=='u' || f[1]=='x')){
                if(*f=='l')isLong=true;
                ++f;
            }

            switch(*f){
            case 'c':
                *s++ = iter.current()->toInt();
                iter.next();
                break;
            case 'd':
                if(isLong)
                    formatSignedLong(s,iter.current()->toLong(),width,precision,zeropad,negpad);
                else
                    formatSignedInt(s,iter.current()->toInt(),width,precision,zeropad,negpad);
                s+=strlen(s);
                iter.next();
                break;
            case 'u':
                if(isLong)
                    formatUnsignedLong(s,iter.current()->toLong(),width,precision,zeropad,negpad);
                else
                    formatUnsignedInt(s,iter.current()->toInt(),width,precision,zeropad,negpad);
                s+=strlen(s);
                iter.next();
                break;
            case 'x':
                if(isLong)
                    formatHexInt(s,iter.current()->toInt(),width,precision,zeropad,negpad);
                else
                    formatHexLong(s,iter.current()->toInt(),width,precision,zeropad,negpad);
                s+=strlen(s);
                iter.next();
                break;
            case 'f':
                formatFloat(s,iter.current()->toDouble(),width,precision,zeropad,negpad);
                s+=strlen(s);
                iter.next();
                break;
            case 'g':
                formatFloat2(s,iter.current()->toDouble(),width,precision,zeropad,negpad);
                s+=strlen(s);
                iter.next();
                break;
            case 's':{
                const StringBuffer& b = iter.current()->toString();
                formatString(s,b.get(),width,precision,negpad);
                s+=strlen(s);
                iter.next();
                break;
            }
            default:
                strcpy(s,p);
                s+=strlen(s);
                goto end;
            }
        } else
            *s++ = *f;
    }
end:
    *s=0;
    Types::tString->set(out,base);
    free(base);
}

}
<commit_msg>%e formatting<commit_after>/**
 * @file
 * String formatting code.
 * Much of this code was adapted from Python's string formatting
 * code, but the actual formatting of individual items is done
 * by constructing printf formats and using them. Ugly, but easy.
 * There may be some dodgy assumptions about lengths here.
 */

#include "angort.h"
#include <ctype.h>
#define max(a,b) ((a)>(b)?(a):(b))

namespace angort {

static void formatSignedInt(char *s,int i,int width,int precision, bool zeropad, bool negpad){
    char format[32];
    sprintf(format,"%%%s%dd",zeropad?"0":"",negpad?-width:width);
    sprintf(s,format,i);
}

static void formatUnsignedInt(char *s,unsigned int i,int width,int precision, bool zeropad, bool negpad){
    char format[32];
    sprintf(format,"%%%s%du",zeropad?"0":"",negpad?-width:width);
    sprintf(s,format,i);
}

static void formatSignedLong(char *s,long i,int width,int precision, bool zeropad, bool negpad){
    char format[32];
    sprintf(format,"%%%s%dld",zeropad?"0":"",negpad?-width:width);
    sprintf(s,format,i);
}

static void formatUnsignedLong(char *s,unsigned long i,int width,int precision, bool zeropad, bool negpad){
    char format[32];
    sprintf(format,"%%%s%dlu",zeropad?"0":"",negpad?-width:width);
    sprintf(s,format,i);
}

static void formatHexInt(char *s,unsigned int i,int width,int precision, bool zeropad, bool negpad){
    char format[32];
    sprintf(format,"%%%s%dx",zeropad?"0":"",negpad?-width:width);
    sprintf(s,format,i);
}
static void formatHexLong(char *s,unsigned long i,int width,int precision, bool zeropad, bool negpad){
    char format[32];
    sprintf(format,"%%%s%dlx",zeropad?"0":"",negpad?-width:width);
    sprintf(s,format,i);
}

static void formatFloat(char *s,double f,int width,int precision, bool zeropad, bool negpad){
    char format[32];
    if(precision!=-9999)
        sprintf(format,"%%%s%d.%df",zeropad?"0":"",negpad?-width:width,precision);
    else
        sprintf(format,"%%%s%df",zeropad?"0":"",negpad?-width:width);
    sprintf(s,format,f);
}

static void formatFloat2(char *s,double f,int width,int precision, bool zeropad, bool negpad){
    char format[32];
    if(precision!=-9999)
        sprintf(format,"%%%s%d.%dg",zeropad?"0":"",negpad?-width:width,precision);
    else
        sprintf(format,"%%%s%dg",zeropad?"0":"",negpad?-width:width);
    sprintf(s,format,f);
}

static void formatScientific(char *s,double f,int width,int precision, bool zeropad, bool negpad){
    char format[32];
    if(precision!=-9999)
        sprintf(format,"%%%s%d.%de",zeropad?"0":"",negpad?-width:width,precision);
    else
        sprintf(format,"%%%s%de",zeropad?"0":"",negpad?-width:width);
    sprintf(s,format,f);
}

static void formatString(char *s,const char *in,int width,int precision, bool negpad){
    char format[32];
    snprintf(format,20,"%%%ds",negpad?-width:width);
    sprintf(s,format,in);
}

void format(Value *out,Value *formatVal,ArrayList<Value> *items){

    // sorry, it actually has to be a string.
    if(formatVal->t != Types::tString)
        throw RUNT(EX_TYPE,"format must be a string");

    const char *format = Types::tString->getData(formatVal);

    ArrayListIterator<Value> iter(items);
    iter.first();

    unsigned int width,precision;

    // pass 1, work out the buffer size
    int size=0;
    int strsz;
    for(const char *f = format;*f;f++){
        precision=0;
        width=0;
        if(*f=='%'){
            const char *p = f++;
            if(*f=='-')f++;
            while(isdigit(*f))
                width = (width*10) + (*f++ - '0');
            if(*f=='.'){
                f++;
                while(isdigit(*f))
                    precision = (precision*10) + (*f++ - '0');
            }
            while(*f && *f!='%' && !isalpha(*f))
                ;
            if((*f=='l' || *f=='z') && (f[1]=='d' || f[1]=='u' || f[1]=='x'))
                ++f; // skip length flag (dealt with in pass 2)
            switch(*f){
            case 'c':
                iter.next();
                // fall through
            case '%':
                size++;
                break;
            case 'd':case 'u':case 'x':
                // 50 should be plenty
                iter.next();
                size+=max(50,width);
                break;
            case 'f':
            case 'g':
            case 'e':
                iter.next();
                size+=50; // got to draw the line somewhere.
                break;
            case 's':{
                const StringBuffer& b = iter.current()->toString();
                strsz = max(strlen(b.get()),width);
                size+=strsz;
                iter.next();
                break;
            }
            default://unknown code; just add the rest of the string in. Ugh.
                size+=strlen(p);
                goto expand;
                break;
            }
        } else
            size++;
    }
expand:
    // now allocate a temporary buffer
    char *base=(char *)malloc(size+2);
    memset(base,0,size+1);
    char *s = base;

    // pass 2 - do the formatting
    iter.first();
    for(const char *f = format;*f;f++){
        if(*f=='%'){
            bool isLong=false;
            bool zeropad=false;
            bool negpad=false;
            const char *p = f++;
            precision=-9999; // rogue value for "no precision"
            width=0;
            if(*f=='-'){
                negpad=true;
                f++;
            }
            if(*f=='0')
                zeropad=true;
            while(isdigit(*f))
                width = (width*10) + (*f++ - '0');
            if(*f=='.'){
                precision=0;
                f++;
                while(isdigit(*f))
                    precision = (precision*10) + (*f++ - '0');
            }
            while(*f && *f!='%' && !isalpha(*f))
                f++;
            // length flags
            if((*f=='l' || *f=='z') && (f[1]=='d' || f[1]=='u' || f[1]=='x')){
                if(*f=='l')isLong=true;
                ++f;
            }

            switch(*f){
            case 'c':
                *s++ = iter.current()->toInt();
                iter.next();
                break;
            case 'd':
                if(isLong)
                    formatSignedLong(s,iter.current()->toLong(),width,precision,zeropad,negpad);
                else
                    formatSignedInt(s,iter.current()->toInt(),width,precision,zeropad,negpad);
                s+=strlen(s);
                iter.next();
                break;
            case 'u':
                if(isLong)
                    formatUnsignedLong(s,iter.current()->toLong(),width,precision,zeropad,negpad);
                else
                    formatUnsignedInt(s,iter.current()->toInt(),width,precision,zeropad,negpad);
                s+=strlen(s);
                iter.next();
                break;
            case 'x':
                if(isLong)
                    formatHexInt(s,iter.current()->toInt(),width,precision,zeropad,negpad);
                else
                    formatHexLong(s,iter.current()->toInt(),width,precision,zeropad,negpad);
                s+=strlen(s);
                iter.next();
                break;
            case 'f':
                formatFloat(s,iter.current()->toDouble(),width,precision,zeropad,negpad);
                s+=strlen(s);
                iter.next();
                break;
            case 'g':
                formatFloat2(s,iter.current()->toDouble(),width,precision,zeropad,negpad);
                s+=strlen(s);
                iter.next();
                break;
            case 'e':
                formatScientific(s,iter.current()->toDouble(),width,precision,zeropad,negpad);
                s+=strlen(s);
                iter.next();
                break;
            case 's':{
                const StringBuffer& b = iter.current()->toString();
                formatString(s,b.get(),width,precision,negpad);
                s+=strlen(s);
                iter.next();
                break;
            }
            default:
                strcpy(s,p);
                s+=strlen(s);
                goto end;
            }
        } else
            *s++ = *f;
    }
end:
    *s=0;
    Types::tString->set(out,base);
    free(base);
}

}
<|endoftext|>


<commit_before>#include "mainwindow.h"
#include <QApplication>
#include <QGridLayout>
#include <QWidget>
#include <QLabel>
#include <QMenuBar>
#include <QToolBar>
#include <QStatusBar>
#include <QAction>
#include <QFileDialog>
#include <QDebug>
#include <QMessageBox>
#include "newimagedialog.h"
#include "util.h"
#include "imageeditwindow.h"

/**
 * @brief MainWindow::MainWindow
 * @brief mainwindow的构造函数
 * @param parent 是qt widget的父指针
 * @return 没有返回值
 */
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent)
{
    this->initWindowLayout();
    this->initAction();

    QIcon icon(":/image/open.png"); //设置程序图标
    this->setWindowIcon(icon);

    this->fileMenu = this->menuBar()->addMenu("&File");
    this->fileMenu->addAction(this->loadSourceImageAction);

    this->helpMenu = this->menuBar()->addMenu("&Help");
    this->helpMenu->addAction(this->aboutAction);

    this->menuBar()->setStyleSheet(" QMenuBar{background-color: #333337; padding-left: 5px;}\
                            QMenuBar::item {background-color: #333337; padding:2px; margin:6px 10px 0px 0px;} \
                            QMenuBar::item:selected {background: #3e3e40;} \
                            QMenuBar::item:pressed {background: #1b1b1c;}\
                            ");

    QToolBar* toolbar = this->addToolBar("Standard Tool Bar");
    toolbar->addAction(this->loadSourceImageAction);

    QStatusBar* statusBar = this->statusBar();

}

/**
 * @brief MainWindow::initAction
 * @brief 用于mainwindow的action的定义、connect、插入
 * @param 没有参数
 * @return 没有返回值
 */
void MainWindow::initAction(){
    this->loadSourceImageAction = new QAction(QIcon(":/image/open.png"),"&Load",this);
    QObject::connect(this->loadSourceImageAction, &QAction::triggered, this, &MainWindow::loadSourceImage);

    this->viewSourceImageAction = new QAction(QIcon(":/image/open.png"),"&View",this);
    QObject::connect(this->viewSourceImageAction, &QAction::triggered, this, &MainWindow::viewSourceImage);

    this->editSourceGuidanceAction = new QAction(QIcon(":/image/open.png"),"&Edit",this);
    QObject::connect(this->editSourceGuidanceAction, &QAction::triggered, this, &MainWindow::editSourceGuidance);

    this->viewTargetGuidanceAction = new QAction(QIcon(":/image/open.png"),"&View",this);
    QObject::connect(this->viewTargetGuidanceAction, &QAction::triggered, this, &MainWindow::viewTargetGuidance);

    this->newImageAction = new QAction(QIcon(":/image/open.png"),"&Create new guidance",this);
    QObject::connect(this->newImageAction, &QAction::triggered, this, &MainWindow::newImage);

    this->editTargetGuidanceAction = new QAction(QIcon(":/image/open.png"),"&Edit",this);
    QObject::connect(this->editTargetGuidanceAction, &QAction::triggered, this, &MainWindow::editTargetGuidance);

    this->aboutAction = new QAction(QIcon(":/image/open.png"),"&About",this);
    QObject::connect(this->aboutAction, &QAction::triggered, this, &MainWindow::about);

    //Action 插入段
    this->sourceImageLabel->addAction(this->viewSourceImageAction);     //左上角的view
    this->sourceImageLabel->addAction(this->loadSourceImageAction);     //左上角的load

    this->sourceGuidanceLabel->addAction(new QAction("&View",this));
    this->sourceGuidanceLabel->addAction(this->editSourceGuidanceAction);

    this->targetGuidanceLabel->addAction(this->viewTargetGuidanceAction);
    this->targetGuidanceLabel->addAction(this->newImageAction);
    this->targetGuidanceLabel->addAction(this->editTargetGuidanceAction);

}

/**
 * @brief MainWindow::loadSourceImage
 * @brief load image的action的入口函数，用于载入一个原图，并显示在左上角，顺带初始化右上角的source guidance（同等大小的白图）。
 * @param 没有参数
 * @return 没有返回值
 */
void MainWindow::loadSourceImage(){
    QFileDialog* fileDialog = new QFileDialog(this, tr("Open image File"), ".", tr("Image files(*.png)"));
    fileDialog->setFileMode(QFileDialog::ExistingFiles);
    fileDialog->setViewMode(QFileDialog::Detail);

    if (fileDialog->exec() == QDialog::Accepted)    //成功选择一个png图片
    {
        this->sourceImage =new QImage(fileDialog->selectedFiles().first());     //此处会有内存泄漏，以后处理
        this->sourceImage->save("./sourceImage.png");
        this->sourceImageFrame->setStyleSheet("background-image: url(./sourceImage.png);background-position:center center;background-repeat: no-repeat");

        this->sourceGuidance = new QImage(this->sourceImage->width(), this->sourceImage->height(), QImage::Format_RGB888);  //新建一个同等大小的空图像
        this->sourceGuidance->fill(QColor(255,255,255));        //填充白色
        for(QString elem : Util::guidanceChannel){
            this->sourceGuidance->save("./sourceGuidance"+elem+".png");
        }
        this->sourceGuidanceFrame->setStyleSheet("background-image: url(./sourceGuidanceLabelChannel.png);background-position:center center;background-repeat: no-repeat"); //显示在右上角
    }
}

MainWindow::~MainWindow()
{
}

/**
 * @brief MainWindow::initWindowLayout
 * @brief 用于管理mainwindow的窗口设置、layout布局、内部控件声明及摆放
 * @param 没有参数
 * @return 没有返回值
 */
void MainWindow::initWindowLayout(){
    this->setWindowState(Qt::WindowMaximized);      //设置窗口最大化
    this->setStyleSheet("background-color: #333337; color: #f1f1f1;");      //设置窗口样式（酷黑）

    QWidget* centerWidget = new QWidget(this);  //声明widget并设置为窗口的中央widget（这样才能设置layout）
    this->setCentralWidget(centerWidget);

    QGridLayout* gridLayout = new QGridLayout(centerWidget);    //在中央widget开启网格布局
    centerWidget->setLayout(gridLayout);

    this->sourceImageLabel = new QLabel(centerWidget);  //左上角label声明：放置source image
    this->sourceImageLabel->setStyleSheet("background-color: #696969;");
    gridLayout->addWidget(sourceImageLabel,0,0);
    this->sourceImageLabel->setContextMenuPolicy(Qt::ActionsContextMenu);       //激活右键菜单策略
    QGridLayout* sourceImageLabelGridLayout = new QGridLayout(this->sourceImageLabel);    //在label内建一个layout放置一个Frame，可以保证右键菜单的背景不受改变
    this->sourceImageLabel->setLayout(sourceImageLabelGridLayout);
    this->sourceImageFrame = new QFrame(this->sourceImageLabel);
    sourceImageLabelGridLayout->addWidget(this->sourceImageFrame,0,0);

    this->sourceGuidanceLabel = new QLabel(centerWidget);   //右上角label声明：放置source guidance
    this->sourceGuidanceLabel->setStyleSheet("background-color: #696969;");
    gridLayout->addWidget(this->sourceGuidanceLabel,0,1);
    this->sourceGuidanceLabel->setContextMenuPolicy(Qt::ActionsContextMenu);       //激活右键菜单策略
    QGridLayout* sourceGuidanceLabelGridLayout = new QGridLayout(this->sourceGuidanceLabel);    //在label内建一个layout放置一个Frame，可以保证右键菜单的背景不受改变
    this->sourceGuidanceLabel->setLayout(sourceGuidanceLabelGridLayout);
    this->sourceGuidanceFrame = new QFrame(this->sourceGuidanceLabel);
    sourceGuidanceLabelGridLayout->addWidget(this->sourceGuidanceFrame,0,0);

    this->targetGuidanceLabel = new QLabel(centerWidget);   //  左下角label声明：放置target guidance
    this->targetGuidanceLabel->setStyleSheet("background-color: #696969;");
    gridLayout->addWidget(this->targetGuidanceLabel,1,0);
    this->targetGuidanceLabel->setContextMenuPolicy(Qt::ActionsContextMenu);       //激活右键菜单策略
    QGridLayout* targetGuidanceLabelGridLayout = new QGridLayout(this->targetGuidanceLabel);    //在label内建一个layout放置一个Frame，可以保证右键菜单的背景不受改变
    this->targetGuidanceLabel->setLayout(targetGuidanceLabelGridLayout);
    this->targetGuidanceFrame = new QFrame(this->targetGuidanceLabel);
    targetGuidanceLabelGridLayout->addWidget(this->targetGuidanceFrame,0,0);

    QLabel* label4 = new QLabel(centerWidget);
    label4->setStyleSheet("background-color: #696969;");
    gridLayout->addWidget(label4,1,1);
    label4->setContextMenuPolicy(Qt::ActionsContextMenu);       //激活右键菜单策略
    label4->addAction(new QAction("&View",this));

}

/**
 * @brief MainWindow::newImage
 * @brief mainwindow中点击新建导引图片的action
 * @param 没有参数
 * @return 没有返回值
 */
void MainWindow::newImage(){
    NewImageDialog* newImageDialog = new NewImageDialog();
    if(newImageDialog->exec() == QDialog::Accepted){
        this->targetGuidanceFrame->setStyleSheet("background-image: url(./targetGuidanceLabelChannel.png);background-position:center center;background-repeat: no-repeat"); //显示在右上角
    }
}

void MainWindow::editSourceGuidance(){
    ImageEditWindow* imageEditWindow = new ImageEditWindow(config::sourceGuidance, config::editable, this);
    imageEditWindow->show();
}

void MainWindow::viewSourceImage(){
    ImageEditWindow* imageEditWindow = new ImageEditWindow(config::sourceImage, config::readOnly, this);
    imageEditWindow->show();
}

void MainWindow::about()
{
    QMessageBox::about(this, tr("About Uncle Zhou UI"),
        tr("
Uncle Zhou UI
"
        "Open sourced under the MIT license.
"
           "Copyright (c) 2015 NetBeen
"
           "netbeen.cn@gmail.com"));

}

void MainWindow::editTargetGuidance(){
    ImageEditWindow* imageEditWindow = new ImageEditWindow(config::targetGuidance, config::editable, this);
    imageEditWindow->show();
}

void MainWindow::viewTargetGuidance(){
    ImageEditWindow* imageEditWindow = new ImageEditWindow(config::targetGuidance, config::readOnly, this);
    imageEditWindow->show();
}
<commit_msg>修改菜单名称，使之更加明确其含义<commit_after>#include "mainwindow.h"
#include <QApplication>
#include <QGridLayout>
#include <QWidget>
#include <QLabel>
#include <QMenuBar>
#include <QToolBar>
#include <QStatusBar>
#include <QAction>
#include <QFileDialog>
#include <QDebug>
#include <QMessageBox>
#include "newimagedialog.h"
#include "util.h"
#include "imageeditwindow.h"

/**
 * @brief MainWindow::MainWindow
 * @brief mainwindow的构造函数
 * @param parent 是qt widget的父指针
 * @return 没有返回值
 */
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent)
{
    this->initWindowLayout();
    this->initAction();

    QIcon icon(":/image/open.png"); //设置程序图标
    this->setWindowIcon(icon);

    this->fileMenu = this->menuBar()->addMenu("&File");
    this->fileMenu->addAction(this->loadSourceImageAction);

    this->helpMenu = this->menuBar()->addMenu("&Help");
    this->helpMenu->addAction(this->aboutAction);

    this->menuBar()->setStyleSheet(" QMenuBar{background-color: #333337; padding-left: 5px;}\
                            QMenuBar::item {background-color: #333337; padding:2px; margin:6px 10px 0px 0px;} \
                            QMenuBar::item:selected {background: #3e3e40;} \
                            QMenuBar::item:pressed {background: #1b1b1c;}\
                            ");

    QToolBar* toolbar = this->addToolBar("Standard Tool Bar");
    toolbar->addAction(this->loadSourceImageAction);

    QStatusBar* statusBar = this->statusBar();

}

/**
 * @brief MainWindow::initAction
 * @brief 用于mainwindow的action的定义、connect、插入
 * @param 没有参数
 * @return 没有返回值
 */
void MainWindow::initAction(){
    this->loadSourceImageAction = new QAction(QIcon(":/image/open.png"),"&Load Source Image",this);
    QObject::connect(this->loadSourceImageAction, &QAction::triggered, this, &MainWindow::loadSourceImage);

    this->viewSourceImageAction = new QAction(QIcon(":/image/open.png"),"&View Source Image",this);
    QObject::connect(this->viewSourceImageAction, &QAction::triggered, this, &MainWindow::viewSourceImage);

    this->editSourceGuidanceAction = new QAction(QIcon(":/image/open.png"),"&Edit Source Guidance",this);
    QObject::connect(this->editSourceGuidanceAction, &QAction::triggered, this, &MainWindow::editSourceGuidance);

    this->viewTargetGuidanceAction = new QAction(QIcon(":/image/open.png"),"&View Target Guidance",this);
    QObject::connect(this->viewTargetGuidanceAction, &QAction::triggered, this, &MainWindow::viewTargetGuidance);

    this->newImageAction = new QAction(QIcon(":/image/open.png"),"&Create New Guidance",this);
    QObject::connect(this->newImageAction, &QAction::triggered, this, &MainWindow::newImage);

    this->editTargetGuidanceAction = new QAction(QIcon(":/image/open.png"),"&Edit Target Guidance",this);
    QObject::connect(this->editTargetGuidanceAction, &QAction::triggered, this, &MainWindow::editTargetGuidance);

    this->aboutAction = new QAction(QIcon(":/image/open.png"),"&About",this);
    QObject::connect(this->aboutAction, &QAction::triggered, this, &MainWindow::about);

    //Action 插入段
    this->sourceImageLabel->addAction(this->viewSourceImageAction);     //左上角的view
    this->sourceImageLabel->addAction(this->loadSourceImageAction);     //左上角的load

    this->sourceGuidanceLabel->addAction(new QAction("&View",this));
    this->sourceGuidanceLabel->addAction(this->editSourceGuidanceAction);

    this->targetGuidanceLabel->addAction(this->viewTargetGuidanceAction);
    this->targetGuidanceLabel->addAction(this->newImageAction);
    this->targetGuidanceLabel->addAction(this->editTargetGuidanceAction);

}

/**
 * @brief MainWindow::loadSourceImage
 * @brief load image的action的入口函数，用于载入一个原图，并显示在左上角，顺带初始化右上角的source guidance（同等大小的白图）。
 * @param 没有参数
 * @return 没有返回值
 */
void MainWindow::loadSourceImage(){
    QFileDialog* fileDialog = new QFileDialog(this, tr("Open image File"), ".", tr("Image files(*.png)"));
    fileDialog->setFileMode(QFileDialog::ExistingFiles);
    fileDialog->setViewMode(QFileDialog::Detail);

    if (fileDialog->exec() == QDialog::Accepted)    //成功选择一个png图片
    {
        this->sourceImage =new QImage(fileDialog->selectedFiles().first());     //此处会有内存泄漏，以后处理
        this->sourceImage->save("./sourceImage.png");
        this->sourceImageFrame->setStyleSheet("background-image: url(./sourceImage.png);background-position:center center;background-repeat: no-repeat");

        this->sourceGuidance = new QImage(this->sourceImage->width(), this->sourceImage->height(), QImage::Format_RGB888);  //新建一个同等大小的空图像
        this->sourceGuidance->fill(QColor(255,255,255));        //填充白色
        for(QString elem : Util::guidanceChannel){
            this->sourceGuidance->save("./sourceGuidance"+elem+".png");
        }
        this->sourceGuidanceFrame->setStyleSheet("background-image: url(./sourceGuidanceLabelChannel.png);background-position:center center;background-repeat: no-repeat"); //显示在右上角
    }
}

MainWindow::~MainWindow()
{
}

/**
 * @brief MainWindow::initWindowLayout
 * @brief 用于管理mainwindow的窗口设置、layout布局、内部控件声明及摆放
 * @param 没有参数
 * @return 没有返回值
 */
void MainWindow::initWindowLayout(){
    this->setWindowState(Qt::WindowMaximized);      //设置窗口最大化
    this->setStyleSheet("background-color: #333337; color: #f1f1f1;");      //设置窗口样式（酷黑）

    QWidget* centerWidget = new QWidget(this);  //声明widget并设置为窗口的中央widget（这样才能设置layout）
    this->setCentralWidget(centerWidget);

    QGridLayout* gridLayout = new QGridLayout(centerWidget);    //在中央widget开启网格布局
    centerWidget->setLayout(gridLayout);

    this->sourceImageLabel = new QLabel(centerWidget);  //左上角label声明：放置source image
    this->sourceImageLabel->setStyleSheet("background-color: #696969;");
    gridLayout->addWidget(sourceImageLabel,0,0);
    this->sourceImageLabel->setContextMenuPolicy(Qt::ActionsContextMenu);       //激活右键菜单策略
    QGridLayout* sourceImageLabelGridLayout = new QGridLayout(this->sourceImageLabel);    //在label内建一个layout放置一个Frame，可以保证右键菜单的背景不受改变
    this->sourceImageLabel->setLayout(sourceImageLabelGridLayout);
    this->sourceImageFrame = new QFrame(this->sourceImageLabel);
    sourceImageLabelGridLayout->addWidget(this->sourceImageFrame,0,0);

    this->sourceGuidanceLabel = new QLabel(centerWidget);   //右上角label声明：放置source guidance
    this->sourceGuidanceLabel->setStyleSheet("background-color: #696969;");
    gridLayout->addWidget(this->sourceGuidanceLabel,0,1);
    this->sourceGuidanceLabel->setContextMenuPolicy(Qt::ActionsContextMenu);       //激活右键菜单策略
    QGridLayout* sourceGuidanceLabelGridLayout = new QGridLayout(this->sourceGuidanceLabel);    //在label内建一个layout放置一个Frame，可以保证右键菜单的背景不受改变
    this->sourceGuidanceLabel->setLayout(sourceGuidanceLabelGridLayout);
    this->sourceGuidanceFrame = new QFrame(this->sourceGuidanceLabel);
    sourceGuidanceLabelGridLayout->addWidget(this->sourceGuidanceFrame,0,0);

    this->targetGuidanceLabel = new QLabel(centerWidget);   //  左下角label声明：放置target guidance
    this->targetGuidanceLabel->setStyleSheet("background-color: #696969;");
    gridLayout->addWidget(this->targetGuidanceLabel,1,0);
    this->targetGuidanceLabel->setContextMenuPolicy(Qt::ActionsContextMenu);       //激活右键菜单策略
    QGridLayout* targetGuidanceLabelGridLayout = new QGridLayout(this->targetGuidanceLabel);    //在label内建一个layout放置一个Frame，可以保证右键菜单的背景不受改变
    this->targetGuidanceLabel->setLayout(targetGuidanceLabelGridLayout);
    this->targetGuidanceFrame = new QFrame(this->targetGuidanceLabel);
    targetGuidanceLabelGridLayout->addWidget(this->targetGuidanceFrame,0,0);

    QLabel* label4 = new QLabel(centerWidget);
    label4->setStyleSheet("background-color: #696969;");
    gridLayout->addWidget(label4,1,1);
    label4->setContextMenuPolicy(Qt::ActionsContextMenu);       //激活右键菜单策略
    label4->addAction(new QAction("&View",this));

}

/**
 * @brief MainWindow::newImage
 * @brief mainwindow中点击新建导引图片的action
 * @param 没有参数
 * @return 没有返回值
 */
void MainWindow::newImage(){
    NewImageDialog* newImageDialog = new NewImageDialog();
    if(newImageDialog->exec() == QDialog::Accepted){
        this->targetGuidanceFrame->setStyleSheet("background-image: url(./targetGuidanceLabelChannel.png);background-position:center center;background-repeat: no-repeat"); //显示在右上角
    }
}

void MainWindow::editSourceGuidance(){
    ImageEditWindow* imageEditWindow = new ImageEditWindow(config::sourceGuidance, config::editable, this);
    imageEditWindow->show();
}

void MainWindow::viewSourceImage(){
    ImageEditWindow* imageEditWindow = new ImageEditWindow(config::sourceImage, config::readOnly, this);
    imageEditWindow->show();
}

void MainWindow::about()
{
    QMessageBox::about(this, tr("About Uncle Zhou UI"),
        tr("
Uncle Zhou UI
"
        "Open sourced under the MIT license.
"
           "Copyright (c) 2015 NetBeen
"
           "netbeen.cn@gmail.com"));

}

void MainWindow::editTargetGuidance(){
    ImageEditWindow* imageEditWindow = new ImageEditWindow(config::targetGuidance, config::editable, this);
    imageEditWindow->show();
}

void MainWindow::viewTargetGuidance(){
    ImageEditWindow* imageEditWindow = new ImageEditWindow(config::targetGuidance, config::readOnly, this);
    imageEditWindow->show();
}
<|endoftext|>


<commit_before>/*
  Copyright 2014 Sarah Wong

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/

#include "mainwindow.h"
#include "about.h"

#include <QPainter>
#include <QResizeEvent>

#include <cmath>

#include "config.h"

ViewerWidget::ViewerWidget(QWidget* parent)
    : QGLWidget(parent),
      m_parent(dynamic_cast<MainWindow*>(parent)),
      m_update_pending(false)
{
}

void ViewerWidget::renderLater() {
    if (!m_update_pending) {
        m_update_pending = true;
        QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest));
    }
}

namespace {

double frequencyToKey(double frequency)
{
  // http://en.wikipedia.org/wiki/Piano_key_frequencies
  return 12 * log2(frequency / 440) + 49;
}

} // namespace anonymous

void ViewerWidget::renderNow() {
  QPainter painter(this);

  painter.fillRect(rect(), Qt::black);

  const QPen penWhite(QColor(255, 255, 255));
  const QBrush brushWhite(QColor(255, 255, 255));

  const auto& uiConfig = m_parent->config().uiConfig;

  int width = size().width();
  int height = size().height();

  std::lock_guard<std::mutex> lockGuard(m_parent->f0thread().mutex());

  double minNote = frequencyToKey(uiConfig.min_note);
  double maxNote = frequencyToKey(uiConfig.max_note);

  auto noteToPos = [this, uiConfig, height, minNote, maxNote](double note) {
    note = frequencyToKey(note);
    return height -
           (note - minNote) *
               (static_cast<double>(height) / (maxNote - minNote));
  };

  const double noteWidth = uiConfig.note_width;

  double position = 0;
  for (auto f0 : m_parent->f0thread().cb()) {
    if (f0 != 0) {

      double ypos = noteToPos(f0);

      painter.setPen(penWhite);
      painter.setBrush(brushWhite);

      painter.drawRect(position, ypos - 1, noteWidth, noteWidth);
    }

    position += noteWidth;
  }

  for (const auto& line : m_parent->config().uiMarkerLines.lines) {
    double ypos = noteToPos(line.frequency);
    painter.setPen(line.pen);
    painter.drawLine(0, ypos, width, ypos);
  }
}

bool ViewerWidget::event(QEvent* event)
{
  switch (event->type()) {
  case QEvent::UpdateRequest:
    m_update_pending = false;
    renderNow();
    return true;
  default:
    return QGLWidget::event(event);
  }
}

void ViewerWidget::paintEvent(QPaintEvent* event)
{
  renderNow();
}

void ViewerWidget::resizeEvent(QResizeEvent* event)
{
  emit widthChanged(event->size().width());
}

MainWindow::MainWindow(const config::Config& config, F0Thread& f0thread)
    : m_config(config), m_f0thread(f0thread)
{
  ViewerWidget* vw = new ViewerWidget(this);
  vw->setObjectName("viewer");

  m_ui.setupUi(this);
  resize(m_config.uiConfig.width, m_config.uiConfig.height);

  setCentralWidget(vw);

  QObject::connect(&f0thread, SIGNAL(updated()), vw, SLOT(renderLater()));
}

void MainWindow::on_action_About_triggered()
{
  About* about = new About(this);
  about->show();
}

void MainWindow::on_viewer_widthChanged(int width)
{
  std::lock_guard<std::mutex> lockGuard(m_f0thread.mutex());
  m_f0thread.cb().resize(width / m_config.uiConfig.note_width);
}
<commit_msg>shorten critical section of mutex<commit_after>/*
  Copyright 2014 Sarah Wong

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/

#include "mainwindow.h"
#include "about.h"

#include <QPainter>
#include <QResizeEvent>

#include <cmath>

#include "config.h"

ViewerWidget::ViewerWidget(QWidget* parent)
    : QGLWidget(parent),
      m_parent(dynamic_cast<MainWindow*>(parent)),
      m_update_pending(false)
{
}

void ViewerWidget::renderLater() {
    if (!m_update_pending) {
        m_update_pending = true;
        QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest));
    }
}

namespace {

double frequencyToKey(double frequency)
{
  // http://en.wikipedia.org/wiki/Piano_key_frequencies
  return 12 * log2(frequency / 440) + 49;
}

} // namespace anonymous

void ViewerWidget::renderNow() {
  QPainter painter(this);

  painter.fillRect(rect(), Qt::black);

  const QPen penWhite(QColor(255, 255, 255));
  const QBrush brushWhite(QColor(255, 255, 255));

  const auto& uiConfig = m_parent->config().uiConfig;

  int width = size().width();
  int height = size().height();

  double minNote = frequencyToKey(uiConfig.min_note);
  double maxNote = frequencyToKey(uiConfig.max_note);

  auto noteToPos = [this, uiConfig, height, minNote, maxNote](double note) {
    note = frequencyToKey(note);
    return height -
           (note - minNote) *
               (static_cast<double>(height) / (maxNote - minNote));
  };

  const double noteWidth = uiConfig.note_width;

  {
    std::lock_guard<std::mutex> lockGuard(m_parent->f0thread().mutex());

    double position = 0;
    for (auto f0 : m_parent->f0thread().cb()) {
      if (f0 != 0) {
        double ypos = noteToPos(f0);

        painter.setPen(penWhite);
        painter.setBrush(brushWhite);

        painter.drawRect(position, ypos - 1, noteWidth, noteWidth);
      }

      position += noteWidth;
    }
  }

  for (const auto& line : m_parent->config().uiMarkerLines.lines) {
    double ypos = noteToPos(line.frequency);
    painter.setPen(line.pen);
    painter.drawLine(0, ypos, width, ypos);
  }
}

bool ViewerWidget::event(QEvent* event)
{
  switch (event->type()) {
  case QEvent::UpdateRequest:
    m_update_pending = false;
    renderNow();
    return true;
  default:
    return QGLWidget::event(event);
  }
}

void ViewerWidget::paintEvent(QPaintEvent* event)
{
  renderNow();
}

void ViewerWidget::resizeEvent(QResizeEvent* event)
{
  emit widthChanged(event->size().width());
}

MainWindow::MainWindow(const config::Config& config, F0Thread& f0thread)
    : m_config(config), m_f0thread(f0thread)
{
  ViewerWidget* vw = new ViewerWidget(this);
  vw->setObjectName("viewer");

  m_ui.setupUi(this);
  resize(m_config.uiConfig.width, m_config.uiConfig.height);

  setCentralWidget(vw);

  QObject::connect(&f0thread, SIGNAL(updated()), vw, SLOT(renderLater()));
}

void MainWindow::on_action_About_triggered()
{
  About* about = new About(this);
  about->show();
}

void MainWindow::on_viewer_widthChanged(int width)
{
  std::lock_guard<std::mutex> lockGuard(m_f0thread.mutex());
  m_f0thread.cb().resize(width / m_config.uiConfig.note_width);
}
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "CppUnitTest.h"
#include "../CPPace.Lib/MinimumFillIn.h"

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

namespace CPPaceTests {
  TEST_CLASS(MinimumFillInTests) {
  public:
    TEST_METHOD(ChordlessPath) {
      AdjacencyList graph(5);
      Assert::IsTrue(MinimumFillIn::is_path_chordless(graph, vector<int> { 0 }));

      // 0-1 2 3 4
      graph.add_edge(0, 1);
      Assert::IsTrue(MinimumFillIn::is_path_chordless(graph, vector<int> { 0 }));
      Assert::IsTrue(MinimumFillIn::is_path_chordless(graph, vector<int> { 0, 1 }));

      // 0-1-2-3-4
      graph.add_edge(1, 2);
      graph.add_edge(3, 4);
      graph.add_edge(2, 3);
      Assert::IsTrue(MinimumFillIn::is_path_chordless(graph, vector<int> { 0, 1, 2, 3, 4 }));
      Assert::IsTrue(MinimumFillIn::is_path_chordless(graph, vector<int> { 4, 3, 2, 1, 0 }));

      // 0   2-3-4
      //  \_/
      graph.add_edge(0, 2);
      Assert::IsFalse(MinimumFillIn::is_path_chordless(graph, vector<int> { 0, 1, 2, 3, 4 }));
      Assert::IsFalse(MinimumFillIn::is_path_chordless(graph, vector<int> { 4, 3, 2, 1, 0 }));
      Assert::IsTrue(MinimumFillIn::is_path_chordless(graph, vector<int> { 0, 2, 3, 4 }));
      Assert::IsTrue(MinimumFillIn::is_path_chordless(graph, vector<int> { 4, 3, 2, 0 }));

      // 0   2-3-4
      //  \_/ \_/
      graph.add_edge(2, 4);
      Assert::IsFalse(MinimumFillIn::is_path_chordless(graph, vector<int> { 0, 2, 3, 4 }));
      Assert::IsFalse(MinimumFillIn::is_path_chordless(graph, vector<int> { 4, 3, 2, 0 }));
    }

    TEST_METHOD(FindFourCycle) {
      AdjacencyList graph(5);
      vector<int> cycle;
      Assert::IsFalse(MinimumFillIn::find_four_cycle(graph, cycle));

      graph.add_edge(0, 1);
      Assert::IsFalse(MinimumFillIn::find_four_cycle(graph, cycle));
      Assert::AreEqual(0, (int)cycle.size());

      graph.add_edge(1, 2);
      Assert::IsFalse(MinimumFillIn::find_four_cycle(graph, cycle));
      Assert::AreEqual(0, (int)cycle.size());

      graph.add_edge(2, 3);
      Assert::IsFalse(MinimumFillIn::find_four_cycle(graph, cycle));
      Assert::AreEqual(0, (int)cycle.size());

      graph.add_edge(3, 4);
      Assert::IsFalse(MinimumFillIn::find_four_cycle(graph, cycle));
      Assert::AreEqual(0, (int)cycle.size());

      graph.add_edge(4, 0);
      Assert::IsFalse(MinimumFillIn::find_four_cycle(graph, cycle));
      Assert::AreEqual(0, (int)cycle.size());

      graph.add_edge(3, 0);
      Assert::IsTrue(MinimumFillIn::find_four_cycle(graph, cycle));
      Assert::AreEqual(4, (int)cycle.size());

      graph.remove_vertex(0);
      Assert::IsFalse(MinimumFillIn::find_four_cycle(graph, cycle));
      Assert::AreEqual(0, (int)cycle.size());

      graph.add_edge(1, 4);
      Assert::IsTrue(MinimumFillIn::find_four_cycle(graph, cycle));
      Assert::AreEqual(4, (int)cycle.size());

      graph.add_vertex(0);
      graph.remove_edge(1, 4);
      Assert::IsTrue(MinimumFillIn::find_four_cycle(graph, cycle));
      Assert::AreEqual(4, (int)cycle.size());
    }

    TEST_METHOD(FindFourCycleBerryBordat) {
      AdjacencyList graph = SampleGraphs::berry_bordat();
      vector<int> cycle;
      Assert::IsTrue(MinimumFillIn::find_four_cycle(graph, cycle));
      Assert::AreEqual(4, (int)cycle.size());

      graph.remove_vertex(5);
      Assert::IsFalse(MinimumFillIn::find_four_cycle(graph, cycle));
      Assert::AreEqual(0, (int)cycle.size());
    }

    TEST_METHOD(FindVStar) {
      int v_star;
      AdjacencyList graph(5);
      Assert::IsFalse(MinimumFillIn::find_v_star(graph, 0, 2, set<int>(), v_star));

      graph.add_edge(0, 1);
      Assert::IsFalse(MinimumFillIn::find_v_star(graph, 0, 2, set<int>(), v_star));

      graph.add_edge(1, 2);
      Assert::IsTrue(MinimumFillIn::find_v_star(graph, 0, 2, set<int>(), v_star));
      Assert::AreEqual(1, v_star);

      graph.add_edge(2, 3);
      Assert::IsTrue(MinimumFillIn::find_v_star(graph, 0, 3, set<int>(), v_star));
      Assert::IsTrue(v_star == 1 || v_star == 2);

      graph.remove_vertex(2);
      Assert::IsFalse(MinimumFillIn::find_v_star(graph, 0, 2, set<int>(), v_star));
      Assert::IsFalse(MinimumFillIn::find_v_star(graph, 0, 3, set<int>(), v_star));

      graph.add_edge(1, 4);
      graph.add_edge(3, 4);
      Assert::IsTrue(MinimumFillIn::find_v_star(graph, 0, 3, set<int>(), v_star));
      Assert::IsTrue(v_star == 4 || v_star == 1);

      Assert::IsTrue(MinimumFillIn::find_v_star(graph, 0, 3, set<int>(), v_star));
      Assert::IsTrue(v_star == 4 || v_star == 1);

      graph.add_vertex(2);

      Assert::IsTrue(MinimumFillIn::find_v_star(graph, 0, 3, set<int>(), v_star));
      Assert::AreEqual(1, v_star);

      graph.add_edge(0, 4);
      Assert::IsFalse(MinimumFillIn::find_v_star(graph, 0, 3, set<int>(), v_star));

      Assert::IsTrue(MinimumFillIn::find_v_star(graph, 0, 3, set<int> { 4 }, v_star));
      Assert::IsTrue(v_star == 1 || v_star == 2);
    }

    TEST_METHOD(FindMoplexesBerryBordat) {
      AdjacencyList graph = SampleGraphs::berry_bordat();
      vector<set<int>> moplexes = MinimumFillIn::find_moplexes(graph);
      Assert::IsTrue(vector<set<int>> {
        set<int> { 0, 1 },
        set<int> { 2 },
        set<int> { 3 },
        set<int> { 4 },
        set<int> { 6 },
        set<int> { 7 }
      } == moplexes);
    }

    TEST_METHOD(FindMinFillBerryBordat) {
      AdjacencyList graph = SampleGraphs::berry_bordat();
      stack<pair<int, int>> edges = MinimumFillIn::minimum_fill_in(graph);
      Assert::AreEqual(2, (int)edges.size());
      Assert::IsTrue(edges.top().first == 4 && edges.top().second == 5 || edges.top().first == 5 && edges.top().second == 6);
      edges.pop();
      Assert::IsTrue(edges.top().first == 4 && edges.top().second == 5 || edges.top().first == 5 && edges.top().second == 6);
    }

    TEST_METHOD(MinimumFillInKTests) {
      //4-cycle
      AdjacencyList graph = AdjacencyList(4);
      graph.add_edge(0, 1);
      graph.add_edge(1, 2);
      graph.add_edge(2, 3);
      graph.add_edge(3, 0);

      stack<pair<int, int>> result = MinimumFillIn::minimum_fill_in(graph);
      Assert::IsTrue(1 == result.size());

      //5-cycle
      graph = AdjacencyList(5);
      graph.add_edge(0, 1);
      graph.add_edge(1, 2);
      graph.add_edge(2, 3);
      graph.add_edge(3, 4);
      graph.add_edge(4, 0);

      result = MinimumFillIn::minimum_fill_in(graph);
      Assert::IsTrue(2 == result.size());

      //2 single nodes
      graph = AdjacencyList(2);

      result = MinimumFillIn::minimum_fill_in(graph);
      Assert::IsTrue(0 == result.size());

      //2 4-cycles
      graph = AdjacencyList(8);
      graph.add_edge(0, 1);
      graph.add_edge(1, 2);
      graph.add_edge(2, 3);
      graph.add_edge(3, 0);

      graph.add_edge(4, 5);
      graph.add_edge(5, 6);
      graph.add_edge(6, 7);
      graph.add_edge(7, 4);

      result = MinimumFillIn::minimum_fill_in(graph);
      Assert::IsTrue(2 == result.size());

      //10 cycle
      graph = AdjacencyList(10);
      graph.add_edge(0, 1);
      graph.add_edge(1, 2);
      graph.add_edge(2, 3);
      graph.add_edge(3, 4);
      graph.add_edge(4, 5);
      graph.add_edge(5, 6);
      graph.add_edge(6, 7);
      graph.add_edge(7, 8);
      graph.add_edge(8, 9);
      graph.add_edge(9, 0);

      result = MinimumFillIn::minimum_fill_in(graph);
      Assert::IsTrue(7 == result.size());
    }
  };
}
<commit_msg>More minimumFillInTests<commit_after>#include "stdafx.h"
#include "CppUnitTest.h"
#include "../CPPace.Lib/MinimumFillIn.h"

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

namespace CPPaceTests {
  TEST_CLASS(MinimumFillInTests) {
  public:
    TEST_METHOD(ChordlessPath) {
      AdjacencyList graph(5);
      Assert::IsTrue(MinimumFillIn::is_path_chordless(graph, vector<int> { 0 }));

      // 0-1 2 3 4
      graph.add_edge(0, 1);
      Assert::IsTrue(MinimumFillIn::is_path_chordless(graph, vector<int> { 0 }));
      Assert::IsTrue(MinimumFillIn::is_path_chordless(graph, vector<int> { 0, 1 }));

      // 0-1-2-3-4
      graph.add_edge(1, 2);
      graph.add_edge(3, 4);
      graph.add_edge(2, 3);
      Assert::IsTrue(MinimumFillIn::is_path_chordless(graph, vector<int> { 0, 1, 2, 3, 4 }));
      Assert::IsTrue(MinimumFillIn::is_path_chordless(graph, vector<int> { 4, 3, 2, 1, 0 }));

      // 0   2-3-4
      //  \_/
      graph.add_edge(0, 2);
      Assert::IsFalse(MinimumFillIn::is_path_chordless(graph, vector<int> { 0, 1, 2, 3, 4 }));
      Assert::IsFalse(MinimumFillIn::is_path_chordless(graph, vector<int> { 4, 3, 2, 1, 0 }));
      Assert::IsTrue(MinimumFillIn::is_path_chordless(graph, vector<int> { 0, 2, 3, 4 }));
      Assert::IsTrue(MinimumFillIn::is_path_chordless(graph, vector<int> { 4, 3, 2, 0 }));

      // 0   2-3-4
      //  \_/ \_/
      graph.add_edge(2, 4);
      Assert::IsFalse(MinimumFillIn::is_path_chordless(graph, vector<int> { 0, 2, 3, 4 }));
      Assert::IsFalse(MinimumFillIn::is_path_chordless(graph, vector<int> { 4, 3, 2, 0 }));
    }

    TEST_METHOD(FindFourCycle) {
      AdjacencyList graph(5);
      vector<int> cycle;
      Assert::IsFalse(MinimumFillIn::find_four_cycle(graph, cycle));

      graph.add_edge(0, 1);
      Assert::IsFalse(MinimumFillIn::find_four_cycle(graph, cycle));
      Assert::AreEqual(0, (int)cycle.size());

      graph.add_edge(1, 2);
      Assert::IsFalse(MinimumFillIn::find_four_cycle(graph, cycle));
      Assert::AreEqual(0, (int)cycle.size());

      graph.add_edge(2, 3);
      Assert::IsFalse(MinimumFillIn::find_four_cycle(graph, cycle));
      Assert::AreEqual(0, (int)cycle.size());

      graph.add_edge(3, 4);
      Assert::IsFalse(MinimumFillIn::find_four_cycle(graph, cycle));
      Assert::AreEqual(0, (int)cycle.size());

      graph.add_edge(4, 0);
      Assert::IsFalse(MinimumFillIn::find_four_cycle(graph, cycle));
      Assert::AreEqual(0, (int)cycle.size());

      graph.add_edge(3, 0);
      Assert::IsTrue(MinimumFillIn::find_four_cycle(graph, cycle));
      Assert::AreEqual(4, (int)cycle.size());

      graph.remove_vertex(0);
      Assert::IsFalse(MinimumFillIn::find_four_cycle(graph, cycle));
      Assert::AreEqual(0, (int)cycle.size());

      graph.add_edge(1, 4);
      Assert::IsTrue(MinimumFillIn::find_four_cycle(graph, cycle));
      Assert::AreEqual(4, (int)cycle.size());

      graph.add_vertex(0);
      graph.remove_edge(1, 4);
      Assert::IsTrue(MinimumFillIn::find_four_cycle(graph, cycle));
      Assert::AreEqual(4, (int)cycle.size());
    }

    TEST_METHOD(FindFourCycleBerryBordat) {
      AdjacencyList graph = SampleGraphs::berry_bordat();
      vector<int> cycle;
      Assert::IsTrue(MinimumFillIn::find_four_cycle(graph, cycle));
      Assert::AreEqual(4, (int)cycle.size());

      graph.remove_vertex(5);
      Assert::IsFalse(MinimumFillIn::find_four_cycle(graph, cycle));
      Assert::AreEqual(0, (int)cycle.size());
    }

    TEST_METHOD(FindVStar) {
      int v_star;
      AdjacencyList graph(5);
      Assert::IsFalse(MinimumFillIn::find_v_star(graph, 0, 2, set<int>(), v_star));

      graph.add_edge(0, 1);
      Assert::IsFalse(MinimumFillIn::find_v_star(graph, 0, 2, set<int>(), v_star));

      graph.add_edge(1, 2);
      Assert::IsTrue(MinimumFillIn::find_v_star(graph, 0, 2, set<int>(), v_star));
      Assert::AreEqual(1, v_star);

      graph.add_edge(2, 3);
      Assert::IsTrue(MinimumFillIn::find_v_star(graph, 0, 3, set<int>(), v_star));
      Assert::IsTrue(v_star == 1 || v_star == 2);

      graph.remove_vertex(2);
      Assert::IsFalse(MinimumFillIn::find_v_star(graph, 0, 2, set<int>(), v_star));
      Assert::IsFalse(MinimumFillIn::find_v_star(graph, 0, 3, set<int>(), v_star));

      graph.add_edge(1, 4);
      graph.add_edge(3, 4);
      Assert::IsTrue(MinimumFillIn::find_v_star(graph, 0, 3, set<int>(), v_star));
      Assert::IsTrue(v_star == 4 || v_star == 1);

      Assert::IsTrue(MinimumFillIn::find_v_star(graph, 0, 3, set<int>(), v_star));
      Assert::IsTrue(v_star == 4 || v_star == 1);

      graph.add_vertex(2);

      Assert::IsTrue(MinimumFillIn::find_v_star(graph, 0, 3, set<int>(), v_star));
      Assert::AreEqual(1, v_star);

      graph.add_edge(0, 4);
      Assert::IsFalse(MinimumFillIn::find_v_star(graph, 0, 3, set<int>(), v_star));

      Assert::IsTrue(MinimumFillIn::find_v_star(graph, 0, 3, set<int> { 4 }, v_star));
      Assert::IsTrue(v_star == 1 || v_star == 2);
    }

    TEST_METHOD(FindMoplexesBerryBordat) {
      AdjacencyList graph = SampleGraphs::berry_bordat();
      vector<set<int>> moplexes = MinimumFillIn::find_moplexes(graph);
      Assert::IsTrue(vector<set<int>> {
        set<int> { 0, 1 },
        set<int> { 2 },
        set<int> { 3 },
        set<int> { 4 },
        set<int> { 6 },
        set<int> { 7 }
      } == moplexes);
    }

    TEST_METHOD(FindMinFillBerryBordat) {
      AdjacencyList graph = SampleGraphs::berry_bordat();
      stack<pair<int, int>> edges = MinimumFillIn::minimum_fill_in(graph);
      Assert::AreEqual(2, (int)edges.size());
      Assert::IsTrue(edges.top().first == 4 && edges.top().second == 5 || edges.top().first == 5 && edges.top().second == 6);
      edges.pop();
      Assert::IsTrue(edges.top().first == 4 && edges.top().second == 5 || edges.top().first == 5 && edges.top().second == 6);
    }

    TEST_METHOD(MinimumFillInKTests) {
      //4-cycle
      AdjacencyList graph = AdjacencyList(4);
      graph.add_edge(0, 1);
      graph.add_edge(1, 2);
      graph.add_edge(2, 3);
      graph.add_edge(3, 0);

      stack<pair<int, int>> result = MinimumFillIn::minimum_fill_in(graph);
      Assert::IsTrue(1 == result.size());

      //5-cycle
      graph = AdjacencyList(5);
      graph.add_edge(0, 1);
      graph.add_edge(1, 2);
      graph.add_edge(2, 3);
      graph.add_edge(3, 4);
      graph.add_edge(4, 0);

      result = MinimumFillIn::minimum_fill_in(graph);
      Assert::IsTrue(2 == result.size());

      //2 single nodes
      graph = AdjacencyList(2);

      result = MinimumFillIn::minimum_fill_in(graph);
      Assert::IsTrue(0 == result.size());

      //2 4-cycles
      graph = AdjacencyList(8);
      graph.add_edge(0, 1);
      graph.add_edge(1, 2);
      graph.add_edge(2, 3);
      graph.add_edge(3, 0);

      graph.add_edge(4, 5);
      graph.add_edge(5, 6);
      graph.add_edge(6, 7);
      graph.add_edge(7, 4);

      result = MinimumFillIn::minimum_fill_in(graph);
      Assert::IsTrue(2 == result.size());

      //10 cycle
      graph = AdjacencyList(10);
      graph.add_edge(0, 1);
      graph.add_edge(1, 2);
      graph.add_edge(2, 3);
      graph.add_edge(3, 4);
      graph.add_edge(4, 5);
      graph.add_edge(5, 6);
      graph.add_edge(6, 7);
      graph.add_edge(7, 8);
      graph.add_edge(8, 9);
      graph.add_edge(9, 0);

      result = MinimumFillIn::minimum_fill_in(graph);
      Assert::IsTrue(7 == result.size());

      //2 combined 4-cycles. Solvable with one.
      graph = AdjacencyList(6);
      graph.add_edge(0, 1);
      graph.add_edge(1, 4);
      graph.add_edge(0, 2);
      graph.add_edge(0, 3);
      graph.add_edge(3, 4);

      result = MinimumFillIn::minimum_fill_in(graph);
      Assert::IsTrue(1 == result.size());

      //10 combined 4-cycles. Solvable with one
      graph = AdjacencyList(12);
      graph.add_edge(0, 1);
      graph.add_edge(0, 2);
      graph.add_edge(0, 3);
      graph.add_edge(0, 5);
      graph.add_edge(0, 6);
      graph.add_edge(0, 7);
      graph.add_edge(0, 8);
      graph.add_edge(0, 9);
      graph.add_edge(0, 10);
      graph.add_edge(0, 11);
      graph.add_edge(4, 1);
      graph.add_edge(4, 2);
      graph.add_edge(4, 3);
      graph.add_edge(4, 5);
      graph.add_edge(4, 6);
      graph.add_edge(4, 7);
      graph.add_edge(4, 8);
      graph.add_edge(4, 9);
      graph.add_edge(4, 10);
      graph.add_edge(4, 11);

      result = MinimumFillIn::minimum_fill_in(graph);
      Assert::IsTrue(1 == result.size());
    }
  };
}
<|endoftext|>


<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/format_macros.h"
#include "base/path_service.h"
#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/autocomplete/autocomplete.h"
#include "chrome/browser/autocomplete/autocomplete_edit.h"
#include "chrome/browser/autocomplete/autocomplete_match.h"
#include "chrome/browser/autocomplete/autocomplete_popup_model.h"
#include "chrome/browser/extensions/extension_browsertest.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/unpacked_installer.h"
#include "chrome/browser/history/history.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/omnibox/location_bar.h"
#include "chrome/browser/ui/omnibox/omnibox_view.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_types.h"
#include "testing/gtest/include/gtest/gtest.h"

// Autocomplete test is flaky on ChromeOS.
// http://crbug.com/52928
#if defined(OS_CHROMEOS)
#define MAYBE_Autocomplete FLAKY_Autocomplete
#else
#define MAYBE_Autocomplete Autocomplete
#endif

namespace {

string16 AutocompleteResultAsString(const AutocompleteResult& result) {
  std::string output(base::StringPrintf("{%" PRIuS "} ", result.size()));
  for (size_t i = 0; i < result.size(); ++i) {
    AutocompleteMatch match = result.match_at(i);
    std::string provider_name = match.provider->name();
    output.append(base::StringPrintf("[\"%s\" by \"%s\"] ",
                                     UTF16ToUTF8(match.contents).c_str(),
                                     provider_name.c_str()));
  }
  return UTF8ToUTF16(output);
}

}  // namespace

class AutocompleteBrowserTest : public ExtensionBrowserTest {
 protected:
  LocationBar* GetLocationBar() const {
    return browser()->window()->GetLocationBar();
  }

  AutocompleteController* GetAutocompleteController() const {
    return GetLocationBar()->location_entry()->model()->popup_model()->
        autocomplete_controller();
  }
};

#if defined(OS_WIN) || defined(OS_LINUX)
#define MAYBE_Basic FLAKY_Basic
#else
#define MAYBE_Basic Basic
#endif
IN_PROC_BROWSER_TEST_F(AutocompleteBrowserTest, MAYBE_Basic) {
  LocationBar* location_bar = GetLocationBar();

  EXPECT_TRUE(location_bar->GetInputString().empty());
  EXPECT_EQ(UTF8ToUTF16(chrome::kAboutBlankURL),
            location_bar->location_entry()->GetText());
  // TODO(phajdan.jr): check state of IsSelectAll when it's consistent across
  // platforms.

  location_bar->FocusLocation(true);

  EXPECT_TRUE(location_bar->GetInputString().empty());
  EXPECT_EQ(UTF8ToUTF16(chrome::kAboutBlankURL),
            location_bar->location_entry()->GetText());
  EXPECT_TRUE(location_bar->location_entry()->IsSelectAll());

  location_bar->location_entry()->SetUserText(ASCIIToUTF16("chrome"));

  EXPECT_TRUE(location_bar->GetInputString().empty());
  EXPECT_EQ(ASCIIToUTF16("chrome"), location_bar->location_entry()->GetText());
  EXPECT_FALSE(location_bar->location_entry()->IsSelectAll());

  location_bar->location_entry()->RevertAll();

  EXPECT_TRUE(location_bar->GetInputString().empty());
  EXPECT_EQ(UTF8ToUTF16(chrome::kAboutBlankURL),
            location_bar->location_entry()->GetText());
  EXPECT_FALSE(location_bar->location_entry()->IsSelectAll());

  location_bar->location_entry()->SetUserText(ASCIIToUTF16("chrome"));
  location_bar->Revert();

  EXPECT_TRUE(location_bar->GetInputString().empty());
  EXPECT_EQ(UTF8ToUTF16(chrome::kAboutBlankURL),
            location_bar->location_entry()->GetText());
  EXPECT_FALSE(location_bar->location_entry()->IsSelectAll());
}

IN_PROC_BROWSER_TEST_F(AutocompleteBrowserTest, MAYBE_Autocomplete) {
  // The results depend on the history backend being loaded. Make sure it is
  // loaded so that the autocomplete results are consistent.
  ui_test_utils::WaitForHistoryToLoad(browser());

  LocationBar* location_bar = GetLocationBar();
  AutocompleteController* autocomplete_controller = GetAutocompleteController();

  {
    autocomplete_controller->Start(
        ASCIIToUTF16("chrome"), string16(), true, false, true,
        AutocompleteInput::SYNCHRONOUS_MATCHES);

    EXPECT_TRUE(autocomplete_controller->done());
    EXPECT_TRUE(location_bar->GetInputString().empty());
    EXPECT_TRUE(location_bar->location_entry()->GetText().empty());
    EXPECT_TRUE(location_bar->location_entry()->IsSelectAll());
    const AutocompleteResult& result = autocomplete_controller->result();
    // We get two matches because we have a provider for extension apps and the
    // Chrome Web Store is a built-in Extension app. For this test, we only care
    // about the other match existing.
    ASSERT_GE(result.size(), 1U) << AutocompleteResultAsString(result);
    AutocompleteMatch match = result.match_at(0);
    EXPECT_EQ(AutocompleteMatch::SEARCH_WHAT_YOU_TYPED, match.type);
    EXPECT_FALSE(match.deletable);
  }

  {
    location_bar->Revert();

    EXPECT_TRUE(location_bar->GetInputString().empty());
    EXPECT_EQ(UTF8ToUTF16(chrome::kAboutBlankURL),
              location_bar->location_entry()->GetText());
    EXPECT_FALSE(location_bar->location_entry()->IsSelectAll());
    const AutocompleteResult& result = autocomplete_controller->result();
    EXPECT_TRUE(result.empty()) << AutocompleteResultAsString(result);
  }
}

IN_PROC_BROWSER_TEST_F(AutocompleteBrowserTest, TabAwayRevertSelect) {
  // http://code.google.com/p/chromium/issues/detail?id=38385
  // Make sure that tabbing away from an empty omnibar causes a revert
  // and select all.
  LocationBar* location_bar = GetLocationBar();
  EXPECT_EQ(UTF8ToUTF16(chrome::kAboutBlankURL),
            location_bar->location_entry()->GetText());
  location_bar->location_entry()->SetUserText(string16());
  ui_test_utils::WindowedNotificationObserver observer(
      content::NOTIFICATION_LOAD_STOP,
      content::NotificationService::AllSources());
  browser()->AddSelectedTabWithURL(GURL(chrome::kAboutBlankURL),
                                   content::PAGE_TRANSITION_START_PAGE);
  observer.Wait();
  EXPECT_EQ(UTF8ToUTF16(chrome::kAboutBlankURL),
            location_bar->location_entry()->GetText());
  browser()->CloseTab();
  EXPECT_EQ(UTF8ToUTF16(chrome::kAboutBlankURL),
            location_bar->location_entry()->GetText());
  EXPECT_TRUE(location_bar->location_entry()->IsSelectAll());
}

IN_PROC_BROWSER_TEST_F(AutocompleteBrowserTest, FocusSearch) {
  LocationBar* location_bar = GetLocationBar();

  // Focus search when omnibox is blank
  {
    EXPECT_TRUE(location_bar->GetInputString().empty());
    EXPECT_EQ(UTF8ToUTF16(chrome::kAboutBlankURL),
              location_bar->location_entry()->GetText());

    location_bar->FocusSearch();
    EXPECT_TRUE(location_bar->GetInputString().empty());
    EXPECT_EQ(ASCIIToUTF16("?"), location_bar->location_entry()->GetText());

    size_t selection_start, selection_end;
    location_bar->location_entry()->GetSelectionBounds(&selection_start,
                                                       &selection_end);
    EXPECT_EQ(1U, selection_start);
    EXPECT_EQ(1U, selection_end);
  }

  // Focus search when omnibox is _not_ alread in forced query mode.
  {
    location_bar->location_entry()->SetUserText(ASCIIToUTF16("foo"));
    EXPECT_TRUE(location_bar->GetInputString().empty());
    EXPECT_EQ(ASCIIToUTF16("foo"), location_bar->location_entry()->GetText());

    location_bar->FocusSearch();
    EXPECT_TRUE(location_bar->GetInputString().empty());
    EXPECT_EQ(ASCIIToUTF16("?"), location_bar->location_entry()->GetText());

    size_t selection_start, selection_end;
    location_bar->location_entry()->GetSelectionBounds(&selection_start,
                                                       &selection_end);
    EXPECT_EQ(1U, selection_start);
    EXPECT_EQ(1U, selection_end);
  }

  // Focus search when omnibox _is_ already in forced query mode, but no query
  // has been typed.
  {
    location_bar->location_entry()->SetUserText(ASCIIToUTF16("?"));
    EXPECT_TRUE(location_bar->GetInputString().empty());
    EXPECT_EQ(ASCIIToUTF16("?"), location_bar->location_entry()->GetText());

    location_bar->FocusSearch();
    EXPECT_TRUE(location_bar->GetInputString().empty());
    EXPECT_EQ(ASCIIToUTF16("?"), location_bar->location_entry()->GetText());

    size_t selection_start, selection_end;
    location_bar->location_entry()->GetSelectionBounds(&selection_start,
                                                       &selection_end);
    EXPECT_EQ(1U, selection_start);
    EXPECT_EQ(1U, selection_end);
  }

  // Focus search when omnibox _is_ already in forced query mode, and some query
  // has been typed.
  {
    location_bar->location_entry()->SetUserText(ASCIIToUTF16("?foo"));
    EXPECT_TRUE(location_bar->GetInputString().empty());
    EXPECT_EQ(ASCIIToUTF16("?foo"), location_bar->location_entry()->GetText());

    location_bar->FocusSearch();
    EXPECT_TRUE(location_bar->GetInputString().empty());
    EXPECT_EQ(ASCIIToUTF16("?foo"), location_bar->location_entry()->GetText());

    size_t selection_start, selection_end;
    location_bar->location_entry()->GetSelectionBounds(&selection_start,
                                                       &selection_end);
    EXPECT_EQ(1U, std::min(selection_start, selection_end));
    EXPECT_EQ(4U, std::max(selection_start, selection_end));
  }

  // Focus search when omnibox is in forced query mode with leading whitespace.
  {
    location_bar->location_entry()->SetUserText(ASCIIToUTF16("   ?foo"));
    EXPECT_TRUE(location_bar->GetInputString().empty());
    EXPECT_EQ(ASCIIToUTF16("   ?foo"),
              location_bar->location_entry()->GetText());

    location_bar->FocusSearch();
    EXPECT_TRUE(location_bar->GetInputString().empty());
    EXPECT_EQ(ASCIIToUTF16("   ?foo"),
              location_bar->location_entry()->GetText());

    size_t selection_start, selection_end;
    location_bar->location_entry()->GetSelectionBounds(&selection_start,
                                                       &selection_end);
    EXPECT_EQ(4U, std::min(selection_start, selection_end));
    EXPECT_EQ(7U, std::max(selection_start, selection_end));
  }
}

IN_PROC_BROWSER_TEST_F(AutocompleteBrowserTest, ExtensionAppProvider) {
  ExtensionService* service = browser()->profile()->GetExtensionService();
  size_t extension_count = service->extensions()->size();

  FilePath test_dir;
  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir));
  // Load a packaged app.
  extensions::UnpackedInstaller::Create(service)->Load(
      test_dir.AppendASCII("extensions").AppendASCII("packaged_app"));
  WaitForExtensionLoad();
  // Load a hosted app.
  extensions::UnpackedInstaller::Create(service)->Load(
      test_dir.AppendASCII("extensions").AppendASCII("app"));
  WaitForExtensionLoad();
  ASSERT_EQ(extension_count + 2U, service->extensions()->size());

  // The results depend on the history backend being loaded. Make sure it is
  // loaded so that the autocomplete results are consistent.
  ui_test_utils::WaitForHistoryToLoad(browser());

  LocationBar* location_bar = GetLocationBar();
  AutocompleteController* autocomplete_controller = GetAutocompleteController();

  // Try out the packaged app.
  {
    autocomplete_controller->Start(
        ASCIIToUTF16("Packaged App Test"), string16(), true, false, true,
        AutocompleteInput::SYNCHRONOUS_MATCHES);

    EXPECT_TRUE(autocomplete_controller->done());
    EXPECT_TRUE(location_bar->GetInputString().empty());
    EXPECT_TRUE(location_bar->location_entry()->GetText().empty());
    EXPECT_TRUE(location_bar->location_entry()->IsSelectAll());
    const AutocompleteResult& result = autocomplete_controller->result();
    EXPECT_GT(result.size(), 1U) << AutocompleteResultAsString(result);
    AutocompleteMatch match = result.match_at(0);
    EXPECT_EQ(ASCIIToUTF16("Packaged App Test"), match.contents);
    EXPECT_EQ(AutocompleteMatch::EXTENSION_APP, match.type);
    EXPECT_FALSE(match.deletable);
    location_bar->AcceptInput();
  }

  browser()->NewTab();

  // Try out the hosted app.
  {
    autocomplete_controller->Start(
        ASCIIToUTF16("App Test"), string16(), true, false, true,
        AutocompleteInput::SYNCHRONOUS_MATCHES);

    EXPECT_TRUE(autocomplete_controller->done());
    EXPECT_TRUE(location_bar->GetInputString().empty());
    EXPECT_TRUE(location_bar->location_entry()->GetText().empty());
    EXPECT_TRUE(location_bar->location_entry()->IsSelectAll());
    const AutocompleteResult& result = autocomplete_controller->result();
    // 'App test' is also a substring of extension 'Packaged App Test'.
    EXPECT_GT(result.size(), 2U) << AutocompleteResultAsString(result);
    AutocompleteMatch match = result.match_at(0);
    EXPECT_EQ(ASCIIToUTF16("App Test"), match.contents);
    EXPECT_EQ(AutocompleteMatch::EXTENSION_APP, match.type);
    EXPECT_FALSE(match.deletable);
    location_bar->AcceptInput();
  }
}
<commit_msg>Mark AutocompleteBrowserTest.FocusSearch flaky on Windows and Linux. (reland)<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/format_macros.h"
#include "base/path_service.h"
#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/autocomplete/autocomplete.h"
#include "chrome/browser/autocomplete/autocomplete_edit.h"
#include "chrome/browser/autocomplete/autocomplete_match.h"
#include "chrome/browser/autocomplete/autocomplete_popup_model.h"
#include "chrome/browser/extensions/extension_browsertest.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/unpacked_installer.h"
#include "chrome/browser/history/history.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/omnibox/location_bar.h"
#include "chrome/browser/ui/omnibox/omnibox_view.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_types.h"
#include "testing/gtest/include/gtest/gtest.h"

// Autocomplete test is flaky on ChromeOS.
// http://crbug.com/52928
#if defined(OS_CHROMEOS)
#define MAYBE_Autocomplete FLAKY_Autocomplete
#else
#define MAYBE_Autocomplete Autocomplete
#endif

namespace {

string16 AutocompleteResultAsString(const AutocompleteResult& result) {
  std::string output(base::StringPrintf("{%" PRIuS "} ", result.size()));
  for (size_t i = 0; i < result.size(); ++i) {
    AutocompleteMatch match = result.match_at(i);
    std::string provider_name = match.provider->name();
    output.append(base::StringPrintf("[\"%s\" by \"%s\"] ",
                                     UTF16ToUTF8(match.contents).c_str(),
                                     provider_name.c_str()));
  }
  return UTF8ToUTF16(output);
}

}  // namespace

class AutocompleteBrowserTest : public ExtensionBrowserTest {
 protected:
  LocationBar* GetLocationBar() const {
    return browser()->window()->GetLocationBar();
  }

  AutocompleteController* GetAutocompleteController() const {
    return GetLocationBar()->location_entry()->model()->popup_model()->
        autocomplete_controller();
  }
};

#if defined(OS_WIN) || defined(OS_LINUX)
#define MAYBE_Basic FLAKY_Basic
#else
#define MAYBE_Basic Basic
#endif
IN_PROC_BROWSER_TEST_F(AutocompleteBrowserTest, MAYBE_Basic) {
  LocationBar* location_bar = GetLocationBar();

  EXPECT_TRUE(location_bar->GetInputString().empty());
  EXPECT_EQ(UTF8ToUTF16(chrome::kAboutBlankURL),
            location_bar->location_entry()->GetText());
  // TODO(phajdan.jr): check state of IsSelectAll when it's consistent across
  // platforms.

  location_bar->FocusLocation(true);

  EXPECT_TRUE(location_bar->GetInputString().empty());
  EXPECT_EQ(UTF8ToUTF16(chrome::kAboutBlankURL),
            location_bar->location_entry()->GetText());
  EXPECT_TRUE(location_bar->location_entry()->IsSelectAll());

  location_bar->location_entry()->SetUserText(ASCIIToUTF16("chrome"));

  EXPECT_TRUE(location_bar->GetInputString().empty());
  EXPECT_EQ(ASCIIToUTF16("chrome"), location_bar->location_entry()->GetText());
  EXPECT_FALSE(location_bar->location_entry()->IsSelectAll());

  location_bar->location_entry()->RevertAll();

  EXPECT_TRUE(location_bar->GetInputString().empty());
  EXPECT_EQ(UTF8ToUTF16(chrome::kAboutBlankURL),
            location_bar->location_entry()->GetText());
  EXPECT_FALSE(location_bar->location_entry()->IsSelectAll());

  location_bar->location_entry()->SetUserText(ASCIIToUTF16("chrome"));
  location_bar->Revert();

  EXPECT_TRUE(location_bar->GetInputString().empty());
  EXPECT_EQ(UTF8ToUTF16(chrome::kAboutBlankURL),
            location_bar->location_entry()->GetText());
  EXPECT_FALSE(location_bar->location_entry()->IsSelectAll());
}

IN_PROC_BROWSER_TEST_F(AutocompleteBrowserTest, MAYBE_Autocomplete) {
  // The results depend on the history backend being loaded. Make sure it is
  // loaded so that the autocomplete results are consistent.
  ui_test_utils::WaitForHistoryToLoad(browser());

  LocationBar* location_bar = GetLocationBar();
  AutocompleteController* autocomplete_controller = GetAutocompleteController();

  {
    autocomplete_controller->Start(
        ASCIIToUTF16("chrome"), string16(), true, false, true,
        AutocompleteInput::SYNCHRONOUS_MATCHES);

    EXPECT_TRUE(autocomplete_controller->done());
    EXPECT_TRUE(location_bar->GetInputString().empty());
    EXPECT_TRUE(location_bar->location_entry()->GetText().empty());
    EXPECT_TRUE(location_bar->location_entry()->IsSelectAll());
    const AutocompleteResult& result = autocomplete_controller->result();
    // We get two matches because we have a provider for extension apps and the
    // Chrome Web Store is a built-in Extension app. For this test, we only care
    // about the other match existing.
    ASSERT_GE(result.size(), 1U) << AutocompleteResultAsString(result);
    AutocompleteMatch match = result.match_at(0);
    EXPECT_EQ(AutocompleteMatch::SEARCH_WHAT_YOU_TYPED, match.type);
    EXPECT_FALSE(match.deletable);
  }

  {
    location_bar->Revert();

    EXPECT_TRUE(location_bar->GetInputString().empty());
    EXPECT_EQ(UTF8ToUTF16(chrome::kAboutBlankURL),
              location_bar->location_entry()->GetText());
    EXPECT_FALSE(location_bar->location_entry()->IsSelectAll());
    const AutocompleteResult& result = autocomplete_controller->result();
    EXPECT_TRUE(result.empty()) << AutocompleteResultAsString(result);
  }
}

IN_PROC_BROWSER_TEST_F(AutocompleteBrowserTest, TabAwayRevertSelect) {
  // http://code.google.com/p/chromium/issues/detail?id=38385
  // Make sure that tabbing away from an empty omnibar causes a revert
  // and select all.
  LocationBar* location_bar = GetLocationBar();
  EXPECT_EQ(UTF8ToUTF16(chrome::kAboutBlankURL),
            location_bar->location_entry()->GetText());
  location_bar->location_entry()->SetUserText(string16());
  ui_test_utils::WindowedNotificationObserver observer(
      content::NOTIFICATION_LOAD_STOP,
      content::NotificationService::AllSources());
  browser()->AddSelectedTabWithURL(GURL(chrome::kAboutBlankURL),
                                   content::PAGE_TRANSITION_START_PAGE);
  observer.Wait();
  EXPECT_EQ(UTF8ToUTF16(chrome::kAboutBlankURL),
            location_bar->location_entry()->GetText());
  browser()->CloseTab();
  EXPECT_EQ(UTF8ToUTF16(chrome::kAboutBlankURL),
            location_bar->location_entry()->GetText());
  EXPECT_TRUE(location_bar->location_entry()->IsSelectAll());
}

#if defined(OS_WIN) || defined(OS_LINUX)
// http://crbug.com/104307
#define MAYBE_FocusSearch FLAKY_FocusSearch
#else
#define MAYBE_FocusSearch FocusSearch
#endif
IN_PROC_BROWSER_TEST_F(AutocompleteBrowserTest, MAYBE_FocusSearch) {
  LocationBar* location_bar = GetLocationBar();

  // Focus search when omnibox is blank
  {
    EXPECT_TRUE(location_bar->GetInputString().empty());
    EXPECT_EQ(UTF8ToUTF16(chrome::kAboutBlankURL),
              location_bar->location_entry()->GetText());

    location_bar->FocusSearch();
    EXPECT_TRUE(location_bar->GetInputString().empty());
    EXPECT_EQ(ASCIIToUTF16("?"), location_bar->location_entry()->GetText());

    size_t selection_start, selection_end;
    location_bar->location_entry()->GetSelectionBounds(&selection_start,
                                                       &selection_end);
    EXPECT_EQ(1U, selection_start);
    EXPECT_EQ(1U, selection_end);
  }

  // Focus search when omnibox is _not_ alread in forced query mode.
  {
    location_bar->location_entry()->SetUserText(ASCIIToUTF16("foo"));
    EXPECT_TRUE(location_bar->GetInputString().empty());
    EXPECT_EQ(ASCIIToUTF16("foo"), location_bar->location_entry()->GetText());

    location_bar->FocusSearch();
    EXPECT_TRUE(location_bar->GetInputString().empty());
    EXPECT_EQ(ASCIIToUTF16("?"), location_bar->location_entry()->GetText());

    size_t selection_start, selection_end;
    location_bar->location_entry()->GetSelectionBounds(&selection_start,
                                                       &selection_end);
    EXPECT_EQ(1U, selection_start);
    EXPECT_EQ(1U, selection_end);
  }

  // Focus search when omnibox _is_ already in forced query mode, but no query
  // has been typed.
  {
    location_bar->location_entry()->SetUserText(ASCIIToUTF16("?"));
    EXPECT_TRUE(location_bar->GetInputString().empty());
    EXPECT_EQ(ASCIIToUTF16("?"), location_bar->location_entry()->GetText());

    location_bar->FocusSearch();
    EXPECT_TRUE(location_bar->GetInputString().empty());
    EXPECT_EQ(ASCIIToUTF16("?"), location_bar->location_entry()->GetText());

    size_t selection_start, selection_end;
    location_bar->location_entry()->GetSelectionBounds(&selection_start,
                                                       &selection_end);
    EXPECT_EQ(1U, selection_start);
    EXPECT_EQ(1U, selection_end);
  }

  // Focus search when omnibox _is_ already in forced query mode, and some query
  // has been typed.
  {
    location_bar->location_entry()->SetUserText(ASCIIToUTF16("?foo"));
    EXPECT_TRUE(location_bar->GetInputString().empty());
    EXPECT_EQ(ASCIIToUTF16("?foo"), location_bar->location_entry()->GetText());

    location_bar->FocusSearch();
    EXPECT_TRUE(location_bar->GetInputString().empty());
    EXPECT_EQ(ASCIIToUTF16("?foo"), location_bar->location_entry()->GetText());

    size_t selection_start, selection_end;
    location_bar->location_entry()->GetSelectionBounds(&selection_start,
                                                       &selection_end);
    EXPECT_EQ(1U, std::min(selection_start, selection_end));
    EXPECT_EQ(4U, std::max(selection_start, selection_end));
  }

  // Focus search when omnibox is in forced query mode with leading whitespace.
  {
    location_bar->location_entry()->SetUserText(ASCIIToUTF16("   ?foo"));
    EXPECT_TRUE(location_bar->GetInputString().empty());
    EXPECT_EQ(ASCIIToUTF16("   ?foo"),
              location_bar->location_entry()->GetText());

    location_bar->FocusSearch();
    EXPECT_TRUE(location_bar->GetInputString().empty());
    EXPECT_EQ(ASCIIToUTF16("   ?foo"),
              location_bar->location_entry()->GetText());

    size_t selection_start, selection_end;
    location_bar->location_entry()->GetSelectionBounds(&selection_start,
                                                       &selection_end);
    EXPECT_EQ(4U, std::min(selection_start, selection_end));
    EXPECT_EQ(7U, std::max(selection_start, selection_end));
  }
}

IN_PROC_BROWSER_TEST_F(AutocompleteBrowserTest, ExtensionAppProvider) {
  ExtensionService* service = browser()->profile()->GetExtensionService();
  size_t extension_count = service->extensions()->size();

  FilePath test_dir;
  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir));
  // Load a packaged app.
  extensions::UnpackedInstaller::Create(service)->Load(
      test_dir.AppendASCII("extensions").AppendASCII("packaged_app"));
  WaitForExtensionLoad();
  // Load a hosted app.
  extensions::UnpackedInstaller::Create(service)->Load(
      test_dir.AppendASCII("extensions").AppendASCII("app"));
  WaitForExtensionLoad();
  ASSERT_EQ(extension_count + 2U, service->extensions()->size());

  // The results depend on the history backend being loaded. Make sure it is
  // loaded so that the autocomplete results are consistent.
  ui_test_utils::WaitForHistoryToLoad(browser());

  LocationBar* location_bar = GetLocationBar();
  AutocompleteController* autocomplete_controller = GetAutocompleteController();

  // Try out the packaged app.
  {
    autocomplete_controller->Start(
        ASCIIToUTF16("Packaged App Test"), string16(), true, false, true,
        AutocompleteInput::SYNCHRONOUS_MATCHES);

    EXPECT_TRUE(autocomplete_controller->done());
    EXPECT_TRUE(location_bar->GetInputString().empty());
    EXPECT_TRUE(location_bar->location_entry()->GetText().empty());
    EXPECT_TRUE(location_bar->location_entry()->IsSelectAll());
    const AutocompleteResult& result = autocomplete_controller->result();
    EXPECT_GT(result.size(), 1U) << AutocompleteResultAsString(result);
    AutocompleteMatch match = result.match_at(0);
    EXPECT_EQ(ASCIIToUTF16("Packaged App Test"), match.contents);
    EXPECT_EQ(AutocompleteMatch::EXTENSION_APP, match.type);
    EXPECT_FALSE(match.deletable);
    location_bar->AcceptInput();
  }

  browser()->NewTab();

  // Try out the hosted app.
  {
    autocomplete_controller->Start(
        ASCIIToUTF16("App Test"), string16(), true, false, true,
        AutocompleteInput::SYNCHRONOUS_MATCHES);

    EXPECT_TRUE(autocomplete_controller->done());
    EXPECT_TRUE(location_bar->GetInputString().empty());
    EXPECT_TRUE(location_bar->location_entry()->GetText().empty());
    EXPECT_TRUE(location_bar->location_entry()->IsSelectAll());
    const AutocompleteResult& result = autocomplete_controller->result();
    // 'App test' is also a substring of extension 'Packaged App Test'.
    EXPECT_GT(result.size(), 2U) << AutocompleteResultAsString(result);
    AutocompleteMatch match = result.match_at(0);
    EXPECT_EQ(ASCIIToUTF16("App Test"), match.contents);
    EXPECT_EQ(AutocompleteMatch::EXTENSION_APP, match.type);
    EXPECT_FALSE(match.deletable);
    location_bar->AcceptInput();
  }
}
<|endoftext|>