<commit_before>#include "matrix.h"

//
// Public member functions
//

Matrix::Matrix() {
    // USAGE: Constructor for the matrix class
    lines = 0;
    score = 0;
    active_piece = nullptr;
    initGrid();
}

void Matrix::printGrid(bool mode) {
    // USAGE: Prints out contents of cells in the grid
    if (mode) {
        for (int i = 0; i < 22; ++i) {
            for (int j = 0; j < 10; ++j) {
                auto temp = grid[i][j].label;
                if (grid[i][j].isActive()) temp[0] = std::toupper(temp[0]);
                std::cout << temp << " ";
            }
            std::cout << std::endl;
         }
    }
    else {
        for (int i = 0; i < 22; ++i) {
            for (int j = 0; j < 10; ++j) {
                std::cout << backup_grid[i][j].label << " ";
            }
            std::cout << std::endl;
         }
    }
    if (game_over) std::cout << "Game Over\n";
}

void Matrix::printActive() {
    // USAGE: Prints out the current active piece
    active_piece -> print();
}

void Matrix::given() {
    // USAGE: Allows an input stream of 22 characters to set table
    initGrid();
    for (int i = 0; i < 22; i++) {
        for (int j = 0; j < 10; j++) {
            std::string temp;
            std::cin >> temp;
            if (temp != ".") {
                auto temp_ptr = std::make_shared<Tetramino>(temp);
                grid[i][j].assign(temp_ptr);
            }
        }
    }
    updateBackup();
}

void Matrix::clear() {
    // USAGE: Clears the board
    initGrid();
}

int Matrix::get_score() {
    // USAGE: Prints current user score with cout
    return score;
}

int Matrix::get_lines() {
    // USAGE: Prints current liens cleared by user with cout
    return lines;
}

void Matrix::step() {
    // USAGE: Checks for filled rows and updates grid accordingly
    //int pushes[22] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
    for (int i = 0; i < 22; ++i) {
        // Check if row is completely filled
        bool filled = true;
        for (int j = 0; j < 10; ++j) {
            if (grid[i][j].checkOccupied() == nullptr) filled = false;
        }

        if (filled) {
            // Clear the cells in the row
            for (int j = 0; j < 10; ++j) grid[i][j].remove();
            // Increment # of pushes for above rows
            //for (int x = i-1; x >= 0; ++x) pushes[x]++;
            lines += 1;
            score += 100;
        }
    }

    updateBackup();

    if (!checkTopEmpty()) game_over = true;

    /*
    // Update the grid starting from the bottom
    for (int i = 21; i >= 0; --i) {
        if (pushes[i] > 0) {
            // Push everything in current row i to row i + pushes[i]
            int new_row = i + pushes[i];
            for (int j = 0; j < 10; ++j) {
                auto temp = grid[i][j].checkOccupied();
                grid[new_row][j].assign(temp);
                grid[i][j].remove();
            }
        }
    }*/
}

auto Matrix::setActive(char type) -> std::shared_ptr<Tetramino> {
    if (game_over) return nullptr;
    if (active_piece != nullptr) {
        active_piece->active = false;
        active_piece = nullptr;
    }
    switch(type) {
        case 'I':
            active_piece = std::make_shared<I_Type>();
            initPiece(type);
            return active_piece;
            break;
        case 'O':
            active_piece = std::make_shared<O_Type>();
            initPiece(type);
            return active_piece;
            break;
        case 'Z':
            active_piece = std::make_shared<Z_Type>();
            initPiece(type);
            return active_piece;
            break;
        case 'S':
            active_piece = std::make_shared<S_Type>();
            initPiece(type);
            return active_piece;
            break;
        case 'J':
            active_piece = std::make_shared<J_Type>();
            initPiece(type);
            return active_piece;
            break;
        case 'L':
            active_piece = std::make_shared<L_Type>();
            initPiece(type);
            return active_piece;
            break;
        case 'T':
            active_piece = std::make_shared<T_Type>();
            initPiece(type);
            return active_piece;
            break;
        default:
            return nullptr;
            break;
    }
}

void Matrix::rotateCW() {
    // USAGE: Checks if rotation is allowed and do it if it is
    if (game_over) return;
    auto cell_list = active_piece -> checkCW();
    if (checkSpaceEmpty(cell_list)) {
        move(cell_list);
        active_piece -> rotateCW();
    }
}

void Matrix::rotateCCW() {
    // USAGE: Checks if rotation is allowed and does it if it is
    if (game_over) return;
    auto cell_list = active_piece -> checkCCW();
    if (checkSpaceEmpty(cell_list)) {
        move(cell_list);
        active_piece -> rotateCCW();
    }
}

void Matrix::moveLeft() {
    // USAGE: Check if current active piece can move to left and if it can, move there
    if (game_over) return;
    auto cell_list = active_piece -> checkLeft();
    if (checkSpaceEmpty(cell_list)) {
        move(cell_list);
    }
}

void Matrix::moveRight() {
    // USAGE: Check if current active piece can move to right and if it can, move there
    if (game_over) return;
    auto cell_list = active_piece -> checkRight();
    if (checkSpaceEmpty(cell_list)) {
        move(cell_list);
    }
}

void Matrix::moveDown() {
    // USAGE: Check if current active piece can move to right and if it can, move there
    if (game_over) return;
    auto cell_list = active_piece -> checkDown();
    if (checkSpaceEmpty(cell_list)) {
        move(cell_list);
    }
}

void Matrix::moveHardDown() {
    // USAGE: Moves active piece down until it hits a boundary or another piece
    if (game_over) return;
    auto cell_list = active_piece -> checkDown();
    while (checkSpaceEmpty(cell_list)) {
        move(cell_list);
        cell_list = active_piece -> checkDown();
    }
    active_piece -> active = false;
    active_piece = nullptr;
    step();
}

//
// Private member functions
//

void Matrix::initGrid() {
    // USAGE: Creates a blank grid and sets it to the matrix object
    for (int i = 0; i < 22; ++i) {
        for (int j = 0; j < 10; ++j) {
            grid[i][j] = Cell();
            grid[i][j].setCoordinates(i,j);
        }
    }
    active_piece = nullptr;
    game_over = false;
    updateBackup();
}

void Matrix::initPiece(char type) {
    //USAGE: Places a newly made active piece on the grid
    switch(type) {
        case 'I':
            assert(grid[1][3].assign(active_piece) != 1);
            assert(grid[1][4].assign(active_piece) != 1);
            assert(grid[1][5].assign(active_piece) != 1);
            assert(grid[1][6].assign(active_piece) != 1);
            break;
        case 'O':
            assert(grid[0][4].assign(active_piece) != 1);
            assert(grid[0][5].assign(active_piece) != 1);
            assert(grid[1][4].assign(active_piece) != 1);
            assert(grid[1][5].assign(active_piece) != 1);
            break;
        case 'S':
            assert(grid[0][4].assign(active_piece) != 1);
            assert(grid[0][5].assign(active_piece) != 1);
            assert(grid[1][3].assign(active_piece) != 1);
            assert(grid[1][4].assign(active_piece) != 1);
            break;
        case 'Z':
            assert(grid[0][3].assign(active_piece) != 1);
            assert(grid[0][4].assign(active_piece) != 1);
            assert(grid[1][4].assign(active_piece) != 1);
            assert(grid[1][5].assign(active_piece) != 1);
            break;
        case 'J':
            assert(grid[0][3].assign(active_piece) != 1);
            assert(grid[1][3].assign(active_piece) != 1);
            assert(grid[1][4].assign(active_piece) != 1);
            assert(grid[1][5].assign(active_piece) != 1);
            break;
        case 'L':
            assert(grid[0][5].assign(active_piece) != 1);
            assert(grid[1][3].assign(active_piece) != 1);
            assert(grid[1][4].assign(active_piece) != 1);
            assert(grid[1][5].assign(active_piece) != 1);
            break;
        case 'T':
            assert(grid[0][4].assign(active_piece) != 1);
            assert(grid[1][3].assign(active_piece) != 1);
            assert(grid[1][4].assign(active_piece) != 1);
            assert(grid[1][5].assign(active_piece) != 1);
            break;
        default:
            break;
    }
}

void Matrix::updateBackup() {
    // USAGE: Updates backup_grid after every init, step, and given function call
    for (int i = 0; i < 22; ++i) {
        for (int j = 0; j < 10; ++j) {
            backup_grid[i][j] = grid[i][j];
        }
    }
}

bool Matrix::checkSpaceEmpty(const std::vector<std::tuple<int,int>> & cell_list) {
    // USAGE: Helper function for checking if cells in a list are occupied
    for (auto itr = cell_list.begin(); itr != cell_list.end(); ++itr) {
        int x = std::get<0>(*itr);
        int y = std::get<1>(*itr);

        // Check for boundary collision
        if (x < 0 || x > 21 || y < 0 || y > 9) return false;

        // Check if there is a piece already there
        if (grid[x][y].checkOccupied() != nullptr && !grid[x][y].isActive())
            return false;
    }
    return true;
}

bool Matrix::checkTopEmpty() {
    // USAGE: Helper function to check top rows before setting new active piece
    for (int i = 0; i < 2; ++i) {
        for (int j = 0; j < 10; ++j) {
            if (grid[i][j].checkOccupied() != nullptr) return false;
        }
    }
    return true;
}

int Matrix::move(const std::vector<std::tuple<int,int>> & cell_list) {
    // USAGE: Accepts a tuple vector of new coordinates after a move
    auto old_cells = active_piece -> getCells();
    for (auto itr = old_cells.begin(); itr != old_cells.end(); ++itr) {
        (*itr) -> remove();
    }
    for (auto itr = cell_list.begin(); itr != cell_list.end(); ++itr) {
        int x = std::get<0>(*itr);
        int y = std::get<1>(*itr);

        grid[x][y].assign(active_piece);
    }
    return 0;
}
<commit_msg>Fix seg fault with move<commit_after>#include "matrix.h"

//
// Public member functions
//

Matrix::Matrix() {
    // USAGE: Constructor for the matrix class
    lines = 0;
    score = 0;
    active_piece = nullptr;
    initGrid();
}

void Matrix::printGrid(bool mode) {
    // USAGE: Prints out contents of cells in the grid
    if (mode) {
        for (int i = 0; i < 22; ++i) {
            for (int j = 0; j < 10; ++j) {
                auto temp = grid[i][j].label;
                if (grid[i][j].isActive()) temp[0] = std::toupper(temp[0]);
                std::cout << temp << " ";
            }
            std::cout << std::endl;
         }
    }
    else {
        for (int i = 0; i < 22; ++i) {
            for (int j = 0; j < 10; ++j) {
                std::cout << backup_grid[i][j].label << " ";
            }
            std::cout << std::endl;
         }
    }
    if (game_over) std::cout << "Game Over\n";
}

void Matrix::printActive() {
    // USAGE: Prints out the current active piece
    active_piece -> print();
}

void Matrix::given() {
    // USAGE: Allows an input stream of 22 characters to set table
    initGrid();
    for (int i = 0; i < 22; i++) {
        for (int j = 0; j < 10; j++) {
            std::string temp;
            std::cin >> temp;
            if (temp != ".") {
                auto temp_ptr = std::make_shared<Tetramino>(temp);
                grid[i][j].assign(temp_ptr);
            }
        }
    }
    updateBackup();
}

void Matrix::clear() {
    // USAGE: Clears the board
    initGrid();
}

int Matrix::get_score() {
    // USAGE: Prints current user score with cout
    return score;
}

int Matrix::get_lines() {
    // USAGE: Prints current liens cleared by user with cout
    return lines;
}

void Matrix::step() {
    // USAGE: Checks for filled rows and updates grid accordingly
    int pushes[22] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
    for (int i = 0; i < 22; ++i) {
        // Check if row is completely filled
        bool filled = true;
        for (int j = 0; j < 10; ++j) {
            if (grid[i][j].checkOccupied() == nullptr) filled = false;
        }

        if (filled) {
            // Clear the cells in the row
            for (int j = 0; j < 10; ++j) grid[i][j].remove();
            // Increment # of pushes for above rows
            for (int x = i-1; x >= 0; --x) pushes[x]++;
            lines += 1;
            score += 100;
        }
    }

    // Update the grid starting from the bottom
    for (int i = 21; i >= 0; --i) {
        if (pushes[i] > 0) {
            // Push everything in current row i to row i + pushes[i]
            int new_row = i + pushes[i];
            assert (new_row < 22);

            for (int j = 0; j < 10; ++j) {
                auto temp = grid[i][j].checkOccupied();
                if (temp != nullptr) {
                    grid[new_row][j].assign(temp);
                    grid[i][j].remove();
                }
            }
        }
    }

    updateBackup();
    if (!checkTopEmpty()) game_over = true;
}

auto Matrix::setActive(char type) -> std::shared_ptr<Tetramino> {
    if (game_over) return nullptr;
    if (active_piece != nullptr) {
        active_piece->active = false;
        active_piece = nullptr;
    }
    switch(type) {
        case 'I':
            active_piece = std::make_shared<I_Type>();
            initPiece(type);
            return active_piece;
            break;
        case 'O':
            active_piece = std::make_shared<O_Type>();
            initPiece(type);
            return active_piece;
            break;
        case 'Z':
            active_piece = std::make_shared<Z_Type>();
            initPiece(type);
            return active_piece;
            break;
        case 'S':
            active_piece = std::make_shared<S_Type>();
            initPiece(type);
            return active_piece;
            break;
        case 'J':
            active_piece = std::make_shared<J_Type>();
            initPiece(type);
            return active_piece;
            break;
        case 'L':
            active_piece = std::make_shared<L_Type>();
            initPiece(type);
            return active_piece;
            break;
        case 'T':
            active_piece = std::make_shared<T_Type>();
            initPiece(type);
            return active_piece;
            break;
        default:
            return nullptr;
            break;
    }
}

void Matrix::rotateCW() {
    // USAGE: Checks if rotation is allowed and do it if it is
    if (game_over || active_piece == nullptr) return;
    auto cell_list = active_piece -> checkCW();
    if (checkSpaceEmpty(cell_list)) {
        move(cell_list);
        active_piece -> rotateCW();
    }
}

void Matrix::rotateCCW() {
    // USAGE: Checks if rotation is allowed and does it if it is
    if (game_over || active_piece == nullptr) return;
    auto cell_list = active_piece -> checkCCW();
    if (checkSpaceEmpty(cell_list)) {
        move(cell_list);
        active_piece -> rotateCCW();
    }
}

void Matrix::moveLeft() {
    // USAGE: Check if current active piece can move to left and if it can, move there
    if (game_over || active_piece == nullptr) return;
    auto cell_list = active_piece -> checkLeft();
    if (checkSpaceEmpty(cell_list)) {
        move(cell_list);
    }
}

void Matrix::moveRight() {
    // USAGE: Check if current active piece can move to right and if it can, move there
    if (game_over || active_piece == nullptr) return;
    auto cell_list = active_piece -> checkRight();
    if (checkSpaceEmpty(cell_list)) {
        move(cell_list);
    }
}

void Matrix::moveDown() {
    // USAGE: Check if current active piece can move to right and if it can, move there
    if (game_over || active_piece == nullptr) return;
    auto cell_list = active_piece -> checkDown();
    if (checkSpaceEmpty(cell_list)) {
        move(cell_list);
    }
    else {
        active_piece -> active = false;
        active_piece = nullptr;
        step();
    }
}

void Matrix::moveHardDown() {
    // USAGE: Moves active piece down until it hits a boundary or another piece
    if (game_over || active_piece == nullptr) return;
    auto cell_list = active_piece -> checkDown();
    while (checkSpaceEmpty(cell_list)) {
        move(cell_list);
        cell_list = active_piece -> checkDown();
    }
    active_piece -> active = false;
    active_piece = nullptr;
    step();
}

//
// Private member functions
//

void Matrix::initGrid() {
    // USAGE: Creates a blank grid and sets it to the matrix object
    for (int i = 0; i < 22; ++i) {
        for (int j = 0; j < 10; ++j) {
            grid[i][j] = Cell();
            grid[i][j].setCoordinates(i,j);
        }
    }
    active_piece = nullptr;
    game_over = false;
    updateBackup();
}

void Matrix::initPiece(char type) {
    //USAGE: Places a newly made active piece on the grid
    switch(type) {
        case 'I':
            assert(grid[1][3].assign(active_piece) != 1);
            assert(grid[1][4].assign(active_piece) != 1);
            assert(grid[1][5].assign(active_piece) != 1);
            assert(grid[1][6].assign(active_piece) != 1);
            break;
        case 'O':
            assert(grid[0][4].assign(active_piece) != 1);
            assert(grid[0][5].assign(active_piece) != 1);
            assert(grid[1][4].assign(active_piece) != 1);
            assert(grid[1][5].assign(active_piece) != 1);
            break;
        case 'S':
            assert(grid[0][4].assign(active_piece) != 1);
            assert(grid[0][5].assign(active_piece) != 1);
            assert(grid[1][3].assign(active_piece) != 1);
            assert(grid[1][4].assign(active_piece) != 1);
            break;
        case 'Z':
            assert(grid[0][3].assign(active_piece) != 1);
            assert(grid[0][4].assign(active_piece) != 1);
            assert(grid[1][4].assign(active_piece) != 1);
            assert(grid[1][5].assign(active_piece) != 1);
            break;
        case 'J':
            assert(grid[0][3].assign(active_piece) != 1);
            assert(grid[1][3].assign(active_piece) != 1);
            assert(grid[1][4].assign(active_piece) != 1);
            assert(grid[1][5].assign(active_piece) != 1);
            break;
        case 'L':
            assert(grid[0][5].assign(active_piece) != 1);
            assert(grid[1][3].assign(active_piece) != 1);
            assert(grid[1][4].assign(active_piece) != 1);
            assert(grid[1][5].assign(active_piece) != 1);
            break;
        case 'T':
            assert(grid[0][4].assign(active_piece) != 1);
            assert(grid[1][3].assign(active_piece) != 1);
            assert(grid[1][4].assign(active_piece) != 1);
            assert(grid[1][5].assign(active_piece) != 1);
            break;
        default:
            break;
    }
}

void Matrix::updateBackup() {
    // USAGE: Updates backup_grid after every init, step, and given function call
    for (int i = 0; i < 22; ++i) {
        for (int j = 0; j < 10; ++j) {
            backup_grid[i][j] = grid[i][j];
        }
    }
}

bool Matrix::checkSpaceEmpty(const std::vector<std::tuple<int,int>> & cell_list) {
    // USAGE: Helper function for checking if cells in a list are occupied
    for (auto itr = cell_list.begin(); itr != cell_list.end(); ++itr) {
        int x = std::get<0>(*itr);
        int y = std::get<1>(*itr);

        // Check for boundary collision
        if (x < 0 || x > 21 || y < 0 || y > 9) return false;

        // Check if there is a piece already there
        if (grid[x][y].checkOccupied() != nullptr && !grid[x][y].isActive())
            return false;
    }
    return true;
}

bool Matrix::checkTopEmpty() {
    // USAGE: Helper function to check top rows before setting new active piece
    for (int i = 0; i < 2; ++i) {
        for (int j = 0; j < 10; ++j) {
            if (grid[i][j].checkOccupied() != nullptr) return false;
        }
    }
    return true;
}

int Matrix::move(const std::vector<std::tuple<int,int>> & cell_list) {
    // USAGE: Accepts a tuple vector of new coordinates after a move
    auto old_cells = active_piece -> getCells();
    for (auto itr = old_cells.begin(); itr != old_cells.end(); ++itr) {
        (*itr) -> remove();
    }
    for (auto itr = cell_list.begin(); itr != cell_list.end(); ++itr) {
        int x = std::get<0>(*itr);
        int y = std::get<1>(*itr);

        grid[x][y].assign(active_piece);
    }
    return 0;
}
<|endoftext|>


<commit_before>#include "memory.h"
#include "cartridge.h"
#include <assert.h>

u8 Memory::read_byte(uint address) const
{
  if (address < 0x8000 || (address >= 0xa000 && address < 0xc000))
  {
    // ROM / external RAM
    return cart.get8(address);
  }
  else if (address >= 0x8000 && address < 0xa000)
  {
    // VRAM - Video RAM
    return vram[address - 0x8000];
  }
  else if (address >= 0xc000 && address < 0xd000)
  {
    // WRAM - Work RAM bank 0
    return wram[address - 0xc000];
  }
  else if (address >= 0xd000 && address < 0xe000)
  {
    // Switchable Work RAM bank (1 - 7)
    // TODO make switchable
    return wram[address - 0xc000];
  }
  else if (address >= 0xe000 && address < 0xfe00)
  {
    // ECHO - Mirror of C000 - DDFF
    return wram[address - 0xe000];
  }
  else if (address >= 0xfe00 && address < 0xfea0)
  {
    // Sprite attribute table
  }
  else if (address >= 0xfea0 && address < 0xff00)
  {
    // Not usable
  }
  else if (address >= 0xff00 && address < 0xff80)
  {
    // IO registers
  }
  else if (address >= 0xff80 && address < 0xffff)
  {
    // HRAM - High RAM
  }
  else if (address == 0xffff)
  {
    // Interrupt enable register
  }

  // Should never get here
  abort();
}

void Memory::write_byte(uint address, u8 value)
{
  if (address < 0x8000 || (address >= 0xa000 && address < 0xc000))
  {
    // ROM / external RAM
    cart.set8(address, value);
  }
  // TODO
}
<commit_msg>Memory: use memory map for writing too<commit_after>#include "memory.h"
#include "cartridge.h"
#include <assert.h>

u8 Memory::read_byte(uint address) const
{
  if (address < 0x8000 || (address >= 0xa000 && address < 0xc000))
  {
    // ROM / external RAM
    return cart.get8(address);
  }
  else if (address >= 0x8000 && address < 0xa000)
  {
    // VRAM - Video RAM
    return vram[address - 0x8000];
  }
  else if (address >= 0xc000 && address < 0xd000)
  {
    // WRAM - Work RAM bank 0
    return wram[address - 0xc000];
  }
  else if (address >= 0xd000 && address < 0xe000)
  {
    // Switchable Work RAM bank (1 - 7)
    // TODO make switchable
    return wram[address - 0xc000];
  }
  else if (address >= 0xe000 && address < 0xfe00)
  {
    // ECHO - Mirror of C000 - DDFF
    return wram[address - 0xe000];
  }
  else if (address >= 0xfe00 && address < 0xfea0)
  {
    // Sprite attribute table
  }
  else if (address >= 0xfea0 && address < 0xff00)
  {
    // Not usable
  }
  else if (address >= 0xff00 && address < 0xff80)
  {
    // IO registers
  }
  else if (address >= 0xff80 && address < 0xffff)
  {
    // HRAM - High RAM
  }
  else if (address == 0xffff)
  {
    // Interrupt enable register
  }

  // Should never get here
  abort();
}

void Memory::write_byte(uint address, u8 value)
{
  if (address < 0x8000 || (address >= 0xa000 && address < 0xc000))
  {
    // ROM / external RAM
    cart.set8(address, value);
  }
  else if (address >= 0x8000 && address < 0xa000)
  {
    // VRAM - Video RAM
    vram[address - 0x8000] = value;
  }
  else if (address >= 0xc000 && address < 0xd000)
  {
    // WRAM - Work RAM bank 0
    wram[address - 0xc000] = value;
  }
  else if (address >= 0xd000 && address < 0xe000)
  {
    // Switchable Work RAM bank (1 - 7)
    // TODO make switchable
    wram[address - 0xc000] = value;
  }
  else if (address >= 0xe000 && address < 0xfe00)
  {
    // ECHO - Mirror of C000 - DDFF
    wram[address - 0xe000] = value;
  }
  else if (address >= 0xfe00 && address < 0xfea0)
  {
    // Sprite attribute table
  }
  else if (address >= 0xfea0 && address < 0xff00)
  {
    // Not usable
  }
  else if (address >= 0xff00 && address < 0xff80)
  {
    // IO registers
  }
  else if (address >= 0xff80 && address < 0xffff)
  {
    // HRAM - High RAM
  }
  else if (address == 0xffff)
  {
    // Interrupt enable register
  }
  else
  {
    // Should never get here
    abort();
  }
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 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/command_line.h"
#include "chrome/browser/devtools/devtools_window.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/singleton_tabs.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/chrome_switches.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/public/browser/notification_service.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"

using content::RenderViewHost;
using content::RenderWidgetHost;
using content::WebContents;

namespace {

int RenderProcessHostCount() {
  content::RenderProcessHost::iterator hosts =
      content::RenderProcessHost::AllHostsIterator();
  int count = 0;
  while (!hosts.IsAtEnd()) {
    if (hosts.GetCurrentValue()->HasConnection())
      count++;
    hosts.Advance();
  }
  return count;
}

RenderViewHost* FindFirstDevToolsHost() {
  content::RenderProcessHost::iterator hosts =
      content::RenderProcessHost::AllHostsIterator();
  for (; !hosts.IsAtEnd(); hosts.Advance()) {
    content::RenderProcessHost* render_process_host = hosts.GetCurrentValue();
    DCHECK(render_process_host);
    if (!render_process_host->HasConnection())
      continue;
    content::RenderProcessHost::RenderWidgetHostsIterator iter(
        render_process_host->GetRenderWidgetHostsIterator());
    for (; !iter.IsAtEnd(); iter.Advance()) {
      const RenderWidgetHost* widget = iter.GetCurrentValue();
      DCHECK(widget);
      if (!widget || !widget->IsRenderView())
        continue;
      RenderViewHost* host =
          RenderViewHost::From(const_cast<RenderWidgetHost*>(widget));
      WebContents* contents = WebContents::FromRenderViewHost(host);
      GURL url = contents->GetURL();
      if (url.SchemeIs(chrome::kChromeDevToolsScheme))
        return host;
    }
  }
  return NULL;
}

}  // namespace

class ChromeRenderProcessHostTest : public InProcessBrowserTest {
 public:
  ChromeRenderProcessHostTest() {}

  // Show a tab, activating the current one if there is one, and wait for
  // the renderer process to be created or foregrounded, returning the process
  // handle.
  base::ProcessHandle ShowSingletonTab(const GURL& page) {
    chrome::ShowSingletonTab(browser(), page);
    WebContents* wc = browser()->tab_strip_model()->GetActiveWebContents();
    CHECK(wc->GetURL() == page);

    // Ensure that the backgrounding / foregrounding gets a chance to run.
    content::BrowserThread::PostTaskAndReply(
        content::BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
        base::Bind(&base::DoNothing), MessageLoop::QuitClosure());
    MessageLoop::current()->Run();

    return wc->GetRenderProcessHost()->GetHandle();
  }

  // When we hit the max number of renderers, verify that the way we do process
  // sharing behaves correctly.  In particular, this test is verifying that even
  // when we hit the max process limit, that renderers of each type will wind up
  // in a process of that type, even if that means creating a new process.
  void TestProcessOverflow() {
    int tab_count = 1;
    int host_count = 1;
    WebContents* tab1 = NULL;
    WebContents* tab2 = NULL;
    content::RenderProcessHost* rph1 = NULL;
    content::RenderProcessHost* rph2 = NULL;
    content::RenderProcessHost* rph3 = NULL;

    // Change the first tab to be the new tab page (TYPE_WEBUI).
    GURL newtab(chrome::kChromeUINewTabURL);
    ui_test_utils::NavigateToURL(browser(), newtab);
    EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
    tab1 = browser()->tab_strip_model()->GetWebContentsAt(tab_count - 1);
    rph1 = tab1->GetRenderProcessHost();
    EXPECT_EQ(tab1->GetURL(), newtab);
    EXPECT_EQ(host_count, RenderProcessHostCount());

    // Create a new TYPE_TABBED tab.  It should be in its own process.
    GURL page1("data:text/html,hello world1");

    ui_test_utils::WindowedTabAddedNotificationObserver observer1(
        content::NotificationService::AllSources());
    chrome::ShowSingletonTab(browser(), page1);
    observer1.Wait();

    tab_count++;
    host_count++;
    EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
    tab1 = browser()->tab_strip_model()->GetWebContentsAt(tab_count - 1);
    rph2 = tab1->GetRenderProcessHost();
    EXPECT_EQ(tab1->GetURL(), page1);
    EXPECT_EQ(host_count, RenderProcessHostCount());
    EXPECT_NE(rph1, rph2);

    // Create another TYPE_TABBED tab.  It should share the previous process.
    GURL page2("data:text/html,hello world2");
    ui_test_utils::WindowedTabAddedNotificationObserver observer2(
        content::NotificationService::AllSources());
    chrome::ShowSingletonTab(browser(), page2);
    observer2.Wait();
    tab_count++;
    EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
    tab2 = browser()->tab_strip_model()->GetWebContentsAt(tab_count - 1);
    EXPECT_EQ(tab2->GetURL(), page2);
    EXPECT_EQ(host_count, RenderProcessHostCount());
    EXPECT_EQ(tab2->GetRenderProcessHost(), rph2);

    // Create another TYPE_WEBUI tab.  It should share the process with newtab.
    // Note: intentionally create this tab after the TYPE_TABBED tabs to
    // exercise bug 43448 where extension and WebUI tabs could get combined into
    // normal renderers.
    GURL history(chrome::kChromeUIHistoryURL);
    ui_test_utils::WindowedTabAddedNotificationObserver observer3(
        content::NotificationService::AllSources());
    chrome::ShowSingletonTab(browser(), history);
    observer3.Wait();
    tab_count++;
    EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
    tab2 = browser()->tab_strip_model()->GetWebContentsAt(tab_count - 1);
    EXPECT_EQ(tab2->GetURL(), GURL(history));
    EXPECT_EQ(host_count, RenderProcessHostCount());
    EXPECT_EQ(tab2->GetRenderProcessHost(), rph1);

    // Create a TYPE_EXTENSION tab.  It should be in its own process.
    // (the bookmark manager is implemented as an extension)
    GURL bookmarks(chrome::kChromeUIBookmarksURL);
    ui_test_utils::WindowedTabAddedNotificationObserver observer4(
        content::NotificationService::AllSources());
    chrome::ShowSingletonTab(browser(), bookmarks);
    observer4.Wait();
    tab_count++;
    host_count++;
    EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
    tab1 = browser()->tab_strip_model()->GetWebContentsAt(tab_count - 1);
    rph3 = tab1->GetRenderProcessHost();
    EXPECT_EQ(tab1->GetURL(), bookmarks);
    EXPECT_EQ(host_count, RenderProcessHostCount());
    EXPECT_NE(rph1, rph3);
    EXPECT_NE(rph2, rph3);
  }
};

class ChromeRenderProcessHostTestWithCommandLine
    : public ChromeRenderProcessHostTest {
 protected:
  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
    command_line->AppendSwitchASCII(switches::kRendererProcessLimit, "1");
  }
};

IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTest, ProcessPerTab) {
  // Set max renderers to 1 to force running out of processes.
  content::RenderProcessHost::SetMaxRendererProcessCount(1);

  CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
  parsed_command_line.AppendSwitch(switches::kProcessPerTab);

  int tab_count = 1;
  int host_count = 1;

  // Change the first tab to be the new tab page (TYPE_WEBUI).
  GURL newtab(chrome::kChromeUINewTabURL);
  ui_test_utils::NavigateToURL(browser(), newtab);
  EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
  EXPECT_EQ(host_count, RenderProcessHostCount());

  // Create a new TYPE_TABBED tab.  It should be in its own process.
  GURL page1("data:text/html,hello world1");
  ui_test_utils::WindowedTabAddedNotificationObserver observer1(
      content::NotificationService::AllSources());
  chrome::ShowSingletonTab(browser(), page1);
  observer1.Wait();
  tab_count++;
  host_count++;
  EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
  EXPECT_EQ(host_count, RenderProcessHostCount());

  // Create another TYPE_TABBED tab.  It should share the previous process.
  GURL page2("data:text/html,hello world2");
  ui_test_utils::WindowedTabAddedNotificationObserver observer2(
      content::NotificationService::AllSources());
  chrome::ShowSingletonTab(browser(), page2);
  observer2.Wait();
  tab_count++;
  EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
  EXPECT_EQ(host_count, RenderProcessHostCount());

  // Create another new tab.  It should share the process with the other WebUI.
  ui_test_utils::WindowedTabAddedNotificationObserver observer3(
      content::NotificationService::AllSources());
  chrome::NewTab(browser());
  observer3.Wait();
  tab_count++;
  EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
  EXPECT_EQ(host_count, RenderProcessHostCount());

  // Create another new tab.  It should share the process with the other WebUI.
  ui_test_utils::WindowedTabAddedNotificationObserver observer4(
      content::NotificationService::AllSources());
  chrome::NewTab(browser());
  observer4.Wait();
  tab_count++;
  EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
  EXPECT_EQ(host_count, RenderProcessHostCount());
}

// We don't change process priorities on Mac or Posix because the user lacks the
// permission to raise a process' priority even after lowering it.
#if defined(OS_WIN) || defined(OS_LINUX)
IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTest, Backgrounding) {
  if (!base::Process::CanBackgroundProcesses()) {
    LOG(ERROR) << "Can't background processes";
    return;
  }
  CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
  parsed_command_line.AppendSwitch(switches::kProcessPerTab);

  // Change the first tab to be the new tab page (TYPE_WEBUI).
  GURL newtab(chrome::kChromeUINewTabURL);
  ui_test_utils::NavigateToURL(browser(), newtab);

  // Create a new tab. It should be foreground.
  GURL page1("data:text/html,hello world1");
  base::ProcessHandle pid1 = ShowSingletonTab(page1);
  EXPECT_FALSE(base::Process(pid1).IsProcessBackgrounded());

  // Create another tab. It should be foreground, and the first tab should
  // now be background.
  GURL page2("data:text/html,hello world2");
  base::ProcessHandle pid2 = ShowSingletonTab(page2);
  EXPECT_NE(pid1, pid2);
  EXPECT_TRUE(base::Process(pid1).IsProcessBackgrounded());
  EXPECT_FALSE(base::Process(pid2).IsProcessBackgrounded());

  // Navigate back to first page. It should be foreground again, and the second
  // tab should be background.
  EXPECT_EQ(pid1, ShowSingletonTab(page1));
  EXPECT_FALSE(base::Process(pid1).IsProcessBackgrounded());
  EXPECT_TRUE(base::Process(pid2).IsProcessBackgrounded());
}
#endif

IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTest, ProcessOverflow) {
  // Set max renderers to 1 to force running out of processes.
  content::RenderProcessHost::SetMaxRendererProcessCount(1);
  TestProcessOverflow();
}

// Variation of the ProcessOverflow test, which is driven through command line
// parameter instead of direct function call into the class.
IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTestWithCommandLine,
                       ProcessOverflow) {
  TestProcessOverflow();
}

// Ensure that DevTools opened to debug DevTools is launched in a separate
// process when --process-per-tab is set. See crbug.com/69873.
IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTest,
                       DevToolsOnSelfInOwnProcessPPT) {
  CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
  parsed_command_line.AppendSwitch(switches::kProcessPerTab);

  int tab_count = 1;
  int host_count = 1;

  GURL page1("data:text/html,hello world1");
  ui_test_utils::WindowedTabAddedNotificationObserver observer1(
      content::NotificationService::AllSources());
  chrome::ShowSingletonTab(browser(), page1);
  observer1.Wait();
  tab_count++;
  host_count++;
  EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
  EXPECT_EQ(host_count, RenderProcessHostCount());

  // DevTools start in docked mode (no new tab), in a separate process.
  chrome::ToggleDevToolsWindow(browser(), DEVTOOLS_TOGGLE_ACTION_INSPECT);
  host_count++;
  EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
  EXPECT_EQ(host_count, RenderProcessHostCount());

  RenderViewHost* devtools = FindFirstDevToolsHost();
  DCHECK(devtools);

  // DevTools start in a separate process.
  DevToolsWindow::ToggleDevToolsWindow(
      devtools, true, DEVTOOLS_TOGGLE_ACTION_INSPECT);
  host_count++;
  EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
  EXPECT_EQ(host_count, RenderProcessHostCount());
}

// Ensure that DevTools opened to debug DevTools is launched in a separate
// process. See crbug.com/69873.
IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTest,
                       DevToolsOnSelfInOwnProcess) {
  int tab_count = 1;
  int host_count = 1;

  GURL page1("data:text/html,hello world1");
  ui_test_utils::WindowedTabAddedNotificationObserver observer1(
      content::NotificationService::AllSources());
  chrome::ShowSingletonTab(browser(), page1);
  observer1.Wait();
  tab_count++;
  host_count++;
  EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
  EXPECT_EQ(host_count, RenderProcessHostCount());

  // DevTools start in docked mode (no new tab), in a separate process.
  chrome::ToggleDevToolsWindow(browser(), DEVTOOLS_TOGGLE_ACTION_INSPECT);
  host_count++;
  EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
  EXPECT_EQ(host_count, RenderProcessHostCount());

  RenderViewHost* devtools = FindFirstDevToolsHost();
  DCHECK(devtools);

  // DevTools start in a separate process.
  DevToolsWindow::ToggleDevToolsWindow(
      devtools, true, DEVTOOLS_TOGGLE_ACTION_INSPECT);
  host_count++;
  EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
  EXPECT_EQ(host_count, RenderProcessHostCount());
}
<commit_msg>Mark ProcessOverflow test as SLOW<commit_after>// Copyright (c) 2012 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/command_line.h"
#include "chrome/browser/devtools/devtools_window.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/singleton_tabs.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/chrome_switches.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/public/browser/notification_service.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"

using content::RenderViewHost;
using content::RenderWidgetHost;
using content::WebContents;

namespace {

int RenderProcessHostCount() {
  content::RenderProcessHost::iterator hosts =
      content::RenderProcessHost::AllHostsIterator();
  int count = 0;
  while (!hosts.IsAtEnd()) {
    if (hosts.GetCurrentValue()->HasConnection())
      count++;
    hosts.Advance();
  }
  return count;
}

RenderViewHost* FindFirstDevToolsHost() {
  content::RenderProcessHost::iterator hosts =
      content::RenderProcessHost::AllHostsIterator();
  for (; !hosts.IsAtEnd(); hosts.Advance()) {
    content::RenderProcessHost* render_process_host = hosts.GetCurrentValue();
    DCHECK(render_process_host);
    if (!render_process_host->HasConnection())
      continue;
    content::RenderProcessHost::RenderWidgetHostsIterator iter(
        render_process_host->GetRenderWidgetHostsIterator());
    for (; !iter.IsAtEnd(); iter.Advance()) {
      const RenderWidgetHost* widget = iter.GetCurrentValue();
      DCHECK(widget);
      if (!widget || !widget->IsRenderView())
        continue;
      RenderViewHost* host =
          RenderViewHost::From(const_cast<RenderWidgetHost*>(widget));
      WebContents* contents = WebContents::FromRenderViewHost(host);
      GURL url = contents->GetURL();
      if (url.SchemeIs(chrome::kChromeDevToolsScheme))
        return host;
    }
  }
  return NULL;
}

}  // namespace

class ChromeRenderProcessHostTest : public InProcessBrowserTest {
 public:
  ChromeRenderProcessHostTest() {}

  // Show a tab, activating the current one if there is one, and wait for
  // the renderer process to be created or foregrounded, returning the process
  // handle.
  base::ProcessHandle ShowSingletonTab(const GURL& page) {
    chrome::ShowSingletonTab(browser(), page);
    WebContents* wc = browser()->tab_strip_model()->GetActiveWebContents();
    CHECK(wc->GetURL() == page);

    // Ensure that the backgrounding / foregrounding gets a chance to run.
    content::BrowserThread::PostTaskAndReply(
        content::BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
        base::Bind(&base::DoNothing), MessageLoop::QuitClosure());
    MessageLoop::current()->Run();

    return wc->GetRenderProcessHost()->GetHandle();
  }

  // When we hit the max number of renderers, verify that the way we do process
  // sharing behaves correctly.  In particular, this test is verifying that even
  // when we hit the max process limit, that renderers of each type will wind up
  // in a process of that type, even if that means creating a new process.
  void TestProcessOverflow() {
    int tab_count = 1;
    int host_count = 1;
    WebContents* tab1 = NULL;
    WebContents* tab2 = NULL;
    content::RenderProcessHost* rph1 = NULL;
    content::RenderProcessHost* rph2 = NULL;
    content::RenderProcessHost* rph3 = NULL;

    // Change the first tab to be the new tab page (TYPE_WEBUI).
    GURL newtab(chrome::kChromeUINewTabURL);
    ui_test_utils::NavigateToURL(browser(), newtab);
    EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
    tab1 = browser()->tab_strip_model()->GetWebContentsAt(tab_count - 1);
    rph1 = tab1->GetRenderProcessHost();
    EXPECT_EQ(tab1->GetURL(), newtab);
    EXPECT_EQ(host_count, RenderProcessHostCount());

    // Create a new TYPE_TABBED tab.  It should be in its own process.
    GURL page1("data:text/html,hello world1");

    ui_test_utils::WindowedTabAddedNotificationObserver observer1(
        content::NotificationService::AllSources());
    chrome::ShowSingletonTab(browser(), page1);
    observer1.Wait();

    tab_count++;
    host_count++;
    EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
    tab1 = browser()->tab_strip_model()->GetWebContentsAt(tab_count - 1);
    rph2 = tab1->GetRenderProcessHost();
    EXPECT_EQ(tab1->GetURL(), page1);
    EXPECT_EQ(host_count, RenderProcessHostCount());
    EXPECT_NE(rph1, rph2);

    // Create another TYPE_TABBED tab.  It should share the previous process.
    GURL page2("data:text/html,hello world2");
    ui_test_utils::WindowedTabAddedNotificationObserver observer2(
        content::NotificationService::AllSources());
    chrome::ShowSingletonTab(browser(), page2);
    observer2.Wait();
    tab_count++;
    EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
    tab2 = browser()->tab_strip_model()->GetWebContentsAt(tab_count - 1);
    EXPECT_EQ(tab2->GetURL(), page2);
    EXPECT_EQ(host_count, RenderProcessHostCount());
    EXPECT_EQ(tab2->GetRenderProcessHost(), rph2);

    // Create another TYPE_WEBUI tab.  It should share the process with newtab.
    // Note: intentionally create this tab after the TYPE_TABBED tabs to
    // exercise bug 43448 where extension and WebUI tabs could get combined into
    // normal renderers.
    GURL history(chrome::kChromeUIHistoryURL);
    ui_test_utils::WindowedTabAddedNotificationObserver observer3(
        content::NotificationService::AllSources());
    chrome::ShowSingletonTab(browser(), history);
    observer3.Wait();
    tab_count++;
    EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
    tab2 = browser()->tab_strip_model()->GetWebContentsAt(tab_count - 1);
    EXPECT_EQ(tab2->GetURL(), GURL(history));
    EXPECT_EQ(host_count, RenderProcessHostCount());
    EXPECT_EQ(tab2->GetRenderProcessHost(), rph1);

    // Create a TYPE_EXTENSION tab.  It should be in its own process.
    // (the bookmark manager is implemented as an extension)
    GURL bookmarks(chrome::kChromeUIBookmarksURL);
    ui_test_utils::WindowedTabAddedNotificationObserver observer4(
        content::NotificationService::AllSources());
    chrome::ShowSingletonTab(browser(), bookmarks);
    observer4.Wait();
    tab_count++;
    host_count++;
    EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
    tab1 = browser()->tab_strip_model()->GetWebContentsAt(tab_count - 1);
    rph3 = tab1->GetRenderProcessHost();
    EXPECT_EQ(tab1->GetURL(), bookmarks);
    EXPECT_EQ(host_count, RenderProcessHostCount());
    EXPECT_NE(rph1, rph3);
    EXPECT_NE(rph2, rph3);
  }
};

class ChromeRenderProcessHostTestWithCommandLine
    : public ChromeRenderProcessHostTest {
 protected:
  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
    command_line->AppendSwitchASCII(switches::kRendererProcessLimit, "1");
  }
};

IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTest, ProcessPerTab) {
  // Set max renderers to 1 to force running out of processes.
  content::RenderProcessHost::SetMaxRendererProcessCount(1);

  CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
  parsed_command_line.AppendSwitch(switches::kProcessPerTab);

  int tab_count = 1;
  int host_count = 1;

  // Change the first tab to be the new tab page (TYPE_WEBUI).
  GURL newtab(chrome::kChromeUINewTabURL);
  ui_test_utils::NavigateToURL(browser(), newtab);
  EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
  EXPECT_EQ(host_count, RenderProcessHostCount());

  // Create a new TYPE_TABBED tab.  It should be in its own process.
  GURL page1("data:text/html,hello world1");
  ui_test_utils::WindowedTabAddedNotificationObserver observer1(
      content::NotificationService::AllSources());
  chrome::ShowSingletonTab(browser(), page1);
  observer1.Wait();
  tab_count++;
  host_count++;
  EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
  EXPECT_EQ(host_count, RenderProcessHostCount());

  // Create another TYPE_TABBED tab.  It should share the previous process.
  GURL page2("data:text/html,hello world2");
  ui_test_utils::WindowedTabAddedNotificationObserver observer2(
      content::NotificationService::AllSources());
  chrome::ShowSingletonTab(browser(), page2);
  observer2.Wait();
  tab_count++;
  EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
  EXPECT_EQ(host_count, RenderProcessHostCount());

  // Create another new tab.  It should share the process with the other WebUI.
  ui_test_utils::WindowedTabAddedNotificationObserver observer3(
      content::NotificationService::AllSources());
  chrome::NewTab(browser());
  observer3.Wait();
  tab_count++;
  EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
  EXPECT_EQ(host_count, RenderProcessHostCount());

  // Create another new tab.  It should share the process with the other WebUI.
  ui_test_utils::WindowedTabAddedNotificationObserver observer4(
      content::NotificationService::AllSources());
  chrome::NewTab(browser());
  observer4.Wait();
  tab_count++;
  EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
  EXPECT_EQ(host_count, RenderProcessHostCount());
}

// We don't change process priorities on Mac or Posix because the user lacks the
// permission to raise a process' priority even after lowering it.
#if defined(OS_WIN) || defined(OS_LINUX)
IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTest, Backgrounding) {
  if (!base::Process::CanBackgroundProcesses()) {
    LOG(ERROR) << "Can't background processes";
    return;
  }
  CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
  parsed_command_line.AppendSwitch(switches::kProcessPerTab);

  // Change the first tab to be the new tab page (TYPE_WEBUI).
  GURL newtab(chrome::kChromeUINewTabURL);
  ui_test_utils::NavigateToURL(browser(), newtab);

  // Create a new tab. It should be foreground.
  GURL page1("data:text/html,hello world1");
  base::ProcessHandle pid1 = ShowSingletonTab(page1);
  EXPECT_FALSE(base::Process(pid1).IsProcessBackgrounded());

  // Create another tab. It should be foreground, and the first tab should
  // now be background.
  GURL page2("data:text/html,hello world2");
  base::ProcessHandle pid2 = ShowSingletonTab(page2);
  EXPECT_NE(pid1, pid2);
  EXPECT_TRUE(base::Process(pid1).IsProcessBackgrounded());
  EXPECT_FALSE(base::Process(pid2).IsProcessBackgrounded());

  // Navigate back to first page. It should be foreground again, and the second
  // tab should be background.
  EXPECT_EQ(pid1, ShowSingletonTab(page1));
  EXPECT_FALSE(base::Process(pid1).IsProcessBackgrounded());
  EXPECT_TRUE(base::Process(pid2).IsProcessBackgrounded());
}
#endif

IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTest, SLOW_ProcessOverflow) {
  // Set max renderers to 1 to force running out of processes.
  content::RenderProcessHost::SetMaxRendererProcessCount(1);
  TestProcessOverflow();
}

// Variation of the ProcessOverflow test, which is driven through command line
// parameter instead of direct function call into the class.
IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTestWithCommandLine,
                       ProcessOverflow) {
  TestProcessOverflow();
}

// Ensure that DevTools opened to debug DevTools is launched in a separate
// process when --process-per-tab is set. See crbug.com/69873.
IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTest,
                       DevToolsOnSelfInOwnProcessPPT) {
  CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
  parsed_command_line.AppendSwitch(switches::kProcessPerTab);

  int tab_count = 1;
  int host_count = 1;

  GURL page1("data:text/html,hello world1");
  ui_test_utils::WindowedTabAddedNotificationObserver observer1(
      content::NotificationService::AllSources());
  chrome::ShowSingletonTab(browser(), page1);
  observer1.Wait();
  tab_count++;
  host_count++;
  EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
  EXPECT_EQ(host_count, RenderProcessHostCount());

  // DevTools start in docked mode (no new tab), in a separate process.
  chrome::ToggleDevToolsWindow(browser(), DEVTOOLS_TOGGLE_ACTION_INSPECT);
  host_count++;
  EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
  EXPECT_EQ(host_count, RenderProcessHostCount());

  RenderViewHost* devtools = FindFirstDevToolsHost();
  DCHECK(devtools);

  // DevTools start in a separate process.
  DevToolsWindow::ToggleDevToolsWindow(
      devtools, true, DEVTOOLS_TOGGLE_ACTION_INSPECT);
  host_count++;
  EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
  EXPECT_EQ(host_count, RenderProcessHostCount());
}

// Ensure that DevTools opened to debug DevTools is launched in a separate
// process. See crbug.com/69873.
IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTest,
                       DevToolsOnSelfInOwnProcess) {
  int tab_count = 1;
  int host_count = 1;

  GURL page1("data:text/html,hello world1");
  ui_test_utils::WindowedTabAddedNotificationObserver observer1(
      content::NotificationService::AllSources());
  chrome::ShowSingletonTab(browser(), page1);
  observer1.Wait();
  tab_count++;
  host_count++;
  EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
  EXPECT_EQ(host_count, RenderProcessHostCount());

  // DevTools start in docked mode (no new tab), in a separate process.
  chrome::ToggleDevToolsWindow(browser(), DEVTOOLS_TOGGLE_ACTION_INSPECT);
  host_count++;
  EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
  EXPECT_EQ(host_count, RenderProcessHostCount());

  RenderViewHost* devtools = FindFirstDevToolsHost();
  DCHECK(devtools);

  // DevTools start in a separate process.
  DevToolsWindow::ToggleDevToolsWindow(
      devtools, true, DEVTOOLS_TOGGLE_ACTION_INSPECT);
  host_count++;
  EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
  EXPECT_EQ(host_count, RenderProcessHostCount());
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: prnsetup.cxx,v $
 * $Revision: 1.10 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_svtools.hxx"
#include <tools/debug.hxx>
#ifndef _VCL_PRINT_HXX
#include <vcl/print.hxx>
#endif

#ifndef GCC
#endif

#include <svtools/svtdata.hxx>
#include "prnsetup.hrc"
#include <svtools/prnsetup.hxx>

// =======================================================================

void ImplFillPrnDlgListBox( const Printer* pPrinter,
                            ListBox* pBox, PushButton* pPropBtn )
{
    ImplFreePrnDlgListBox( pBox );

    const std::vector<rtl::OUString>& rPrinters = Printer::GetPrinterQueues();
    unsigned int nCount = rPrinters.size();
    if ( nCount )
    {
        for( unsigned int i = 0; i < nCount; i++ )
            pBox->InsertEntry( rPrinters[i] );
        pBox->SelectEntry( pPrinter->GetName() );
    }

    pBox->Enable( nCount != 0 );
    pPropBtn->Enable( pPrinter->HasSupport( SUPPORT_SETUPDIALOG ) );
}

// -----------------------------------------------------------------------

void ImplFreePrnDlgListBox( ListBox* pBox, BOOL bClear )
{
    if ( bClear )
        pBox->Clear();
}

// -----------------------------------------------------------------------

Printer* ImplPrnDlgListBoxSelect( ListBox* pBox, PushButton* pPropBtn,
                                  Printer* pPrinter, Printer* pTempPrinter )
{
    if ( pBox->GetSelectEntryPos() != LISTBOX_ENTRY_NOTFOUND )
    {
        const QueueInfo* pInfo = Printer::GetQueueInfo( pBox->GetSelectEntry(), true );
        if( pInfo)
        {
            if ( !pTempPrinter )
            {
                if ( (pPrinter->GetName() == pInfo->GetPrinterName()) &&
                     (pPrinter->GetDriverName() == pInfo->GetDriver()) )
                    pTempPrinter = new Printer( pPrinter->GetJobSetup() );
                else
                    pTempPrinter = new Printer( *pInfo );
            }
            else
            {
                if ( (pTempPrinter->GetName() != pInfo->GetPrinterName()) ||
                     (pTempPrinter->GetDriverName() != pInfo->GetDriver()) )
                {
                    delete pTempPrinter;
                    pTempPrinter = new Printer( *pInfo );
                }
            }

            pPropBtn->Enable( pTempPrinter->HasSupport( SUPPORT_SETUPDIALOG ) );
        }
        else
            pPropBtn->Disable();
    }
    else
        pPropBtn->Disable();

    return pTempPrinter;
}

// -----------------------------------------------------------------------

Printer* ImplPrnDlgUpdatePrinter( Printer* pPrinter, Printer* pTempPrinter )
{
    XubString aPrnName;
    if ( pTempPrinter )
        aPrnName = pTempPrinter->GetName();
    else
        aPrnName = pPrinter->GetName();

    if ( ! Printer::GetQueueInfo( aPrnName, false ) )
    {
        if ( pTempPrinter )
            delete pTempPrinter;
        pTempPrinter = new Printer;
    }

    return pTempPrinter;
}

// -----------------------------------------------------------------------

void ImplPrnDlgUpdateQueueInfo( ListBox* pBox, QueueInfo& rInfo )
{
    if ( pBox->GetSelectEntryPos() != LISTBOX_ENTRY_NOTFOUND )
    {
        const QueueInfo* pInfo = Printer::GetQueueInfo( pBox->GetSelectEntry(), true );
        if( pInfo )
            rInfo = *pInfo;
    }
}

// -----------------------------------------------------------------------

static void ImplPrnDlgAddString( XubString& rStr, const XubString& rAddStr )
{
    if ( rStr.Len() )
        rStr.AppendAscii( "; " );
    rStr += rAddStr;
}

// -----------------------------------------------------------------------

static void ImplPrnDlgAddResString( XubString& rStr, USHORT nResId )
{
    SvtResId aResId( nResId );
    XubString aAddStr( aResId );
    ImplPrnDlgAddString( rStr, aAddStr );
}

// -----------------------------------------------------------------------

XubString ImplPrnDlgGetStatusText( const QueueInfo& rInfo )
{
    XubString   aStr;
    ULONG       nStatus = rInfo.GetStatus();

    // Default-Printer
    if ( rInfo.GetPrinterName().Len() &&
         (rInfo.GetPrinterName() == Printer::GetDefaultPrinterName()) )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_DEFPRINTER );

    // Status
    if ( nStatus & QUEUE_STATUS_READY )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_READY );
    if ( nStatus & QUEUE_STATUS_PAUSED )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_PAUSED );
    if ( nStatus & QUEUE_STATUS_PENDING_DELETION )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_PENDING );
    if ( nStatus & QUEUE_STATUS_BUSY )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_BUSY );
    if ( nStatus & QUEUE_STATUS_INITIALIZING )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_INITIALIZING );
    if ( nStatus & QUEUE_STATUS_WAITING )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_WAITING );
    if ( nStatus & QUEUE_STATUS_WARMING_UP )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_WARMING_UP );
    if ( nStatus & QUEUE_STATUS_PROCESSING )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_PROCESSING );
    if ( nStatus & QUEUE_STATUS_PRINTING )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_PRINTING );
    if ( nStatus & QUEUE_STATUS_OFFLINE )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_OFFLINE );
    if ( nStatus & QUEUE_STATUS_ERROR )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_ERROR );
    if ( nStatus & QUEUE_STATUS_SERVER_UNKNOWN )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_SERVER_UNKNOWN );
    if ( nStatus & QUEUE_STATUS_PAPER_JAM )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_PAPER_JAM );
    if ( nStatus & QUEUE_STATUS_PAPER_OUT )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_PAPER_OUT );
    if ( nStatus & QUEUE_STATUS_MANUAL_FEED )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_MANUAL_FEED );
    if ( nStatus & QUEUE_STATUS_PAPER_PROBLEM )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_PAPER_PROBLEM );
    if ( nStatus & QUEUE_STATUS_IO_ACTIVE )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_IO_ACTIVE );
    if ( nStatus & QUEUE_STATUS_OUTPUT_BIN_FULL )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_OUTPUT_BIN_FULL );
    if ( nStatus & QUEUE_STATUS_TONER_LOW )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_TONER_LOW );
    if ( nStatus & QUEUE_STATUS_NO_TONER )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_NO_TONER );
    if ( nStatus & QUEUE_STATUS_PAGE_PUNT )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_PAGE_PUNT );
    if ( nStatus & QUEUE_STATUS_USER_INTERVENTION )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_USER_INTERVENTION );
    if ( nStatus & QUEUE_STATUS_OUT_OF_MEMORY )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_OUT_OF_MEMORY );
    if ( nStatus & QUEUE_STATUS_DOOR_OPEN )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_DOOR_OPEN );
    if ( nStatus & QUEUE_STATUS_POWER_SAVE )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_POWER_SAVE );

    // Anzahl Jobs
    ULONG nJobs = rInfo.GetJobs();
    if ( nJobs && (nJobs != QUEUE_JOBS_DONTKNOW) )
    {
        XubString aJobStr( SvtResId( STR_SVT_PRNDLG_JOBCOUNT ) );
        XubString aJobs( XubString::CreateFromInt32( nJobs ) );
        aJobStr.SearchAndReplaceAscii( "%d", aJobs );
        ImplPrnDlgAddString( aStr, aJobStr );
    }

    return aStr;
}

// =======================================================================

PrinterSetupDialog::PrinterSetupDialog( Window* pWindow ) :
    ModalDialog     ( pWindow, SvtResId( DLG_SVT_PRNDLG_PRNSETUPDLG ) ),
    maFlPrinter     ( this, SvtResId( FL_PRINTER ) ),
    maFtName        ( this, SvtResId( FT_NAME ) ),
    maLbName        ( this, SvtResId( LB_NAMES ) ),
    maBtnProperties ( this, SvtResId( BTN_PROPERTIES ) ),
    maBtnOptions    ( this, SvtResId( BTN_OPTIONS ) ),
    maFtStatus      ( this, SvtResId( FT_STATUS ) ),
    maFiStatus      ( this, SvtResId( FI_STATUS ) ),
    maFtType        ( this, SvtResId( FT_TYPE ) ),
    maFiType        ( this, SvtResId( FI_TYPE ) ),
    maFtLocation    ( this, SvtResId( FT_LOCATION ) ),
    maFiLocation    ( this, SvtResId( FI_LOCATION ) ),
    maFtComment     ( this, SvtResId( FT_COMMENT ) ),
    maFiComment     ( this, SvtResId( FI_COMMENT ) ),
    maFlSepButton   ( this, SvtResId( FL_SEPBUTTON ) ),
    maBtnOK         ( this, SvtResId( BTN_OK ) ),
    maBtnCancel     ( this, SvtResId( BTN_CANCEL ) ),
    maBtnHelp       ( this, SvtResId( BTN_HELP ) )
{
    FreeResource();

    // show options button only if link is set
    maBtnOptions.Hide();

    mpPrinter       = NULL;
    mpTempPrinter   = NULL;

    maStatusTimer.SetTimeout( IMPL_PRINTDLG_STATUS_UPDATE );
    maStatusTimer.SetTimeoutHdl( LINK( this, PrinterSetupDialog, ImplStatusHdl ) );
    maBtnProperties.SetClickHdl( LINK( this, PrinterSetupDialog, ImplPropertiesHdl ) );
    maLbName.SetSelectHdl( LINK( this, PrinterSetupDialog, ImplChangePrinterHdl ) );
}

// -----------------------------------------------------------------------

PrinterSetupDialog::~PrinterSetupDialog()
{
    ImplFreePrnDlgListBox( &maLbName, FALSE );
    delete mpTempPrinter;
}

// -----------------------------------------------------------------------

void PrinterSetupDialog::SetOptionsHdl( const Link& rLink )
{
    maBtnOptions.SetClickHdl( rLink );
    maBtnOptions.Show( rLink.IsSet() );
}

const Link& PrinterSetupDialog::GetOptionsHdl() const
{
    return maBtnOptions.GetClickHdl();
}

void PrinterSetupDialog::ImplSetInfo()
{
    const QueueInfo* pInfo = Printer::GetQueueInfo(maLbName.GetSelectEntry(), true);
    if ( pInfo )
    {
        maFiType.SetText( pInfo->GetDriver() );
        maFiLocation.SetText( pInfo->GetLocation() );
        maFiComment.SetText( pInfo->GetComment() );
        maFiStatus.SetText( ImplPrnDlgGetStatusText( *pInfo ) );
    }
    else
    {
        XubString aTempStr;
        maFiType.SetText( aTempStr );
        maFiLocation.SetText( aTempStr );
        maFiComment.SetText( aTempStr );
        maFiStatus.SetText( aTempStr );
    }
}

// -----------------------------------------------------------------------

IMPL_LINK( PrinterSetupDialog, ImplStatusHdl, Timer*, EMPTYARG )
{
    QueueInfo aInfo;
    ImplPrnDlgUpdateQueueInfo( &maLbName, aInfo );
    maFiStatus.SetText( ImplPrnDlgGetStatusText( aInfo ) );

    return 0;
}

// -----------------------------------------------------------------------

IMPL_LINK( PrinterSetupDialog, ImplPropertiesHdl, void*, EMPTYARG )
{
    if ( !mpTempPrinter )
        mpTempPrinter = new Printer( mpPrinter->GetJobSetup() );
    mpTempPrinter->Setup( this );

    return 0;
}

// -----------------------------------------------------------------------

IMPL_LINK( PrinterSetupDialog, ImplChangePrinterHdl, void*, EMPTYARG )
{
    mpTempPrinter = ImplPrnDlgListBoxSelect( &maLbName, &maBtnProperties,
                                             mpPrinter, mpTempPrinter );
    ImplSetInfo();
    return 0;
}

// -----------------------------------------------------------------------

long PrinterSetupDialog::Notify( NotifyEvent& rNEvt )
{
    if ( (rNEvt.GetType() == EVENT_GETFOCUS) && IsReallyVisible() )
        ImplStatusHdl( &maStatusTimer );

    return ModalDialog::Notify( rNEvt );
}

// -----------------------------------------------------------------------

void PrinterSetupDialog::DataChanged( const DataChangedEvent& rDCEvt )
{
    if ( rDCEvt.GetType() == DATACHANGED_PRINTER )
    {
        mpTempPrinter = ImplPrnDlgUpdatePrinter( mpPrinter, mpTempPrinter );
        Printer* pPrn;
        if ( mpTempPrinter )
            pPrn = mpTempPrinter;
        else
            pPrn = mpPrinter;
        ImplFillPrnDlgListBox( pPrn, &maLbName, &maBtnProperties );
        ImplSetInfo();
    }

    ModalDialog::DataChanged( rDCEvt );
}

// -----------------------------------------------------------------------

short PrinterSetupDialog::Execute()
{
    if ( !mpPrinter || mpPrinter->IsPrinting() || mpPrinter->IsJobActive() )
    {
        DBG_ERRORFILE( "PrinterSetupDialog::Execute() - No Printer or printer is printing" );
        return FALSE;
    }

    Printer::updatePrinters();

    ImplFillPrnDlgListBox( mpPrinter, &maLbName, &maBtnProperties );
    ImplSetInfo();
    maStatusTimer.Start();

    // Dialog starten
    short nRet = ModalDialog::Execute();

    // Wenn Dialog mit OK beendet wurde, dann die Daten updaten
    if ( nRet == TRUE )
    {
        if ( mpTempPrinter )
            mpPrinter->SetPrinterProps( mpTempPrinter );
    }

    maStatusTimer.Stop();

    return nRet;
}
<commit_msg>printerpullpages: #i106762# hide properties button instead of disabling it when no printer setup dialog is available<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: prnsetup.cxx,v $
 * $Revision: 1.10 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_svtools.hxx"
#include <tools/debug.hxx>
#ifndef _VCL_PRINT_HXX
#include <vcl/print.hxx>
#endif

#ifndef GCC
#endif

#include <svtools/svtdata.hxx>
#include "prnsetup.hrc"
#include <svtools/prnsetup.hxx>

// =======================================================================

void ImplFillPrnDlgListBox( const Printer* pPrinter,
                            ListBox* pBox, PushButton* pPropBtn )
{
    ImplFreePrnDlgListBox( pBox );

    const std::vector<rtl::OUString>& rPrinters = Printer::GetPrinterQueues();
    unsigned int nCount = rPrinters.size();
    if ( nCount )
    {
        for( unsigned int i = 0; i < nCount; i++ )
            pBox->InsertEntry( rPrinters[i] );
        pBox->SelectEntry( pPrinter->GetName() );
    }

    pBox->Enable( nCount != 0 );
    pPropBtn->Show( pPrinter->HasSupport( SUPPORT_SETUPDIALOG ) );
}

// -----------------------------------------------------------------------

void ImplFreePrnDlgListBox( ListBox* pBox, BOOL bClear )
{
    if ( bClear )
        pBox->Clear();
}

// -----------------------------------------------------------------------

Printer* ImplPrnDlgListBoxSelect( ListBox* pBox, PushButton* pPropBtn,
                                  Printer* pPrinter, Printer* pTempPrinter )
{
    if ( pBox->GetSelectEntryPos() != LISTBOX_ENTRY_NOTFOUND )
    {
        const QueueInfo* pInfo = Printer::GetQueueInfo( pBox->GetSelectEntry(), true );
        if( pInfo)
        {
            if ( !pTempPrinter )
            {
                if ( (pPrinter->GetName() == pInfo->GetPrinterName()) &&
                     (pPrinter->GetDriverName() == pInfo->GetDriver()) )
                    pTempPrinter = new Printer( pPrinter->GetJobSetup() );
                else
                    pTempPrinter = new Printer( *pInfo );
            }
            else
            {
                if ( (pTempPrinter->GetName() != pInfo->GetPrinterName()) ||
                     (pTempPrinter->GetDriverName() != pInfo->GetDriver()) )
                {
                    delete pTempPrinter;
                    pTempPrinter = new Printer( *pInfo );
                }
            }

            pPropBtn->Enable( pTempPrinter->HasSupport( SUPPORT_SETUPDIALOG ) );
        }
        else
            pPropBtn->Disable();
    }
    else
        pPropBtn->Disable();

    return pTempPrinter;
}

// -----------------------------------------------------------------------

Printer* ImplPrnDlgUpdatePrinter( Printer* pPrinter, Printer* pTempPrinter )
{
    XubString aPrnName;
    if ( pTempPrinter )
        aPrnName = pTempPrinter->GetName();
    else
        aPrnName = pPrinter->GetName();

    if ( ! Printer::GetQueueInfo( aPrnName, false ) )
    {
        if ( pTempPrinter )
            delete pTempPrinter;
        pTempPrinter = new Printer;
    }

    return pTempPrinter;
}

// -----------------------------------------------------------------------

void ImplPrnDlgUpdateQueueInfo( ListBox* pBox, QueueInfo& rInfo )
{
    if ( pBox->GetSelectEntryPos() != LISTBOX_ENTRY_NOTFOUND )
    {
        const QueueInfo* pInfo = Printer::GetQueueInfo( pBox->GetSelectEntry(), true );
        if( pInfo )
            rInfo = *pInfo;
    }
}

// -----------------------------------------------------------------------

static void ImplPrnDlgAddString( XubString& rStr, const XubString& rAddStr )
{
    if ( rStr.Len() )
        rStr.AppendAscii( "; " );
    rStr += rAddStr;
}

// -----------------------------------------------------------------------

static void ImplPrnDlgAddResString( XubString& rStr, USHORT nResId )
{
    SvtResId aResId( nResId );
    XubString aAddStr( aResId );
    ImplPrnDlgAddString( rStr, aAddStr );
}

// -----------------------------------------------------------------------

XubString ImplPrnDlgGetStatusText( const QueueInfo& rInfo )
{
    XubString   aStr;
    ULONG       nStatus = rInfo.GetStatus();

    // Default-Printer
    if ( rInfo.GetPrinterName().Len() &&
         (rInfo.GetPrinterName() == Printer::GetDefaultPrinterName()) )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_DEFPRINTER );

    // Status
    if ( nStatus & QUEUE_STATUS_READY )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_READY );
    if ( nStatus & QUEUE_STATUS_PAUSED )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_PAUSED );
    if ( nStatus & QUEUE_STATUS_PENDING_DELETION )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_PENDING );
    if ( nStatus & QUEUE_STATUS_BUSY )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_BUSY );
    if ( nStatus & QUEUE_STATUS_INITIALIZING )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_INITIALIZING );
    if ( nStatus & QUEUE_STATUS_WAITING )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_WAITING );
    if ( nStatus & QUEUE_STATUS_WARMING_UP )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_WARMING_UP );
    if ( nStatus & QUEUE_STATUS_PROCESSING )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_PROCESSING );
    if ( nStatus & QUEUE_STATUS_PRINTING )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_PRINTING );
    if ( nStatus & QUEUE_STATUS_OFFLINE )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_OFFLINE );
    if ( nStatus & QUEUE_STATUS_ERROR )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_ERROR );
    if ( nStatus & QUEUE_STATUS_SERVER_UNKNOWN )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_SERVER_UNKNOWN );
    if ( nStatus & QUEUE_STATUS_PAPER_JAM )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_PAPER_JAM );
    if ( nStatus & QUEUE_STATUS_PAPER_OUT )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_PAPER_OUT );
    if ( nStatus & QUEUE_STATUS_MANUAL_FEED )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_MANUAL_FEED );
    if ( nStatus & QUEUE_STATUS_PAPER_PROBLEM )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_PAPER_PROBLEM );
    if ( nStatus & QUEUE_STATUS_IO_ACTIVE )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_IO_ACTIVE );
    if ( nStatus & QUEUE_STATUS_OUTPUT_BIN_FULL )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_OUTPUT_BIN_FULL );
    if ( nStatus & QUEUE_STATUS_TONER_LOW )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_TONER_LOW );
    if ( nStatus & QUEUE_STATUS_NO_TONER )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_NO_TONER );
    if ( nStatus & QUEUE_STATUS_PAGE_PUNT )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_PAGE_PUNT );
    if ( nStatus & QUEUE_STATUS_USER_INTERVENTION )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_USER_INTERVENTION );
    if ( nStatus & QUEUE_STATUS_OUT_OF_MEMORY )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_OUT_OF_MEMORY );
    if ( nStatus & QUEUE_STATUS_DOOR_OPEN )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_DOOR_OPEN );
    if ( nStatus & QUEUE_STATUS_POWER_SAVE )
        ImplPrnDlgAddResString( aStr, STR_SVT_PRNDLG_POWER_SAVE );

    // Anzahl Jobs
    ULONG nJobs = rInfo.GetJobs();
    if ( nJobs && (nJobs != QUEUE_JOBS_DONTKNOW) )
    {
        XubString aJobStr( SvtResId( STR_SVT_PRNDLG_JOBCOUNT ) );
        XubString aJobs( XubString::CreateFromInt32( nJobs ) );
        aJobStr.SearchAndReplaceAscii( "%d", aJobs );
        ImplPrnDlgAddString( aStr, aJobStr );
    }

    return aStr;
}

// =======================================================================

PrinterSetupDialog::PrinterSetupDialog( Window* pWindow ) :
    ModalDialog     ( pWindow, SvtResId( DLG_SVT_PRNDLG_PRNSETUPDLG ) ),
    maFlPrinter     ( this, SvtResId( FL_PRINTER ) ),
    maFtName        ( this, SvtResId( FT_NAME ) ),
    maLbName        ( this, SvtResId( LB_NAMES ) ),
    maBtnProperties ( this, SvtResId( BTN_PROPERTIES ) ),
    maBtnOptions    ( this, SvtResId( BTN_OPTIONS ) ),
    maFtStatus      ( this, SvtResId( FT_STATUS ) ),
    maFiStatus      ( this, SvtResId( FI_STATUS ) ),
    maFtType        ( this, SvtResId( FT_TYPE ) ),
    maFiType        ( this, SvtResId( FI_TYPE ) ),
    maFtLocation    ( this, SvtResId( FT_LOCATION ) ),
    maFiLocation    ( this, SvtResId( FI_LOCATION ) ),
    maFtComment     ( this, SvtResId( FT_COMMENT ) ),
    maFiComment     ( this, SvtResId( FI_COMMENT ) ),
    maFlSepButton   ( this, SvtResId( FL_SEPBUTTON ) ),
    maBtnOK         ( this, SvtResId( BTN_OK ) ),
    maBtnCancel     ( this, SvtResId( BTN_CANCEL ) ),
    maBtnHelp       ( this, SvtResId( BTN_HELP ) )
{
    FreeResource();

    // show options button only if link is set
    maBtnOptions.Hide();

    mpPrinter       = NULL;
    mpTempPrinter   = NULL;

    maStatusTimer.SetTimeout( IMPL_PRINTDLG_STATUS_UPDATE );
    maStatusTimer.SetTimeoutHdl( LINK( this, PrinterSetupDialog, ImplStatusHdl ) );
    maBtnProperties.SetClickHdl( LINK( this, PrinterSetupDialog, ImplPropertiesHdl ) );
    maLbName.SetSelectHdl( LINK( this, PrinterSetupDialog, ImplChangePrinterHdl ) );
}

// -----------------------------------------------------------------------

PrinterSetupDialog::~PrinterSetupDialog()
{
    ImplFreePrnDlgListBox( &maLbName, FALSE );
    delete mpTempPrinter;
}

// -----------------------------------------------------------------------

void PrinterSetupDialog::SetOptionsHdl( const Link& rLink )
{
    maBtnOptions.SetClickHdl( rLink );
    maBtnOptions.Show( rLink.IsSet() );
}

const Link& PrinterSetupDialog::GetOptionsHdl() const
{
    return maBtnOptions.GetClickHdl();
}

void PrinterSetupDialog::ImplSetInfo()
{
    const QueueInfo* pInfo = Printer::GetQueueInfo(maLbName.GetSelectEntry(), true);
    if ( pInfo )
    {
        maFiType.SetText( pInfo->GetDriver() );
        maFiLocation.SetText( pInfo->GetLocation() );
        maFiComment.SetText( pInfo->GetComment() );
        maFiStatus.SetText( ImplPrnDlgGetStatusText( *pInfo ) );
    }
    else
    {
        XubString aTempStr;
        maFiType.SetText( aTempStr );
        maFiLocation.SetText( aTempStr );
        maFiComment.SetText( aTempStr );
        maFiStatus.SetText( aTempStr );
    }
}

// -----------------------------------------------------------------------

IMPL_LINK( PrinterSetupDialog, ImplStatusHdl, Timer*, EMPTYARG )
{
    QueueInfo aInfo;
    ImplPrnDlgUpdateQueueInfo( &maLbName, aInfo );
    maFiStatus.SetText( ImplPrnDlgGetStatusText( aInfo ) );

    return 0;
}

// -----------------------------------------------------------------------

IMPL_LINK( PrinterSetupDialog, ImplPropertiesHdl, void*, EMPTYARG )
{
    if ( !mpTempPrinter )
        mpTempPrinter = new Printer( mpPrinter->GetJobSetup() );
    mpTempPrinter->Setup( this );

    return 0;
}

// -----------------------------------------------------------------------

IMPL_LINK( PrinterSetupDialog, ImplChangePrinterHdl, void*, EMPTYARG )
{
    mpTempPrinter = ImplPrnDlgListBoxSelect( &maLbName, &maBtnProperties,
                                             mpPrinter, mpTempPrinter );
    ImplSetInfo();
    return 0;
}

// -----------------------------------------------------------------------

long PrinterSetupDialog::Notify( NotifyEvent& rNEvt )
{
    if ( (rNEvt.GetType() == EVENT_GETFOCUS) && IsReallyVisible() )
        ImplStatusHdl( &maStatusTimer );

    return ModalDialog::Notify( rNEvt );
}

// -----------------------------------------------------------------------

void PrinterSetupDialog::DataChanged( const DataChangedEvent& rDCEvt )
{
    if ( rDCEvt.GetType() == DATACHANGED_PRINTER )
    {
        mpTempPrinter = ImplPrnDlgUpdatePrinter( mpPrinter, mpTempPrinter );
        Printer* pPrn;
        if ( mpTempPrinter )
            pPrn = mpTempPrinter;
        else
            pPrn = mpPrinter;
        ImplFillPrnDlgListBox( pPrn, &maLbName, &maBtnProperties );
        ImplSetInfo();
    }

    ModalDialog::DataChanged( rDCEvt );
}

// -----------------------------------------------------------------------

short PrinterSetupDialog::Execute()
{
    if ( !mpPrinter || mpPrinter->IsPrinting() || mpPrinter->IsJobActive() )
    {
        DBG_ERRORFILE( "PrinterSetupDialog::Execute() - No Printer or printer is printing" );
        return FALSE;
    }

    Printer::updatePrinters();

    ImplFillPrnDlgListBox( mpPrinter, &maLbName, &maBtnProperties );
    ImplSetInfo();
    maStatusTimer.Start();

    // Dialog starten
    short nRet = ModalDialog::Execute();

    // Wenn Dialog mit OK beendet wurde, dann die Daten updaten
    if ( nRet == TRUE )
    {
        if ( mpTempPrinter )
            mpPrinter->SetPrinterProps( mpTempPrinter );
    }

    maStatusTimer.Stop();

    return nRet;
}
<|endoftext|>